NEED HELP with lighting

Hello there,
I’m trying to implement lighting to my 3D rendering program. What I did is that I calculated face normals (I’m ok with flat shading because my program use only cubes for now), I stored this normals to VAO and I loaded it into glsl, did some calculations and when I compiled it the object on which light casted was colored with ambient color only. Here is some code:

static GLfloat g_normal_buffer_data[10000]; /*this is normal buffer I wont show how i filled it because I think it's irrelevant. I'm sure normals are calculated good. These data are calculated in different struct as my rendering stuff.*/

GLuint normalBuffer;
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, 1, dataObject->initializeVertices(1) /*this returns normals*/, GL_STATIC_DRAW);

glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glVertexAttribPointer
(
	2,
	3,
	GL_FLOAT,
	GL_FALSE,
	0,
	(void*)0
);/*this is in my game loop*/


//vShader
#version 330 core

layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 color;
layout(location = 2) in vec3 normal;

out vec3 FragPos;
out vec3 Normal;

out vec3 fcolor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{	
        /*what I think is problem here is that face normals are only 10 * vec3(I'm rendering only 5 walls on a rectangle) and vertices are 30 * vec3 so every time it pushes new vertex to compute it pushes new face normal to compute so face normals are finished when 11th vertex starts to compute*/

gl_Position =  projection * view * model * vec4(vertexPosition_modelspace, 1);
FragPos = vec3(model * vec4(vertexPosition_modelspace, 1.0));
Normal = mat3(transpose(inverse(model))) * normal;

	fcolor = color; //object color
}

//fShader
#version 330 core

flat in vec3 fcolor;
flat in vec3 FragPos;
flat in vec3 Normal;

out vec4 color;

uniform vec3 lightColor;
uniform vec3 lightPos;

void main()
{
    float ambientStrength = 0.1f;
    vec3 ambient = ambientStrength * lightColor;

    vec3 lightDir = normalize(lightPos - FragPos);  
    float diff = max(dot(Normal, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    vec3 result = (ambient + diffuse) * fcolor;
    color = vec4(result, 1.0f);
}

I really need help with this. I’m also attaching some screenshots so you can see.![Snímka|690x338]


PS: Could upload only 1 screenshot so I uploaded my face normals.

EDIT:
I wanted to check my normalBuffer directly so I did something like this:

glm::vec3 *dataPointer = new glm::vec3();
glGetNamedBufferSubData(normalBuffer, 0, sizeof(normalBuffer), dataPointer);

std::cout << "bufferX: " << dataPointer->x << std::endl;
std::cout << "bufferY: " << dataPointer->y << std::endl;
std::cout << "bufferZ: " << dataPointer->z << std::endl;

The output was 0 for every case so I think the problem might be in filling buffer with data

OpenGL doesn’t support per-face attributes; all attributes are per-vertex.

The simplest solution is to give each face three distinct vertices, with the face normal associated to each vertex. But that means that you can’t share vertices between faces. A more efficient (but more complex) solution is to use the flat qualifier on the normal and assign normals so that the last vertex of each face has the correct normal (in OpenGL 3.2 and later, you can use glProvokingVertex to use the first vertex of each face for flat-qualified values).

But you still need to ensure that each vertex is used by no more than three faces, and order the element (index) array so that each vertex is the last vertex for at most one face. So you need at least as many vertices as faces, but you don’t need three distinct vertices for each face. For a typical triangle mesh, this roughly doubles the number of vertices required compared to using a single vertex for each distinct position (typical triangle meshes have an average of six faces sharing each vertex).

An alternative approach for flat shading is to calculate the face normal in the fragment shader using something like:

vec3 normal = cross(dFdx(FragPos), dFdy(FragPos));

This is more computationally expensive than passing in normals via attributes, but it eliminates the need for vertex normals.

BTW, FragPos shouldn’t have the flat qualifier; you want that variable to be interpolated.

1 Like

Also: for situations where you need per-face data and can’t figure out how to organise the mesh so that each face has a distinct provoking vertex, you can resort to using arrays (uniforms, SSBOs, textures) indexed with gl_PrimitiveID in the fragment shader or gl_PrimitiveIDIn in a geometry shader. But this is likely to be slower than using vertex attributes.

1 Like

Okay so all I need is compute normal in fragment shader like this:

vec3 normal = cross(dFdx(FragPos), dFdy(FragPos))

And then just do other calculations with that normal to create diffuse lighting ? There’s no need to load normals to glsl and create buffers because of that ?

That will give you the face normal in the same coordinate system as FragPos (presumably model space). dFdx and dFdy will give you tangent vectors (in the plane of the triangle), and their cross product will be perpendicular to both (and thus perpendicular to the plane of the triangle).

1 Like

I did what you said but the value of
vec3 normal = cross(dFdx(FragPos), dFdy(FragPos));
was vec3(0.0f, 0.0f, 0.0f). I thought that maybe my FragPos vector is equal to zero but it’s not. Some very wierd stuff is going on in my shaders as I tried soo many possibilities but I cannot setup diffuse lighting in my program for 3 days now.

Did you remove the flat qualifier from FragPos? If you didn’t, the value from the last vertex will be used for every fragment and its derivatives will be zero.

1 Like

I didn’t my bad. At this point I’m only learning so I don’t clearly understand how this code works because I try to follow some tutorials and learn from them and this code is only copy paste from one of them. But you’ve helped me so much. Now I can calculate normals within fragment shader. No tutorial mentioned that and I think that that was the main problem. Anyway all works so thanks for your help and your time… :slight_smile: