How to get flat normals on a cube

I use OpenGL without outdated functions, and my light counting is done on a fragment shader. So, I am doing smooth shading.

My problem is that when I draw a cube I need flat normals. By flat normals, I mean that each fragment generated in a face has the same normal.

My solution for this is to create different vertices for each face. So, instead of 8 vertices, now I have 24 (6 * 4) vertices.

But it seems wrong to me, replicating tops. Is there a better way to get flat normals?

Update: I am using OpenGL version 3.3.0, I do not have OpenGL 4 support yet.

+4
source share
3 answers

If you use lighting in camera space, you can use dFdx / dFdy to calculate the normal to the face from the camera position at the top.

So, the fragment shader will look something like this.

varying vec3 v_PositionCS; // Position of the vertex in camera/eye-space (passed in from the vertex shader) void main() { // Calculate the face normal in camera space vec3 normalCs = normalize(cross(dFdx(v_PositionCS), dFdy(v_PositionCS))); // Perform lighting ... ... } 
+9
source

Since the geometric shader can "see" all three vertices of the triangle at the same time, you can use the geometric shader to calculate the normals and send them to your fragment shader. This way you do not need to duplicate the vertices.

 // Geometry Shader #version 330 layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; out vec3 gNormal; // You will need to pass your untransformed positions in from the vertex shader in vec3 vPosition[]; uniform mat3 normalMatrix; void main() { vec3 side2 = vPosition[2] - vPosition[0]; vec3 side0 = vPosition[1] - vPosition[0]; vec3 facetNormal = normalize(normalMatrix * cross(side0, side2)); gNormal = facetNormal; gl_Position = gl_in[0].gl_Position; EmitVertex(); gNormal = facetNormal; gl_Position = gl_in[1].gl_Position; EmitVertex(); gNormal = facetNormal; gl_Position = gl_in[2].gl_Position; EmitVertex(); EndPrimitive(); } 
+5
source

Another option would be to pass the MV matrix and the raw AxisAligned coordinate to the fragment shader:

  attribute aCoord; varying vCoord; void main() { vCoord = aCoord; glPosition = aCoord * MVP; } 

In the Fragment Shader, you can then identify the normal by calculating the dominant vCoord axis, setting it to 1.0 (or -1.0), and the remaining coordinates are zero - this is the normal one that the MV matrix should be rotated.

+3
source

All Articles