Skip to main content
Mixup with first loop index
Source Link
DMGregory
  • 139k
  • 22
  • 253
  • 386

Another user was struggling to implement this with the existing answer, so I thought I'd show a slightly deeper code example for folks in a similar situation.

I'll use Unity C# syntax since it's what I use most often, but the same steps can be applied to any language/framework.

CalculateVertexNormals(Vector3[] vertexPositions, int[] triangleIndices, Vector3[] vertexNormals)  
{

    // Zero-out our normal buffer to start from a clean slate.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)
        vertexNormals[vertex] = Vector3.zero;

    // For each face, compute the face normal, and accumulate it into each vertex.
    for(int vertexindex = 0; vertexindex < vertexPositionstriangleIndices.Length; vertexindex += 3) {
        int vertexA = triangleIndices[vertex];triangleIndices[index];
        int vertexB = triangleIndices[vertextriangleIndices[index + 1];
        int vertexC = triangleIndices[vertextriangleIndices[index + 2];    

        var edgeAB = vertexPositions[vertexB] - vertexPositions[vertexA];
        var edgeAC = vertexPositions[vertexC] - vertexPositions[vertexA];

        // The cross product is perpendicular to both input vectors (normal to the plane).
        // Flip the argument order if you need the opposite winding.    
        var areaWeightedNormal = Vector3.Cross(edgeAB, edgeAC);

        // Don't normalize this vector just yet. Its magnitude is proportional to the
        // area of the triangle (times 2), so this helps ensure tiny/skinny triangles
        // don't have an outsized impact on the final normal per vertex.
        
        // Accumulate this cross product into each vertex normal slot.
        vertexNormals[vertexA] += areaWeightedNormal;
        vertexNormals[vertexB] += areaWeightedNormal;
        vertexNormals[vertexC] += areaWeightedNormal;
    }       

    // Finally, normalize all the sums to get a unit-length, area-weighted average.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)    
        vertexNormals[vertex] = Vector3.Normalize(normal);
}

Another user was struggling to implement this with the existing answer, so I thought I'd show a slightly deeper code example for folks in a similar situation.

I'll use Unity C# syntax since it's what I use most often, but the same steps can be applied to any language/framework.

CalculateVertexNormals(Vector3[] vertexPositions, int[] triangleIndices, Vector3[] vertexNormals) {

    // Zero-out our normal buffer to start from a clean slate.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)
        vertexNormals[vertex] = Vector3.zero;

    // For each face, compute the face normal, and accumulate it into each vertex.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex += 3) {
        int vertexA = triangleIndices[vertex];
        int vertexB = triangleIndices[vertex + 1];
        int vertexC = triangleIndices[vertex + 2];    

        var edgeAB = vertexPositions[vertexB] - vertexPositions[vertexA];
        var edgeAC = vertexPositions[vertexC] - vertexPositions[vertexA];

        // The cross product is perpendicular to both input vectors (normal to the plane).
        // Flip the argument order if you need the opposite winding.    
        var areaWeightedNormal = Vector3.Cross(edgeAB, edgeAC);

        // Don't normalize this vector just yet. Its magnitude is proportional to the
        // area of the triangle (times 2), so this helps ensure tiny/skinny triangles
        // don't have an outsized impact on the final normal per vertex.
        
        // Accumulate this cross product into each vertex normal slot.
        vertexNormals[vertexA] += areaWeightedNormal;
        vertexNormals[vertexB] += areaWeightedNormal;
        vertexNormals[vertexC] += areaWeightedNormal;
    }       

    // Finally, normalize all the sums to get a unit-length, area-weighted average.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)    
        vertexNormals[vertex] = Vector3.Normalize(normal);
}

Another user was struggling to implement this with the existing answer, so I thought I'd show a slightly deeper code example for folks in a similar situation.

I'll use Unity C# syntax since it's what I use most often, but the same steps can be applied to any language/framework.

CalculateVertexNormals(Vector3[] vertexPositions, int[] triangleIndices, Vector3[] vertexNormals) 
{

    // Zero-out our normal buffer to start from a clean slate.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)
        vertexNormals[vertex] = Vector3.zero;

    // For each face, compute the face normal, and accumulate it into each vertex.
    for(int index = 0; index < triangleIndices.Length; index += 3) {
        int vertexA = triangleIndices[index];
        int vertexB = triangleIndices[index + 1];
        int vertexC = triangleIndices[index + 2];    

        var edgeAB = vertexPositions[vertexB] - vertexPositions[vertexA];
        var edgeAC = vertexPositions[vertexC] - vertexPositions[vertexA];

        // The cross product is perpendicular to both input vectors (normal to the plane).
        // Flip the argument order if you need the opposite winding.    
        var areaWeightedNormal = Vector3.Cross(edgeAB, edgeAC);

        // Don't normalize this vector just yet. Its magnitude is proportional to the
        // area of the triangle (times 2), so this helps ensure tiny/skinny triangles
        // don't have an outsized impact on the final normal per vertex.
        
        // Accumulate this cross product into each vertex normal slot.
        vertexNormals[vertexA] += areaWeightedNormal;
        vertexNormals[vertexB] += areaWeightedNormal;
        vertexNormals[vertexC] += areaWeightedNormal;
    }       

    // Finally, normalize all the sums to get a unit-length, area-weighted average.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)    
        vertexNormals[vertex] = Vector3.Normalize(normal);
}
Source Link
DMGregory
  • 139k
  • 22
  • 253
  • 386

Another user was struggling to implement this with the existing answer, so I thought I'd show a slightly deeper code example for folks in a similar situation.

I'll use Unity C# syntax since it's what I use most often, but the same steps can be applied to any language/framework.

CalculateVertexNormals(Vector3[] vertexPositions, int[] triangleIndices, Vector3[] vertexNormals) {

    // Zero-out our normal buffer to start from a clean slate.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)
        vertexNormals[vertex] = Vector3.zero;

    // For each face, compute the face normal, and accumulate it into each vertex.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex += 3) {
        int vertexA = triangleIndices[vertex];
        int vertexB = triangleIndices[vertex + 1];
        int vertexC = triangleIndices[vertex + 2];    

        var edgeAB = vertexPositions[vertexB] - vertexPositions[vertexA];
        var edgeAC = vertexPositions[vertexC] - vertexPositions[vertexA];

        // The cross product is perpendicular to both input vectors (normal to the plane).
        // Flip the argument order if you need the opposite winding.    
        var areaWeightedNormal = Vector3.Cross(edgeAB, edgeAC);

        // Don't normalize this vector just yet. Its magnitude is proportional to the
        // area of the triangle (times 2), so this helps ensure tiny/skinny triangles
        // don't have an outsized impact on the final normal per vertex.
        
        // Accumulate this cross product into each vertex normal slot.
        vertexNormals[vertexA] += areaWeightedNormal;
        vertexNormals[vertexB] += areaWeightedNormal;
        vertexNormals[vertexC] += areaWeightedNormal;
    }       

    // Finally, normalize all the sums to get a unit-length, area-weighted average.
    for(int vertex = 0; vertex < vertexPositions.Length; vertex++)    
        vertexNormals[vertex] = Vector3.Normalize(normal);
}