Page 1 of 1

[fixed] Collision bug fix

Posted: Wed Sep 14, 2005 8:21 pm
by Spintz
In CSceneCollisionManager.cpp, change the function getCollisionPoint to this -

Code: Select all

//! Finds the collision point of a line and lots of triangles, if there is one.
bool CSceneCollisionManager::getCollisionPoint(const core::line3d<f32>& ray,
	ITriangleSelector* selector, core::vector3df& outIntersection,
	core::triangle3df& outTriangle)
{
	if (!selector)
	{
		_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
		return false;
	}

	s32 totalcnt = selector->getTriangleCount();
	Triangles.set_used(totalcnt);

	s32 cnt = 0;
	selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray);

	core::vector3df linevect = ray.getVector().normalize();
                core::vector3df intersection;
	f32 nearest = 9999999999999.0f;
	bool found = false;
	f32 tmp;
    
	for( s32 i = 0; i < cnt; ++i )
	{
		if( Triangles[i].getIntersectionWithLine( ray.start, linevect, intersection ) )
		{
			if( intersection.isBetweenPoints( ray.start, ray.end ) )
			{
				tmp = (f32)intersection.getDistanceFromSQ( ray.start );

				if( tmp < nearest )
				{
					nearest = tmp;
					outTriangle = Triangles[i];
					outIntersection = intersection;
					found = true;
				}
			}
		}
	}

	_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
	return found;
}
EDIT: The lineVect needs to be normalized for the functions to work properly. The other changes are just minor speed ups.

Also, in triangle3d.h, change the getIntersectionWithLine function to -

EDIT: Don't use isPointInsideFast, I came across a bug with that as well, where not all intersections were returned. If you keep using isPointInside and then fix the isOnSameSide function, it will work perfectly!!!

In triangle3d.h, change isOnSameSide to

Code: Select all

bool isOnSameSide(const vector3d<T>& p1, const vector3d<T>& p2, 
	const vector3d<T>& a, const vector3d<T>& b) const
{
	vector3d<T> bminusa = b - a;
	vector3d<T> cp1 = bminusa.crossProduct(p1 - a);
	vector3d<T> cp2 = bminusa.crossProduct(p2 - a);
	return (cp1.dotProduct(cp2) >= 0.0f);
}
The single small change in this function, is in the return call, it currently is '>' and should be '>='!!!!

Also in triangle3d.h, change getIntersectionOfPlaneWithLine function to -

Code: Select all

bool getIntersectionOfPlaneWithLine(const vector3d<T>& linePoint,
	const vector3d<T>& lineVect, vector3d<T>& outIntersection) const
{
	vector3d<T> normal = getNormal().normalize();
	T t2 = normal.dotProduct( lineVect );

	if( t2 == 0.0f )
		return false;

	T d = pointA.dotProduct( normal );
	T t = -( normal.dotProduct( linePoint ) - d ) / t2;
	outIntersection = linePoint + (lineVect * t);
	return true;
}
Here, the normal of the triangle needs to be normalized. getNormal() for a triangle only returns the vector representing the direction the triangle is facing, and does not normalize it!

Happy colliding! :D

Posted: Thu Sep 15, 2005 12:09 am
by Spintz
BTW, I checked the paper by Kasper Fauerby and the function is correct, as he has listed in the paper, however, it does not work for all cases and the scope of that funciton is a little beyond me. The extremely minimal speed gain by using that function, is not worth the time to debug it, IMO ( so I won't! :P )

Posted: Thu Sep 15, 2005 1:55 am
by Fred
Tries these changes but they made no difference.

Posted: Thu Sep 15, 2005 6:32 pm
by Spintz
You'll also need to apply -

http://irrlicht.sourceforge.net/phpBB2/ ... php?t=8773

to fix the FPU precision for accurate collision detections when using DirectX.

Posted: Fri Sep 16, 2005 3:10 am
by Spintz
Found one other small change needed in aabbox3d.h

Replace this function -

Code: Select all

//! Tests if the box intersects with a line
//! \return Returns true if there is an intersection and false if not.
bool intersectsWithLine(const vector3d<T>& linemiddle, 
						const vector3d<T>& linevect,
						T halflength) const
{
	const vector3d<T> e = getExtent(); 
	const vector3d<T> t = getCenter() - linemiddle;
	float r;

	if ((fabs(t.X) > e.X + halflength * fabs(linevect.X)) || 
		(fabs(t.Y) > e.Y + halflength * fabs(linevect.Y)) ||
		(fabs(t.Z) > e.Z + halflength * fabs(linevect.Z)) )
		return false;

	r = e.Y * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.Y);
	if (fabs(t.Y*linevect.Z - t.Z*linevect.Y) > r )
		return false;

	r = e.X * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.X);
	if (fabs(t.Z*linevect.X - t.X*linevect.Z) > r )
		return false;

	r = e.X * (T)fabs(linevect.Y) + e.Y * (T)fabs(linevect.X);
	if (fabs(t.X*linevect.Y - t.Y*linevect.X) > r)
		return false;

	return true;
}

Posted: Fri Sep 16, 2005 11:43 am
by Fred
I'll try this out tonight. If this fixes the problem, I hope Niko can fold these changes back into the engine.

Posted: Thu Nov 02, 2006 8:50 pm
by bronxbomber92
Sorry for bumping this old thread, but I'm confused on exactly what I should change and shouldn't (since all the edits creates moe confusion).

Posted: Fri Nov 03, 2006 12:08 am
by Spintz
I'll re-evaluate the changes and see if they've been implemented in SVN. Let you know results soon...

Posted: Sat Nov 04, 2006 5:14 am
by bronxbomber92
Alright, thanks :)

Posted: Fri Nov 10, 2006 7:08 pm
by Spintz
I'm still planning on getting to this. Been very busy lately....

Posted: Fri Nov 10, 2006 7:55 pm
by bronxbomber92
Take your time :)

Posted: Fri Nov 10, 2006 11:46 pm
by bitplane
just checked these...
triange3d isOnSameSide, getIntersectionOfPlaneWithLine, and aabbox intersectsWithLine were applied sometime before 1.1

CSceneCollisionManager::getCollisionPoint didn't normalize the ray's vector, i've added this as of the latest svn revision.

Posted: Mon Nov 13, 2006 2:04 pm
by Spintz
Thanks bitplane :)

Posted: Tue Nov 14, 2006 3:00 am
by bronxbomber92
I'm uding the mac version, which I believe to be 1.0... So I don't think those are applied for me.

Posted: Tue Nov 14, 2006 1:33 pm
by Spintz
Well, all the code excerpts in this function are what the functions should be. So look at the code in your engine for these functions. If it's not the same, make it like these!