Recalculate mesh normals for CAOs (#10000)
authorDanila Shutov <dcbrwn2@gmail.com>
Sun, 7 Jun 2020 16:14:00 +0000 (19:14 +0300)
committerGitHub <noreply@github.com>
Sun, 7 Jun 2020 16:14:00 +0000 (18:14 +0200)
src/client/content_cao.cpp
src/client/mesh.cpp
src/client/mesh.h

index 85572964226c7e93a4d203898ad13f712d63e0b5..a6ce06d205dbfb31a0f8c3945f9fab33ecf72f2c 100644 (file)
@@ -726,6 +726,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                                addAnimatedMeshSceneNode(mesh, m_matrixnode);
                        m_animated_meshnode->grab();
                        mesh->drop(); // The scene node took hold of it
+
+                       if (!checkMeshNormals(mesh)) {
+                               infostream << "GenericCAO: recalculating normals for mesh "
+                                       << m_prop.mesh << std::endl;
+                               m_smgr->getMeshManipulator()->
+                                               recalculateNormals(mesh, true, false);
+                       }
+
                        m_animated_meshnode->animateJoints(); // Needed for some animations
                        m_animated_meshnode->setScale(m_prop.visual_size);
 
index 4d73ead8abad4ae298606355a4e3c92d210ee58d..91781373c55284394ab39adc0929f7590b61c984 100644 (file)
@@ -328,6 +328,26 @@ void recalculateBoundingBox(scene::IMesh *src_mesh)
        src_mesh->setBoundingBox(bbox);
 }
 
+bool checkMeshNormals(scene::IMesh *mesh)
+{
+       u32 buffer_count = mesh->getMeshBufferCount();
+
+       for (u32 i = 0; i < buffer_count; i++) {
+               scene::IMeshBuffer *buffer = mesh->getMeshBuffer(i);
+
+               // Here we intentionally check only first normal, assuming that if buffer
+               // has it valid, then most likely all other ones are fine too. We can
+               // check all of the normals to have length, but it seems like an overkill
+               // hurting the performance and covering only really weird broken models.
+               f32 length = buffer->getNormal(0).getLength();
+
+               if (!isfinite(length) || fabs(length) < 1e-10)
+                       return false;
+       }
+
+       return true;
+}
+
 scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer)
 {
        switch (mesh_buffer->getVertexType()) {
index 0c4094de2a7777e5138ceb47b99b188a0c945c6f..103c61e45fe2f0d3941d71d426a84d515aa4b3ec 100644 (file)
@@ -121,6 +121,12 @@ scene::IMesh* convertNodeboxesToMesh(const std::vector<aabb3f> &boxes,
 */
 void recalculateBoundingBox(scene::IMesh *src_mesh);
 
+/*
+       Check if mesh has valid normals and return true if it does.
+       We assume normal to be valid when it's 0 < length < Inf. and not NaN
+ */
+bool checkMeshNormals(scene::IMesh *mesh);
+
 /*
        Vertex cache optimization according to the Forsyth paper:
        http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html