How to get flat normals on a cube

天大地大妈咪最大 提交于 2019-12-01 03:39:26

问题


I am using OpenGL without the deprecated features and my light calculation is done on fragment shader. So, I am doing smooth shading.

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

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

But this seems wrong to me, replicating the vertexes. Is there a better way to get flat normals?

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


回答1:


If you do the lighting in camera-space, you can use dFdx/dFdy to calculate the normal of the face from the camera-space position of the vertex.

So the fragment shader would look a little 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 
      ...
      ...
    }



回答2:


Since a geometry shader can "see" all three vertices of a triangle at once, you can use a geometry shader to calculate the normals and send them to your fragment shader. This way, you don't have to duplicate 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();
}



回答3:


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

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

At Fragment shader one can then identify the normal by calculating the dominating axis of vCoord, setting that to 1.0 (or -1.0) and the other coordinates to zero -- that is the normal, which has to be rotated by the MV -matrix.



来源:https://stackoverflow.com/questions/14980712/how-to-get-flat-normals-on-a-cube

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!