YardenJ2R

06-14-2017, 12:10 PM

The specular light is affecting the lateral sides of the cube, when it shouldn't because the light is in front of the cube. The camera is at position (0, 0, 3), the light at (0, 0, 5). The model is the identity matrix, thus the cube is at (0, 0, 0). I'm calculating everything in the view space. I've made some classes in order to reuse code and to abstract some concepts. I'll put some code lines that I think are important to solve the problem and some images to show exactly what I'm talking about.

Vertex shader:

...

void main()

{

gl_Position = mvpMatrix * inPosition;

viewPosition = (modelView * inPosition).xyz;

//normal = mat3(modelView) * inNormal;

normal = mat3(transpose(inverse(modelView))) * inNormal;

}

Fragment shader:

...

void main()

{

vec3 ambientColor = material.ambient_ * light.ambient_;

vec3 lightDirection = normalize(light.position_ - viewPosition);

vec3 normalNormalized = normalize(normal);

float dotNormalLightDir = dot(normalNormalized, lightDirection);

float diffuseFactor = max(dotNormalLightDir, 0.0f);

if (dotNormalLightDir > 0.0f)

{

vec3 diffuseColor = diffuseFactor * material.diffuse_ * light.diffuse_;

vec3 viewerDirection = normalize(-viewPosition);

vec3 reflectedDirection = reflect(-lightDirection, normalNormalized);

float specularFactor = pow(max(dot(viewerDirection, reflectedDirection), 0.0f), material.shininess_);

vec3 specularColor = (specularFactor * material.specular_) * light.specular_;

color = clamp(ambientColor + diffuseColor + specularColor, 0.0f, 1.0f);

}

else

{

color = clamp(ambientColor, 0.0f, 1.0f);

}

}

OpenGLCube.cpp:

...

const float length = 0.5f;

const std::vector<glm::vec3> positions =

{

//front

{ -length, -length, length },

{ length, -length, length },

{ length, length, length },

{ -length, length, length },

//back

{ -length, -length, -length },

{ length, -length, -length },

{ length, length, -length },

{ -length, length, -length },

//front

{ -length, -length, length },

{ length, -length, length },

{ length, length, length },

{ -length, length, length },

//back

{ -length, -length, -length },

{ length, -length, -length },

{ length, length, -length },

{ -length, length, -length },

//front

{ -length, -length, length },

{ length, -length, length },

{ length, length, length },

{ -length, length, length },

//back

{ -length, -length, -length },

{ length, -length, -length },

{ length, length, -length },

{ -length, length, -length }

};

const std::vector<GLuint> indices =

{

// front

0, 1, 2,

2, 3, 0,

// top

11, 10, 6,

6, 7, 11,

// back

15, 14, 5,

5, 4, 15,

// bottom

12, 13, 9,

9, 8, 12,

// left

20, 16, 19,

19, 23, 20,

// right

17, 21, 22,

22, 18, 17

};

const std::vector<glm::vec3>& normals(GetNormalsByFace(positions, indices));

I calculate the normals through this method:

std::vector<glm::vec3> GetNormalsByFace(const std::vector<glm::vec3>& vertices, const std::vector<GLuint>& indices)

{

size_t nTriangles(indices.size() / 3);

std::vector<glm::vec3> normals(vertices.size());

for (size_t i = 0; i < nTriangles; ++i)

{

const int i3 = i * 3;

GLint v1(indices[i3]), v2(indices[i3 + 1]), v3(indices[i3 + 2]);

const glm::vec3& u1(vertices[v1]), u2(vertices[v2]), u3(vertices[v3]);

glm::vec3 a1(u2 - u1), a2(u3 - u1);

glm::vec3 normal(glm::cross(a1, a2));

normals[v1] = normal;

normals[v2] = normal;

normals[v3] = normal;

}

return normals;

}

This method seems correct as I tested some values. If you need more code for me to add here, I will gladly do it. Thanks!

@edit

Sorry everyone, I forgot to put the images. Here they are:

That's from one of the sides of the cube, when I rotate the camera. That dark side is the back face. I think it is wrong:

2390

That's the front of the cube. I think it is ok:

2389

It's also good to say that I update the light position at every frame by multiplying it by the view matrix as I mentioned below. I'm going to put here some images of an icosphere instead of the cube. It seems to be correctly lit, but I'm not sure though. If it is, then probably the problem is with the cube.

Front of the icosphere:

2391

Side of the icosphere:

2392

Almost back of the icosphere:

2393

Vertex shader:

...

void main()

{

gl_Position = mvpMatrix * inPosition;

viewPosition = (modelView * inPosition).xyz;

//normal = mat3(modelView) * inNormal;

normal = mat3(transpose(inverse(modelView))) * inNormal;

}

Fragment shader:

...

void main()

{

vec3 ambientColor = material.ambient_ * light.ambient_;

vec3 lightDirection = normalize(light.position_ - viewPosition);

vec3 normalNormalized = normalize(normal);

float dotNormalLightDir = dot(normalNormalized, lightDirection);

float diffuseFactor = max(dotNormalLightDir, 0.0f);

if (dotNormalLightDir > 0.0f)

{

vec3 diffuseColor = diffuseFactor * material.diffuse_ * light.diffuse_;

vec3 viewerDirection = normalize(-viewPosition);

vec3 reflectedDirection = reflect(-lightDirection, normalNormalized);

float specularFactor = pow(max(dot(viewerDirection, reflectedDirection), 0.0f), material.shininess_);

vec3 specularColor = (specularFactor * material.specular_) * light.specular_;

color = clamp(ambientColor + diffuseColor + specularColor, 0.0f, 1.0f);

}

else

{

color = clamp(ambientColor, 0.0f, 1.0f);

}

}

OpenGLCube.cpp:

...

const float length = 0.5f;

const std::vector<glm::vec3> positions =

{

//front

{ -length, -length, length },

{ length, -length, length },

{ length, length, length },

{ -length, length, length },

//back

{ -length, -length, -length },

{ length, -length, -length },

{ length, length, -length },

{ -length, length, -length },

//front

{ -length, -length, length },

{ length, -length, length },

{ length, length, length },

{ -length, length, length },

//back

{ -length, -length, -length },

{ length, -length, -length },

{ length, length, -length },

{ -length, length, -length },

//front

{ -length, -length, length },

{ length, -length, length },

{ length, length, length },

{ -length, length, length },

//back

{ -length, -length, -length },

{ length, -length, -length },

{ length, length, -length },

{ -length, length, -length }

};

const std::vector<GLuint> indices =

{

// front

0, 1, 2,

2, 3, 0,

// top

11, 10, 6,

6, 7, 11,

// back

15, 14, 5,

5, 4, 15,

// bottom

12, 13, 9,

9, 8, 12,

// left

20, 16, 19,

19, 23, 20,

// right

17, 21, 22,

22, 18, 17

};

const std::vector<glm::vec3>& normals(GetNormalsByFace(positions, indices));

I calculate the normals through this method:

std::vector<glm::vec3> GetNormalsByFace(const std::vector<glm::vec3>& vertices, const std::vector<GLuint>& indices)

{

size_t nTriangles(indices.size() / 3);

std::vector<glm::vec3> normals(vertices.size());

for (size_t i = 0; i < nTriangles; ++i)

{

const int i3 = i * 3;

GLint v1(indices[i3]), v2(indices[i3 + 1]), v3(indices[i3 + 2]);

const glm::vec3& u1(vertices[v1]), u2(vertices[v2]), u3(vertices[v3]);

glm::vec3 a1(u2 - u1), a2(u3 - u1);

glm::vec3 normal(glm::cross(a1, a2));

normals[v1] = normal;

normals[v2] = normal;

normals[v3] = normal;

}

return normals;

}

This method seems correct as I tested some values. If you need more code for me to add here, I will gladly do it. Thanks!

@edit

Sorry everyone, I forgot to put the images. Here they are:

That's from one of the sides of the cube, when I rotate the camera. That dark side is the back face. I think it is wrong:

2390

That's the front of the cube. I think it is ok:

2389

It's also good to say that I update the light position at every frame by multiplying it by the view matrix as I mentioned below. I'm going to put here some images of an icosphere instead of the cube. It seems to be correctly lit, but I'm not sure though. If it is, then probably the problem is with the cube.

Front of the icosphere:

2391

Side of the icosphere:

2392

Almost back of the icosphere:

2393