44

Physx之解决三角形顶点相近卡住的问题

 4 years ago
source link: http://pkxpp.github.io/2019/11/13/PhysX之解决三角形顶点相近卡住的问题/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

[TOC]

今天遇到一个问题,角色卡在一个模型边上,在PVD看模型也比较正常,一直调试跟踪,最终找到了问题所在。

原因

1.问题出在最后一个sweepCapsuleTriangles函数里面,代码如下:

#ifdef __SPU__
				Vec3V dummy1, dummy2;
				FloatV result = distanceSegmentTriangleSquared(
					V3LoadU(capsule.p0), V3LoadU(capsule.p1), V3LoadU(p0), V3LoadU(p1), V3LoadU(p2), dummy1, dummy2);
				PxReal dist2 = FStore(result);
	#else
				// AP: switching to SIMD version produced -25% regression in Sweep*SphereHfld
				PxReal dist2 = distanceSegmentTriangleSquared(capsule.p0, segmentExtent, p0, p1 - p0, p2 - p0);
	#endif
				if (dist2<=r2)
				{
					hitIndex    = i;
					t            = 0.0f;
					normal        = -unitDir;
					outFlags    = PxHitFlag::eDISTANCE|PxHitFlag::eNORMAL;
					_triNormal    = denormalizedNormal.getNormalized();
					return true;
				}

当p0、p1和p2有有两个点相同的时候,会导致p1-p0和p2-p0其中一个向量为0,得到的dist2为负无穷大,所以就会执行代码中的条件语句。最终结果是move函数移动成功了,但是只移动了0的位移,表现上就是一直卡在那个地方。

  1. 至于顶点一样的情况,其实并不是完全一样,而是有很小的差异。再加上浮点数运算会丢失精度,这个很小的差异被抹掉了,所以到上面代码的时候就出现相同的点了。

计算的代码位置(没看太明白):

PX_FORCE_INLINE void Gu::TriangleMesh::computeWorldTriangle(PxTriangle& worldTri, PxTriangleID triangleIndex, const Cm::Matrix34& worldMatrix, PxU32* PX_RESTRICT vertexIndices, PxU32* PX_RESTRICT adjacencyIndices) const
	{
		PxU32 vref0, vref1, vref2;
		if(mMesh.has16BitIndices())
		{
			const Gu::TriangleT<PxU16>& T = ((const Gu::TriangleT<PxU16>*)getTrianglesFast())[triangleIndex];
			vref0 = T.v[0];
			vref1 = T.v[1];
			vref2 = T.v[2];
		}
		else
		{
			const Gu::TriangleT<PxU32>& T = ((const Gu::TriangleT<PxU32>*)getTrianglesFast())[triangleIndex];
			vref0 = T.v[0];
			vref1 = T.v[1];
			vref2 = T.v[2];
		}
		const PxVec3* PX_RESTRICT vertices = getVerticesFast();
		worldTri.verts[0] = worldMatrix.transform(vertices[vref0]);
		worldTri.verts[1] = worldMatrix.transform(vertices[vref1]);
		worldTri.verts[2] = worldMatrix.transform(vertices[vref2]);
	
		if(vertexIndices)
		{
			vertexIndices[0] = vref0;
			vertexIndices[1] = vref1;
			vertexIndices[2] = vref2;
		}

		if(adjacencyIndices)
		{
			if(mMesh.getAdjacencies())
			{
				adjacencyIndices[0] = mMesh.getAdjacencies()[triangleIndex*3 + 0];
				adjacencyIndices[1] = mMesh.getAdjacencies()[triangleIndex*3 + 1];
				adjacencyIndices[2] = mMesh.getAdjacencies()[triangleIndex*3 + 2];
			}
			else
			{
				adjacencyIndices[0] = 0xffffffff;
				adjacencyIndices[1] = 0xffffffff;
				adjacencyIndices[2] = 0xffffffff;
			}
		}
	}
  • 问题数据

出现问题的时候,断点的数据如下:

vertices[vref0] = {x = -4.10000086, y = -0.200000167, z = -3.56512594}
	vertices[vref1] = {x = -4.10000086, y = -0.200000077, z = -3.56512594}
	vertices[vref2] = {x = -4.10000086, y = -0.200000212, z = -4.10000229}

	worldMatrix.transform.base3 = {x=72.3379974 y=4.76143503 z=18.5843773 }

	// 得到这个三角形前两个点完全一样
	worldTri.verts[0] = { x = 68.237990, y = 4.56143475, z = 15.0192509}
	worldTri.verts[1] = { x = 68.237990, y = 4.56143475, z = 15.0192509}
	worldTri.verts[2] = { x = 68.237990, y = 4.56143475, z = 14.4843750}

简单来说就是:

4.76143503 + -0.200000167 = 4.56143475
	4.76143503 + -0.200000077 = 4.56143475

至于为什么请参考另外一篇文章[1] 为什单精度浮点数的有效位时7位

解决

  • 1.把顶点传到PhysX之前,先检查一遍。可以删掉重新组织Vertex和Index,我简单处理的方法是把两个顶点很近的时候,标记为同一个索引,这样的三角形比较容易标识
    if (fMinDist <= 1e-5)
                  {
                      // set the same index, and then cooking will process it. eREMOVE_DUPLICATED_TRIANGLES
                      pIndices[3 * i + nIndexIndex1] = pIndices[3 * i + nIndexIndex2];
                  }
  • 2.PhysxCooking的参数增加去重的Flag,这样上面的三角形就会被PhysX剔除,从而就解决了这样的问题:如下
physx::PxCookingParams cookingParams(scale);
		cookingParams.buildTriangleAdjacencies = true;
		cookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES |
			PxMeshPreprocessingFlag::eREMOVE_UNREFERENCED_VERTICES | PxMeshPreprocessingFlag::eREMOVE_DUPLICATED_TRIANGLES);

参考

[1] 为什么单精度浮点数的精度是7位


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK