Deferred Rendering strange behaviour - opengl

I'm having a little trouble implementing a deferred rendering engine using OpenGL.
I can render to texture and all the datas are correct for the first pass (calculating albedo, normals and depth), but when it comes to calculate the textures for the lightning (emissive and specular) I'm having some troubles.
This is what I've got so far:
The problem is, as you might have guessed, is that sort of line showing some sort of division between my red and blue light.
Using NSight to see the history of a pixel right next to the line that should have been red (or blended with a blue light pixel), I can see this:
So the pixel IS actually getting colored by the red light, but then it goes back to blue, and I really can't understand why.
This is the code I use to do deferred drawing:
//
// Preparing albedo, normals and depth
//
GetGBuffer("PrepassBuffer")->BindAsRenderTarget();
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
DeferredPreparePass(stage, shadersManager->GetProgramFromName("deferred-prepare"));
Finish(stage);
//
// Peparing light emissive and specular textures
//
GetGBuffer("LightsBuffer")->BindAsRenderTarget();
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
DeferredPointPass(stage, shadersManager->GetProgramFromName("deferred-point"));
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Finish(stage);
//
// Final composition of the image
//
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
DeferredCombinePass(stage, shadersManager->GetProgramFromName("deferred-combine"));
Finish(stage);
This is the code I use to do the point light pass (DeferredPointPass function call above) (_pointLightMesh is a Icosahedron Sphere mesh)
for (ASizeT i = 0; i < nLights; i++)
{
AnimaLight* light = lightsManager->GetLight((AUint)i);
if (!light->IsPointLight())
continue;
AnimaVertex3f lPos = light->GetPosition();
AFloat range = light->GetRange();
AnimaMatrix m1, m2, m3;
m1.Translate(lPos);
m2.Scale(range, range, range, 1.0f);
m3 = m1 * m2;
float dist = (lPos - activeCamera->GetPosition()).Length();
if (dist < light->GetRange())
glCullFace(GL_FRONT);
else
glCullFace(GL_BACK);
program->UpdateLightProperies(light);
program->UpdateMeshProperies(_pointLightMesh, m3);
program->UpdateRenderingManagerProperies(this);
program->EnableInputs(_pointLightMesh);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _pointLightMesh->GetIndexesBufferObject());
glDrawElements(GL_TRIANGLES, _pointLightMesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0);
program->DisableInputs();
}
And this is the shader I use to calculate my emissive and specular maps for the point lightn pass:
#version 150 core
in mat4 frag_inverseProjectionViewMatrix;
out vec4 FragColor[2];
uniform sampler2D REN_GB_PrepassBuffer_DepthMap;
uniform sampler2D REN_GB_PrepassBuffer_NormalMap;
uniform vec2 REN_InverseScreenSize;
uniform vec3 CAM_Position;
uniform float PTL_Range;
uniform vec3 PTL_Position;
uniform vec3 PTL_Color;
uniform float PTL_ConstantAttenuation;
uniform float PTL_LinearAttenuation;
uniform float PTL_ExponentAttenuation;
void main()
{
vec3 pos = vec3((gl_FragCoord.x * REN_InverseScreenSize.x), (gl_FragCoord.y * REN_InverseScreenSize.y), 0.0f);
pos.z = texture(REN_GB_PrepassBuffer_DepthMap, pos.xy).r;
vec3 normal = normalize(texture(REN_GB_PrepassBuffer_NormalMap, pos.xy).xyz * 2.0f - 1.0f);
vec4 clip = frag_inverseProjectionViewMatrix * vec4(pos * 2.0f - 1.0f, 1.0f);
pos = clip.xyz / clip.w;
float dist = length(PTL_Position - pos);
if(dist > PTL_Range)
{
discard;
}
float atten = (PTL_ConstantAttenuation + PTL_LinearAttenuation * dist + PTL_ExponentAttenuation * dist * dist + 0.00001);
vec3 incident = normalize(PTL_Position - pos);
vec3 viewDir = normalize(CAM_Position - pos);
vec3 halfDir = normalize(incident + viewDir);
float lambert = clamp(dot(incident, normal), 0.0f, 1.0f);
float rFactor = clamp(dot(halfDir, normal), 0.0f, 1.0f);
float sFactor = pow(rFactor, 33.0f);
FragColor[0] = vec4(PTL_Color * lambert / atten, 1.0f);
FragColor[1] = vec4(PTL_Color * sFactor / atten * 0.33f, 1.0f);
}
I hope someone has and idea of what's going on here, thanks in advance!

Ok I figured out what I was missing. I needed to disable depth test before doing the point light pass and the re-enable it to combine the final image.
My code for the deferred rendering function now looks like this (all the rest is still the same):
// Same as before
// ...
//
//
// Peparing light emissive and specular textures
//
GetGBuffer("LightsBuffer")->BindAsRenderTarget();
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDepthMask(GL_FALSE); // <---- this is what I was missing
DeferredPointPass(stage, shadersManager->GetProgramFromName("deferred-point"));
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_TRUE); // <---- this is what I was missing
Finish(stage);
// Same as before
// ...
//

Related

How to Rotate a Quad

I'm trying to make a quad rotate around its center. I am using glm::rotate() and setting the quad to rotate on the z axis. However when I do this it gives this weird effect. The quad stretches and warps. It almost looks 3d but since I am rotating it around the z axis that shouldn't happen right?
Here's relevant code for context:
float rotation = 0.0f;
double prevTime = glfwGetTime();
while (!glfwWindowShouldClose(window))
{
GLCall(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GLCall(glClear(GL_COLOR_BUFFER_BIT));
updateInput(window);
shader.Use();
glUniform1f(xMov, x);
glUniform1f(yMov, y);
test.Bind();
double crntTime = glfwGetTime();
if (crntTime - prevTime >= 1 / 60)
{
rotation += 0.5f;
prevTime = crntTime;
}
glm::mat4 model = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f));
int modelLoc = glGetUniformLocation(shader.id, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
vao.Bind();
vBuffer1.Bind();
iBuffer1.Bind();
GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
glfwSwapBuffers(window);
glfwPollEvents();
}
Shader:
#version 440 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTex;
out vec3 color;
out vec2 texCoord;
uniform float xMove;
uniform float yMove;
uniform mat4 model;
void main()
{
gl_Position = model * vec4(aPos.x + xMove, aPos.y + yMove, aPos.z, 1.0);
color = aColor;
texCoord = aTex;
}
Without you showing the graphical output it is hard to say.
Your first issue is, you are not rotating around the center, to rotate by the center you must, offset the quad so that its center is at 0,0. then rotate, then offset back to the original position, but you have this line:
gl_Position = model * vec4(aPos.x + xMove, aPos.y + yMove, aPos.z, 1.0);
Under the assumption that the quad as at the origin to begin with you are rotating it around the point (-xMove, -yMove).

OpenGL Projection Matrix showing Orthographic

I got an orthographic camera working however I wanted to try and implement a perspective camera so I can do some parallax effects later down the line. I am having some issues when trying to implement it. It seems like the depth is not working correctly. I am rotating a 2d image along the x-axis to simulate it laying somewhat down so I get see the projection matrix working. It is still showing as an orthographic perspective though.
Here is some of my code:
CameraPersp::CameraPersp() :
_camPos(0.0f,0.0f,0.0f), _modelMatrix(1.0f), _viewMatrix(1.0f), _projectionMatrix(1.0f)
Function called init to setup the matrix variables:
void CameraPersp::init(int screenWidth, int screenHeight)
{
_screenHeight = screenHeight;
_screenWidth = screenWidth;
_modelMatrix = glm::translate(_modelMatrix, glm::vec3(0.0f, 0.0f, 0.0f));
_modelMatrix = glm::rotate(_modelMatrix, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
_viewMatrix = glm::translate(_viewMatrix, glm::vec3(0.0f, 0.0f, -3.0f));
_projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast<float>(_screenWidth) / _screenHeight, 0.1f, 100.0f);
}
Initializing a texture to be loaded in with x,y,z,width,height,src
_sprites.back()->init(-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, "src/content/sprites/DungeonCrawlStoneSoupFull/monster/deep_elf_death_mage.png");
Sending in the matrices to the vertexShader:
GLint mLocation = _colorProgram.getUniformLocation("M");
glm::mat4 mMatrix = _camera.getMMatrix();
//glUniformMatrix4fv(mLocation, 1, GL_FALSE, &(mMatrix[0][0]));
glUniformMatrix4fv(mLocation, 1, GL_FALSE, glm::value_ptr(mMatrix));
GLint vLocation = _colorProgram.getUniformLocation("V");
glm::mat4 vMatrix = _camera.getVMatrix();
//glUniformMatrix4fv(vLocation, 1, GL_FALSE, &(vMatrix[0][0]));
glUniformMatrix4fv(vLocation, 1, GL_FALSE, glm::value_ptr(vMatrix));
GLint pLocation = _colorProgram.getUniformLocation("P");
glm::mat4 pMatrix = _camera.getPMatrix();
//glUniformMatrix4fv(pLocation, 1, GL_FALSE, &(pMatrix[0][0]));
glUniformMatrix4fv(pLocation, 1, GL_FALSE, glm::value_ptr(pMatrix));
Here is my vertex shader:
#version 460
//The vertex shader operates on each vertex
//input data from VBO. Each vertex is 2 floats
in vec3 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
out vec3 fragPosition;
out vec4 fragColor;
out vec2 fragUV;
//uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
void main() {
//Set the x,y position on the screen
//gl_Position.xy = vertexPosition;
gl_Position = M * V * P * vec4(vertexPosition, 1.0);
//the z position is zero since we are 2d
//gl_Position.z = 0.0;
//indicate that the coordinates are nomalized
gl_Position.w = 1.0;
fragPosition = vertexPosition;
fragColor = vertexColor;
// opengl needs to flip the coordinates
fragUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
I can see the image "squish" a little because it is still rendering the perspective as orthographic. If I remove the rotation on the x-axis, it is not longer squished because it isn't laying down at all. Any thoughts on what I am doing wrong? I can supply more info upon request but I think I put in most of the meat of things.
Picture:
You shouldn't modify gl_Position.w
gl_Position = M * V * P * vec4(vertexPosition, 1.0); // gl_Position is good
//indicate that the coordinates are nomalized < not true
gl_Position.w = 1.0; // Now perspective divisor is lost, projection isn't correct

How to add countless lights in framebuffer

Following the learnopengl tutorial (https://learnopengl.com/Advanced-Lighting/Deferred-Shading)
the author leaves fixed the amount of light (32 lights) as shown by the GLSL:
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;
struct Light {
vec3 Position;
color;
};
const int NR_LIGHTS = 32;
uniform Light lights [NR_LIGHTS];
uniform vec3 viewPos;
void main ()
{
// retrieve data from G-buffer
vec3 FragPos = texture (gPosition, TexCoords) .rgb;
vec3 Normal = texture (gNormal, TexCoords) .rgb;
vec3 Albedo = texture (gAlbedoSpec, TexCoords) .rgb;
float Specular = texture (gAlbedoSpec, TexCoords) .a;
// then calculate lighting as usual
vec3 lighting = Albedo * 0.1; // hard-coded ambient component
vec3 viewDir = normalize (viewPos - FragPos);
for (int i = 0; i <NR_LIGHTS; ++ i)
{
// diffuse
vec3 lightDir = normalize (lights [i] .Position - FragPos);
vec3 diffuse = max (dot (Normal, lightDir), 0.0) * Albedo * lights [i] .Color;
lighting + = diffuse;
}
FragColor = vec4 (lighting, 1.0);
}
And when it comes to applying the lights:
glBindFramebuffer (GL_FRAMEBUFFER, 0);
// 2. lighting pass: calculate lighting by iterating over screen filled quad pixel-by-pixel using the gbuffer's content.
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shaderLightingPass.use ();
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, gPosition);
glActiveTexture (GL_TEXTURE1);
glBindTexture (GL_TEXTURE_2D, gNormal);
glActiveTexture (GL_TEXTURE2);
glBindTexture (GL_TEXTURE_2D, gAlbedoSpec);
// send light relevant uniforms
for (unsigned int i = 0; i <lightPositions.size (); i ++)
{
shaderLightingPass.setVec3 ("lights [" + std :: to_string (i) + "] .Position", lightPositions [i]);
shaderLightingPass.setVec3 ("lights [" + std :: to_string (i) + "] .Color", lightColors [i]);
// update attenuation parameters and calculate radius
const float constant = 1.0; // note that we do not send this to the shader, we assume it is always 1.0 (in our case)
const float linear = 0.7;
const float quadratic = 1.8;
shaderLightingPass.setFloat ("lights [" + std :: to_string (i) + "] .Linear", linear);
shaderLightingPass.setFloat ("lights [" + std :: to_string (i) + "] .Quadratic", quadratic);
}
shaderLightingPass.setVec3 ("viewPos", camera.Position);
// finally render quad
renderQuad ();
but I would like to be able to add as many lights as I want, because my project will have countless lights (laser guns, bonfire, blast), so I made some changes:
GLSL:
uniform Light light;
uniform vec3 viewPos;
void main()
{
// retrieve data from gbuffer
vec3 FragPos = texture(gPosition, TexCoords).rgb;
vec3 Normal = texture(gNormal, TexCoords).rgb;
vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb;
float Specular = texture(gAlbedoSpec, TexCoords).a;
// then calculate lighting as usual
vec3 lighting = Diffuse * 0.1; // hard-coded ambient component
vec3 viewDir = normalize(viewPos - FragPos);
// diffuse
vec3 lightDir = normalize(light.Position - FragPos);
vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * light.Color;
// specular
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0);
vec3 specular = light.Color * spec * Specular;
// attenuation
float distance = length(light.Position - FragPos);
float attenuation = 1.0 / (1.0 + light.Linear * distance + light.Quadratic * distance * distance);
diffuse *= attenuation;
specular *= attenuation;
lighting += diffuse + specular;
FragColor = vec4(lighting, 1.0);
}
And then I passed the values one by one and rendered a quad:
for (unsigned int i = 0; i < lightPositions.size(); i++)
{
shaderLightingPass.use();
shaderLightingPass.setInt("gPosition", 0);
shaderLightingPass.setInt("gNormal", 1);
shaderLightingPass.setInt("gAlbedoSpec", 2);
shaderLightingPass.setVec3("light.Position", lightPositions[i]);
shaderLightingPass.setVec3("light.Color", lightColors[i]);
const float constant = 1.0; // note that we don't send this to the shader, we assume it is always 1.0 (in our case)
const float linear = 0.7;
const float quadratic = 0.08;
shaderLightingPass.setFloat("light.Linear", linear);
shaderLightingPass.setFloat("light.Quadratic", quadratic);
shaderLightingPass.setVec3("viewPos", camera.Position);
renderQuad();
glUseProgram(-1);
}
and also added a new shader to render the framebuffer on the screen:
screenShader.use();
renderQuad();
but my code renders only the first light:
Result
could anyone tell me what I am doing wrong and how to add the lights in the end result?
Please include code like below
void renderDeferredPass(int i)
{
glUseProgram(ps[Passes::Deferred]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_fbo);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
//mat4 model = glm::scale(mat4(1.0f), vec3(3.1f, 3.1f, 3.1f));
model = glm::translate(mat4(1.0f), vec3(-150.0f, -600.0f, -800.0f+camera));
model = glm::rotate(model, 30.0f, vec3(0.0f, 1.0f, 0.0f));
mat4 view = glm::lookAt(glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 0.0, -5.0), glm::vec3(0.0, 1.0, 0.0));
glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &model[0][0]);
glUniformMatrix4fv(viewLocation, 1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(projLocation, 1, GL_FALSE, &projection[0][0]);
glUniform1i(textureLocation, 0);
quad->Render();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glUseProgram(0);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
}
And
void renderLightPass()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glUseProgram(ps[Passes::LightPass]);
glBindVertexArray(quadVAO);
bindUbo();
for (unsigned int i = 0; i < NUM_GBUFFER_TEXTURES; i++)
{
glActiveTexture(GL_TEXTURE1 + i);
glBindTexture(GL_TEXTURE_2D,
g_textures[POSITION_TEXTURE + i]);
}
glUniform1i(mapLocations[POSITION_TEXTURE], 1);
glUniform1i(mapLocations[DIFFUSE_TEXTURE], 2);
glUniform1i(mapLocations[NORMAL_TEXTURE], 3);
glUniform1i(mapLocations[TEXCOORD_TEXTURE], 4);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glUseProgram(0);
glBindVertexArray(0);
glEnable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
And your draw function should look like
void display()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glGenerateMipmap(GL_TEXTURE_2D);
glEnable(GL_MULTISAMPLE);
//for (int i = 0; i < quad->m_Entries.size(); i++)
{
renderDeferredPass(0);
renderLightPass();
}
glutSwapBuffers();
glutPostRedisplay();
}
For complete implementation refer following
https://github.com/PixelClear/Deferred-renderer
I have above code where we store light information in SSBO so this demo has 32 lights but can easily extended to many.
The problem is due to the fixed "ambient" term being repeated for the # of lights that overlap the scene.
The shader contains:
vec3 lighting = Diffuse * 0.1; // hard-coded ambient component
This effectively re-adds albedo everytime a light overlaps.
The old code had the following sum:
vec3 lighting = Diffuse * 0.1;
foreach (Light l : lights)
lighting += Diffuse * (l's diffuse lighting)
But now with additive blending you have:
foreach (Light l : lights)
lighting += Diffuse * 0.1;
lighting += Diffuse * (l's diffuse lighting)
As such you got the overbrightening of ambient in https://i.ibb.co/gMBtM6c/With-Blend.png
To fix this you need to separate the (Diffuse * 0.1) term into a separate shader. You would have 1 draw call to apply ambient, then n draw calls for n lights.
The algorithm on the C++ side would then look like:
Make sure you have additive blend still.
Clear Screen
Set Ambient shader, Draw Quad.
Set Light shader, Do your lighting loop and Draw n Quads for n lights.
EDIT: Also it looks like you aren't reading the right Albedo texture based off of your screenshots. It looks like you are reading the position buffer based off of the colors you're getting.

OpenGL Depth Buffer not using z value

I have a QtOpenglWidget with OpenGL 3.3 running and attempting to do instance rendering, but my z-buffer will not work
Currently, I add the 3 test cubes in draw order of cube3, cube2, then cube1 and changing it shows it is just displaying the last cube drawn. I also know DEPTH_TEST is enabled as messing with glDepthFunc will just not show anything.
My init:
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
My Draw:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Vertex:
layout(location = 0) in highp vec3 position;
layout(location = 1) in highp mat4 modelToWorld;
uniform mat4 MVP;
out highp float DEPTH;
void main() {
gl_Position = MVP * modelToWorld * vec4(position, 1.0);
DEPTH = gl_Position.z / 20.0f;
}
Frag:
in highp float DEPTH;
out highp vec4 fColor;
void main() {
fColor = vec4(DEPTH, DEPTH, DEPTH,1.0);
}
EDIT
I am finding out this might be a QtWidget issue, The first thing being called in main is
QSurfaceFormat format;
format.setVersion(3, 3);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
After HOURS of debugging and referencing examples, I found the issue!
It was this line
void MyWidget::resizeGL(int width, int height) {
...
m_projection.perspective(45.0f, width / float(height), 0.0f, 1000.0f);
...
}
it should be
void MyWidget::resizeGL(int width, int height) {
...
m_projection.perspective(45.0f, width / float(height), 0.1f, 1000.0f);
...
}
Apparently setting my projection with a nearPlane to 0 causes this. I actually don't know WHY this occurs so please enlighten me in comments if you know
Note: this is the QMatrix4x4 class

OpenGL Matrices and Shaders Confusion

I've been following a tutorial on modern OpenGL with the GLM library
I'm on a segment where we introduce matrices for transforming models, positioning the camera, and adding perspective.
I've got a triangle:
const GLfloat vertexBufferData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
I've got my shaders:
GLuint programID = loadShaders("testVertexShader.glsl",
"testFragmentShader.glsl");
I've got a model matrix that does no transformations:
glm::mat4 modelMatrix = glm::mat4(1.0f); /* Identity matrix */
I've got a camera matrix:
glm::mat4 cameraMatrix = glm::lookAt(
glm::vec3(4.0f, 4.0f, 3.0f), /*Camera position*/
glm::vec3(0.0f, 0.0f, 0.0f), /*Camera target*/
glm::vec3(0.0f, 1.0f, 0.0f) /*Up vector*/
);
And I've got a projection matrix:
glm::mat4 projectionMatrix = glm::perspective(
90.0f, /*FOV in degrees*/
4.0f / 3.0f, /*Aspect ratio*/
0.1f, /*Near clipping distance*/
100.0f /*Far clipping distance*/
);
Then I multiply all the matrices together to get the final matrix for the triangle I want to draw:
glm::mat4 finalMatrix = projectionMatrix
* cameraMatrix
* modelMatrix;
Then I send the matrix to GLSL (I think?):
GLuint matrixID = glGetUniformLocation(programID, "MVP");
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &finalMatrix[0][0]);
Then I do shader stuff I don't understand very well:
/*vertex shader*/
#version 330 core
in vec3 vertexPosition_modelspace;
uniform mat4 MVP;
void main(){
vec4 v = vec4(vertexPosition_modelspace, 1);
gl_Position = MVP * v;
}
/*fragment shader*/
#version 330 core
out vec3 color;
void main(){
color = vec3(1, 1, 0);
}
Everything compiles and runs, but I see no triangle. I've moved the triangle and camera around, thinking maybe the camera was pointed the wrong way, but with no success. I was able to successfully get a triangle on the screen before we introduced matrices, but now, no triangle. The triangle should be at origin, and the camera is a few units away from origin, looking at origin.
Turns out, you need to send the matrix to the shader after you've bound the shader.
In other words, you call glUniformMatrix4fv() after glUseProgram()
Lots of things could be your problem - try outputting a vec4 color instead, with alpha explicitly set to 1. One thing I often do as a sanity check is to have the vertex shader ignore all inputs, and to just output vertices directly, e.g. something like:
void main(){
if (gl_VertexID == 0) {
gl_Position = vec4(-1, -1, 0, 1);
} else if (gl_VertexID == 1) {
gl_Position = vec4(1, -1, 0, 1);
} else if (gl_VertexID == 2) {
gl_Position = vec4(0, 1, 0, 1);
}
}
If that works, then you can try adding your vertex position input back in. If that works, you can add your camera or projection matrices back in, etc.
More generally, remove things until something works, and you understand why it works, and then add parts back in until you stop understanding why things don't work. Quite often I've been off by a sign, or in the order of multiplication.