FyroxEngine/Fyrox · warning

Degenerated triangle found when calculating tangents…

Error message

Degenerated triangle found when calculating tangents. Lighting may be incorrect! Triangle indices: {triangle:?}. Triangle vertices: {v1:?} {v2:?} {v3:?}

What it means

While computing tangent vectors for a mesh surface (needed for normal mapping), Fyrox detects a triangle whose vertex positions coincide (two or more identical vertices). Such a degenerate triangle has no meaningful surface basis, so tangents for it are undefined and lighting (especially normal maps) may render incorrectly. The calculation continues, only logging this warning with the offending triangle indices and vertices.

Solutions

  1. Fix the mesh: find the triangle with the reported indices and remove or repair it in the source model.
  2. Validate vertex/index buffers before building surfaces — reject triangles with duplicate position vertices.
  3. Re-export the asset from the modeling tool with weld/merge-vertices enabled.

Example fix

// before: indices [0, 1, 1] create a degenerate triangle
let indices = vec![0, 1, 1, 2, 3, 4];
data.geometry().set_index_buffer(...);
data.calculate_tangents().unwrap();
// after: validate first
assert_ne!(v1, v2, "degenerate triangle: duplicate vertex positions");
data.calculate_tangents().unwrap();
Defensive patterns

Strategy: validation

Validate before calling

fn has_degenerate(positions: &[Vector3<f32>], triangle: [u32; 3]) -> bool {
    let [a, b, c] = [triangle[0] as usize, triangle[1] as usize, triangle[2] as usize];
    positions[a] == positions[b] || positions[a] == positions[c] || positions[b] == positions[c]
}

Prevention

When it happens

Trigger: Calling SurfaceData::calculate_tangents (indirectly via build_surface_data) on a mesh containing a triangle whose Position attributes are equal for any two of its three vertices.

Common situations: Hand-built vertex buffers with duplicated vertex positions, broken model exports from DCC tools, index buffers referencing the same vertex twice within one triangle, geometry simplification/merge bugs.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/2eb110c14c8db44f. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-impl/src/scene/mesh/surface.rs:331

        let mut tan1 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];
        let mut tan2 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];

        for triangle in self.geometry_buffer.iter() {
            let i1 = triangle[0] as usize;
            let i2 = triangle[1] as usize;
            let i3 = triangle[2] as usize;

            let view1 = &self.vertex_buffer.get(i1).unwrap();
            let view2 = &self.vertex_buffer.get(i2).unwrap();
            let view3 = &self.vertex_buffer.get(i3).unwrap();

            let v1 = view1.read_3_f32(VertexAttributeUsage::Position)?;
            let v2 = view2.read_3_f32(VertexAttributeUsage::Position)?;
            let v3 = view3.read_3_f32(VertexAttributeUsage::Position)?;

            // Check for degenerated triangles
            if v1 == v2 || v1 == v3 || v2 == v3 {
                Log::warn(format!(
                    "Degenerated triangle found when calculating tangents. Lighting may be \
                    incorrect! Triangle indices: {triangle:?}. Triangle vertices: {v1:?} {v2:?} {v3:?}",
                ));
            }

            let w1 = view1.read_3_f32(VertexAttributeUsage::TexCoord0)?;
            let w2 = view2.read_3_f32(VertexAttributeUsage::TexCoord0)?;
            let w3 = view3.read_3_f32(VertexAttributeUsage::TexCoord0)?;

            let x1 = v2.x - v1.x;
            let x2 = v3.x - v1.x;
            let y1 = v2.y - v1.y;
            let y2 = v3.y - v1.y;
            let z1 = v2.z - v1.z;
            let z2 = v3.z - v1.z;

            let s1 = w2.x - w1.x;
            let s2 = w3.x - w1.x;

View on GitHub (pinned to 76c91aad8e)