/// <summary> /// Internal method which locates any visible objects attached to this node and adds them to the passed in queue. /// </summary> /// <param name="camera">Active camera.</param> /// <param name="queue">Queue to which these objects should be added.</param> /// <param name="includeChildren">If true, cascades down to all children.</param> /// <param name="displayNodes">Renders the local axes for the node.</param> /// <param name="onlyShadowCasters"></param> public virtual void FindVisibleObjects(Camera camera, RenderQueue queue, bool includeChildren, bool displayNodes, bool onlyShadowCasters) { // if we aren't visible, then quit now // TODO: Make sure sphere is calculated properly for all objects, then switch to cull using that if (!camera.IsObjectVisible(this.worldAABB)) { return; } // add visible objects to the render queue //objectListMeter.Enter(); foreach (var obj in this.objectList.Values) { // tell attached object about current camera in case it wants to know //notifyCameraMeter.Enter(); obj.NotifyCurrentCamera(camera); //notifyCameraMeter.Exit(); // if this object is visible, add it to the render queue if (obj.IsVisible && (!onlyShadowCasters || obj.CastShadows)) { //updateQueueMeter.Enter(); obj.UpdateRenderQueue(queue); //updateQueueMeter.Exit(); } } //objectListMeter.Exit(); //childListMeter.Enter(); if (includeChildren) { // ask all child nodes to update the render queue with visible objects foreach (SceneNode childNode in childNodes.Values) { if (childNode.IsVisible) { childNode.FindVisibleObjects(camera, queue, includeChildren, displayNodes, onlyShadowCasters); } } } //childListMeter.Exit(); // if we wanna display nodes themself.. if (displayNodes) { // hey, lets just add ourself right to the render queue queue.AddRenderable(GetDebugRenderable()); } // do we wanna show our beautiful bounding box? // do it if either we want it, or the SceneManager dictates it if (this.showBoundingBox || (this.creator != null && this.creator.ShowBoundingBoxes)) { AddBoundingBoxToQueue(queue); } }
private void CheckShadowCasters( IList casters, PlaneBoundedVolume nearClipVol, Light light, bool extrudeInSoftware, bool finiteExtrude, bool zfailAlgo, Camera camera, float extrudeDistance, bool stencil2sided, LightList tmpLightList ) { int flags; for ( int i = 0; i < casters.Count; i++ ) { ShadowCaster caster = (ShadowCaster)casters[ i ]; if ( nearClipVol.Intersects( caster.GetWorldBoundingBox() ) ) { // We have a zfail case, we must use zfail for all objects zfailAlgo = true; break; } } for ( int ci = 0; ci < casters.Count; ci++ ) { ShadowCaster caster = (ShadowCaster)casters[ ci ]; flags = 0; if ( light.Type != LightType.Directional ) { extrudeDistance = caster.GetPointExtrusionDistance( light ); } if ( !extrudeInSoftware && !finiteExtrude ) { // hardware extrusion, to infinity (and beyond!) flags |= (int)ShadowRenderableFlags.ExtrudeToInfinity; } if ( zfailAlgo ) { // We need to include the light and / or dark cap // But only if they will be visible if ( camera.IsObjectVisible( caster.GetLightCapBounds() ) ) { flags |= (int)ShadowRenderableFlags.IncludeLightCap; } } // Dark cap (no dark cap for directional lights using // hardware extrusion to infinity) if ( !( ( flags & (int)ShadowRenderableFlags.ExtrudeToInfinity ) != 0 && light.Type == LightType.Directional ) && camera.IsObjectVisible( caster.GetDarkCapBounds( light, extrudeDistance ) ) ) { flags |= (int)ShadowRenderableFlags.IncludeDarkCap; } // get shadow renderables IEnumerator renderables = caster.GetShadowVolumeRenderableEnumerator( this.shadowTechnique, light, this.shadowIndexBuffer, extrudeInSoftware, extrudeDistance, flags ); // If using one-sided stencil, render the first pass of all shadow // renderables before all the second passes for ( int i = 0; i < ( stencil2sided ? 1 : 2 ); i++ ) { if ( i == 1 ) { renderables = caster.GetLastShadowVolumeRenderableEnumerator(); } while ( renderables.MoveNext() ) { ShadowRenderable sr = (ShadowRenderable)renderables.Current; // omit hidden renderables if ( sr.IsVisible ) { // render volume, including dark and (maybe) light caps this.RenderSingleShadowVolumeToStencil( sr, zfailAlgo, stencil2sided, tmpLightList, ( i > 0 ) ); // optionally render separate light cap if ( sr.IsLightCapSeperate && ( ( flags & (int)ShadowRenderableFlags.IncludeLightCap ) ) > 0 ) { // must always fail depth check this.targetRenderSystem.DepthBufferFunction = CompareFunction.AlwaysFail; Debug.Assert( sr.LightCapRenderable != null, "Shadow renderable is missing a separate light cap renderable!" ); this.RenderSingleShadowVolumeToStencil( sr.LightCapRenderable, zfailAlgo, stencil2sided, tmpLightList, ( i > 0 ) ); // reset depth function this.targetRenderSystem.DepthBufferFunction = CompareFunction.Less; } } } } } }
/// <summary> /// Internal method for locating a list of shadow casters which /// could be affecting the frustum for a given light. /// </summary> /// <remarks> /// Custom scene managers are encouraged to override this method to add optimizations, /// and to add their own custom shadow casters (perhaps for world geometry) /// </remarks> /// <param name="light"></param> /// <param name="camera"></param> protected virtual IList FindShadowCastersForLight( Light light, Camera camera ) { this.shadowCasterList.Clear(); if ( light.Type == LightType.Directional ) { // Basic AABB query encompassing the frustum and the extrusion of it AxisAlignedBox aabb = new AxisAlignedBox(); Vector3[] corners = camera.WorldSpaceCorners; Vector3 min, max; Vector3 extrude = light.DerivedDirection * -this.shadowDirLightExtrudeDist; // do first corner min = max = corners[ 0 ]; min.Floor( corners[ 0 ] + extrude ); max.Ceil( corners[ 0 ] + extrude ); for ( int c = 1; c < 8; ++c ) { min.Floor( corners[ c ] ); max.Ceil( corners[ c ] ); min.Floor( corners[ c ] + extrude ); max.Ceil( corners[ c ] + extrude ); } aabb.SetExtents( min, max ); if ( this.shadowCasterAABBQuery == null ) { this.shadowCasterAABBQuery = this.CreateAABBRegionQuery( aabb ); } else { this.shadowCasterAABBQuery.Box = aabb; } // Execute, use callback this.shadowCasterQueryListener.Prepare( false, light.GetFrustumClipVolumes( camera ), light, camera, this.shadowCasterList, light.ShadowFarDistanceSquared ); this.shadowCasterAABBQuery.Execute( this.shadowCasterQueryListener ); } else { Sphere s = new Sphere( light.DerivedPosition, light.AttenuationRange ); // eliminate early if camera cannot see light sphere if ( camera.IsObjectVisible( s ) ) { // create or init a sphere region query if ( this.shadowCasterSphereQuery == null ) { this.shadowCasterSphereQuery = this.CreateSphereRegionQuery( s ); } else { this.shadowCasterSphereQuery.Sphere = s; } // check if the light is within view of the camera bool lightInFrustum = camera.IsObjectVisible( light.DerivedPosition ); PlaneBoundedVolumeList volumeList = null; // Only worth building an external volume list if // light is outside the frustum if ( !lightInFrustum ) { volumeList = light.GetFrustumClipVolumes( camera ); } // prepare the query and execute using the callback this.shadowCasterQueryListener.Prepare( lightInFrustum, volumeList, light, camera, this.shadowCasterList, light.ShadowFarDistanceSquared ); this.shadowCasterSphereQuery.Execute( this.shadowCasterQueryListener ); } } return this.shadowCasterList; }
/// <summary> /// Internal method for locating a list of lights which could be affecting the frustum. /// </summary> /// <remarks> /// Custom scene managers are encouraged to override this method to make use of their /// scene partitioning scheme to more efficiently locate lights, and to eliminate lights /// which may be occluded by word geometry. /// </remarks> /// <param name="camera">Camera to find lights within it's view.</param> protected virtual void FindLightsAffectingFrustum( Camera camera ) { // Basic iteration for this scene manager this.lightsAffectingFrustum.Clear(); MovableObjectCollection lightList = this.GetMovableObjectCollection( LightFactory.TypeName ); // sphere to use for testing Sphere sphere = new Sphere(); foreach ( Light light in lightList.Values ) { if ( light.IsVisible ) { if ( light.Type == LightType.Directional ) { // Always visible this.lightsAffectingFrustum.Add( light ); } else { // treating spotlight as point for simplicity // Just see if the lights attenuation range is within the frustum sphere.Center = light.DerivedPosition; sphere.Radius = light.AttenuationRange; if ( camera.IsObjectVisible( sphere ) ) { this.lightsAffectingFrustum.Add( light ); } } } } // notify light dirty, so all movable objects will re-populate // their light list next time NotifyLightsDirty(); }
/// <summary> /// Tags geometry in the leaf specified for later rendering. /// </summary> protected void ProcessVisibleLeaf( BspNode leaf, Camera camera, bool onlyShadowCasters ) { // Skip world geometry if we're only supposed to process shadow casters // World is pre-lit if ( !onlyShadowCasters ) { // Parse the leaf node's faces, add face groups to material map int numGroups = leaf.NumFaceGroups; int idx = leaf.FaceGroupStart; while ( numGroups-- > 0 ) { int realIndex = this.level.LeafFaceGroups[ idx++ ]; // Is it already checked ? if ( this.faceGroupChecked.ContainsKey( realIndex ) && this.faceGroupChecked[ realIndex ] == true ) { continue; } this.faceGroupChecked[ realIndex ] = true; BspStaticFaceGroup faceGroup = this.level.FaceGroups[ realIndex ]; // Get Material reference by handle Material mat = GetMaterial( faceGroup.materialHandle ); // Check normal (manual culling) ManualCullingMode cullMode = mat.GetTechnique( 0 ).GetPass( 0 ).ManualCullingMode; if ( cullMode != ManualCullingMode.None ) { float dist = faceGroup.plane.GetDistance( camera.DerivedPosition ); if ( ( ( dist < 0 ) && ( cullMode == ManualCullingMode.Back ) ) || ( ( dist > 0 ) && ( cullMode == ManualCullingMode.Front ) ) ) { continue; } } // Try to insert, will find existing if already there this.matFaceGroupMap.Add( mat, faceGroup ); } } // Add movables to render queue, provided it hasn't been seen already. foreach ( MovableObject obj in leaf.Objects.Values ) { if ( !this.objectsForRendering.ContainsKey( obj.Name ) ) { if ( obj.IsVisible && ( !onlyShadowCasters || obj.CastShadows ) && camera.IsObjectVisible( obj.GetWorldBoundingBox() ) ) { obj.NotifyCurrentCamera( camera ); obj.UpdateRenderQueue( renderQueue ); // Check if the bounding box should be shown. var node = (SceneNode)obj.ParentNode; if ( node.ShowBoundingBox || showBoundingBoxes ) { node.AddBoundingBoxToQueue( renderQueue ); } this.objectsForRendering.Add( obj ); } } } }
/// <summary> /// Determines whether the supplied billboard is visible in the camera or not. /// </summary> /// <param name="camera"></param> /// <param name="billboard"></param> /// <returns></returns> protected bool IsBillboardVisible( Camera camera, Billboard billboard ) { // if not culling each one, return true always if ( !this.cullIndividual ) { return true; } // get the world matrix of this billboard set this.GetWorldTransforms( this.world ); // get the center of the bounding sphere this.sphere.Center = this.world[ 0 ] * billboard.Position; // calculate the radius of the bounding sphere for the billboard if ( billboard.HasOwnDimensions ) { this.sphere.Radius = Utility.Max( billboard.Width, billboard.Height ); } else { this.sphere.Radius = Utility.Max( this.defaultParticleWidth, this.defaultParticleHeight ); } // finally, see if the sphere is visible in the camera return camera.IsObjectVisible( this.sphere ); }
public override void NotifyCurrentCamera(Camera cam) { if (cam.IsObjectVisible(worldAABB)) { isVisible = true; } else { isVisible = false; return; } }
public override void NotifyCurrentCamera(Camera camera) { if (!camera.IsObjectVisible(GetWorldBoundingBox(true))) { widgetNode.NodeVisible = false; } else { widgetNode.NodeVisible = true; } }
public void Notify(Vector3 pos, Camera Cam) { if (isLoaded && Cam.IsObjectVisible(pageNode.WorldAABB)) //----------------- //&& Cam->getVisibility (mBoundsExt)) { for ( long i = 0; i < numTiles; i++ ) { for ( long j = 0; j < numTiles; j++ ) { tiles[ i ][ j].Notify( pos, Cam); } } } }
//--------------------------------------------------------------------- protected override void FindLightsAffectingFrustum( Camera camera ) { base.FindLightsAffectingFrustum( camera ); return; // Similar to the basic SceneManager, we iterate through // lights to see which ones affect the frustum. However, // since we have camera & lights partitioned by zones, // we can check only those lights which either affect the // zone the camera is in, or affect zones which are visible to // the camera MovableObjectCollection lights = GetMovableObjectCollection( PCZLightFactory.TypeName ); lock ( lights ) { foreach ( PCZLight l in lights.Values ) { if ( l.IsVisible /* && l.AffectsVisibleZone */ ) { LightInfo lightInfo; lightInfo.light = l; lightInfo.type = (int)l.Type; if ( lightInfo.type == (int)LightType.Directional ) { // Always visible lightInfo.position = Vector3.Zero; lightInfo.range = 0; this.mTestLightInfos.Add( lightInfo ); } else { // NB treating spotlight as point for simplicity // Just see if the lights attenuation range is within the frustum lightInfo.range = l.AttenuationRange; lightInfo.position = l.GetDerivedPosition(); var sphere = new Sphere( lightInfo.position, lightInfo.range ); if ( camera.IsObjectVisible( sphere ) ) { this.mTestLightInfos.Add( lightInfo ); } } } } } // release lock on lights collection base.FindLightsAffectingFrustum( camera ); // from here on down this function is same as Ogre::SceneManager // Update lights affecting frustum if changed if ( this.mCachedLightInfos != this.mTestLightInfos ) { //mLightsAffectingFrustum.resize(mTestLightInfos.size()); //LightInfoList::const_iterator i; //LightList::iterator j = mLightsAffectingFrustum.begin(); //for (i = mTestLightInfos.begin(); i != mTestLightInfos.end(); ++i, ++j) //{ // *j = i->light; // // add cam distance for sorting if texture shadows // if (isShadowTechniqueTextureBased()) // { // (*j)->tempSquareDist = // (camera->getDerivedPosition() - (*j)->getDerivedPosition()).squaredLength(); // } //} foreach ( LightInfo i in this.mTestLightInfos ) { if ( IsShadowTechniqueTextureBased ) { i.light.TempSquaredDist = ( camera.DerivedPosition - i.light.GetDerivedPosition() ).LengthSquared; } } if ( IsShadowTechniqueTextureBased ) { } // Sort the lights if using texture shadows, since the first 'n' will be // used to generate shadow textures and we should pick the most appropriate //if (IsShadowTechniqueTextureBased) //{ // // Allow a ShadowListener to override light sorting // // Reverse iterate so last takes precedence // bool overridden = false; // foreach(object o in base.) // for (ListenerList::reverse_iterator ri = mListeners.rbegin(); // ri != mListeners.rend(); ++ri) // { // overridden = (*ri)->sortLightsAffectingFrustum(mLightsAffectingFrustum); // if (overridden) // break; // } // if (!overridden) // { // // default sort (stable to preserve directional light ordering // std::stable_sort( // mLightsAffectingFrustum.begin(), mLightsAffectingFrustum.end(), // lightsForShadowTextureLess()); // } //} // Use swap instead of copy operator for efficiently //mCachedLightInfos.swap(mTestLightInfos); this.mCachedLightInfos = this.mTestLightInfos; // notify light dirty, so all movable objects will re-populate // their light list next time //_notifyLightsDirty(); //Check: do we have something like this here? } }
/// <summary> /// Internal method which locates any visible objects attached to this node and adds them to the passed in queue. /// </summary> /// <param name="camera">Active camera.</param> /// <param name="queue">Queue to which these objects should be added.</param> /// <param name="includeChildren">If true, cascades down to all children.</param> /// <param name="displayNodes">Renders the local axes for the node.</param> /// <param name="onlyShadowCasters"></param> public virtual void FindVisibleObjects( Camera camera, RenderQueue queue, bool includeChildren, bool displayNodes, bool onlyShadowCasters ) { // if we aren't visible, then quit now // TODO: Make sure sphere is calculated properly for all objects, then switch to cull using that if ( !camera.IsObjectVisible( worldAABB ) ) return; // add visible objects to the render queue //objectListMeter.Enter(); foreach ( MovableObject obj in objectList.Values ) { // tell attached object about current camera in case it wants to know //notifyCameraMeter.Enter(); obj.NotifyCurrentCamera( camera ); //notifyCameraMeter.Exit(); // if this object is visible, add it to the render queue if ( obj.IsVisible && ( !onlyShadowCasters || obj.CastShadows ) ) { //updateQueueMeter.Enter(); obj.UpdateRenderQueue( queue ); //updateQueueMeter.Exit(); } } //objectListMeter.Exit(); //childListMeter.Enter(); if ( includeChildren ) { // ask all child nodes to update the render queue with visible objects foreach ( SceneNode childNode in childNodes.Values ) { if ( childNode.IsVisible ) childNode.FindVisibleObjects( camera, queue, includeChildren, displayNodes, onlyShadowCasters ); } } //childListMeter.Exit(); // if we wanna display nodes themself.. if ( displayNodes ) { // hey, lets just add ourself right to the render queue queue.AddRenderable( GetDebugRenderable() ); } // do we wanna show our beautiful bounding box? // do it if either we want it, or the SceneManager dictates it if ( showBoundingBox || ( creator != null && creator.ShowBoundingBoxes ) ) { AddBoundingBoxToQueue( queue ); } }
public void PerFrameProcessing(float time, Camera camera) { Debug.Assert(inBoundary); bool updateVisibility = false; if (pendingTreeTypes != null) { ProcessTreeTypes(); TerrainManager.Instance.RecreateCollisionTiles(); updateVisibility = true; } SpeedTreeWrapper.Time = time; if (bounds != null && camera.IsObjectVisible(bounds)) { // this stuff only needs to be done if the forest is visible // process wind speedWind.Advance(time, windStrength, SpeedTreeUtil.ToSpeedTree(windDirection)); // determine whether the camera changed direction or location since the last frame if (camera.Direction != lastCameraDirection || camera.Position != lastCameraLocation) { updateVisibility = true; lastCameraLocation = camera.Position; lastCameraDirection = camera.Direction; } // if the camera changed position or direction, or new trees were added, then recompute the visibility of this tree if (updateVisibility) { foreach (TreeGroup group in groups) { group.CameraChange(camera); } } foreach (TreeGroup group in groups) { group.UpdateMaterials(); } } }
/// <summary> /// Internal method for locating a list of lights which could be affecting the frustum. /// </summary> /// <remarks> /// Custom scene managers are encouraged to override this method to make use of their /// scene partitioning scheme to more efficiently locate lights, and to eliminate lights /// which may be occluded by word geometry. /// </remarks> /// <param name="camera">Camera to find lights within it's view.</param> protected virtual void FindLightsAffectingFrustum(Camera camera) { // Basic iteration for this scene manager lightsAffectingFrustum.Clear(); // sphere to use for testing Sphere sphere = new Sphere(); ICollection<MovableObject> lightList = GetMovableObjectCollection("Light"); foreach (Light light in lightList) { if (light.IsVisible) { if(light.Type == LightType.Directional) { // Always visible lightsAffectingFrustum.Add(light); } else { // treating spotlight as point for simplicity // Just see if the lights attenuation range is within the frustum sphere.Center = light.DerivedPosition; sphere.Radius = light.AttenuationRange; if (camera.IsObjectVisible(sphere)) { lightsAffectingFrustum.Add(light); } } } } }
// formerly UpdateVisibility(Camera camera) public void CameraChange(Camera camera) { // we need to draw the tree if it intersects with the camera frustrum renderFlag = camera.IsObjectVisible(bounds); if (renderFlag) { // if the tree is still visible, update the camera dependent rendering args UpdateRenderArgs(); } }
public void CameraChange(Camera camera) { visible = camera.IsObjectVisible(bounds); // mark branches, fronds and leaves as not visible. If any of the trees have them visible, // the tree will set them to true in their own CameraChange() method. visibleBranches.Clear(); visibleFronds.Clear(); visibleLeaves.Clear(); visibleBillboards.Clear(); // force rebuilding of billboards before next render billboardsDirty = true; if (visible) { foreach (Tree t in trees) { t.CameraChange(camera); } //SortTrees(); } else { //ClearBuckets(); } }
/// <summary> /// Walks the BSP tree looking for the node which the camera is in, and tags any geometry /// which is in a visible leaf for later processing. /// </summary> protected BspNode WalkTree(Camera camera, bool onlyShadowCasters) { // Locate the leaf node where the camera is located BspNode cameraNode = level.FindLeaf(camera.DerivedPosition); matFaceGroupMap.Clear(); faceGroupChecked = new bool[level.FaceGroups.Length]; TextureLight[] lights = new TextureLight[lightList.Count]; BspNode[] lightNodes = new BspNode[lightList.Count]; Sphere[] lightSpheres = new Sphere[lightList.Count]; // The base SceneManager uses this for shadows. // The BspSceneManager uses this for texture lighting as well. if (shadowTechnique == ShadowTechnique.None) { lightsAffectingFrustum.Clear(); lightAddedToFrustum = new bool[lightList.Count]; } for (int lp=0; lp < lightList.Count; lp++) { TextureLight light = (TextureLight) lightList[lp]; lights[lp] = light; lightNodes[lp] = (BspNode) level.objectToNodeMap.FindFirst(light); if (light.Type != LightType.Directional) { // treating spotlight as point for simplicity lightSpheres[lp] = new Sphere(light.DerivedPosition, light.AttenuationRange); } } // Scan through all the other leaf nodes looking for visibles int i = level.NumNodes - level.LeafStart; int p = level.LeafStart; BspNode node; while(i-- > 0) { node = level.Nodes[p]; if(level.IsLeafVisible(cameraNode, node)) { // Visible according to PVS, check bounding box against frustum FrustumPlane plane; if(camera.IsObjectVisible(node.BoundingBox, out plane)) { if (!onlyShadowCasters) { for (int lp=0; lp < lights.Length; lp++) { if (lightAddedToFrustum[lp] || !lights[lp].IsVisible) continue; if (level.IsLeafVisible(lightNodes[lp], node) && (lights[lp].Type == LightType.Directional || lightSpheres[lp].Intersects(node.BoundingBox))) { // This is set so that the lights are rendered with ascending // Priority order. lights[lp].TempSquaredDist = lights[lp].Priority; lightsAffectingFrustum.Add(lights[lp]); lightAddedToFrustum[lp] = true; } } } ProcessVisibleLeaf(node, camera, onlyShadowCasters); if(showNodeAABs) AddBoundingBox(node.BoundingBox, true); } } p++; } return cameraNode; }