What is a surface normal?

A surface normal is a vector perpendicular to a surface at a specific point, indicating the direction the surface faces. It provides valuable information about the orientation of a surface, enabling realistic simulations and interactions.

Surface normals are used in computer graphics, physics simulations, 3D reconstruction, and object recognition. In computer graphics and related fields, surface normals are crucial in determining how light interacts with a surface, affecting its shading and rendering.

Calculating the surface normal

For a polygon with nn vertices, where nn is greater than 3, we can calculate the surface normal by considering the average of the face normals of its individual triangles. Here’s the general method:

  • Split the polygon into triangles:

    • For each vertex ViV_i from 11 to n2n-2, create triangles using the vertices V0V_0, ViV_i, and Vi+1V_{i+1}.

  • Calculate the face normals of each triangle:

    • The general formula for calculating the surface normal of a triangle, given its three vertices (V1V_1, V2V_2, and V3V_3), is as follows:

      • Calculate the two vectors on the surface:

        • U=V2V1\vec{U} = V_2 - V_1

        • V=V3V1\vec{V} = V_3 - V_1

      • Compute the cross product of the two vectors:

        • W=U×V\vec{W} = \vec{U} \times \vec{V}

      • Normalize the surface normal vector:

        • Divide the surface normal vector by its magnitude to ensure its length is 1:

        • W=W/W\vec{W} = \vec{W} / ||\vec{W|}|

  • Compute the average of the face normals:

    • Sum up all the face normals and divide by the number of triangles.

    • Z=(W1+W2+...+Wn)/N\vec{Z} = (\vec{W_1} + \vec{W_2} + ... + \vec{W_n}) / N

  • Normalize the resulting surface normal vector:

    • Divide the resulting surface normal vector by its magnitude to ensure its length is 1.

    • Z=Z/Z\vec{Z} = \vec{Z} / ||\vec{Z}|

Code example

Let’s look at an example to calculate the surface normal of a triangle:

import numpy as np
def calculate_surface_normal(vertex1, vertex2, vertex3):
V1 = vertex2 - vertex1
V2 = vertex3 - vertex1
normal_vector = np.cross(V1, V2)
norm = np.linalg.norm(normal_vector)
if norm == 0:
return normal_vector
normal_vector = normal_vector / norm
return normal_vector
v1 = np.array([3, 2, 1])
v2 = np.array([2, 5, 3])
v3 = np.array([6, 2, 2])
surface_normal = calculate_surface_normal(v1, v2, v3)
print("Surface Normal:", surface_normal)

Code explanation

Let’s understand the code step by step:

  • Lines 17–19: We create the three input vertices v1, v2, and v3 as NumPy arrays.

  • Line 21: We provide three vertices v1, v2, and v3 as input to the calculate_surface_normal function.

  • Line 3: We create a function called calculate_surface_normal that takes three vertices vertex1, vertex2, and vertex3 as input.

  • Lines 4–5: The V1 and V2 vectors are calculated by subtracting vertex1 from vertex2 and vertex3, respectively.

  • Line 7: We compute the cross product of the two vectors V1 and V2 using np.cross() and assign it to the normal_vector variable.

  • Line 8: We calculate the magnitude (norm) of the normal_vector using np.linalg.norm(). This will be used for the normalization step.

  • Lines 10–15: If the magnitude is zero (indicating a degenerate triangle with all vertices on the same line), the function returns normal_vector as it is. Otherwise, the normal_vector is divided by the magnitude (norm) to normalize it, ensuring that its length becomes 1.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved