0
\$\begingroup\$

I am trying to build a cube as a composition of many quads, with each quad being composed of two triangles. All the triangles have the same size. I am dong this (instead of drawing a single cube with just six faces) in order to have better lighting effects.

The final cube itself looks perfect however when I calculate the normals the final result looks weird. Really weird as you can see in the picture.

That's how I am calculating the normals:

For every triangle:

  • calculate the normal by doing the cross product. The result is then normalized.

    For each vertex of this triangle:

  • Assign the same normal to all the three vertices

  • if a normal was previously assigned to the same vertex, sum it with the newly calculated value. Keep track on how many times that vertex is "shared"

  • Once the loop over the vertex is finished, divide each component of the normal vector with the number of times the vertex was shared.

In this picture the front face of the cube: Front face of the cube

Also, I am adding some code:

//in vertices(which is an ArrayList<Float[]>) I have all my vertices.

public ArrayList<Float[]> getNormals()
{



        normals = new ArrayList<Float[]>();
        
        LinkedHashMap<String, ArrayList<Float[]>> map = new LinkedHashMap<String, ArrayList<Float[]>>();

        
        for(int i=0; i<(vertices.size()-2); i=i+3)
        {
            float x1 = vertices.get(i)[0];   float y1 = vertices.get(i)[1];   float z1 = vertices.get(i)[2];    
            float x2 = vertices.get(i+1)[0]; float y2 = vertices.get(i+1)[1]; float z2 = vertices.get(i+1)[2];    
            float x3 = vertices.get(i+2)[0]; float y3 = vertices.get(i+2)[1]; float z3 = vertices.get(i+2)[2]; 
            
            float[] U;
            float[] V; 

                U = new float[]{x1-x2, y1-y2, z1-z2};
                V = new float[]{x1-x3, y1-y3, z1-z3};
            

            Float[] normal = new Float[]
                    {
                        (U[1] * V[2]) - (U[2]-V[1]),
                        (U[2] * V[0]) - (U[0]-V[2]),
                        (U[0] * V[1]) - (U[1]-V[0])
                    };


            
            normal = normalize(normal);
            
            ArrayList<Float[]> newList = new ArrayList<Float[]>();
            newList.add(normal);
            
            ArrayList<Float[]> list = map.get(x1+" "+y1+" "+z1);
            if(list==null) map.put(x1+" "+y1+" "+z1, newList);
            else{
                  list.add(normal);
                 map.put(x1+" "+y1+" "+z1, list);
            }
            
            list = map.get(x2+" "+y2+" "+z2);
            if(list==null) map.put(x2+" "+y2+" "+z2, newList);
            else{
                 list.add(normal);
                 map.put(x2+" "+y2+" "+z2, list);
            }
            
            
            list = map.get(x3+" "+y3+" "+z3);
            if(list==null) map.put(x3+" "+y3+" "+z3, newList);
            else{
                 list.add(normal);
                 map.put(x3+" "+y3+" "+z3, list);
            }
            
            
            
            
        }
        
        //averaging normals
    
            for(int i=0; i<vertices.size(); i++)
            {
                
                String key = vertices.get(i)[0]+" "+vertices.get(i)[1]+" "+vertices.get(i)[2];
                
                Float[] newNormal = new Float[]{0f,0f,0f};
                
                ArrayList<Float[]> lists = map.get(key);

                for(int j=0; j<lists.size(); j++)
                    {
                      newNormal[0] += lists.get(j)[0];
                      newNormal[1] += lists.get(j)[1];
                      newNormal[2] += lists.get(j)[2];
                    }
                
                  newNormal[0] /= ((float)lists.size());
                  newNormal[1] /= ((float)lists.size());
                  newNormal[2] /= ((float)lists.size());
                  
                  normals.add(normalize(newNormal));
            }
            
            
        
        
        return normals;
}
\$\endgroup\$
4
  • 2
    \$\begingroup\$ With no code posted this might be a bit hard.. Could you try enabling this calculations step by step to see what step starts causing the issue. Begin with setting a static normal values per vertex. Also at least a description of expected result may be very helpful. \$\endgroup\$ Oct 3, 2014 at 12:06
  • \$\begingroup\$ Question is edited. It has now code and a better explanation. \$\endgroup\$
    – alefzero
    Oct 3, 2014 at 12:46
  • \$\begingroup\$ How many vertices are you using? Also, averaging the normals for the vertices at the corners causes the lighting to, well, no longer look like a cube. \$\endgroup\$ Oct 3, 2014 at 15:02
  • \$\begingroup\$ Are you doing averaging so that the cube edges and corners appear rounded? Also, and average of two normalized vectors is no longer normalized (unless they were same). From picture, looks like there's some glitch where not all vertices are treated the same. \$\endgroup\$ Oct 3, 2014 at 17:48

1 Answer 1

1
\$\begingroup\$

if a normal was previously assigned to the same vertex, average it with the newly calculated value

Let's say you have normals n1, n2 and n3 that you want to add to a vertex. The vertex's normal shall be N;

Your method: apply n1: N = n1; apply n2: N = ( N + n2 ) / 2. So, N = ( n1 + n2 ) / 2. It's still fine until now. apply n3: N = ( N + n3 ) / 2. Let's do a little math: N = ( ( n1 + n2 ) / 2 + n3 ) / 2. That means N = n1 / 4 + n2 / 4 + n3 / 2 That is not the average normal. You should not be averaging N and n3. Instead, do it so when applying a triangle's normal to a vertex:

You need another integer value, initialized at 0: int number = 0; and when applying a triangle's normal n to a vertex:

if ( number == 0 )
    N = n;
else
{
    N = N + n;
    number = number + 1
}

When you are finished do so: N = N / number; // first check that number is not 0 That way, the real average will be computed.

Hope it helps!

\$\endgroup\$
1
  • \$\begingroup\$ Yes, you're right. And I did as you described in the first place. I just wrote the whole thing wrong. However, I added some code. Thanks \$\endgroup\$
    – alefzero
    Oct 3, 2014 at 12:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .