Skip to content

Commit dd80a3a

Browse files
committed
Fix jolt_physics soft body vertex normal calculation
The code previously iterated through each face and set all vertices to that face's normal. This resulted in each vertex getting the normal from just one face that it belonged to (whichever face was last in this array). This caused weird shading artifacts. This fixes the code so that the vertex normal is now the average normal of all faces that it belongs to. This results in "smooth shading" behavior for soft body meshes. This is still somewhat undesirable if the input mesh was using flat shading, but it looks less bad than the previous behavior of picking a normal at random from one attached face. This matches the behavior of GodotPhysicsServer3D. Fixes #107831.
1 parent 4e6ac9b commit dd80a3a

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

modules/jolt_physics/objects/jolt_soft_body_3d.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -628,8 +628,13 @@ void JoltSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHandl
628628

629629
const int physics_vertex_count = (int)physics_vertices.size();
630630

631+
normals.clear();
631632
normals.resize(physics_vertex_count);
632633

634+
// Compute vertex normals using smooth-shading:
635+
// Each vertex should use the average normal of all faces it is a part of.
636+
// Iterate over each face, and add the face normal to each of the face vertices.
637+
// By the end of the loop, each vertex normal will be the sum of all face normals it belongs to.
633638
for (const SoftBodyFace &physics_face : physics_faces) {
634639
// Jolt uses a different winding order, so we swap the indices to account for that.
635640

@@ -643,9 +648,18 @@ void JoltSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHandl
643648

644649
const Vector3 normal = (v2 - v0).cross(v1 - v0).normalized();
645650

646-
normals[i0] = normal;
647-
normals[i1] = normal;
648-
normals[i2] = normal;
651+
normals[i0] += normal;
652+
normals[i1] += normal;
653+
normals[i2] += normal;
654+
}
655+
// Normalize the vertex normals to have length 1.0
656+
for (Vector3 &n : normals) {
657+
real_t len = n.length();
658+
// Some normals may have length 0 if the face was degenerate,
659+
// so don't divide by zero.
660+
if (len > CMP_EPSILON) {
661+
n /= len;
662+
}
649663
}
650664

651665
const int mesh_vertex_count = shared->mesh_to_physics.size();

0 commit comments

Comments
 (0)