Is rayscenequery my best option?

Problems building or running the engine, queries about how to use features etc.
Post Reply
NQ
Kobold
Posts: 39
Joined: Fri Apr 08, 2005 5:18 pm

Is rayscenequery my best option?

Post by NQ »

Hey all! I'm trying to do some extremely rudimentary physics, but I'm running into speed issues. I was hoping I could get some suggestions about what to do here.

In a game I'm making I have about a hundred objects lying around on a TerrainSceneManager terrain surface. Some or them are moving and but most are not. All I want is basic gravity and bounds checking (that means: if object is below ground then move it up to the surface).

At the moment I have solved this by having each object, in every frame, perform a rayscenequery straight downwards (it starts at height 100 which should always be above the object and is aimed atVector3::NEGATIVE_UNIT_Y). It expects that one of the results is the terrain, and checks "if object is below ground then move it up to ground altitude" and "if object is above ground altitude then add gravity acceleration downwards".

My problem is that this appears to be SLOW! Should performing 100 rayscenequeries every frame be slow? (i get about 8 FPS on a good computer, and I tracked it down to the rayscenequery->execute call using my timetracking system). In the future I will have thousands of objects, not just a hundred, so this performance is an issue.

Is there a less computation-intensive way to do these extremely rudimentary physics? I have included some pseudocode for my current solution below. Thanks for your help!

Code: Select all

for (all objects)
{
	// perform rayscenequery
	RaySceneQuery* mRayQuery = COgreFramework::getSingletonPtr()->m_pSceneMgr->createRayQuery(Ray(Vector3(objPos.x, 100.0, objPos.z), Vector3::NEGATIVE_UNIT_Y));
	RaySceneQueryResult &result = mRayQuery->execute(); // this line computes VERY SLOWLY compared to everything else

	// wander through the results
	for (RaySceneQueryResult::iterator itr = result.begin(); itr != result.end(); itr++)
	{
		if (itr->worldFragment) // if it's a worldFragment
		{
			Real terrainHeight = itr->worldFragment->singleIntersection.y;
			if (objPos.y == terrainHeight) // if on ground then add friction (almost never happens except when standing still anyway)
			{
				objectStatus[SpeedX] *= 0.9;
				objectStatus[SpeedY] *= 0.9;
				objectStatus[SpeedZ] *= 0.9;
			}
			if (objPos.y < terrainHeight) // if below ground then move it up and add friction
			{
				object->setPosition( Vector3(objPos.x, terrainHeight, objPos.z) );
				objectStatus[SpeedY] = 0;
				objectStatus[SpeedX] *= 0.9;
				objectStatus[SpeedZ] *= 0.9;
			}
			if (objPos.y > terrainHeight) // if above ground then make it fall (add gravity)
			{
				objectStatus[SpeedY] -= CONST_GRAVITY*timeSinceLastFrame;
			}
			break; // only do the above the first time we find a worldFragment
		}
	}
}
NQ
Kobold
Posts: 39
Joined: Fri Apr 08, 2005 5:18 pm

Re: Is rayscenequery my best option?

Post by NQ »

Haha lol... I did spend quite a while searching the forum and wiki before I posted, and now even more time but I finally found some potential answers. I am now compiling them into this slightly more comprehensive entry;
http://www.ogre3d.org/forums/viewtopic. ... 65#p309965
nullsquared wrote:
KungFooMasta wrote: 2. Hey look, there is an inneficient function that I don't need. I just won't use it. I could even roll my own or improve this if I needed to.
The problem is that you well understand the causes of why its inefficient, but others won't. Newbies will constantly come with something like:
So I'm using the PreciseSceneQuery to pick my RTS units (and some of the units can programatically 'pick' other units), and once I have about 50 or more units spawned, it gets very slow. Each unit is about 5000 triangles or so. Here's my code:

Code: Select all

Ogre::PreciseRaySceneQuery *query = sceneMgr->createPreciseRaySceneQuery(ray);
query->execute(); // <-- this is where it is very slow, and causes choppy gameplay
And then we tell him/her that this is slow because it iterates through all of the triangles manually, and that it has to download vertex/index data from the GPU, etc.
Hm. I think the OgreTeam should optimize this function. Ogre is well optimized all around but here, and this is a very useful function, so it should be optimized just like the rest of the engine.
Catch my drift?
nullsquared says this is a common question? And is refering to previous posts by newbies, but I haven't been able to find such things. So maybe I should use a physics lib? That struck me as preposterous since all I wished to do was to check if some position was below the terrain! Anyway, here might be my answer in a post by tuan kuranes:

http://www.ogre3d.org/forums/viewtopic. ... 35#p244135
tuan kuranes wrote:
#1 would be preferred, but if it's too slow your only option is to use #2 (which is what I'm doing now).
Strange, it should be as fast as calculating it yourself.

Ogre basic terrain scene manager (like PLSM2) use a special case handling (if ray direction is Vector3::NEGATIVE_UNIT_Y) where it just compute results on heightfield instead of really launching a ray through all tiles (which is indeed slow, especially on highly scaled terrain.).
So TSM is correctly using this optimisation, It should be pretty fast.

You have to make sure scene manager use that optimisation, stop at first result, (otherwise it will pass the ray query on octree scene manager to launch rays).

search in terrain rayscenequery code, you'll see the special case (look for TerrainRaySceneQuery::execute). Perhaps try to put a breakpoint in TerrainRaySceneQuery::execute to see if your case goes trough that special case, and returns as soon it gets results (to make sure it does you can/should use a RaySceneQueryListener ).

And make sure you put all required flags on the ray scene query.

Code: Select all

 _ray_query = mCamera->getSceneManager()->createRayQuery(ray);    _ray_query->setQueryTypeMask(Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK );   _ray_query->setWorldFragmentType(Ogre::SceneQuery::WFT_SINGLE_INTERSECTION);
 ray.setDirection(Vector3::NEGATIVE_UNIT_Y);
So there's this way to mask the query, aye? Making it faster? I gotta try this out. I'll post back with the results, but still feel free to post other suggestions.
NQ
Kobold
Posts: 39
Joined: Fri Apr 08, 2005 5:18 pm

Re: Is rayscenequery my best option?

Post by NQ »

Masking the query produced no performance results :(
I'm going to find a physics engine. If you got a better idea then please stop me, because otherwise I might just be giving myself alot of extra work here.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: Is rayscenequery my best option?

Post by jacmoe »

You are definitely on the right track here. :)
Use a physics library.
Most of what a physics library does is employing clever algorithms to optimise collision detection routines.
I've been down that old school manual route before, and it's not an easy road.
And then I didn't even get to the physics bits: how you react to a collision.
That's a whole different set of problems..
And you will never get that kind of performance you get when using a dedicated library.
So save yourself from a lot of grief and use a good library - like Bullet, Newton, Havok .. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
NQ
Kobold
Posts: 39
Joined: Fri Apr 08, 2005 5:18 pm

Re: Is rayscenequery my best option?

Post by NQ »

Thanks for the input! I often reinvent the wheel but this time I'm looking into OgreNewt (i checked the addons forum and selected the engine with the most posts :) )

Also, since the tutorials and wiki doesn't seem to even mention this problem exists, I think I better go in there and write something about it.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 534

Re: Is rayscenequery my best option?

Post by Kojack »

The TerrainSceneManager provides a method called getHeightAt. You give it the x,z coordinates on the terrain, and it uses the heightmap to calculate the height at that point. Should be vastly faster than a ray query and easier than adding a physics engine if all you want is terrain following.
Post Reply