Scaled getWorldBoundingSphere() bug introduced in 1.7

Problems building or running the engine, queries about how to use features etc.
Post Reply
FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Scaled getWorldBoundingSphere() bug introduced in 1.7

Post by FuzzyShoting »

I am porting code from 1.6 to 1.7 and seeing a huge performance gain.
There is this one pickle tho. The code uses this example http://www.ogre3d.org/tikiwiki/ManualSp ... e=Cookbook

I am using intersects() to detect if the player is touching the sphere.
And here's some code:

I create the initial sphere that is shared with the size 1

Code: Select all

createSphereMesh("CollSphere",1);
During level loading am I check if portals are present and if they are, then they're created by this function:
center = Position on map
range = how big the CollSphere should be scaled up (for example 40)
destName = Where the player is thrown

Code: Select all

void createPortal(const Vector3 &center, const Real &range, String destName)
{
	if(!mSceneMgr)return;

	Portal tPortal;
	tPortal.mEnt = mSceneMgr->createEntity("PortalSphere"+StringConverter::toString(portal.size()+1),"CollSphere");
	tPortal.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	tPortal.mNode->attachObject(tPortal.mEnt);
	tPortal.mNode->setScale(range,range,range);
	tPortal.mNode->setPosition(center);
	tPortal.mNode->_updateBounds();
	tPortal.mNode->showBoundingBox(true);
	tPortal.dest = destName;
	for(int i=0;i<(int)destName.length();i++)if(destName[i]==' ')destName[i] = '_';
	tPortal.mEnt->setMaterialName("Portal/"+destName);
	portal.push_back(tPortal);
}

struct Portal
{
	SceneNode *mNode;
	Entity *mEnt;
	String dest;
	Portal()
	{
		mNode = 0;
		mEnt = 0;
		dest = "";
	}
	bool collides(const AxisAlignedBox &target)
	{
		if(!mEnt || dest=="")return false;
		
		if(mEnt->getWorldBoundingSphere().intersects(target))return true; // getWorldBoundingSphere doesn't work properly
		return false;
	}
};
I am in the update code calling collides to see if the player's boundingbox is intersecting with the sphere's boundingbox.
This works excellent in Ogre 1.6
But the behavior in Ogre 1.7.4 seems to be slight different:
I can see that the portals are scaled correctly visually and I can see the boundingbox around them. But I cannot get within 20meters of the Portal without my collides code returns true and I get thrown to the next map.

Test 1:
If I exchange getWorldBoundingSphere() with getWorldBoundingBox() however, then it works just fine again.

Test 2:
If I instead of using setScale(40, 40, 40) on the SceneNode and do createSphereMesh("CollSphere",40); then it also works fine. That however breaks the idea of reusing the collsphere.


So, it seems getWorldBoundingSphere() is somehow broken for me. What gives?
And Italic text on the forum is broken too :C
Last edited by FuzzyShoting on Sat Apr 28, 2012 1:31 am, edited 1 time in total.

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: ManualSphereMeshes and Ogre 1.7 intersect differences?

Post by FuzzyShoting »

Tried to get out mRadius during the collides code:

Code: Select all

	bool collides(const AxisAlignedBox &target)
	{
		if(!mEnt || dest=="")return false;
		Ogre::Sphere t = mEnt->getWorldBoundingSphere();//mRadius: 625
		if(t.intersects(target))return true; // getWorldBoundingSphere doesn't work properly
		return false;
	}
And found that reading off t.mRadius is now 625. Which is weird because my scale is 40.

I tried the same in the createPortal code:

Code: Select all

	void createPortal(const Vector3 &center, const Real &range, String destName)
	{
		if(!mSceneMgr)return;

		Portal tPortal;
		tPortal.mEnt = mSceneMgr->createEntity("PortalSphere"+StringConverter::toString(portal.size()+1),"CollSphere");
		tPortal.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		tPortal.mNode->attachObject(tPortal.mEnt);
Ogre::Sphere t = tPortal.mEnt->getWorldBoundingSphere();//mRadius: 1
		tPortal.mNode->setScale(range,range,range);
t = tPortal.mEnt->getWorldBoundingSphere();//mRadius: 1
		tPortal.mNode->setPosition(center);
		tPortal.mNode->_updateBounds();
		tPortal.dest = destName;
		for(int i=0;i<(int)destName.length();i++)if(destName[i]==' ')destName[i] = '_';
		tPortal.mEnt->setMaterialName("Portal/"+destName);
		portal.push_back(tPortal);
	}
Both they were in both cases 1.

mRadius is protected in OgreSphere.h, which leaves only setRadius() to change it.
I looked through my code is found no setRadius().

That leaves 3rd party code such as Ogre to do the change.

Code: Select all

Search "setRadius" (11 hits in 8 files)
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\include\OgreSphere.h (1 hits)
	Line 70:         void setRadius(Real radius) { mRadius = radius; }
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\src\OgreBillboardSet.cpp (2 hits)
	Line 1003:             sph.setRadius(std::max(bill.mWidth, bill.mHeight));
	Line 1007:             sph.setRadius(std::max(mDefaultWidth, mDefaultHeight));
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\src\OgreDefaultSceneQueries.cpp (1 hits)
	Line 250: 				testSphere.setRadius(a->getBoundingRadius());
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\src\OgreMovableObject.cpp (1 hits)
	Line 334: 			mWorldBoundingSphere.setRadius(getBoundingRadius() * factor);
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\src\OgreStreamSerialiser.cpp (1 hits)
	Line 692: 			sphere->setRadius(radius);
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\PlugIns\PCZSceneManager\include\OgreCapsule.h (1 hits)
	Line 56: 		void setRadius(Real newRadius);
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\PlugIns\PCZSceneManager\src\OgreCapsule.cpp (1 hits)
	Line 69: void Capsule::setRadius(Real newRadius)
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\PlugIns\PCZSceneManager\src\OgrePortalBase.cpp (3 hits)
It's not in OgreSphere.h since that is just the code to set mRadius.
It's not in OgreBillboardSet.cpp since that works on a billboard and creates its own sphere.
It's not in OgreDefaultSceneQueries.cpp since that works on its own test sphere.
It could be in OgreMovableObject.cpp but that would require some of my code to call getWorldBoundingSphere(true), but I am calling getWorldBoundingSphere() for which derive is false per default. Other code in Ogre could however be calling getWorldBoundingSphere(true)
It could be in OgreStreamSerialiser.cpp. I dont exactly understand what is going on in it
It's not in the PCZ Plugin since I dont use that.

Okay working theory:
Something is calling getWorldBoundingSphere(true) in Ogre
To test this am I inserting the code during the portal creation

Code: Select all

		Portal tPortal;
		tPortal.mEnt = mSceneMgr->createEntity("PortalSphere"+StringConverter::toString(portal.size()+1),"CollSphere");
		tPortal.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		tPortal.mNode->attachObject(tPortal.mEnt);
		tPortal.mNode->setScale(range,range,range);
		Ogre::Sphere t = tPortal.mEnt->getWorldBoundingSphere(true);
		tPortal.mNode->setPosition(center);
		t = tPortal.mEnt->getWorldBoundingSphere();
This time is both t.mRadius 625! Meaning just doing getWorldBoundingSphere(true) once sets the mRadius forever.
Again, my own code is only calling getWorldBoundingSphere(false).
Who's the bad ogre who has been sleeping in my bed.

Time hunt down Ogre's source.
Again, searching:

Code: Select all

  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\src\OgreEntity.cpp (1 hits)
	Line 538: 				child_itr->second->getWorldBoundingSphere(true);
  C:\kito\git\sources\dependencies\ogre_src_v1-7-4\OgreMain\src\OgreRenderQueue.cpp (2 hits)
	Line 300: 					mo->getWorldBoundingSphere(true), cam, 
	Line 310: 				mo->getWorldBoundingSphere(true), cam);
We can skip OgreEntity.cpp since that requires

Code: Select all

const Sphere& Entity::getWorldBoundingSphere(bool derive) const
to be true

That leaves OgreRenderQueue.
Now interesting, comparing Ogre 1.6.0 against 1.7.4.
Then Ogre 1.6.0 doesn't even have this function:

Code: Select all

	void RenderQueue::processVisibleObject(MovableObject* mo, 
		Camera* cam, 
		bool onlyShadowCasters, 
		VisibleObjectsBoundsInfo* visibleBounds)
	{
		bool receiveShadows = getQueueGroup(mo->getRenderQueueGroup())->getShadowsEnabled()
			&& mo->getReceivesShadows();

		mo->_notifyCurrentCamera(cam);
		if ( mo->isVisible() &&
			(!onlyShadowCasters || mo->getCastShadows()))
		{
			mo -> _updateRenderQueue( this );

			if (visibleBounds)
			{
				visibleBounds->merge(mo->getWorldBoundingBox(true), 
					mo->getWorldBoundingSphere(true), cam, 
					receiveShadows);
			}
		}
		// not shadow caster, receiver only?
		else if (mo->isVisible() &&
			onlyShadowCasters && !mo->getCastShadows() && 
			receiveShadows)
		{
			visibleBounds->mergeNonRenderedButInFrustum(mo->getWorldBoundingBox(true), 
				mo->getWorldBoundingSphere(true), cam);
		}

	}
Ogre 1.6.0 however has some other uses of getWorldBoundingSphere(true) elsewhere, but they don't seem to conflict.
Also, between 1.6.0 and 1.7.4 is getWorldBoundingSphere changed.
1.6.0:

Code: Select all

	const Sphere& MovableObject::getWorldBoundingSphere(bool derive) const
	{
		if (derive)
		{
			mWorldBoundingSphere.setRadius(getBoundingRadius());
			mWorldBoundingSphere.setCenter(mParentNode->_getDerivedPosition());
		}
		return mWorldBoundingSphere;
	}
1.7.4

Code: Select all

	const Sphere& MovableObject::getWorldBoundingSphere(bool derive) const
	{
		if (derive)
		{
			const Vector3& scl = mParentNode->_getDerivedScale();
			Real factor = std::max(std::max(scl.x, scl.y), scl.z);
			mWorldBoundingSphere.setRadius(getBoundingRadius() * factor);
			mWorldBoundingSphere.setCenter(mParentNode->_getDerivedPosition());
		}
		return mWorldBoundingSphere;
	}
The factor seems to be messing with me.. Hmm, what to do, what to do now.

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: ManualSphereMeshes and Ogre 1.7 intersect differences?

Post by FuzzyShoting »


FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: ManualSphereMeshes and Ogre 1.7 intersect differences?

Post by FuzzyShoting »

Inserted the code from Ogre's MovableObject::getWorldBoundingSphere

Seems I remembered wrong before. Range is 25 per default.

Code: Select all

		Portal tPortal;
		tPortal.mEnt = mSceneMgr->createEntity("PortalSphere"+StringConverter::toString(portal.size()+1),"CollSphere");
		tPortal.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		tPortal.mNode->attachObject(tPortal.mEnt);
		tPortal.mNode->setScale(range,range,range);
		//Ogre::Sphere t = tPortal.mEnt->getWorldBoundingSphere(true);
		tPortal.mNode->setPosition(center);
		Ogre::Node* n = tPortal.mEnt->getParentNode();
		const Vector3& scl = n->_getDerivedScale();
		Real factor = std::max(std::max(scl.x, scl.y), scl.z);
		Real bRadius = tPortal.mEnt->getBoundingRadius();
		Ogre::Sphere t = tPortal.mEnt->getWorldBoundingSphere();
range = 25
scl = 25, 25, 25
factor = 25
bRadius = 25
Once mWorldBoundingSphere.setRadius(getBoundingRadius() * factor); gets running, then that sums up to 625.
So both the factor and the bradius is 25.
One of them has to be 1 for my WorldBoundingSphere has to be 25 instead of 625.

_getDerivedScale() reveals _updateFromParent() that reveals updateFromParentImpl().
And that function is the only function changing mDerivedScale returned by _getDerivedScale()

One of the paths uses mInheritScale and if that is false, then falls to mDerivedScale = mScale; Wonder if that fixes it

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: ManualSphereMeshes and Ogre 1.7 intersect differences?

Post by FuzzyShoting »

So, no dice with that.
Going back to what I knew worked:
Create a Sphere mesh with size 25 instead of 1:

Code: Select all

createSphereMesh("CollSphere",25);
Let range be 1:

Code: Select all

		Portal tPortal;
		tPortal.mEnt = mSceneMgr->createEntity("PortalSphere"+StringConverter::toString(portal.size()+1),"CollSphere");
		tPortal.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		tPortal.mNode->attachObject(tPortal.mEnt);
		tPortal.mNode->setInheritScale(false);
		tPortal.mNode->setScale(1,1,1);
		//Ogre::Sphere t = tPortal.mEnt->getWorldBoundingSphere(true);
		tPortal.mNode->setPosition(center);
		Ogre::Node* n = tPortal.mEnt->getParentNode();
		const Vector3& scl = n->_getDerivedScale();
		Real factor = std::max(std::max(scl.x, scl.y), scl.z);
		Real bRadius = tPortal.mEnt->getBoundingRadius();
		Ogre::Sphere t = tPortal.mEnt->getWorldBoundingSphere();
factor is now 1.
bRadius is still 25.

At this point am I tempted to remove the patch Sinbad created and revert to the old 1.6 code :C

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: ManualSphereMeshes and Ogre 1.7 intersect differences?

Post by FuzzyShoting »

To help illustrate the problem I used the 'Character sample':

Portal 1 is created by createSphere("name", 1), then that is scaled to 10.
Portal 0 is created by createSphere("name10", 10) with no scaling.

Portal 1 on the left ---- Portal 0 on the right
Showing no collision
Image


Go forwards a few steps
And portal 1 is now colliding with the player!
Image

Walking to Portal 0
Almost touching it, no collision
Image

One more step.
Bounding box is now seen touching it and the collision is detected
Image

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: ManualSphereMeshes and Ogre 1.7 intersect differences?

Post by FuzzyShoting »

Demo of bug and source based on Character Sample: http://jesper.staunhansen.dk/files/ogre ... n%20bug.7z

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: Scaled getWorldBoundingSphere() bug introduced in 1.7

Post by masterfalcon »

Interesting find. If you haven't already, would you mind writing this up as a bug? It could get lost and forgotten on the forums.

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: Scaled getWorldBoundingSphere() bug introduced in 1.7

Post by FuzzyShoting »

Created: http://www.ogre3d.org/mantis/view.php?id=533
Linked to here since most of the info already is here.

FuzzyShoting
Kobold
Posts: 28
Joined: Sun Apr 22, 2012 3:34 pm
x 1

Re: Scaled getWorldBoundingSphere() bug introduced in 1.7

Post by FuzzyShoting »

Limited my search to this changeset in the source between 1.6.5 and 1.7.4
I have commented it out to revert to the old behavior.
For whatever reason then I just cannot figure out why it was included in the first place


http://i.imgur.com/s5ygL.png
Image

Post Reply