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/3d/mesh_instance.h"
20 #include "nel/3d/mesh.h"
21 #include "nel/3d/skeleton_model.h"
22 #include "nel/3d/u_scene.h"
23 #include "nel/3d/scene.h"
27 using namespace NLMISC
;
36 // ***************************************************************************
37 CMeshInstance::CMeshInstance()
41 // LoadBalancing is not useful for Mesh, because meshs cannot be reduced in faces.
42 // Override CTransformShape state.
43 CTransform::setIsLoadbalancable(false);
45 // Mesh support shadow map casting only
46 CTransform::setIsShadowMapCaster(true);
49 // ***************************************************************************
50 CMeshInstance::~CMeshInstance()
52 // Auto detach me from skeleton. Must do it here, not in ~CTransform().
53 if(_FatherSkeletonModel
)
55 // detach me from the skeleton.
56 // hrc and clip hierarchy is modified.
57 _FatherSkeletonModel
->detachSkeletonSon(this);
58 nlassert(_FatherSkeletonModel
==NULL
);
61 // delete the shadowMap
66 // ***************************************************************************
67 void CMeshInstance::registerBasic()
69 CScene::registerModel(MeshInstanceId
, MeshBaseInstanceId
, CMeshInstance::creator
);
72 // ***************************************************************************
73 void CMeshInstance::setApplySkin(bool state
)
75 // Call parents method
76 CMeshBaseInstance::setApplySkin (state
);
78 // Get a pointer on the shape
79 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
84 pMesh
->computeBonesId (_FatherSkeletonModel
);
87 // update the skeleton usage according to the mesh.
88 pMesh
->updateSkeletonUsage(_FatherSkeletonModel
, state
);
92 // ***************************************************************************
93 const std::vector
<sint32
> *CMeshInstance::getSkinBoneUsage() const
95 // Get a pointer on the shape
96 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
99 pMesh
->computeBonesId (_FatherSkeletonModel
);
102 return &pMesh
->getMeshGeom().getSkinBoneUsage();
106 // ***************************************************************************
107 const std::vector
<NLMISC::CBSphere
> *CMeshInstance::getSkinBoneSphere() const
109 // Get a pointer on the shape
110 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
112 // Recompute the id, and skin spheres, if needed
113 pMesh
->computeBonesId (_FatherSkeletonModel
);
116 return &pMesh
->getMeshGeom().getSkinBoneSphere();
120 // ***************************************************************************
121 bool CMeshInstance::isSkinnable() const
126 // Get a pointer on the shape
127 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
129 // true if the mesh is skinned
130 return pMesh
->getMeshGeom().isSkinned();
134 // ***************************************************************************
135 void CMeshInstance::renderSkin(float alphaMRM
)
137 // Don't setup lighting or matrix in Skin. Done by the skeleton
139 if(Shape
&& getVisibility() != CHrcTrav::Hide
)
141 // Get a pointer on the shape
142 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
144 // render the meshGeom
145 CMeshGeom
&meshGeom
= const_cast<CMeshGeom
&>(pMesh
->getMeshGeom ());
146 meshGeom
.renderSkin( this, alphaMRM
);
151 // ***************************************************************************
152 void CMeshInstance::initRenderFilterType()
156 // If the Shape has a VP or not...
157 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
159 if( pMesh
->getMeshGeom().hasMeshVertexProgram() )
160 _RenderFilterType
= UScene::FilterMeshVP
;
162 _RenderFilterType
= UScene::FilterMeshNoVP
;
166 // ***************************************************************************
167 bool CMeshInstance::supportIntersectSkin() const
169 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
170 CMeshGeom
&meshGeom
= const_cast<CMeshGeom
&>(pMesh
->getMeshGeom ());
171 return meshGeom
.supportIntersectSkin();
174 // ***************************************************************************
175 bool CMeshInstance::intersectSkin(const CMatrix
&toRaySpace
, float &dist2D
, float &distZ
, bool computeDist2D
)
177 // Get a pointer on the shape
178 CMesh
*pMesh
= NLMISC::safe_cast
<CMesh
*>((IShape
*)Shape
);
179 // render the meshGeom
180 CMeshGeom
&meshGeom
= const_cast<CMeshGeom
&>(pMesh
->getMeshGeom ());
181 return meshGeom
.intersectSkin(this, toRaySpace
, dist2D
, distZ
, computeDist2D
);
184 // ***************************************************************************
185 // ***************************************************************************
187 // ***************************************************************************
188 // ***************************************************************************
191 // ***************************************************************************
192 void CMeshInstance::generateShadowMap(const CVector
&lightDir
)
194 // get the driver for Texture Render
195 CScene
*scene
= getOwnerScene();
196 CRenderTrav
&renderTrav
= scene
->getRenderTrav();
197 IDriver
*driver
= renderTrav
.getAuxDriver();
202 // update ShadowMap data if needed.
204 updateShadowMap(driver
);
209 // compute the ProjectionMatrix.
212 // get the BBox and localPosMatrix
214 Shape
->getAABBox(bbShape
);
215 CMatrix localPosMatrix
= getWorldMatrix();
216 localPosMatrix
.setPos(CVector::Null
);
218 // setup cameraMatrix with BBox and Enlarge For 1 pixel
219 CMatrix cameraMatrix
;
220 _ShadowMap
->buildCasterCameraMatrix(lightDir
, localPosMatrix
, bbShape
, cameraMatrix
);
225 // setup the orhtogonal frustum and viewMatrix to include all the object.
226 driver
->setFrustum(0,1,0,1,0,1,false);
227 driver
->setupViewMatrix(cameraMatrix
.inverted());
228 driver
->setupModelMatrix(localPosMatrix
);
231 CMaterial
&castMat
= renderTrav
.getShadowMapManager().getCasterShadowMaterial();
232 CMesh
*mesh
= (CMesh
*)(IShape
*)Shape
;
233 driver
->activeVertexBuffer( const_cast<CVertexBuffer
&>(mesh
->getVertexBuffer()) );
234 for(uint mb
=0;mb
<mesh
->getNbMatrixBlock();mb
++)
236 for(uint rp
=0;rp
<mesh
->getNbRdrPass(mb
);rp
++)
238 const CIndexBuffer
&pb
= mesh
->getRdrPassPrimitiveBlock(mb
, rp
);
239 driver
->activeIndexBuffer(const_cast<CIndexBuffer
&>(pb
));
240 driver
->renderTriangles(castMat
, 0, pb
.getNumIndexes()/3);
247 // Compute the BackPoint: the first point to be shadowed.
248 CVector backPoint
= bbShape
.getCenter();
249 // get the 3/4 bottom of the shape
250 backPoint
.z
-= bbShape
.getHalfSize().z
/2;
251 backPoint
= localPosMatrix
* backPoint
;
252 // Use the 3/4 bottom of the BBox minus the light direction in XY. NB: little hack:
253 // suppose no Rotate (but Z) and no scale
254 CVector ldir
= lightDir
;
257 float lenXY
= (CVector(bbShape
.getHalfSize().x
, bbShape
.getHalfSize().y
, 0)).norm();
258 backPoint
-= ldir
*lenXY
;
260 // Compute LocalProjectionMatrix and other infos from cameraMatrix and backPoint?
261 _ShadowMap
->buildProjectionInfos(cameraMatrix
, backPoint
, getShadowMapMaxDepth());
264 // ***************************************************************************
265 CShadowMap
*CMeshInstance::getShadowMap()
270 // ***************************************************************************
271 void CMeshInstance::createShadowMap()
273 // create the shadowMap
276 _ShadowMap
= new CShadowMap(&getOwnerScene()->getRenderTrav().getShadowMapManager());
277 getOwnerScene()->registerShadowCasterToList(this);
281 // ***************************************************************************
282 void CMeshInstance::deleteShadowMap()
288 getOwnerScene()->unregisterShadowCasterToList(this);
292 // ***************************************************************************
293 void CMeshInstance::updateShadowMap(IDriver
* /* driver */)
295 nlassert(_ShadowMap
);
297 // create/update texture
298 if(_ShadowMap
->getTextureSize()!=getOwnerScene()->getShadowMapTextureSize())
300 _ShadowMap
->initTexture(getOwnerScene()->getShadowMapTextureSize());
305 // ***************************************************************************
306 bool CMeshInstance::computeWorldBBoxForShadow(NLMISC::CAABBox
&worldBB
)
308 // If even not visible or empty, no-op
309 if(!isHrcVisible() || !Shape
)
312 // get the shape bbox
313 Shape
->getAABBox(worldBB
);
314 // transform into world
315 worldBB
= CAABBox::transformAABBox(getWorldMatrix(), worldBB
);
320 // ***************************************************************************
321 void CMeshInstance::renderIntoSkeletonShadowMap(CSkeletonModel
*rootSkeleton
, CMaterial
&castMat
)
324 Yoyo: Not Very Robuts here:
325 - suppose the MeshInstance don't have sons.
326 - suppose that the VertexBuffer doesn't have VertexColor (else castMat.color unused).
329 // If even not visible or empty, no-op
330 if(!isHrcVisible() || !Shape
)
333 // render into aux Driver
334 IDriver
*driver
= getOwnerScene()->getRenderTrav().getAuxDriver();
336 // **** Render the Skeleton Skins
337 // The model Matrix is special here. It must be the Skeleton World Matrix, minus The Root Skeleton pos.
338 CMatrix localPosMatrix
;
339 localPosMatrix
.setRot( getWorldMatrix() );
340 // NB: if this==rootSkeleton, then the final pos will be CVector::Null
341 localPosMatrix
.setPos( getWorldMatrix().getPos() - rootSkeleton
->getWorldMatrix().getPos() );
342 driver
->setupModelMatrix(localPosMatrix
);
345 CMesh
*mesh
= (CMesh
*)(IShape
*)Shape
;
346 driver
->activeVertexBuffer( const_cast<CVertexBuffer
&>(mesh
->getVertexBuffer()) );
347 for(uint mb
=0;mb
<mesh
->getNbMatrixBlock();mb
++)
349 for(uint rp
=0;rp
<mesh
->getNbRdrPass(mb
);rp
++)
351 const CIndexBuffer
&pb
= mesh
->getRdrPassPrimitiveBlock(mb
, rp
);
352 driver
->activeIndexBuffer(const_cast<CIndexBuffer
&>(pb
));
353 driver
->renderTriangles(castMat
, 0, pb
.getNumIndexes()/3);