aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorDanila Shutov <dcbrwn2@gmail.com>2020-06-07 19:14:00 +0300
committerGitHub <noreply@github.com>2020-06-07 18:14:00 +0200
commitfe1f72ab0ac8bcc233c91eb5b2d71bd2d2574cf8 (patch)
tree4be77389e38c97dd1391439f212db642b16fac0b /src/client
parent8fc9e7eb117849202b87bf3d764cd3eac6f68c74 (diff)
downloadminetest-fe1f72ab0ac8bcc233c91eb5b2d71bd2d2574cf8.tar.gz
minetest-fe1f72ab0ac8bcc233c91eb5b2d71bd2d2574cf8.tar.bz2
minetest-fe1f72ab0ac8bcc233c91eb5b2d71bd2d2574cf8.zip
Recalculate mesh normals for CAOs (#10000)
Diffstat (limited to 'src/client')
-rw-r--r--src/client/content_cao.cpp8
-rw-r--r--src/client/mesh.cpp20
-rw-r--r--src/client/mesh.h6
3 files changed, 34 insertions, 0 deletions
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index 855729642..a6ce06d20 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -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);
diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp
index 4d73ead8a..91781373c 100644
--- a/src/client/mesh.cpp
+++ b/src/client/mesh.cpp
@@ -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()) {
diff --git a/src/client/mesh.h b/src/client/mesh.h
index 0c4094de2..103c61e45 100644
--- a/src/client/mesh.h
+++ b/src/client/mesh.h
@@ -122,6 +122,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
Ported from irrlicht 1.8