Commit 2b18db4c authored by Rogerborg's avatar Rogerborg

https://sourceforge.net/tracker2/?func=detail&aid=2473520&group_id=74339&atid=540676

Another fix to CSceneCollisionManager::getPickedNodeBB(). Ensure that the collision point with the plane of a box is actually on the box surface rather than outside it.  Retested with regression test and example 07.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2048 dfc29bdd-3216-0410-991c-e03cc46cb475
parent bac02b5b
...@@ -94,25 +94,24 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, ...@@ -94,25 +94,24 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root,
(bits==0 || (bits != 0 && (current->getID() & bits)))) (bits==0 || (bits != 0 && (current->getID() & bits))))
{ {
// get world to object space transform // get world to object space transform
core::matrix4 mat; core::matrix4 worldToObject;
if (!current->getAbsoluteTransformation().getInverse(mat)) if (!current->getAbsoluteTransformation().getInverse(worldToObject))
continue; continue;
// transform vector from world space to object space // transform vector from world space to object space
core::line3df line(truncatedRay); core::line3df objectRay(truncatedRay);
mat.transformVect(line.start); worldToObject.transformVect(objectRay.start);
mat.transformVect(line.end); worldToObject.transformVect(objectRay.end);
core::aabbox3df box = current->getBoundingBox(); const core::aabbox3df & objectBox = current->getBoundingBox();
// do the initial intersection test in object space, since the // Do the initial intersection test in object space, since the
// object space box is more accurate. // object space box test is more accurate.
if(objectBox.isPointInside(objectRay.start))
if(box.isPointInside(line.start))
{ {
// If the line starts inside the box, then consider the distance as being // If the line starts inside the box, then consider the distance as being
// to the centre of the box. // to the centre of the box.
const f32 toIntersectionSq = line.start.getDistanceFromSQ(box.getCenter()); const f32 toIntersectionSq = objectRay.start.getDistanceFromSQ(objectBox.getCenter());
if(toIntersectionSq < outbestdistance) if(toIntersectionSq < outbestdistance)
{ {
outbestdistance = toIntersectionSq; outbestdistance = toIntersectionSq;
...@@ -122,13 +121,15 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, ...@@ -122,13 +121,15 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root,
truncatedRay.end = truncatedRay.start + (rayVector * sqrtf(toIntersectionSq)); truncatedRay.end = truncatedRay.start + (rayVector * sqrtf(toIntersectionSq));
} }
} }
else if (box.intersectsWithLine(line)) else if (objectBox.intersectsWithLine(objectRay))
{ {
// Now transform into world space, to take scaling into account. // Now transform into world space, since we need to use world space
current->getAbsoluteTransformation().transformBox(box); // scales and distances.
core::aabbox3df worldBox(objectBox);
current->getAbsoluteTransformation().transformBox(worldBox);
core::vector3df edges[8]; core::vector3df edges[8];
box.getEdges(edges); worldBox.getEdges(edges);
/* We need to check against each of 6 faces, composed of these corners: /* We need to check against each of 6 faces, composed of these corners:
/3--------/7 /3--------/7
...@@ -162,8 +163,8 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, ...@@ -162,8 +163,8 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root,
edges[faceEdges[face][1]], edges[faceEdges[face][1]],
edges[faceEdges[face][2]]); edges[faceEdges[face][2]]);
// Only consider lines that might be entering through the plane, since we know // Only consider lines that might be entering through this face, since we
// that the start point is outside the box. // already know that the start point is outside the box.
if(facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT) if(facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT)
continue; continue;
...@@ -171,16 +172,26 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, ...@@ -171,16 +172,26 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root,
// enough to intersect with the box. // enough to intersect with the box.
if(facePlane.getIntersectionWithLine(ray.start, rayVector, intersection)) if(facePlane.getIntersectionWithLine(ray.start, rayVector, intersection))
{ {
const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection); const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection);
if(toIntersectionSq < outbestdistance) if(toIntersectionSq < outbestdistance)
{
// We have to check that the intersection with this plane is actually
// on the box, so need to go back to object space again. We also
// need to move the intersection very slightly closer to the centre of
// the box to take into account fp precision losses, since the intersection
// will axiomatically be on the very edge of the box.
worldToObject.transformVect(intersection);
intersection *= 0.99f;
if(objectBox.isPointInside(intersection))
{ {
outbestdistance = toIntersectionSq; outbestdistance = toIntersectionSq;
outbestnode = current; outbestnode = current;
} }
} }
}
// If the ray is entering through the first face of a pair, then it can't // If the ray could be entering through the first face of a pair, then it can't
// also be entering through the opposite face, and so we can skip that face. // also be entering through the opposite face, and so we can skip that face.
if(0 == (face % 2)) if(0 == (face % 2))
++face; ++face;
......
Test suite pass at GMT Tue Jan 06 15:07:16 2009 Test suite pass at GMT Tue Jan 06 15:37:52 2009
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment