Bird is right, the engine probably need to plane collision.
I will add it for core 300.
The reason I never put that in is that Newton collision system in not like the engine that use pure GJK algorithm or simple discreet collision par function as the bases of the collision system, Or like the ex employee engines that simple plagiarize older version of commercial engines and re write as open source.
Newton use his own proprietary steppes descend algorithm descend algorithm to find the closet distance in a Minkosky sum of two convex, the algorism is simple, faster and more robust that GJK, and it does not suffer from the singularity that you get when eth shape are at zero distance.
Newton also uses the GJK as a fallback solution when the numerical error of the steppes plane decend fail des to numerical precision.
the algorithm is this function here
- Code: Select all
dgContactSolver::dgMinkReturnCode dgContactSolver::UpdateSeparatingPlane(dgMinkFace*& plane, const dgVector& origin)
{
dgVector diff[4];
dgVector aveg[4];
plane = NULL;
dgMinkFace* face = &m_simplex[0];
dgMinkFace* lastDescendFace = NULL;
dgMinkReturnCode code = dgMinkIntersecting;
// this loop can calculate the closest point to the origin usually in 4 to 5 passes,
dgInt32 j = 0;
dgInt32 ciclingCount = -1;
dgFloat32 minDist = dgFloat32 (1.0e20f);
for (; face && (j < DG_UPDATE_SEPARATING_PLANE_MAX_ITERATION); j ++) {
face = NULL;
dgVector normal;
// initialize distance to zero (very important)
dgFloat32 maxDist = dgFloat32 (0.0f);
for (dgInt32 i = 0; i < 4; i ++) {
dgInt32 i0 = m_faceIndex[i][0];
dgInt32 i1 = m_faceIndex[i][1];
dgInt32 i2 = m_faceIndex[i][2];
_ASSERTE (i0 == m_simplex[i].m_vertex[0]);
_ASSERTE (i1 == m_simplex[i].m_vertex[1]);
_ASSERTE (i2 == m_simplex[i].m_vertex[2]);
const dgVector& p0 = m_hullVertex[i0];
const dgVector& p1 = m_hullVertex[i1];
const dgVector& p2 = m_hullVertex[i2];
dgVector e0 (p1 - p0);
dgVector e1 (p2 - p0);
dgVector n (e0 * e1);
dgFloat32 dist = n % n;
if (dist > DG_DISTANCE_TOLERANCE_ZERO) {
n = n.Scale (dgRsqrt (dist));
dist = n % (origin - p0);
// find the plane farther away from the origin
if (dist > maxDist) {
maxDist = dist;
normal = n;
face = &m_simplex[i];
}
}
}
// if we do not have a face at this point it means that the mink shape of the tow convexity face have a very
// skew ratios on floating point accuracy is not enough to guarantee convexity of the shape
if (face) {
dgInt32 index = face->m_vertex[0];
CalcSupportVertex (normal, 4);
dgFloat32 dist = normal % (m_hullVertex[4] - m_hullVertex[index]);
// if we are doing too many passes it means that it is a skew shape with big and small floats
// significant bits may be lost in dist calculation, increasing the tolerance help to resolve the problem
if(dist < DG_UPDATE_SEPARATING_PLANE_DISTANCE_TOLERANCE1) {
plane = face;
code = dgMinkDisjoint;
break;
}
if (dist < DG_DISTANCE_TOLERANCE) {
dgInt32 i = 0;
for (; i < 4; i ++ ) {
dgVector error (m_hullVertex[i] - m_hullVertex[4]);
if ((error % error) < (DG_DISTANCE_TOLERANCE * DG_DISTANCE_TOLERANCE)) {
plane = face;
//code = dgMinkDisjoint;
code = UpdateSeparatingPlaneFallbackSolution (plane, origin);
_ASSERTE ((code == dgMinkDisjoint) || ((code == dgMinkIntersecting) && (m_vertexIndex == 4)));
break;
}
}
if (i < 4) {
break;
}
}
dgInt32 i0 = face->m_vertex[0];
dgInt32 i1 = face->m_vertex[1];
dgInt32 i2 = m_faceIndex[face - m_simplex][3];
_ASSERTE (i2 != face->m_vertex[0]);
_ASSERTE (i2 != face->m_vertex[1]);
_ASSERTE (i2 != face->m_vertex[2]);
Swap (m_hullVertex[i0], m_hullVertex[i1]);
Swap (m_averVertex[i0], m_averVertex[i1]);
m_hullVertex[i2] = m_hullVertex[4];
m_averVertex[i2] = m_averVertex[4];
if (!CheckTetrahedronVolume ()) {
Swap (m_hullVertex[1], m_hullVertex[2]);
Swap (m_averVertex[1], m_averVertex[2]);
_ASSERTE (CheckTetrahedronVolume ());
}
}
}
if (j >= DG_UPDATE_SEPARATING_PLANE_MAX_ITERATION) {
_ASSERTE (CheckTetrahedronVolume());
code = UpdateSeparatingPlaneFallbackSolution (plane, origin);
}
return code;
}
Also thi salgorithn is much simpler, faster and robust that GJK, it does no deal with degenrate convex line a plane,ther is a test that check fo rteh intermediate subshape bing generated to have a volume
if (!CheckTetrahedronVolume ()) { ...
and then the sign of teh volume is use as teh decition to what diriction to take. If you ahev tow shapes tah are very thin, of a flat face that is colliong flat wih anoteh shape the is lon and also flat then teh volume of eh contact arear is zero and the algorith never temrinate.
a distance base algorih will no solve that probme either but the go around it but having a "skinthickess" as the minimum distance that teh collsion is valid.
for this reason I decided not to use plane collision, because eventually two plane collide flat and the algorith will simple fail.
Collsion with collision tree and heigh filed is OK because one of the tow collision shape isa simpel convex with non zero volume and threfore all posible permutation of tetrahedras also have non zero volume.
That is the bad news. The good news si that the single do have a polygon to polygon collision functions,
it is use extensivally in the collision tree collider every time the contacts are calculated, There is aslso a point collionde too that is use for closest distance calculation.
basically the polygon and the point colliders are private subshapes classes on the collision tree and the world, but for core 300,
I can make those legitimate shapes and when a convex hull happen to be a flat face, I can generate a convex flat plane instead and special case the Plane-Plane collision.
That should solve the problem.
on the how to detect i fteh fase are flat, teh converhull3d class does generate flat convex I just do no let it return that shape because in my opnion it dis no mak esence to produce a
shape that I new was going to fail later. but teh conve hull produces perfect hull for any set of point, even a single point. with will give a point,
for a tow point it iwll prduce a line, for three point it will produce a triangle, and for more points eieth a flat convex polygon or a regular hull.
I simple report the special cases as NULL.
another quick solution that can be use is to fake the hull. si what Sweenie sugested. Fake teh hull by giving it the thickess.
you can actually do that in your size very eassy.
if you look at the class dgConveHull3d, teh funtion that preproces the point cloud to produce the convex hull is this
- Code: Select all
void dgConvexHull3d::BuildHull (const dgFloat64* const vertexCloud, dgInt32 strideInBytes, dgInt32 count, dgFloat64 distTol, dgInt32 maxVertexCount)
{
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER))
dgUnsigned32 controlWorld = dgControlFP (0xffffffff, 0);
dgControlFP (_PC_53, _MCW_PC);
#endif
dgInt32 treeCount = count / (DG_VERTEX_CLUMP_SIZE_3D>>1);
if (treeCount < 4) {
treeCount = 4;
}
treeCount *= 2;
dgStack<dgHullVertex> points (count);
dgStack<dgAABBPointTree3dClump> treePool (treeCount + 256);
count = InitVertexArray(&points[0], vertexCloud, strideInBytes, count, &treePool[0], treePool.GetSizeInBytes());
if (m_count >= 4) {
CalculateConvexHull (&treePool[0], &points[0], count, distTol, maxVertexCount);
}
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER))
dgControlFP (controlWorld, _MCW_PC);
#endif
}
this is the part part that does no buil teh hull is teh point cloud does no form a hull
count = InitVertexArray(&points[0], vertexCloud, strideInBytes, count, &treePool[0], treePool.GetSizeInBytes());
if (m_count >= 4) {
CalculateConvexHull (&treePool[0], &points[0], count, distTol, maxVertexCount);
}
bascially all you have to do is that is count is less that 4the it is becaus eth epoint are a plane, take any tree point form the original point cloud and make a plane equation.
the for each point in the original point cloud add an extra point that is equal to the point translated by alone teh direction of normal,
somethon
- Code: Select all
if (m_count < 4)
plane makeplane (points[0], points[1], points[2])
stack<dgFloat64> tmp(count * 2 * stride);
copy original points to tmp
for each point in vertexCloud do
vertexCloud[i + count] = vertexCloud[i] + normal.scale (somethikness)
dgStack<dgAABBPointTree3dClump> treePool (treeCount + 256);
count = InitVertexArray(&points[0], tmp, strideInBytes, count, &treePool[0], treePool.GetSizeInBytes());
if (m_count >= 4) {
CalculateConvexHull (&treePool[0], &points[0], count, distTol, maxVertexCount);
}
and that will make a conve hull of a thick plane, and should work as temporary solution.