{"record":{"id":"2eb110c14c8db44f","repo":"FyroxEngine/Fyrox","slug":"degenerated-triangle-found-when-calculating-tangen","errorCode":null,"errorMessage":"Degenerated triangle found when calculating tangents. Lighting may be incorrect! Triangle indices: {triangle:?}. Triangle vertices: {v1:?} {v2:?} {v3:?}","messagePattern":"Degenerated triangle found when calculating tangents\\. Lighting may be incorrect! Triangle indices: (.+?)\\. Triangle vertices: (.+?) (.+?) (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fyrox-impl/src/scene/mesh/surface.rs","lineNumber":331,"sourceCode":"        let mut tan1 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];\n        let mut tan2 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];\n\n        for triangle in self.geometry_buffer.iter() {\n            let i1 = triangle[0] as usize;\n            let i2 = triangle[1] as usize;\n            let i3 = triangle[2] as usize;\n\n            let view1 = &self.vertex_buffer.get(i1).unwrap();\n            let view2 = &self.vertex_buffer.get(i2).unwrap();\n            let view3 = &self.vertex_buffer.get(i3).unwrap();\n\n            let v1 = view1.read_3_f32(VertexAttributeUsage::Position)?;\n            let v2 = view2.read_3_f32(VertexAttributeUsage::Position)?;\n            let v3 = view3.read_3_f32(VertexAttributeUsage::Position)?;\n\n            // Check for degenerated triangles\n            if v1 == v2 || v1 == v3 || v2 == v3 {\n                Log::warn(format!(\n                    \"Degenerated triangle found when calculating tangents. Lighting may be \\\n                    incorrect! Triangle indices: {triangle:?}. Triangle vertices: {v1:?} {v2:?} {v3:?}\",\n                ));\n            }\n\n            let w1 = view1.read_3_f32(VertexAttributeUsage::TexCoord0)?;\n            let w2 = view2.read_3_f32(VertexAttributeUsage::TexCoord0)?;\n            let w3 = view3.read_3_f32(VertexAttributeUsage::TexCoord0)?;\n\n            let x1 = v2.x - v1.x;\n            let x2 = v3.x - v1.x;\n            let y1 = v2.y - v1.y;\n            let y2 = v3.y - v1.y;\n            let z1 = v2.z - v1.z;\n            let z2 = v3.z - v1.z;\n\n            let s1 = w2.x - w1.x;\n            let s2 = w3.x - w1.x;","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-impl/src/scene/mesh/surface.rs#L313-L349","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: indices [0, 1, 1] create a degenerate triangle\nlet indices = vec![0, 1, 1, 2, 3, 4];\ndata.geometry().set_index_buffer(...);\ndata.calculate_tangents().unwrap();\n// after: validate first\nassert_ne!(v1, v2, \"degenerate triangle: duplicate vertex positions\");\ndata.calculate_tangents().unwrap();","handlingStrategy":"validation","validationCode":"fn has_degenerate(positions: &[Vector3<f32>], triangle: [u32; 3]) -> bool {\n    let [a, b, c] = [triangle[0] as usize, triangle[1] as usize, triangle[2] as usize];\n    positions[a] == positions[b] || positions[a] == positions[c] || positions[b] == positions[c]\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["fyrox","mesh","geometry","lighting"],"backgroundTag":"invalid-argument-value","analyzedSha":"76c91aad8eca488ce527b1af707be8b3b24ad72d","analyzedAt":"2026-09-10T16:04:01.633Z","contentChangedAt":"2026-09-10T16:04:01.633Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}