1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/misc/types_nl.h"
20 #include "nel/3d/clip_trav.h"
21 #include "nel/3d/hrc_trav.h"
22 #include "nel/3d/render_trav.h"
23 #include "nel/3d/anim_detail_trav.h"
24 #include "nel/3d/load_balancing_trav.h"
25 #include "nel/3d/cluster.h"
26 #include "nel/3d/scene_group.h"
27 #include "nel/3d/transform_shape.h"
28 #include "nel/3d/camera.h"
29 #include "nel/3d/quad_grid_clip_cluster.h"
30 #include "nel/3d/quad_grid_clip_manager.h"
31 #include "nel/3d/root_model.h"
32 #include "nel/misc/hierarchical_timer.h"
33 #include "nel/3d/scene.h"
34 #include "nel/3d/skeleton_model.h"
35 #include "nel/misc/fast_floor.h"
38 using namespace NLMISC
;
48 // ***************************************************************************
49 CClipTrav::CClipTrav() : ViewPyramid(6), WorldPyramid(6)
51 _VisibleList
.resize(1024);
52 _CurrentNumVisibleModels
= 0;
54 Accel
.create (64, 16.0f
);
56 ForceNoFrustumClip
= false;
57 _QuadGridClipManager
= NULL
;
58 _TrackClusterVisibility
= false;
61 // ***************************************************************************
62 CClipTrav::~CClipTrav()
66 // ***************************************************************************
67 bool CClipTrav::fullSearch (vector
<CCluster
*>& vCluster
, const CVector
& pos
)
69 CQuadGrid
<CCluster
*>::CIterator itAcc
;
71 // search with help of Accel
73 Accel
.select (pos
, pos
);
74 itAcc
= Accel
.begin();
75 while (itAcc
!= Accel
.end())
77 CCluster
*pCluster
= *itAcc
;
78 if (pCluster
->isIn (pos
))
80 vCluster
.push_back (pCluster
);
86 // if not found at all
89 vCluster
.push_back (RootCluster
);
91 // else must filter to take only the ones that are the lower in the hierarchy (same as in old code)
95 std::set
<CCluster
*> parentExclude
;
97 // for each cluster, avoid its parent
98 for(i
=0;i
<vCluster
.size();i
++)
100 CCluster
*cluster
= vCluster
[i
];
101 while(cluster
->Father
)
103 cluster
= cluster
->Father
;
104 parentExclude
.insert(cluster
);
108 // reparse to remove clusters presents in the exclude set
109 std::vector
<CCluster
*>::iterator it
;
110 for(it
=vCluster
.begin(); it
!=vCluster
.end();)
112 if(parentExclude
.find(*it
)!=parentExclude
.end())
113 it
= vCluster
.erase(it
);
120 // Old slow code (up to 5 ms on a 2.4 Ghz, in a big city).
122 for (i = 0; i < pIG->_ClusterInstances.size(); ++i)
124 for (j = 0; j < pIG->_ClusterInstances[i]->Children.size(); ++j)
126 if (fullSearch (vCluster, pIG->_ClusterInstances[i]->Children[j]->Group, pos))
131 for (i = 0; i < pIG->_ClusterInstances.size(); ++i)
133 if (pIG->_ClusterInstances[i]->isIn(pos))
134 vCluster.push_back (pIG->_ClusterInstances[i]);
136 if (!vCluster.empty())
142 /// Set cluster tracking on/off (ie storage of thje visible cluster during clip traversal)
143 void CClipTrav::setClusterVisibilityTracking(bool track
)
145 _TrackClusterVisibility
= track
;
147 /// Check the activation of cluster visibility tracking.
148 bool CClipTrav::getClusterVisibilityTracking()
150 return _TrackClusterVisibility
;
152 /// Add a visible cluster to the list
153 void CClipTrav::addVisibleCluster(CCluster
*cluster
)
155 _VisibleClusters
.push_back(cluster
);
157 /** Return the list of cluster visible after the clip traversal
158 * You must activate the cluster tracking to obtain a result.
160 const std::vector
<CCluster
*> &CClipTrav::getVisibleClusters()
162 return _VisibleClusters
;
166 // ***************************************************************************
167 void CClipTrav::traverse()
169 H_AUTO( NL3D_TravClip
);
171 // The root must exist
172 CTransform
*sceneRoot
= Scene
->getRoot();
174 // Increment the current date of the traversal
176 // Update Clip infos.
177 CTravCameraScene::update();
179 // Compute pyramid in view basis.
181 CVector
lb(Left
, Near
, Bottom
);
182 CVector
lt(Left
, Near
, Top
);
183 CVector
rb(Right
, Near
, Bottom
);
184 CVector
rt(Right
, Near
, Top
);
186 CVector
lbFar(Left
, Far
, Bottom
);
187 CVector
ltFar(Left
, Far
, Top
);
188 CVector
rbFar(Right
, Far
, Bottom
);
189 CVector
rtFar(Right
, Far
, Top
);
193 ViewPyramid
[NL3D_CLIP_PLANE_NEAR
].make(lt
, lb
, rt
);
194 ViewPyramid
[NL3D_CLIP_PLANE_FAR
].make(lbFar
, ltFar
, rtFar
);
198 ViewPyramid
[NL3D_CLIP_PLANE_LEFT
].make(pfoc
, lt
, lb
);
199 ViewPyramid
[NL3D_CLIP_PLANE_TOP
].make(pfoc
, rt
, lt
);
200 ViewPyramid
[NL3D_CLIP_PLANE_RIGHT
].make(pfoc
, rb
, rt
);
201 ViewPyramid
[NL3D_CLIP_PLANE_BOTTOM
].make(pfoc
, lb
, rb
);
205 ViewPyramid
[NL3D_CLIP_PLANE_LEFT
].make(lt
, ltFar
, lbFar
);
206 ViewPyramid
[NL3D_CLIP_PLANE_TOP
].make(lt
, rtFar
, ltFar
);
207 ViewPyramid
[NL3D_CLIP_PLANE_RIGHT
].make(rt
, rbFar
, rtFar
);
208 ViewPyramid
[NL3D_CLIP_PLANE_BOTTOM
].make(lb
, lbFar
, rbFar
);
211 // Compute pyramid in World basis.
212 // The vector transformation M of a plane p is computed as p*M-1.
213 // Here, ViewMatrix== CamMatrix-1. Hence the following formula.
214 for (i
= 0; i
< 6; i
++)
216 WorldPyramid
[i
]= ViewPyramid
[i
]*ViewMatrix
;
219 // bkup this pyramid (because this one may be modified by the cluster system).
220 WorldFrustumPyramid
= WorldPyramid
;
223 // update the QuadGridClipManager.
224 if(_QuadGridClipManager
)
226 _QuadGridClipManager
->updateClustersFromCamera(CamPos
);
229 H_BEFORE( NL3D_TravClip_ClearLists
);
231 // Clear the traversals list.
232 Scene
->getAnimDetailTrav().clearVisibleList();
233 Scene
->getLoadBalancingTrav().clearVisibleList();
234 Scene
->getLightTrav().clearLightedList();
235 Scene
->getRenderTrav().clearRenderList();
237 H_AFTER( NL3D_TravClip_ClearLists
);
240 H_BEFORE( NL3D_TravClip_ResetVisible
);
242 /* For all objects marked visible in preceding render, reset _Visible state here.
243 NB: must reset _Visible State to false because sometimes traverseClip() are even not executed
244 (Cluster clip, QuadGridClipManager clip...).
245 And somes models read this _Visible state. eg: Skins/StickedObjects test the Visible state of
246 their _AncestorSkeletonModel.
248 for (i
=0;i
<_CurrentNumVisibleModels
;i
++)
250 // if the model still exists (see ~CTransform())
251 if( _VisibleList
[i
] )
253 // disable his visibility.
254 _VisibleList
[i
]->_Visible
= false;
255 // let him know that it is no more in the list.
256 _VisibleList
[i
]->_IndexInVisibleList
= -1;
259 // Clear The visible List.
260 _CurrentNumVisibleModels
= 0;
261 // Clear the visible cluster list.
262 _VisibleClusters
.clear();
264 H_AFTER( NL3D_TravClip_ResetVisible
);
266 // Found where is the camera
267 //========================
269 H_BEFORE( NL3D_TravClip_FindCameraCluster
);
271 // Found the cluster where the camera is
272 static vector
<CCluster
*> vCluster
;
275 sceneRoot
->clipDelChild(RootCluster
);
277 // In which cluster is the camera ?
278 CQuadGrid
<CCluster
*>::CIterator itAcc
;
279 if (Camera
->getClusterSystem() == (CInstanceGroup
*)-1)
281 fullSearch(vCluster
, CamPos
);
282 for (i
= 0; i
< vCluster
.size(); ++i
)
283 sceneRoot
->clipAddChild(vCluster
[i
]);
287 bool bInWorld
= true;
288 Accel
.select (CamPos
, CamPos
);
289 itAcc
= Accel
.begin();
290 while (itAcc
!= Accel
.end())
292 CCluster
*pCluster
= *itAcc
;
293 if (pCluster
->Group
== Camera
->getClusterSystem())
294 if (pCluster
->isIn (CamPos
))
296 sceneRoot
->clipAddChild(pCluster
);
297 vCluster
.push_back (pCluster
);
305 sceneRoot
->clipAddChild(RootCluster
);
306 vCluster
.push_back (RootCluster
);
310 /// Flag all cluster to know if they are in camera or not.
311 for(i
=0;i
<vCluster
.size();i
++)
313 vCluster
[i
]->setCameraIn(true);
317 H_AFTER( NL3D_TravClip_FindCameraCluster
);
319 // Manage Moving Objects
320 //=====================
322 H_BEFORE( NL3D_TravClip_MovingObjects
);
324 // Unlink the moving objects from their clusters
325 CHrcTrav
&hrcTrav
= Scene
->getHrcTrav();
326 for (i
= 0; i
< hrcTrav
._MovingObjects
.size(); ++i
)
328 CTransformShape
*pTfmShp
= hrcTrav
._MovingObjects
[i
];
330 static vector
<CTransform
*> vModels
;
332 uint numClipParents
= pTfmShp
->clipGetNumParents();
333 for(j
=0;j
<numClipParents
;j
++)
335 CTransform
*pFather
= pTfmShp
->clipGetParent(j
);
337 // Does the father is a cluster ??
338 if ( pFather
->isCluster() )
340 vModels
.push_back (pFather
);
343 // Remove me from all clusters
344 for (j
= 0; j
< vModels
.size(); ++j
)
346 vModels
[j
]->clipDelChild(pTfmShp
);
348 // Remove me from Root Too
349 sceneRoot
->clipDelChild(pTfmShp
);
351 // NB: only the SonsOfAncestorSkeletonModelGroup may still be here.
354 // Affect the moving objects to their clusters
355 for (i
= 0; i
< hrcTrav
._MovingObjects
.size(); ++i
)
357 CTransformShape
*pTfmShp
= hrcTrav
._MovingObjects
[i
];
359 bool bInWorld
= true;
361 pTfmShp
->getAABBox (box
);
362 // Transform the box in the world
363 CVector c
= box
.getCenter();
364 CVector p
= box
.getCenter()+box
.getHalfSize();
365 const CMatrix
&wm
= pTfmShp
->getWorldMatrix();
368 float s
= (p
- c
).norm();
370 Accel
.select (c
+CVector(s
,s
,s
), c
+CVector(-s
,-s
,-s
));
371 itAcc
= Accel
.begin();
372 while (itAcc
!= Accel
.end())
374 CCluster
*pCluster
= *itAcc
;
375 if (pCluster
->Group
== pTfmShp
->getClusterSystem())
376 if (pCluster
->isIn (c
,s
))
378 pCluster
->clipAddChild(pTfmShp
);
384 // Moving object in the world -> link to root or to the CQuadGridClipManager.
387 if( _QuadGridClipManager
&& pTfmShp
->isQuadGridClipEnabled() )
389 // try to insert in the best cluster of the _QuadGridClipManager.
390 if(!_QuadGridClipManager
->linkModel(pTfmShp
))
391 // if fails, link to "root".
392 RootCluster
->clipAddChild(pTfmShp
);
396 RootCluster
->clipAddChild(pTfmShp
);
401 H_AFTER( NL3D_TravClip_MovingObjects
);
404 //=====================
406 H_BEFORE( NL3D_TravClip_Traverse
);
409 // Traverse the graph.
410 sceneRoot
->traverseClip();
413 // Unlink the cluster where we are
414 for (i
= 0; i
< vCluster
.size(); ++i
)
416 // reset Camera In Flag.
417 vCluster
[i
]->setCameraIn(false);
419 // remove from Clip Root
420 sceneRoot
->clipDelChild(vCluster
[i
]);
423 H_AFTER( NL3D_TravClip_Traverse
);
425 // Load Balance the Skeleton CLod state here.
426 // =========================
427 /* Can't do it in LoadBalancingTrav because sons with _AncestorSkeletonModel!=NULL may be hiden if a skeleton
428 is displayed in CLod mode.
429 So must do it here, then clip all sons of AncestoreSkeletonModelGroup.
431 H_BEFORE( NL3D_TravClip_LoadBalanceCLod
);
432 loadBalanceSkeletonCLod();
433 H_AFTER( NL3D_TravClip_LoadBalanceCLod
);
435 H_BEFORE( NL3D_TravClip_SkeletonClip
);
437 // At the end of the clip traverse, must update clip for Objects which have a skeleton ancestor
438 // =========================
439 // those are linked to the SonsOfAncestorSkeletonModelGroup, so traverse it now.
440 if (Scene
->SonsOfAncestorSkeletonModelGroup
)
441 Scene
->SonsOfAncestorSkeletonModelGroup
->traverseClip();
443 // For All Shadow Casters (skeletons + others), clip their ShadowMap possible projection against the frustum only.
444 // =========================
446 Done here, because can't do in clip() in case of a Model in a cluster
447 (We insert in cluster with the Model BBox, not the Model + Shadow BBox).
451 // Update Here the Skin render Lists of All visible Skeletons
452 // =========================
454 Done here, because AnimDetail and Render need correct lists. NB: important to do it
455 before Render Traversal, because updateSkinRenderLists() may change the transparency flag!!
456 NB: can't do it in any traverse() because must be sure that it is done
457 (traverseHRC not called if SonOfAncestorSkeletonModel, and traverseClip not called if in a cluster).
458 NB: must do even if clipped because:
459 1/ maybe used for generateShadow() (through the ancestorSkeletonModel)
460 2/ the cost of method is 0 all the time (but when true changes)
462 CScene::ItSkeletonModelList itSkel
;
463 for(itSkel
= Scene
->getSkeletonModelListBegin(); itSkel
!=Scene
->getSkeletonModelListEnd(); itSkel
++)
465 CSkeletonModel
*sm
= *itSkel
;
466 sm
->updateSkinRenderLists();
469 H_AFTER( NL3D_TravClip_SkeletonClip
);
473 // ***************************************************************************
474 void CClipTrav::setQuadGridClipManager(CQuadGridClipManager
*mgr
)
476 _QuadGridClipManager
= mgr
;
479 // ***************************************************************************
480 void CClipTrav::registerCluster (CCluster
* pCluster
)
482 pCluster
->AccelIt
= Accel
.insert (pCluster
->getBBox().getMin(), pCluster
->getBBox().getMax(), pCluster
);
485 // ***************************************************************************
486 void CClipTrav::unregisterCluster (CCluster
* pCluster
)
491 Accel
.erase(pCluster
->AccelIt
);
493 // just ensure it point to NULL
494 pCluster
->AccelIt
= CQuadGrid
<CCluster
*>::CIterator();
498 // ***************************************************************************
499 void CClipTrav::loadBalanceSkeletonCLod()
501 CScene::ItSkeletonModelList itSkel
;
502 _TmpSortSkeletons
.clear();
504 // **** compute CLod priority of each skeleton,
505 for(itSkel
= Scene
->getSkeletonModelListBegin(); itSkel
!=Scene
->getSkeletonModelListEnd(); itSkel
++)
507 CSkeletonModel
*sm
= *itSkel
;
508 float pr
= sm
->computeDisplayLodCharacterPriority();
509 // If valid priority (CLOd enabled, and skeleton visible)
512 sm
->setDisplayLodCharacterFlag(false);
514 // don't bother OptFastFloor precision.
515 key
.Priority
= OptFastFloor(pr
*0xFFFFFF00);
516 key
.SkeletonModel
= sm
;
517 _TmpSortSkeletons
.push_back(key
);
521 // **** sort by priority in ascending order
522 uint nMaxSkelsInNotCLodForm
= Scene
->getMaxSkeletonsInNotCLodForm();
523 // Optim: need it only if too many skels
524 if(_TmpSortSkeletons
.size()>nMaxSkelsInNotCLodForm
)
526 sort(_TmpSortSkeletons
.begin(), _TmpSortSkeletons
.end());
529 // **** set CLod flag for skeletons > setting
530 uint n
= min(nMaxSkelsInNotCLodForm
, (uint
)_TmpSortSkeletons
.size());
531 for (uint i
= n
; i
< _TmpSortSkeletons
.size(); i
++)
533 _TmpSortSkeletons
[i
].SkeletonModel
->setDisplayLodCharacterFlag(true);
539 // ***************************************************************************
540 void CClipTrav::reserveVisibleList(uint numModels
)
543 if(numModels
>_VisibleList
.size())
544 _VisibleList
.resize(numModels
);
548 // ***************************************************************************
549 struct CFadeShadowMapSort
554 bool operator<(const CFadeShadowMapSort
&o
) const
560 // ***************************************************************************
561 void CClipTrav::clipShadowCasters()
563 H_AUTO( NL3D_TravClip_ShadowCasters
);
565 CScene::ItShadowCasterList itShadowCaster
;
567 float dFade
= NL3D_SMM_FADE_SPEED
* Scene
->getEllapsedTime();
568 float distFadeStart
= Scene
->getShadowMapDistFadeStart();
569 float distFadeEnd
= Scene
->getShadowMapDistFadeEnd();
570 float OODeltaDistFade
;
571 if(distFadeEnd
-distFadeStart
>0)
572 OODeltaDistFade
= 1.0f
/(distFadeEnd
-distFadeStart
);
574 OODeltaDistFade
= 1000000;
575 uint maxCastInScreen
= Scene
->getShadowMapMaxCasterInScreen();
576 uint maxCastAround
= Scene
->getShadowMapMaxCasterAround();
579 // **** First select ShadowCasters that are visible or that may have their shadow visible
581 // Lod Models that will cast ShadowMaps.
582 static std::vector
<CFadeShadowMapSort
> aroundCasters
;
583 static std::vector
<CFadeShadowMapSort
> screenCasters
;
584 aroundCasters
.clear();
585 screenCasters
.clear();
588 for(itShadowCaster
= Scene
->getShadowCasterListBegin(); itShadowCaster
!=Scene
->getShadowCasterListEnd(); itShadowCaster
++)
590 CTransform
*sc
= *itShadowCaster
;
591 nlassert(sc
->canCastShadowMap());
593 CShadowMap
*shadowMap
= sc
->getShadowMap();
594 nlassert( shadowMap
);
596 // Binded to an Ancestor skeleton?? If so, don't render since the Ancestor Skeleton render all of his sons
597 // Additionally, no-op if this caster is hidden in HRC!!
598 if( sc
->_AncestorSkeletonModel
==NULL
&& sc
->isHrcVisible() )
601 // if we are already visible, then its ok, we either don't need to test.
602 if(sc
->isClipVisible())
604 // else do a bigger test
607 // TODO_SHADOW: Select a better "Caster Sphere".
608 // If the model "sc" is a CSkeletonModel, It depends also on Sticked objects/Skeletons.
609 // Build the sphere around the caster that can receive shadow.
611 // Suppose an Object sphere of 3 meter radius, centered on caster Pos.
612 const float objectRadius
= 3.f
;
613 sphere
.Center
= sc
->getWorldMatrix().getPos();
614 // Add to this sphere the max Depth extent.
615 // NB: works because suppose that the Shadow BBox include the model Center.
616 sphere
.Radius
= objectRadius
+ sc
->getShadowMapMaxDepth();
618 // Clip This sphere against the Frustum.
620 for(uint i
=0;i
<WorldFrustumPyramid
.size();i
++)
622 // if SpherMax OUT return false.
623 float d
= WorldFrustumPyramid
[i
]*sphere
.Center
;
632 // If the ShadowMap is visible, add it to the List Of ShadowMap to Render.
634 Scene
->getRenderTrav().getShadowMapManager().addShadowCaster(sc
);
637 CFadeShadowMapSort fsms
;
639 fsms
.Dist
= (sc
->getWorldMatrix().getPos() - CamPos
).norm();
641 aroundCasters
.push_back(fsms
);
643 screenCasters
.push_back(fsms
);
644 // Compute normal Distance fading.
645 shadowMap
->DistanceFade
= (fsms
.Dist
-distFadeStart
)*OODeltaDistFade
;
646 // Increment the TemporalFadeOut by default (see below)
647 shadowMap
->TemporalOutScreenFade
+= dFade
;
648 // if !visible, increment the InScreenFadeAccum
650 shadowMap
->InScreenFadeAccum
+= dFade
;
652 // If the model is not visible, or if temporary bound to a AncestorSkeletonModel
655 // Increment the TemporalFadeOut. Because since will be hidden (or sticked)
656 // for a long time, allow the process to free texture.
657 shadowMap
->TemporalOutScreenFade
+= dFade
;
658 // Since not visible, increment the InScreenFadeAccum
659 shadowMap
->InScreenFadeAccum
+= dFade
;
663 // **** Load Balance Models that cast ShadowMaps around,
665 sort(aroundCasters
.begin(), aroundCasters
.end());
666 sort(screenCasters
.begin(), screenCasters
.end());
668 // For All Around nearest Casters, decrement their fadeOutScreen
669 uint numNearCast
= min((uint
)aroundCasters
.size(), maxCastAround
);
671 for(i
=0;i
<numNearCast
;i
++)
673 CTransform
*model
= aroundCasters
[i
].Model
;
674 CShadowMap
*shadowMap
= model
->getShadowMap();
675 // Decrement the fade. *2 because default incremented above.
676 shadowMap
->TemporalOutScreenFade
-= 2*dFade
;
679 // For InScreen Casters, increment or decrement their fadeInScreen. Also resolve InScreenFadeAccum.
680 numNearCast
= min((uint
)screenCasters
.size(), maxCastInScreen
);
681 // nearest: decrement fadeInScreen, and remove accum
682 for(i
=0;i
<numNearCast
;i
++)
684 CShadowMap
*shadowMap
= screenCasters
[i
].Model
->getShadowMap();
685 // Decrement the fade.
686 shadowMap
->TemporalInScreenFade
-= dFade
+ shadowMap
->InScreenFadeAccum
;
687 // Since visible and resolved, reset accum
688 shadowMap
->InScreenFadeAccum
= 0;
690 // farthest: increment fadeInScreen, and append accum
691 for(i
=numNearCast
;i
<screenCasters
.size();i
++)
693 CShadowMap
*shadowMap
= screenCasters
[i
].Model
->getShadowMap();
694 // Increment the fade.
695 shadowMap
->TemporalInScreenFade
+= dFade
+ shadowMap
->InScreenFadeAccum
;
696 // Since visible and resolved, reset accum
697 shadowMap
->InScreenFadeAccum
= 0;
701 // clamp values, and release texture where appropriated
702 for(itShadowCaster
= Scene
->getShadowCasterListBegin(); itShadowCaster
!=Scene
->getShadowCasterListEnd(); itShadowCaster
++)
704 CTransform
*sc
= *itShadowCaster
;
705 nlassert(sc
->canCastShadowMap());
707 CShadowMap
*shadowMap
= sc
->getShadowMap();
708 shadowMap
->processFades();
711 // **** Use the rendered Skeletons ShadowMap to select the Ones that will be generated this Frame.
712 Scene
->getRenderTrav().getShadowMapManager().selectShadowMapsToGenerate(Scene
);
715 /* **** Then for All ShadowCasters not visibles but that will generate their shadowMap,
716 - we must compute the LightTraversal(for ShadowLight direction)
717 - for skeleton models only, we must compute the AnimDetailTraversal (for bone animation)
718 We MUST NOT flag the skeleton as Visible, and we MUST NOT insert in LoadBalancing
719 (since won't be rendered)
720 NB: Do nothing for Sons of the Ancestor Skeleton because:
721 1/ light do nothing with them (see std clip)
722 2/ animDetail will be called recursively (see std clip and CSkeletonModel::traverseAnimDetail())
724 for(itShadowCaster
= Scene
->getShadowCasterListBegin(); itShadowCaster
!=Scene
->getShadowCasterListEnd(); itShadowCaster
++)
726 CTransform
*sc
= *itShadowCaster
;
727 // compute its shadowMap this frame? and not visible?
728 if(sc
->isGeneratingShadowMap() && !sc
->isClipVisible() )
730 nlassert(sc
->_AncestorSkeletonModel
==NULL
);
731 // Add it only to the lightTrav
732 if( sc
->isLightable() )
733 Scene
->getLightTrav().addLightedModel(sc
);
734 // If it is a skeleton, add it also to the anim detail
735 if( sc
->isSkeleton() && sc
->isAnimDetailable() )
736 Scene
->getAnimDetailTrav().addVisibleModel(sc
);