There seems to be an odd problem with my Phong lighting shader in OpenGL. The specular highlight appears on the wrong side of the object.
The problem at hand:
As you can see, the specular highlight appears on the opposite side of the cube (and also appears in the corners of the perpendicular edges of the cube, from the light's perspective. It should only appear on the side closest to the light.
The cube's vertices:
float cubeVertices[] = {
// positions // normals // texture coords
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
The vertex shader:
#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos = vec3(model * vec4(vPos, 1.0));
Normal = mat3(transpose(inverse(model))) * vNormal;
TexCoords = vTexCoords;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
The fragment shader:
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform sampler2D diffuseMap;
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light lights[8];
uniform int numLights;
vec3 calculateAmbient(vec3 fragPos, vec3 materialAmbient)
{
vec3 ambient = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
ambient += lights[i].ambient * materialAmbient;
}
return ambient * 0.5;
}
vec3 calculateDiffuse(vec3 fragPos, vec3 normal, vec3 materialDiffuse)
{
vec3 diffuse = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
float diff = max(dot(normal, lightDir), 0.0);
diffuse += lights[i].diffuse * (diff * materialDiffuse);
}
return diffuse;
}
vec3 calculateSpecular(vec3 fragPos, vec3 normal, vec3 viewDir, vec3 materialSpecular, float shininess)
{
vec3 specular = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
specular += lights[i].specular * (spec * materialSpecular);
}
return specular;
}
void main()
{
vec4 tex = texture(diffuseMap, TexCoords);
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 ambient = calculateAmbient(FragPos, material.ambient);
vec3 diffuse = calculateDiffuse(FragPos, norm, material.diffuse);
vec3 specular = calculateSpecular(FragPos, norm, viewDir, material.specular, material.shininess);
vec3 result = (ambient + diffuse + specular) * tex.rgb;
FragColor = vec4(result, 1.0);
}
The specular highlight appears also on the faces which are back side facing to the light source, because relfect actually computes:
refelct(I, N) = I - 2.0 * dot(N, I) * N
On back faces the normal vector points away from the light source, but refelct(I, N) == refelct(I, -N), because:
I - 2.0 * dot(N, I) * N == I - 2.0 * dot(-N, I) * -N
In the Phong reflection model, the specular hightlight is only add, if the diffuse light is > 0. e.g:
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
float NdotL = dot(normal, lightDir);
if (NdotL > 0.0)
{
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
specular += lights[i].specular * (spec * materialSpecular);
}
}
Opengl has right-hand coordinate system. It means z values increase towards me.
right-hand coordinate system
I draw two triangles:
float vertices[] =
{
//position //color
//triangle 1
0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//0
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//1
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//2
//triangle 2
0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//3
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//4
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f//5
};
Why triangle 1 is in front? Triangle 2 should be in front, because of 0.0f > -1.0f.
I have only gl_Position = vec4(aPos, 1.0); in vertex shader.
After it, if I translate vertices by z=-3 in vertex shader, this translation behaves as it should be. Object becomes further.
Why triangle 1 is in front? Triangle 2 should be in front, because of 0.0f > -1.0f.
I have only gl_Position = vec4(aPos, 1.0); in vertex shader.
Of course the red triangle is in front of the blue one, because you don't use any projection matrix. You forgot to transform the input vertex by the projection matrix before you assign the vertex coordinate to gl_Position.
This causes that the vertices are equal to the normalized device space coordinates. In normalized device space the z-axis points into the viewport and the "projection" is orthographic and not perspective.
You have to do something like this:
in vec3 aPos;
mat4 modelProjectionMatrix;
void main()
{
gl_Position = modelProjectionMatrix * vec4(aPos, 1.0);
}
I'was displaying a cube in opengl. Here is my file for vertex shader
#version 330
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 color;
smooth out vec4 theColor;
uniform vec3 offset;
uniform mat4 perspectiveMatrix;
void main()
{
vec4 cameraPos = position + vec4(offset.x, offset.y, offset.z, 0.0);
//gl_Position = perspectiveMatrix * cameraPos;
gl_Position.xy = cameraPos.xy;
gl_Position.z = cameraPos.z*2.0f + 3.0f;
gl_Position.w = -cameraPos.z;
float tmp = gl_Position.z / gl_Position.w;
theColor = color;
}
The result is weird.It seems that the five faces other than the front face are showed, which should all be disappeared.The back face is now in front of the front face.Here is the two triangles for the front face:
0.25f, 0.25f, -1.0f, 1.0f,
0.25f, -0.25f, -1.0f, 1.0f,
-0.25f, 0.25f, -1.0f, 1.0f,
0.25f, -0.25f, -1.0f, 1.0f,
-0.25f, -0.25f, -1.0f, 1.0f,
-0.25f, 0.25f, -1.0f, 1.0f,
the data for the back face:
0.25f, 0.25f, -3.0f, 1.0f,
-0.25f, 0.25f, -3.0f, 1.0f,
0.25f, -0.25f, -3.0f, 1.0f,
0.25f, -0.25f, -3.0f, 1.0f,
-0.25f, 0.25f, -3.0f, 1.0f,
-0.25f, -0.25f, -3.0f, 1.0f,
I choose -1.0f and 3.0f for the near and far plane respectively,so
(n + f) / (f - n) = 2.0f and
(2 * n * f) / (f - n) = 3.0f.Why the result is such weird?
After some test,I get the correct image.
I know what did I do wrong now.
First, the window I created didn't have a depth buffer and I did't enable the depth test.As the data of the five faces other than the front face was loaded after the front face, they were all be drawn.
Second, (n + f) / (f - n) and (2 * n * f) / (f - n) should change to (n + f) / (f - n) and (2 * n * f) / (f - n) .
Why the negations? OpenGL wants to present to the programmer a
right-handed coordinate system before projection and left-handed
coordinate system after projection.
That's the information I found.The larger z values will finally become smaller z value in the window space, which is exactly the depth value.
And as the default value for glDepthFunc is GL_LESS, the front face will show before the other faces.
I want to render two triangles in blue and a "windmill" in red. To do this I have created 2 shaders, which are the same except for the color. The two triangles are a lot bigger than the "windmill". The problem I'm facing is that if I switch between shaders, ONLY the last object will be rendered. If I switch to using only 1 shader, both objects will be drawn, but I can barely see the "windmill" because of the same color. So my question is how to draw both objects with two shaders? (I know I can just pass a color to the fragment shader, but I don't want to do that).
Render loop:
GLint index, index2;
index = glGetUniformLocation(shaders[LINE], "projectionMatrix");
index2 = glGetUniformLocation(shaders[TRIANGLE], "projectionMatrix");
glUniformMatrix3fv(index, 1, true, value_ptr(projectionMatrix));
glUniformMatrix3fv(index2, 1, true, value_ptr(projectionMatrix));
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaders[TRIANGLE]);
glBindVertexArray(vaos[TRIANGLE]);
glDrawArrays(GL_TRIANGLES, 0, tbufindex/sizeof(glm::vec3));
glUseProgram(shaders[LINE]); // If I comment out this line both objects will be drawn
glBindVertexArray(vaos[LINE]);
glDrawArrays(GL_LINE_STRIP, 0, sizeof(vertices_position)/sizeof(glm::vec3));
Line/Triangle.vert:
#version 450
layout (location = 0) in vec3 vPosition;
uniform mat3 projectionMatrix;
void main()
{
vec3 tmp = projectionMatrix*vPosition;
gl_Position = vec4(tmp, 1.0f);
}
Line/triangle.frag:
#version 450
in vec4 gl_FragCoord;
out vec4 fColor;
void main()
{
fColor = vec4(0.0, 0.0, 1.0, 1.0);
}
Also note that I don't have GL_DEPTH_TEST enabled, I'm using 2D coordinates.
Edit positions:
triangles[2] = { { vec3(-0.90f, -0.90f, 1.0f), vec3(0.85f, -0.90f, 1.0f), vec3(-0.90f, 0.85f, 1.0f) },
{ vec3(0.90f, -0.85f, 1.0f), vec3(0.90f, 0.90f, 1.0f), vec3(-0.85f, 0.90f, 1.0f) } };
lines[39] = {
0.0f, 0.0f, 1.0f,
0.5f, 0.0f, 1.0f,
0.5f, 0.5f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.5f, 1.0f,
-0.5f, 0.5f, 1.0f,
0.0f, 0.0f, 1.0f,
-0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, -0.5f, 1.0f,
0.5f, -0.5f, 1.0f,
0.0f, 0.0f, 1.0f
};
glUniform..() must be called after binding the program (source). So the following should work:
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaders[TRIANGLE]);
glUniformMatrix3fv(index2, 1, true, value_ptr(projectionMatrix));
glBindVertexArray(vaos[TRIANGLE]);
glDrawArrays(GL_TRIANGLES, 0, tbufindex/sizeof(glm::vec3));
glUseProgram(shaders[LINE]); // If I comment out this line both objects will be drawn
glUniformMatrix3fv(index, 1, true, value_ptr(projectionMatrix));
glBindVertexArray(vaos[LINE]);
glDrawArrays(GL_LINE_STRIP, 0, sizeof(vertices_position)/sizeof(glm::vec3));
I need to move two objects in OpenGL independently.
This is vertex positions array:
const float vertexPositions[] = {
0.25f, 0.25f, 0.0f, 1.0f,
0.25f, -0.25f, 0.0f, 1.0f,
-0.25f, -0.25f, 0.0f, 1.0f,
0.75f, 0.45f, 0.0f, 1.0f,
0.45f, -0.45f, 0.0f, 1.0f,
-0.65f, -0.95f, 0.0f, 1.0f,
};
This go to a buffer and then there is the following command which draws these triangles:
glDrawArrays(GL_TRIANGLES, 0, 3*2);
Below is part responsible for rotating:
#version 330
layout(location = 0) in vec4 position;
uniform float loopDuration;
uniform float time;
void main()
{
float timeScale = 3.14159f * 2.0f / loopDuration;
float currTime = mod(time, loopDuration);
vec4 totalOffset = vec4(
cos(currTime * timeScale) * 0.5f,
sin(currTime * timeScale) * 0.5f,
0.0f,
0.0f);
gl_Position = position + totalOffset;
}
Unfortunately it does not work as I expected - instead of moving independently, these triangles seems to be joined together like there were on a plate of glass. What I can do in order to translate and rotate them independently? How can I do it using GPU, not CPU?
I think you'ra doing this tutorial. In that case I suggest you to remove the last 12 floats from the vertexPositions, so you get the following:
const float vertexPositions[] = {
0.25f, 0.25f, 0.0f, 1.0f,
0.25f, -0.25f, 0.0f, 1.0f,
-0.25f, -0.25f, 0.0f, 1.0f,
};
And change the glDrawArrays(GL_TRIANGLES, 0, 3*2); to glDrawArrays(GL_TRIANGLES, 0, 3);. In your display() function, paste after the first calling of glDrawArrays() the following:
glUniform1f(loopDurationUnf, 2.5f);
glDrawArrays(GL_TRIANGLES, 0, 3);
This should draw the same triangle with twice the speed.