Quick answer: Pygame Vector3.cross producing normals pointing the wrong direction? Pygame uses right-handed coordinates; some code translated from left-handed systems flips signs.
Computing surface normal from edges via cross gives normals pointing inward into the geometry instead of outward.
Right-Handed Math
Pygame Vector3 follows OpenGL right-handed convention. a.cross(b) follows right-hand rule. If you imported math from a left-handed system (DirectX, Unity), flip cross-products or negate Z.
Swap Operand Order
To flip: b.cross(a) instead of a.cross(b). Negates the result. Cleaner than negating explicitly.
Normal Direction Convention
Decide for your project: normals out (CCW winding) or normals in (CW winding). Standardize across mesh import and runtime.
Validate by Inspection
Draw normals as debug lines. If they all point inward, flip the cross order project-wide.
Verifying
Computed normals point in expected direction. Lighting, collision, projection all use consistent normal direction.
“cross handedness depends on operand order. Pygame is right-handed; pick CCW or CW project-wide.”
Document the project’s winding / normal convention — mixed conventions across imported assets are a constant source of normal flips.