[Solved] Per Vertex Normal Calculation Does not Work

Hi all.

I’m stuck with calculating per vertex normals. I’ve checked this http://www.java-gaming.org/topics/reopened-calculating-normal-vectors/33838/view.html, but got no new information.
I render two objects (see screenshot), the cube is exported from blender and the other one is constructed manually from code. As you see, the blender cube is OK. Also, if I create the same object from blender and export it with normals, it’s also OK.

So I think, something wrong with my manual code. Screenshot: https://drive.google.com/open?id=1hsAFJMJSH9atgcxQNe6o_YyzXqgr2NYh

How triangles constructed: https://drive.google.com/open?id=1YrF6IiHIg9ieNZ1Us9pvKsCp-a4Z6lcm


float[] vertices = new float[]{
                0, 0, 0,
                0, 0, 1,
                1, 0, 1,
                1, 0.5f, 0,
                //1,0.5f,0,
                //1,0,1,
                2, 0, 1,
                2, 0, 0
        };

        int[] indices = new int[]{
                1, 2, 0,
                2, 3, 0,

                2, 5, 3,
                2, 4, 5
        };

        float[] normals=new float[vertices.length];
        int normalsIndex=0;

        Vector3f[] triangleVertices=new Vector3f[3];
        for (int i=0;i<indices.length;i++){
            int index=indices[i];
            Vector3f vertexPos=new Vector3f(
                    vertices[index*3],
                    vertices[index*3+1],
                    vertices[index*3+2]
            );

            if(i%3==0){
                triangleVertices[0]=vertexPos;
            }
            else if(i%3==1){
                triangleVertices[1]=vertexPos;
            }
            else if(i%3==2){
                triangleVertices[2]=vertexPos;
                // Nf = (↑B - ↑A) × (↑C - ↑A)
                Vector3f normal=triangleVertices[1].sub(triangleVertices[0]).cross(triangleVertices[2].sub(triangleVertices[0]));
                normal.normalize();
                normals[normalsIndex++]=normal.x;
                normals[normalsIndex++]=normal.y;
                normals[normalsIndex++]=normal.z;
            }
        }

What you are doing is called “per face” normals. Sure, normals are always assigned to vertices, but you want each vertex of the same face/triangle to have the same normal direction. Therefore, you cannot use indices like you did, because vertices with the same position cannot share the same normal anymore, since the normal depends on the face/triangle that vertex is part of.
That means, we have to duplicate multiple uses of the same vertex position and compute a face normal for all the vertices of the current triangle.
Try this (based on this code, not tested):


/*
 * We have to duplicate same vertex positions
 * because they need multiple normals depending
 * on which face/triangle they are part of.
 */
float[] vertices = new float[] {
  0.0f, 0.0f, 1.0f, // 1
  1.0f, 0.0f, 1.0f, // 2
  0.0f, 0.0f, 0.0f, // 0
  1.0f, 0.0f, 1.0f, // 2
  1.0f, 0.5f, 0.0f, // 3
  0.0f, 0.0f, 0.0f, // 0
  1.0f, 0.0f, 1.0f, // 2
  2.0f, 0.0f, 0.0f, // 5
  1.0f, 0.5f, 0.0f, // 3
  1.0f, 0.0f, 1.0f, // 2
  2.0f, 0.0f, 1.0f, // 4
  2.0f, 0.0f, 0.0f  // 5
};
/*
 * Compute per face normals.
 */
float[] normals = new float[vertices.length];
for (int i = 0; i < vertices.length; i += 3*3) { // <- 3*3 = one triangle/face per iteration
  Vector3f v0 = new Vector3f(vertices[i + 0], vertices[i + 1], vertices[i + 2]);
  Vector3f v1 = new Vector3f(vertices[i + 3], vertices[i + 4], vertices[i + 5]);
  Vector3f v2 = new Vector3f(vertices[i + 6], vertices[i + 7], vertices[i + 8]);
  Vector3f n = v1.sub(v0).cross(v2.sub(v0)).normalize();
  // Assign that normal to all vertices of the current triangle/face
  for (int j = 0; j < 3; j++) {
    normals[i + 3*j + 0] = n.x; 
    normals[i + 3*j + 1] = n.y;
    normals[i + 3*j + 2] = n.z;
  }
}

Yeah, it works! Thanks for your help!