1. Steve Streeting
  2. ogre

Commits

Steve Streeting  committed b562b3b

Fix scene_depth_range and shadow_scene_depth_range when using LiSPSM or other ShadowCameraSetup classes that use custom matrices and don't use a 'real' camera position
- LiSPSM and similar shadow camera setup classes never set the camera position, because everything was encoded into the custom view matrix. The scene depth range code used to calculate the distance from the camera using the camera position which didn't work. So now it transforms the world points using the view matrix instead which always works.
- The calculated depth range only took into account shadow casters and not receivers. While it's true that the visible bounds should only include casters for calculations that are only dependent on that, a linear depth range does not work on this basis because non-caster receivers which are beyond the distance of any other caster will always have a normalised depth of > 1, meaning they're considered to be in shadow. To avoid changing the behaviour, I added an extra min/max distance which means 'not rendered, but still needs to be considered', which objects which are not shadow casters but are shadow receivers go into. The depth ranges are calculated from this. Objects which are not shadow receivers either will be excluded (e.g. skies)
- The determination of whether an object receives shadows has always been a bit awkward because it's a material property (by nature of the rendering approach). So far, only the fact of whether the entire render queue has shadows enabled or not was being used to determine if an object received shadows. This meant that to properly exclude an object from any kind of effect on the shadow range calculation, you had to put it in a queue which had shadows completely disabled. This is still worth doing for skies etc, because this is a fast & easy check to make. However, I've improved things by adding a MovableObject::getReceiveShadows method, which makes a determination via visitRenderables, returning true of any Renderable's material would receive shadows.
- Refactored the common operations normally done in the SceneManager associated with calling MovableObject::_updateRenderQueue but which were duplicated, placed in RenderQueue::processVisibleObject

  • Participants
  • Parent commits 264f63a
  • Branches v1-6

Comments (0)

Files changed (9)

File OgreMain/include/OgreMovableObject.h

View file
         void setCastShadows(bool enabled) { mCastShadows = enabled; }
         /** Returns whether shadow casting is enabled for this object. */
         bool getCastShadows(void) const { return mCastShadows; }
+		/** Returns whether the Material of any Renderable that this MovableObject will add to 
+			the render queue will receive shadows. 
+		*/
+		bool getReceivesShadows();
+			
         /** Get the distance to extrude for a point/spot light */
         Real getPointExtrusionDistance(const Light* l) const;
 		/** Get the 'type flags' for this MovableObject.

File OgreMain/include/OgreRenderQueue.h

View file
 
 namespace Ogre {
 
+	class Camera;
+	class MovableObject;
+	struct VisibleObjectsBoundsInfo;
+
     /** Enumeration of queue groups, by which the application may group queued renderables
         so that they are rendered together with events in between
 	@remarks
 		RenderableListener* getRenderableListener(void) const
 		{ return mRenderableListener; }
 
+		/** Utility method to perform the standard actions associated with 
+			getting a visible object to add itself to the queue. This is 
+			a replacement for SceneManager implementations of the associated
+			tasks related to calling MovableObject::_updateRenderQueue.
+		*/
+		void processVisibleObject(MovableObject* mo, 
+			Camera* cam, 
+			bool onlyShadowCasters, 
+			VisibleObjectsBoundsInfo* visibleBounds);
+
     };
 
 

File OgreMain/include/OgreSceneManager.h

View file
 		Real minDistance;
 		/// The farthest a visible objects is from the camera
 		Real maxDistance;
+		/// The closest a object in the frustum regardless of visibility / shadow caster flags
+		Real minDistanceInFrustum;
+		/// The farthest object in the frustum regardless of visibility / shadow caster flags
+		Real maxDistanceInFrustum;
 
 		VisibleObjectsBoundsInfo()
 		{
 		{
 			aabb.setNull();
 			receiverAabb.setNull();
-			minDistance = std::numeric_limits<Real>::infinity();
-			maxDistance = 0;
+			minDistance = minDistanceInFrustum = std::numeric_limits<Real>::infinity();
+			maxDistance = maxDistanceInFrustum = 0;
 		}
 
 		void merge(const AxisAlignedBox& boxBounds, const Sphere& sphereBounds, 
 			aabb.merge(boxBounds);
 			if (receiver)
 				receiverAabb.merge(boxBounds);
-			Real camDistToCenter = 
-				(cam->getDerivedPosition() - sphereBounds.getCenter()).length();
+			// use view matrix to determine distance, works with custom view matrices
+			Vector3 vsSpherePos = cam->getViewMatrix(true) * sphereBounds.getCenter();
+			Real camDistToCenter = vsSpherePos.length();
 			minDistance = (std::min)(minDistance, (std::max)((Real)0, camDistToCenter - sphereBounds.getRadius()));
 			maxDistance = (std::max)(maxDistance, camDistToCenter + sphereBounds.getRadius());
+			minDistanceInFrustum = (std::min)(minDistanceInFrustum, (std::max)((Real)0, camDistToCenter - sphereBounds.getRadius()));
+			maxDistanceInFrustum = (std::max)(maxDistanceInFrustum, camDistToCenter + sphereBounds.getRadius());
+		}
+
+		/** Merge an object that is not being rendered because it's not a shadow caster, 
+			but is a shadow receiver so should be included in the range.
+		*/
+		void mergeNonRenderedButInFrustum(const AxisAlignedBox& boxBounds, 
+			const Sphere& sphereBounds, const Camera* cam)
+		{
+			// use view matrix to determine distance, works with custom view matrices
+			Vector3 vsSpherePos = cam->getViewMatrix(true) * sphereBounds.getCenter();
+			Real camDistToCenter = vsSpherePos.length();
+			minDistanceInFrustum = (std::min)(minDistanceInFrustum, (std::max)((Real)0, camDistToCenter - sphereBounds.getRadius()));
+			maxDistanceInFrustum = (std::max)(maxDistanceInFrustum, camDistToCenter + sphereBounds.getRadius());
+
 		}
 
 

File OgreMain/src/OgreAutoParamDataSource.cpp

View file
 	//-----------------------------------------------------------------------------
 	const Vector4& AutoParamDataSource::getSceneDepthRange() const
 	{
+		static Vector4 dummy(0, 100000, 100000, 1/100000);
+
 		if (mSceneDepthRangeDirty)
 		{
 			// calculate depth information
-			mSceneDepthRange.x = mMainCamBoundsInfo->minDistance;
-			mSceneDepthRange.y = mMainCamBoundsInfo->maxDistance;
-			mSceneDepthRange.z = mMainCamBoundsInfo->maxDistance - mMainCamBoundsInfo->minDistance;
-			mSceneDepthRange.w = 1.0f / mSceneDepthRange.z;
+			Real depthRange = mMainCamBoundsInfo->maxDistanceInFrustum - mMainCamBoundsInfo->minDistanceInFrustum;
+			if (depthRange > std::numeric_limits<Real>::epsilon())
+			{
+				mSceneDepthRange = Vector4(
+					mMainCamBoundsInfo->minDistanceInFrustum,
+					mMainCamBoundsInfo->maxDistanceInFrustum,
+					depthRange,
+					1.0f / depthRange);
+			}
+			else
+			{
+				mSceneDepthRange = dummy;
+			}
 			mSceneDepthRangeDirty = false;
 		}
 
 					mCurrentSceneManager->getVisibleObjectsBoundsInfo(
 						(Camera*)mCurrentTextureProjector[index]);
 
-				Real depthRange = info.maxDistance - info.minDistance;
+				Real depthRange = info.maxDistanceInFrustum - info.minDistanceInFrustum;
 				if (depthRange > std::numeric_limits<Real>::epsilon())
 				{
 					mShadowCamDepthRanges[index] = Vector4(
-						info.minDistance,
-						info.maxDistance,
+						info.minDistanceInFrustum,
+						info.maxDistanceInFrustum,
 						depthRange,
 						1.0f / depthRange);
 				}

File OgreMain/src/OgreMovableObject.cpp

View file
 			return 0xFFFFFFFF;
 		}
 	}
+	class MORecvShadVisitor : public Renderable::Visitor
+	{
+	public:
+		bool anyReceiveShadows;
+		MORecvShadVisitor() : anyReceiveShadows(false)
+		{
+
+		}
+		void visit(Renderable* rend, ushort lodIndex, bool isDebug, 
+			Any* pAny = 0)
+		{
+			anyReceiveShadows = anyReceiveShadows || 
+				rend->getTechnique()->getParent()->getReceiveShadows();
+		}
+	};
+	//---------------------------------------------------------------------
+	bool MovableObject::getReceivesShadows()
+	{
+		MORecvShadVisitor visitor;
+		visitRenderables(&visitor);
+		return visitor.anyReceiveShadows;		
+
+	}
 	//-----------------------------------------------------------------------
 	//-----------------------------------------------------------------------
 	MovableObject* MovableObjectFactory::createInstance(

File OgreMain/src/OgreRenderQueue.cpp

View file
 #include "OgreRenderQueueSortingGrouping.h"
 #include "OgrePass.h"
 #include "OgreMaterialManager.h"
+#include "OgreSceneManager.h"
+#include "OgreMovableObject.h"
+#include "OgreCamera.h"
 
 
 namespace Ogre {
 			i->second->setShadowCastersCannotBeReceivers(ind);
 		}
 	}
+	//---------------------------------------------------------------------
+	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);
+		}
+
+	}
 
 }
 

File OgreMain/src/OgreSceneNode.cpp

View file
         ObjectMap::iterator iobjend = mObjectsByName.end();
         for (iobj = mObjectsByName.begin(); iobj != iobjend; ++iobj)
         {
-            // Tell attached objects about camera position (incase any extra processing they want to do)
-            iobj->second->_notifyCurrentCamera(cam);
-            if (iobj->second->isVisible() && 
-                (!onlyShadowCasters || iobj->second->getCastShadows()))
-            {
-                iobj->second->_updateRenderQueue(queue);
+			MovableObject* mo = iobj->second;
 
-				// update visible boundaries aab
-				if (visibleBounds)
-				{
-					visibleBounds->merge(iobj->second->getWorldBoundingBox(true), 
-						iobj->second->getWorldBoundingSphere(true), cam, 
-						queue->getQueueGroup(iobj->second->getRenderQueueGroup())->getShadowsEnabled());
-				}
-            }
+			queue->processVisibleObject(mo, cam, onlyShadowCasters, visibleBounds);
         }
 
         if (includeChildren)

File PlugIns/BSPSceneManager/src/OgreBspSceneManager.cpp

View file
             {
                 // It hasn't been seen yet
                 MovableObject *mov = const_cast<MovableObject*>(*oi); // hacky
-                if (mov->isVisible() && 
-                    (!onlyShadowCasters || mov->getCastShadows()) && 
-					cam->isVisible(mov->getWorldBoundingBox()))
-                {
-                    mov->_notifyCurrentCamera(cam);
-                    mov->_updateRenderQueue(getRenderQueue());
-                    // Check if the bounding box should be shown.
-                    SceneNode* sn = static_cast<SceneNode*>(mov->getParentNode());
-                    if (sn->getShowBoundingBox() || mShowBoundingBoxes)
-                    {
-                        sn->_addBoundingBoxToQueue(getRenderQueue());
-                    }
-                    mMovablesForRendering.insert(*oi);
 
-					// update visible boundaries aab
-					if (visibleBounds)
-					{
-						visibleBounds->merge((*oi)->getWorldBoundingBox(true), 
-							(*oi)->getWorldBoundingSphere(true), cam);
-					}
-                }
+				getRenderQueue()->processVisibleObject(mov, cam, onlyShadowCasters, visibleBounds);
 
             }
         }

File PlugIns/OctreeSceneManager/src/OgreOctreeNode.cpp

View file
     while ( mit != mObjectsByName.end() )
     {
         MovableObject * mo = mit->second;
-
-        mo->_notifyCurrentCamera(cam);
-        if ( mo->isVisible() &&
-            (!onlyShadowCasters || mo->getCastShadows()))
-        {
-            mo -> _updateRenderQueue( queue );
-
-			if (visibleBounds)
-			{
-				visibleBounds->merge(mo->getWorldBoundingBox(true), 
-					mo->getWorldBoundingSphere(true), cam, 
-					queue->getQueueGroup(mo->getRenderQueueGroup())->getShadowsEnabled());
-			}
-        }
+		
+		queue->processVisibleObject(mo, cam, onlyShadowCasters, visibleBounds);
 
         ++mit;
     }