, uv, norm=True, out=None, dtype=None)[source]

Compute the tangent vector of a given triangle.

This function can be used to generate tangent vertex attributes for normal mapping. After computing tangents, one may orthogonalize them with vertex normals using the orthogonalize() function, or within the fragment shader. Uses texture coordinates at each triangle vertex to determine the direction of the vector.

  • tri (array_like) – Triangle vertices as 2D (3x3) array [p0, p1, p2] where each vertex is a length 3 array [vx, xy, vz]. The input array can be 3D (Nx3x3) to specify multiple triangles.

  • uv (array_like) – Texture coordinates associated with each face vertex as a 2D array (3x2) where each texture coordinate is length 2 array [u, v]. The input array can be 3D (Nx3x2) to specify multiple texture coordinates if multiple triangles are specified. If so N must be the same size as the first dimension of tri.

  • norm (bool, optional) – Normalize computed tangents if True, default is True.

  • out (ndarray, optional) – Optional output array. Must have one fewer dimensions than tri. The shape of the last dimension must be 3.

  • dtype (dtype or str, optional) – Data type for computations can either be ‘float32’ or ‘float64’. If out is specified, the data type of out is used and this argument is ignored. If out is not provided, ‘float64’ is used by default.


Surface normal of triangle tri.

Return type



Compute surface normals, tangents, and bitangents for a list of triangles:

# triangle vertices (2x3x3)
vertices = [[[-1., 0., 0.], [0., 1., 0.], [1, 0, 0]],
            [[1., 0., 0.], [0., 1., 0.], [-1, 0, 0]]]

# array of triangle texture coordinates (2x3x2)
uv = np.asarray([
    [(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)],   # 1
    [(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)]])  # 2

normals = surfaceNormal(vertices)
tangents = surfaceTangent(vertices, uv)
bitangents = cross(normals, tangents)  # or use `surfaceBitangent`

Orthogonalize a surface tangent with a vertex normal vector to get the vertex tangent and bitangent vectors:

vertexTangent = orthogonalize(faceTangent, vertexNormal)
vertexBitangent = cross(vertexTangent, vertexNormal)

Ensure computed vectors have the same handedness, if not, flip the tangent vector (important for applications like normal mapping):

# tangent, bitangent, and normal are 2D
tangent[dot(cross(normal, tangent), bitangent) < 0.0, :] *= -1.0

Back to top