summaryrefslogtreecommitdiff
path: root/indra/newview/llfloatermodelpreview.cpp
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2011-06-03 00:13:50 -0500
committerDave Parks <davep@lindenlab.com>2011-06-03 00:13:50 -0500
commitb0a04b08f7b3cf4040b9708125a548e646b990f7 (patch)
treea090c45c3623c95ad902fbc87c669bd4f4f8f473 /indra/newview/llfloatermodelpreview.cpp
parent51bc6c01c10723d1682392fe8a15528fc7f4b7cb (diff)
SH-1744 Add havok's degenerate triangle check to importer. Highlight degenerate triangles in physics mesh and block upload when degenerate triangles are present.
Diffstat (limited to 'indra/newview/llfloatermodelpreview.cpp')
-rw-r--r--indra/newview/llfloatermodelpreview.cpp160
1 files changed, 158 insertions, 2 deletions
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 2a3bd37129..b715f326a0 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -178,6 +178,80 @@ std::string lod_label_name[NUM_LOD+1] =
"I went off the end of the lod_label_name array. Me so smart."
};
+
+#define LL_DEGENERACY_TOLERANCE 1e-7f
+
+inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
+{
+ volatile F32 p0 = a[0] * b[0];
+ volatile F32 p1 = a[1] * b[1];
+ volatile F32 p2 = a[2] * b[2];
+ return p0 + p1 + p2;
+}
+
+bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE)
+{
+ // small area check
+ {
+ LLVector4a edge1; edge1.setSub( a, b );
+ LLVector4a edge2; edge2.setSub( a, c );
+ //////////////////////////////////////////////////////////////////////////
+ /// Linden Modified
+ //////////////////////////////////////////////////////////////////////////
+
+ // If no one edge is more than 10x longer than any other edge, we weaken
+ // the tolerance by a factor of 1e-4f.
+
+ LLVector4a edge3; edge3.setSub( c, b );
+ const F32 len1sq = edge1.dot3(edge1).getF32();
+ const F32 len2sq = edge2.dot3(edge2).getF32();
+ const F32 len3sq = edge3.dot3(edge3).getF32();
+ bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
+ bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
+ bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
+ if ( abOK && acOK && cbOK )
+ {
+ tolerance *= 1e-4f;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ /// End Modified
+ //////////////////////////////////////////////////////////////////////////
+
+ LLVector4a cross; cross.setCross3( edge1, edge2 );
+
+ LLVector4a edge1b; edge1b.setSub( b, a );
+ LLVector4a edge2b; edge2b.setSub( b, c );
+ LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
+
+ if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
+ {
+ return true;
+ }
+ }
+
+ // point triangle distance check
+ {
+ LLVector4a Q; Q.setSub(a, b);
+ LLVector4a R; R.setSub(c, b);
+
+ const F32 QQ = dot3fpu(Q, Q);
+ const F32 RR = dot3fpu(R, R);
+ const F32 QR = dot3fpu(R, Q);
+
+ volatile F32 QQRR = QQ * RR;
+ volatile F32 QRQR = QR * QR;
+ F32 Det = (QQRR - QRQR);
+
+ if( Det == 0.0f )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool validate_face(const LLVolumeFace& face)
{
for (U32 i = 0; i < face.mNumIndices; ++i)
@@ -189,6 +263,31 @@ bool validate_face(const LLVolumeFace& face)
}
}
+ if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
+ {
+ llwarns << "Face has invalid number of indices." << llendl;
+ return false;
+ }
+
+ /*const LLVector4a scale(0.5f);
+
+ for (U32 i = 0; i < face.mNumIndices; i+=3)
+ {
+ U16 idx1 = face.mIndices[i];
+ U16 idx2 = face.mIndices[i+1];
+ U16 idx3 = face.mIndices[i+2];
+
+ LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
+
+ if (ll_is_degenerate(v1,v2,v3))
+ {
+ llwarns << "Degenerate face found!" << llendl;
+ return false;
+ }
+ }*/
+
return true;
}
@@ -3752,7 +3851,35 @@ void LLModelPreview::updateStatusMessages()
mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
}
+ bool has_degenerate = false;
+ {//check for degenerate triangles in physics mesh
+ U32 lod = LLModel::LOD_PHYSICS;
+ const LLVector4a scale(0.5f);
+ for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
+ { //for each model in the lod
+ if (mModel[lod][i]->mPhysics.mHull.empty())
+ { //no decomp exists
+ S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
+ for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
+ { //for each submesh (face), add triangles and vertices to current total
+ const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
+ for (S32 k = 0; k < face.mNumIndices && !has_degenerate; )
+ {
+ LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale);
+
+ if (ll_is_degenerate(v1,v2,v3))
+ {
+ has_degenerate = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
std::string mesh_status_na = mFMP->getString("mesh_status_na");
@@ -3853,7 +3980,10 @@ void LLModelPreview::updateStatusMessages()
for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)
{
- upload_ok = upload_ok && mdl->mPhysics.mHull[i].size() <= 256;
+ if (mdl->mPhysics.mHull[j].size() > 256)
+ {
+ upload_ok = false;
+ }
}
}
@@ -3876,7 +4006,7 @@ void LLModelPreview::updateStatusMessages()
}
}
- if ( upload_ok && !errorStateFromLoader && skinAndRigOk )
+ if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate)
{
mFMP->childEnable("ok_btn");
}
@@ -4666,6 +4796,32 @@ BOOL LLModelPreview::render()
glLineWidth(3.f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+
+ { //show degenerate triangles
+ LLStrider<LLVector3> pos_strider;
+ buffer->getVertexStrider(pos_strider, 0);
+ LLVector4a* pos = (LLVector4a*) pos_strider.get();
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ LLGLDisable cull(GL_CULL_FACE);
+ LLStrider<U16> idx;
+ buffer->getIndexStrider(idx, 0);
+
+ glColor4f(1.f,0.f,0.f,1.f);
+ const LLVector4a scale(0.5f);
+ for (U32 i = 0; i < buffer->getNumIndices(); i += 3)
+ {
+ LLVector4a v1; v1.setMul(pos[*idx++], scale);
+ LLVector4a v2; v2.setMul(pos[*idx++], scale);
+ LLVector4a v3; v3.setMul(pos[*idx++], scale);
+
+ if (ll_is_degenerate(v1,v2,v3))
+ {
+ buffer->draw(LLRender::TRIANGLES, 3, i);
+ }
+ }
+ }
+
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glLineWidth(1.f);
}