[GSoC 2008 - Accepted] Different Level of Detail Strategies

Threads related to Google Summer of Code
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Post by LostEra »

Sorry, I wasn't very clear. This is a modification to the distance-based strategy to allow assets using the old method to, with some tweaking, take advantage of viewport size and fov. The pixel count approximation strategy is still probably preferable, but this would be an alternative to converting old assets to the new strategy.

Also, I forget to mention, the reference view is set as follows:

Code: Select all

DistanceLodStrategy::getSingleton().setReferenceView(viewportWidth, viewportHeight, fov);
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Post by LostEra »

It bothered me that squared distances were now required in so many places (particularly material scripts), but no longer. The strategies now supply a method to "transform" user-supplied values. This should make a lot less changes to existing assets necessary.

For anyone looking for an example of the project in action, the PlayPen project included in the Ogre solution contains code for testing lod in the testLod() function. This demonstrates the use lod strategies and lod listeners.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

Just a heads-up, because of a need of my own I added a fairly simple feature that had been mooted in the forum before today, the ability to tell a Camera to use another Camera for LOD calculation purposes. Specifically, this is used by default to make shadow texture renders use the main view's camera for LOD calculation and not the shadow camera, to avoid bad LOD decisions being made for the shadow render.

It's a pretty simple change, I don't know if you want to incorporate it in your branch now, or wait until after the Summer of Code is over and we start to merge branches. Your call, I just thought I'd tell you, just incase you wanted it, or if you had something similar in mind anyway.

Here's the patch against the v1-6 branch, should you want to adapt it:

Code: Select all

Modified: branches/v1-6/OgreMain/include/OgreCamera.h
===================================================================
--- branches/v1-6/OgreMain/include/OgreCamera.h	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/include/OgreCamera.h	2008-07-30 11:03:11 UTC (rev 7804)
@@ -149,6 +149,8 @@
 		Frustum *mCullFrustum;
 		/// Whether or not the rendering distance of objects should take effect for this camera
 		bool mUseRenderingDistance;
+		/// Camera to use for LOD calculation
+		const Camera* mLodCamera;
 
 
         // Internal functions for calcs
@@ -427,8 +429,29 @@
 		*/
 		Real getLodBias(void) const;
 
+		/** Get a pointer to the camera which should be used to determine 
+			LOD settings. 
+		@remarks
+			Sometimes you don't want the LOD of a render to be based on the camera
+			that's doing the rendering, you want it to be based on a different
+			camera. A good example is when rendering shadow maps, since they will 
+			be viewed from the perspective of another camera. Therefore this method
+			lets you associate a different camera instance to use to determine the LOD.
+		@par
+			To revert the camera to determining LOD based on itself, call this method with 
+			a pointer to itself. 
+		*/
+		virtual void setLodCamera(const Camera* lodCam);
 
+		/** Get a pointer to the camera which should be used to determine 
+			LOD settings. 
+		@remarks
+			If setLodCamera hasn't been called with a different camera, this
+			method will return 'this'. 
+		*/
+		virtual const Camera* getLodCamera() const;
 
+
         /** Gets a world space ray as cast from the camera through a viewport position.
         @param screenx, screeny The x and y position at which the ray should intersect the viewport, 
             in normalised screen coordinates [0,1]

Modified: branches/v1-6/OgreMain/src/OgreCamera.cpp
===================================================================
--- branches/v1-6/OgreMain/src/OgreCamera.cpp	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/src/OgreCamera.cpp	2008-07-30 11:03:11 UTC (rev 7804)
@@ -58,7 +58,8 @@
 		mLastViewport(0),
 		mAutoAspectRatio(false),
 		mCullFrustum(0),
-		mUseRenderingDistance(true)
+		mUseRenderingDistance(true),
+		mLodCamera(0)
 
     {
 
@@ -568,6 +569,19 @@
 	{
 		return mSceneLodFactorInv;
 	}
+	//-----------------------------------------------------------------------
+	void Camera::setLodCamera(const Camera* lodCam)
+	{
+		if (lodCam == this)
+			mLodCamera = 0;
+		else
+			mLodCamera = lodCam;
+	}
+	//---------------------------------------------------------------------
+	const Camera* Camera::getLodCamera() const
+	{
+		return mLodCamera? mLodCamera : this;
+	}
     //-----------------------------------------------------------------------
 	Ray Camera::getCameraToViewportRay(Real screenX, Real screenY) const
 	{

Modified: branches/v1-6/OgreMain/src/OgreEntity.cpp
===================================================================
--- branches/v1-6/OgreMain/src/OgreEntity.cpp	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/src/OgreEntity.cpp	2008-07-30 11:03:11 UTC (rev 7804)
@@ -370,13 +370,14 @@
         // Calculate the LOD
         if (mParentNode)
         {
-            Real squaredDepth = mParentNode->getSquaredViewDepth(cam);
+			const Camera* lodCamera = cam->getLodCamera();
+            Real squaredDepth = mParentNode->getSquaredViewDepth(lodCamera);
 
             // Do Mesh LOD
             // Adjust this depth by the entity bias factor
             Real tmp = squaredDepth * mMeshLodFactorInv;
             // Now adjust it by the camera bias
-            tmp = tmp * cam->_getLodBiasInverse();
+            tmp = tmp * lodCamera->_getLodBiasInverse();
             // Get the index at this biased depth
             mMeshLodIndex = mMesh->getLodIndexSquaredDepth(tmp);
             // Apply maximum detail restriction (remember lower = higher detail)
@@ -388,7 +389,7 @@
             // Adjust this depth by the entity bias factor
             tmp = squaredDepth * mMaterialLodFactorInv;
             // Now adjust it by the camera bias
-            tmp = tmp * cam->_getLodBiasInverse();
+            tmp = tmp * lodCamera->_getLodBiasInverse();
             SubEntityList::iterator i, iend;
             iend = mSubEntityList.end();
             for (i = mSubEntityList.begin(); i != iend; ++i)

Modified: branches/v1-6/OgreMain/src/OgreInstancedGeometry.cpp
===================================================================
--- branches/v1-6/OgreMain/src/OgreInstancedGeometry.cpp	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/src/OgreInstancedGeometry.cpp	2008-07-30 11:03:11 UTC (rev 7804)
@@ -1278,7 +1278,7 @@
 	void InstancedGeometry::BatchInstance::_notifyCurrentCamera(Camera* cam)
 	{
 		// Calculate squared view depth
-		Vector3 diff = cam->getDerivedPosition() ;
+		Vector3 diff = cam->getLodCamera()->getDerivedPosition() ;
 		Real squaredDepth = diff.squaredLength();
 
 		// Determine whether to still render

Modified: branches/v1-6/OgreMain/src/OgreMovableObject.cpp
===================================================================
--- branches/v1-6/OgreMain/src/OgreMovableObject.cpp	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/src/OgreMovableObject.cpp	2008-07-30 11:03:11 UTC (rev 7804)
@@ -239,7 +239,7 @@
 			if (cam->getUseRenderingDistance() && mUpperDistance > 0)
 			{
 				Real rad = getBoundingRadius();
-				Real squaredDepth = mParentNode->getSquaredViewDepth(cam);
+				Real squaredDepth = mParentNode->getSquaredViewDepth(cam->getLodCamera());
 				// Max distance to still render
 				Real maxDist = mUpperDistance + rad;
 				if (squaredDepth > Math::Sqr(maxDist))

Modified: branches/v1-6/OgreMain/src/OgreSceneManager.cpp
===================================================================
--- branches/v1-6/OgreMain/src/OgreSceneManager.cpp	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/src/OgreSceneManager.cpp	2008-07-30 11:03:11 UTC (rev 7804)
@@ -5705,6 +5705,9 @@
 			// rebind camera, incase another SM in use which has switched to its cam
 			shadowView->setCamera(texCam);
 			
+			// Associate main view camera as LOD camera
+			texCam->setLodCamera(cam);
+
 			// update shadow cam - light mapping
 			ShadowCamLightMapping::iterator camLightIt = mShadowCamLightMapping.find( texCam );
 			assert(camLightIt != mShadowCamLightMapping.end());

Modified: branches/v1-6/OgreMain/src/OgreStaticGeometry.cpp
===================================================================
--- branches/v1-6/OgreMain/src/OgreStaticGeometry.cpp	2008-07-29 12:53:43 UTC (rev 7803)
+++ branches/v1-6/OgreMain/src/OgreStaticGeometry.cpp	2008-07-30 11:03:11 UTC (rev 7804)
@@ -849,7 +849,7 @@
 	void StaticGeometry::Region::_notifyCurrentCamera(Camera* cam)
 	{
 		// Calculate squared view depth
-		Vector3 diff = cam->getDerivedPosition() - mCentre;
+		Vector3 diff = cam->getLodCamera()->getDerivedPosition() - mCentre;
 		Real squaredDepth = diff.squaredLength();
 
 		// Determine whether to still render

LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Post by LostEra »

Thanks! I had finished implementing the features I had planned for the project and was going to give this a shot myself, but it seems that will now be unnecessary. I will definitely merge this in (and make the changes needed to fit in with the new LOD system).
Vectrex
Ogre Magi
Posts: 1266
Joined: Tue Aug 12, 2003 1:53 am
Location: Melbourne, Australia
x 1
Contact:

Post by Vectrex »

I can't quite tell but will that patch allow it to only calculate one squared depth for each object instead of the old set per camera? Saving a few hundred sqrt's per frame would be nice.
User avatar
Noman
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 714
Joined: Mon Jan 31, 2005 7:21 pm
Location: Israel
x 2
Contact:

Post by Noman »

Howdy fellow SoCer!

I have a question/semi proposal :
I currently have a problem with flickering LODs. I have two levels of detail which are (a bit intentionally) noticably different. It's ok, except for when the camera is very close to the change distance. What happens is that the LODs flicker - about 5 times per second in the worst case.

What I thought to do in order to solve this problem, is to add a 'safety net' for LOD selection.
That is, if the criteria for changing from LOD 1 to LOD 2 is X, the change will only take place 10% into LOD 2's 'zone' (1.1X). Once the change is made, in order to move back to LOD 1, the camera will have to be 10% beyond X, but this time in LOD 1's direction (0.9X). This gives us a safety net of 0.2X to prevent LOD flickering.

Have you considered doing something like this, or anything to prevent LOD flickering in worst cases?
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Post by LostEra »

Sorry for the slow reply, I was on vacation.

Sinbad's lod camera work has now been merged in.

@Vectrex
As far as I can tell, no, and given the way entities are notified of the current camera, this would probably not be an easy thing to achieve without a separate "_notifyCurrentLodCamera" method.

@Noman
I'm not sure why it is flickering (I will look into this), but a "safety net" mechanism would need to be able to handle multiple cameras which would greatly complicate the issue. Entities are notified of the current camera before being rendered but it is entirely possible (and in fact likely with multiple cameras) that the previous camera is not the same as the new one.
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

does anyone knows the status of this project?
is there anything planned about a new Lod approach?
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Post by KungFooMasta »

Or more importantly, how are we affected by this feature, and how can we best utilize the results from this work? Is it already applied automagically?
Creator of QuickGUI!
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

This project is due to be merged into 1.8 soon.

You can try it out just by using the branch it lives on:

https://svn.ogre3d.org/svnroot/ogre/branches/soc08-lod
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Post by LostEra »

As Sinbad said, you can check out the code at: https://svn.ogre3d.org/svnroot/ogre/branches/soc08-lod

For usage examples, take a look at the PlayPen project from the branch. In particular, at the testLod function (in PlayPen.cpp). It includes examples of changing the lod strategy for both meshes and materials. I tried to make it as clear as possible, but there is still a fair bit of code necessary to change such things from code. I will try to get an example mesh uploaded which demonstrates how to accomplish the same thing data-side.

Older assets will still use the old, distance-based strategy (but you can convert them).

EDIT: While putting together a mesh to demonstrate the mesh loading I found a bug in my mesh loading code :oops:. I committed a patch to fix it, so if you already checked out the branch, you probably want to grab the latest version.

With that out of the way, here is a simple mesh xml file to demonstrate the lod system: http://www.mediafire.com/?sharekey=1c30 ... 9ccaa6ece6

If you edit it with a text editor and scroll down to the very end, you can see the lod information. It is currently set to the "Distance" strategy, but you can change it to "PixelCount" and adjust the lod value. Please let me know if you encounter any problems.
compvis
Gremlin
Posts: 165
Joined: Wed Sep 10, 2008 6:14 am

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by compvis »

hi,

How can i use this LOD technique to calculate the size of my entity in pixel ?

I want to know, with which distance from camera, my entity still has a size is one pixel on screen.

thanks,
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by LostEra »

It should be possible to approximate the pixel count of an entity relative to a given camera with the code below (where entity and camera are pointers to the Ogre::Entity and Ogre:Camera in question):

Code: Select all

Ogre::PixelCountLodStrategy::getSingleton().getValue(entity, camera)
The camera is necessary, as the result depends upon the projection type and field of view in use, not only upon the distance.

However, to determine at what distance an entity's bounding sphere will project to a single pixel, you would need to perform the calculation in reverse. If you're sure this is what you really want to do, you can take a look at the implementation of "Ogre::PixelCountLodStrategy::getValueImpl" to see how the pixel count is calculated and work from there. That said, none of this should be necessary if your goal is only to compute LOD based on an approximate pixel count.

Please let me know if any of this is unclear.
compvis
Gremlin
Posts: 165
Joined: Wed Sep 10, 2008 6:14 am

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by compvis »

thank you so much !

Yes, i have a project that needs to calculate the size of entity. I want to know at which distance from camera, my entity has the size is one pixel.

I'm simulating a system that can assist soldiers in practicing to shoot cruise-missiles without real targets. My targets has to see like in real world.

My system includes one pc (runs simulation program) that supports a graphics card can share to two monitors. Images from render window will be rendered to a large screen.
And a gun system, the gun is the DShK Soviet 12.7mm Machine Gun. The soldiers will track targets on such screen. The distance from gun to the screen is 2m.
The camera is necessary, as the result depends upon the projection type and field of view in use, not only upon the distance.
Could you explain more in detail ?
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by LostEra »

Sounds like a very interesting project. I now understand why you need to know when your entity will be a pixel in size.

Regarding the necessity for a camera reference, how large the entity will appear on-screen depends not only on the distance of the entity from the camera, but upon field of view (FOV) and projection type. For instance, when the FOV is small, it is like zooming in, so objects appear larger. Conversely, when the FOV is large, it is like using a wide angle lens, so objects appear smaller. This is why it is necessary to know the FOV when computing the on-screen pixel count. The projection type also affects the way objects are rendered, but it sounds like you only need to worry about a perspective (as opposed to orthographic) projection.

I took at look and saw that the code in PixelCountLodStrategy may be difficult to understand because for efficiency it uses values from the projection matrix instead of computing them from the FOV. Unfortunately, I've long forgotten the formula for computing the projection size, but I'm sure it is on the internet somewhere.

By the way, it sounds like your FOV should probably be fixed at "arctan(real screen width / viewing distance)" radians for natural viewing and aiming and you said your viewing distance was fixed at 2 meters, so if you know the real width of your viewing screen ahead of time also, you can probably precompute the FOV and from that the appropriate distance. Just a thought.

I hope this helps you.
Last edited by LostEra on Tue Aug 11, 2009 4:34 am, edited 1 time in total.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by sinbad »

Good to see you're still watching the thread LostEra :)
LostEra wrote:As Sinbad said, you can check out the code at: https://svn.ogre3d.org/svnroot/ogre/branches/soc08-lod
Just in case anyone else picks up this thread without knowing the context, I just want to point out that all of this work has been in the mainstream trunk for a little while now, so anyone grabbing https://svn.ogre3d.org/svnroot/ogre/trunk will get it too. It's obviously on track for being part of the next stable release (1.7 aka Cthugha).
compvis
Gremlin
Posts: 165
Joined: Wed Sep 10, 2008 6:14 am

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by compvis »

LostEra wrote:
By the way, it sounds like your FOV should probably be fixed at "arctan(real screen width / viewing distance)" radians for natural viewing and aiming and you said your viewing distance was fixed at 2 meters, so if you know the real width of your viewing screen ahead of time also, you can probably precompute the FOV and from that the appropriate distance. Just a thought.
I think, not only FOV, i have to set the aspect ratio of the frustrum viewport

m_Camera->setAspectRatio(reall_screen_width /real_sceen_height);

With reall_screen_width and real_sceen_height is width and height of projector's sceen

That's right ?
LostEra
Google Summer of Code Student
Google Summer of Code Student
Posts: 56
Joined: Wed Jun 07, 2006 8:33 pm
x 1

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by LostEra »

That is correct. You could also use Camera::setAutoAspectRatio.
compvis
Gremlin
Posts: 165
Joined: Wed Sep 10, 2008 6:14 am

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by compvis »

Thank you LostEra !!!
User avatar
oddrose
Orc
Posts: 470
Joined: Thu Feb 15, 2007 2:08 pm
Location: Gothenburg, Sweden
Contact:

Re: [GSoC 2008 - Accepted] Different Level of Detail Strategies

Post by oddrose »

Hi, I built trunk today (sept. 17th) and I ran into some problems with the lod strategies. I have a simple material defined in a material script:

Code: Select all

material PlainGreen
{
	technique
	{
		pass
		{
			diffuse 0.0 1.0 0.0 0.0
		}
	}
}
I can set this as material for a simple box-entity. But when I try to use setMaterial("PlainGreen") on an animated entity the app crashes at startup.

Code: Select all

OgreEntity.cpp line 434:
// Recalculate lod value if strategies do not match
Real biasedMaterialLodValue;
if (meshStrategy == materialStrategy)
       biasedMaterialLodValue = lodValue;
 else
       biasedMaterialLodValue = materialStrategy->getValue(this, cam) * materialStrategy->transformBias(mMaterialLodFactor); <--- this call is on top on the call stack
The problem is that materialStrategy = null, so I get an access violation error.

I haven't been able to exactly trace what's causing the error to occur only for the animated mesh though.
Post Reply