Recalculates vertex normals from triangle geometry (automatic smooth normals). Takes mesh (surface-based mesh entity). Returns nothing. Validates mesh exists, type is ENTITY_MESH, and is surface-based. Three-step algorithm for each surface: (1) Zero all vertex normals, (2) Calculate face normals via cross product (edge1 x edge2), accumulate to vertices, (3) Normalize all vertex normals to unit length. Default normal (0, -1, 0) if normalization fails (zero-length normal).
Recalculates vertex normals from triangle geometry (automatic smooth normals). Takes mesh (surface-based mesh entity). Returns nothing. Validates mesh exists, type is ENTITY_MESH, and is surface-based. Three-step algorithm for each surface: (1) Zero all vertex normals, (2) Calculate face normals via cross product (edge1 x edge2), accumulate to vertices, (3) Normalize all vertex normals to unit length. Default normal (0, -1, 0) if normalization fails (zero-length normal). Sets surface->needsGPUUpload=true and mesh->needsGPUUpload=true. Silently returns on validation errors.
This function automatically generates smooth normals for proper lighting. Normal calculation: face normal = perpendicular to triangle plane via cross product, vertex normal = average of adjacent face normals (creates smooth shading across connected triangles). Algorithm details: Step 1 zeroes normals, Step 2 accumulates unnormalized face normals to vertices (larger triangles contribute more), Step 3 normalizes to unit vectors (length=1.0) for correct lighting math. Call after: vertex position changes (b3dVertexCoords), triangle topology changes (b3dAddTriangle/DeleteTriangle), mesh creation before rendering. Smooth vs hard edges: shared vertices get averaged normals (smooth transitions), duplicate vertices get independent normals (hard creases - create duplicates manually for hard edges). Use cases: (1) After procedural mesh generation, (2) After terrain deformation, (3) After loading mesh without normals, (4) After UV remapping that duplicated vertices, (5) Override incorrect normals from import. Common pattern: b3dLockMesh(mesh), build vertices/triangles via b3dAddVertex/b3dAddTriangle, b3dUpdateNormals(mesh), b3dUnlockMesh(mesh). Cross product: edge1 x edge2 = perpendicular vector, direction follows right-hand rule (CCW winding = outward normal). Normalization: divides by length, makes magnitude=1.0, critical for lighting (non-unit normals cause brightness errors). Zero-length handling: if all face normals cancel out (opposing triangles) or vertex isolated, defaults to (0,-1,0) = upward. Must lock: not required (function handles surface iteration), but typical to call between lock/unlock for consistency. GPU upload deferred: normals updated on b3dUnlockMesh. Alternative: b3dVertexNormal for manual control, modeling software pre-calculated normals. Performance: O(T+V) where T=triangle count, V=vertex count - fast for typical meshes. Processes all surfaces: iterates through mesh->surfaces array, updates each. Hard edge technique: split surface at creases (b3dSplitSurfaces), or manually duplicate vertices before calling b3dUpdateNormals.