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
- Fix the mesh: find the triangle with the reported indices and remove or repair it in the source model.
- Validate vertex/index buffers before building surfaces — reject triangles with duplicate position vertices.
- 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
- Weld/merge duplicate vertices in the DCC tool before export.
- Validate index buffers for triangles referencing identical positions before calculate_tangents.
- Fix or remove any triangle reported in the warning; it corrupts normal mapping.
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
- : Model has triangles with repeated vertices
- Graphics context is uninitialized!
- only rectangle textures can be used as render target!
- Graph pool must be empty on load!
- Attempt to get reference to resource data while it is…
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)