1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2011 Robert TIMM (rti) <mail@rtti.de>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/misc/bsphere.h"
23 #include "nel/misc/system_info.h"
24 #include "nel/misc/hierarchical_timer.h"
25 #include "nel/misc/fast_mem.h"
26 #include "nel/3d/mesh_mrm_skinned.h"
27 #include "nel/3d/mrm_builder.h"
28 #include "nel/3d/mrm_parameters.h"
29 #include "nel/3d/mesh_mrm_skinned_instance.h"
30 #include "nel/3d/scene.h"
31 #include "nel/3d/skeleton_model.h"
32 #include "nel/3d/stripifier.h"
33 #include "nel/3d/mesh_blender.h"
34 #include "nel/3d/render_trav.h"
35 #include "nel/misc/fast_floor.h"
36 #include "nel/3d/raw_skinned.h"
37 #include "nel/3d/shifted_triangle_cache.h"
38 #include "nel/3d/texture_file.h"
39 #include "nel/3d/matrix_3x4.h"
42 using namespace NLMISC
;
53 H_AUTO_DECL( NL3D_MeshMRMGeom_RenderShadow
)
55 // ***************************************************************************
56 // ***************************************************************************
57 // CMeshMRMSkinnedGeom::CLod
58 // ***************************************************************************
59 // ***************************************************************************
62 // ***************************************************************************
63 void CMeshMRMSkinnedGeom::CLod::serial(NLMISC::IStream
&f
)
74 f
.serialCont(RdrPass
);
75 f
.serialCont(Geomorphs
);
76 f
.serialCont(MatrixInfluences
);
78 // Serial array of InfluencedVertices. NB: code written so far for NL3D_MESH_SKINNING_MAX_MATRIX==4 only.
79 nlassert(NL3D_MESH_SKINNING_MAX_MATRIX
==4);
80 for(i
= 0; i
<NL3D_MESH_SKINNING_MAX_MATRIX
; i
++)
82 f
.serialCont(InfluencedVertices
[i
]);
87 // ***************************************************************************
88 void CMeshMRMSkinnedGeom::CLod::optimizeTriangleOrder()
90 CStripifier stripifier
;
93 for(uint rp
=0; rp
<RdrPass
.size(); rp
++ )
95 // stripify list of triangles of this pass.
97 getRdrPassPrimitiveBlock(rp
, block
);
99 stripifier
.optimizeTriangles(block
, block
);
101 buildPrimitiveBlock(rp
, block
);
106 // ***************************************************************************
107 void CMeshMRMSkinnedGeom::CLod::getRdrPassPrimitiveBlock (uint renderPass
, CIndexBuffer
&block
) const
109 const CRdrPass
&rd
= RdrPass
[renderPass
];
110 const uint count
= rd
.getNumTriangle();
111 block
.setFormat(NL_SKINNED_MESH_MRM_INDEX_FORMAT
);
112 block
.setNumIndexes (count
*3);
114 CIndexBufferReadWrite ibaWrite
;
115 block
.lock (ibaWrite
);
118 for (i
=0; i
<count
; i
++)
120 ibaWrite
.setTri (i
*3, rd
.PBlock
[i
*3+0], rd
.PBlock
[i
*3+1], rd
.PBlock
[i
*3+2]);
124 // ***************************************************************************
126 void CMeshMRMSkinnedGeom::CLod::buildPrimitiveBlock(uint renderPass
, const CIndexBuffer
&block
)
128 CRdrPass
&rd
= RdrPass
[renderPass
];
129 const uint count
= block
.getNumIndexes()/3;
130 rd
.PBlock
.resize (3*count
);
132 CIndexBufferRead ibaRead
;
133 block
.lock (ibaRead
);
134 if (ibaRead
.getFormat() == CIndexBuffer::Indices32
)
136 const uint32
*triPtr
= (const uint32
*) ibaRead
.getPtr ();
137 for (i
=0; i
<count
; i
++)
139 rd
.PBlock
[i
*3+0] = (uint16
) (triPtr
[3*i
+0]);
140 rd
.PBlock
[i
*3+1] = (uint16
) (triPtr
[3*i
+1]);
141 rd
.PBlock
[i
*3+2] = (uint16
) (triPtr
[3*i
+2]);
146 const uint16
*triPtr
= (const uint16
*) ibaRead
.getPtr ();
147 for (i
=0; i
<count
; i
++)
149 rd
.PBlock
[i
*3+0] = (triPtr
[3*i
+0]);
150 rd
.PBlock
[i
*3+1] = (triPtr
[3*i
+1]);
151 rd
.PBlock
[i
*3+2] = (triPtr
[3*i
+2]);
156 // ***************************************************************************
157 // ***************************************************************************
158 // CMeshMRMSkinnedGeom.
159 // ***************************************************************************
160 // ***************************************************************************
165 // ***************************************************************************
166 static NLMISC::CAABBoxExt
makeBBox(const std::vector
<CVector
> &Vertices
)
169 nlassert(!Vertices
.empty());
170 ret
.setCenter(Vertices
[0]);
171 for(sint i
=0;i
<(sint
)Vertices
.size();i
++)
173 ret
.extend(Vertices
[i
]);
180 // ***************************************************************************
181 CMeshMRMSkinnedGeom::CMeshMRMSkinnedGeom()
183 _BoneIdComputed
= false;
184 _BoneIdExtended
= false;
185 _PreciseClipping
= false;
187 _SupportShadowSkinGrouping
= false;
191 // ***************************************************************************
192 CMeshMRMSkinnedGeom::~CMeshMRMSkinnedGeom()
197 // ***************************************************************************
198 void CMeshMRMSkinnedGeom::changeMRMDistanceSetup(float distanceFinest
, float distanceMiddle
, float distanceCoarsest
)
201 if(distanceFinest
<0) return;
202 if(distanceMiddle
<=distanceFinest
) return;
203 if(distanceCoarsest
<=distanceMiddle
) return;
206 _LevelDetail
.DistanceFinest
= distanceFinest
;
207 _LevelDetail
.DistanceMiddle
= distanceMiddle
;
208 _LevelDetail
.DistanceCoarsest
= distanceCoarsest
;
211 _LevelDetail
.compileDistanceSetup();
214 // ***************************************************************************
216 void CMeshMRMSkinnedGeom::build(CMesh::CMeshBuild
&m
,
217 uint numMaxMaterial
, const CMRMParameters
¶ms
)
220 if(m
.Vertices
.empty() || m
.Faces
.empty())
222 _VBufferFinal
.clear();
224 _BBox
.setCenter(CVector::Null
);
225 _BBox
.setSize(CVector::Null
);
228 nlassert(numMaxMaterial
>0);
231 /// 0. First, make bbox.
232 //======================
233 // NB: this is equivalent as building BBox from MRM VBuffer, because CMRMBuilder create new vertices
234 // which are just interpolation of original vertices.
235 _BBox
= makeBBox(m
.Vertices
);
238 /// 1. Launch the MRM build process.
239 //================================================
240 CMRMBuilder mrmBuilder
;
241 CMeshBuildMRM meshBuildMRM
;
242 std::vector
<CMesh::CMeshBuild
*> bsList
;
244 mrmBuilder
.compileMRM(m
, bsList
, params
, meshBuildMRM
, numMaxMaterial
);
245 nlassert (meshBuildMRM
.Skinned
);
247 // Then build the packed vertex buffer
248 //================================================
249 _VBufferFinal
.build (meshBuildMRM
.VBuffer
, meshBuildMRM
.SkinWeights
);
250 _Lods
= meshBuildMRM
.Lods
;
252 // Compute degradation control.
253 //================================================
254 _LevelDetail
.DistanceFinest
= meshBuildMRM
.DistanceFinest
;
255 _LevelDetail
.DistanceMiddle
= meshBuildMRM
.DistanceMiddle
;
256 _LevelDetail
.DistanceCoarsest
= meshBuildMRM
.DistanceCoarsest
;
257 nlassert(_LevelDetail
.DistanceFinest
>=0);
258 nlassert(_LevelDetail
.DistanceMiddle
> _LevelDetail
.DistanceFinest
);
259 nlassert(_LevelDetail
.DistanceCoarsest
> _LevelDetail
.DistanceMiddle
);
260 // Compute OODistDelta and DistancePow
261 _LevelDetail
.compileDistanceSetup();
264 // For load balancing.
265 //================================================
266 // compute Max Face Used
267 _LevelDetail
.MaxFaceUsed
= 0;
268 _LevelDetail
.MinFaceUsed
= 0;
269 // Count of primitive block
274 CLod
&firstLod
= _Lods
[0];
275 for (pb
=0; pb
<firstLod
.RdrPass
.size(); pb
++)
277 CRdrPass
&pass
= firstLod
.RdrPass
[pb
];
279 _LevelDetail
.MinFaceUsed
+= pass
.getNumTriangle ();
282 CLod
&lastLod
= _Lods
[_Lods
.size()-1];
283 for (pb
=0; pb
<lastLod
.RdrPass
.size(); pb
++)
285 CRdrPass
&pass
= lastLod
.RdrPass
[pb
];
287 _LevelDetail
.MaxFaceUsed
+= pass
.getNumTriangle ();
293 //================================================
295 // Inform that the mesh data has changed
299 // For AGP SKinning optim, and for Render optim
300 //================================================
302 for(i
=0;i
<_Lods
.size();i
++)
304 // sort triangles for better cache use.
305 _Lods
[i
].optimizeTriangleOrder();
309 //================================================
310 nlassert (meshBuildMRM
.BlendShapes
.empty());
312 // Compact bone id and build a bone id names
313 //================================================
316 std::map
<uint
, uint
> remap
;
319 uint currentBone
= 0;
322 _BonesName
.reserve (m
.BonesNames
.size());
326 CPackedVertexBuffer::CPackedVertex
*vertices
= _VBufferFinal
.getPackedVertices();
327 for (vert
=0; vert
<_VBufferFinal
.getNumVertices(); vert
++)
334 for (weight
=0; weight
<NL3D_MESH_MRM_SKINNED_MAX_MATRIX
; weight
++)
337 if ((vertices
[vert
].Weights
[weight
]>0)||(weight
==0))
340 std::map
<uint
, uint
>::iterator ite
= remap
.find (vertices
[vert
].Matrices
[weight
]);
343 if (ite
== remap
.end())
346 remap
.insert (std::map
<uint
, uint
>::value_type (vertices
[vert
].Matrices
[weight
], currentBone
));
349 nlassert (vertices
[vert
].Matrices
[weight
]<m
.BonesNames
.size());
352 _BonesName
.push_back (m
.BonesNames
[vertices
[vert
].Matrices
[weight
]]);
354 // Set the local bone id
355 vertices
[vert
].Matrices
[weight
] = currentBone
++;
359 // Set the local bone id
360 vertices
[vert
].Matrices
[weight
] = ite
->second
;
372 // Remap the vertex influence by lods
374 for (lod
=0; lod
<_Lods
.size(); lod
++)
376 // For each matrix used
378 for (matrix
=0; matrix
<_Lods
[lod
].MatrixInfluences
.size(); matrix
++)
381 std::map
<uint
, uint
>::iterator ite
= remap
.find (_Lods
[lod
].MatrixInfluences
[matrix
]);
384 if (ite
== remap
.end())
387 _Lods
[lod
].MatrixInfluences
.erase (_Lods
[lod
].MatrixInfluences
.begin()+matrix
);
393 _Lods
[lod
].MatrixInfluences
[matrix
] = ite
->second
;
398 //===================
399 // Some runtime not serialized compilation
404 // ***************************************************************************
405 void CMeshMRMSkinnedGeom::applyMaterialRemap(const std::vector
<sint
> &remap
)
407 for(uint lod
=0;lod
<getNbLod();lod
++)
409 for(uint rp
=0;rp
<getNbRdrPass(lod
);rp
++)
412 uint32
&matId
= _Lods
[lod
].RdrPass
[rp
].MaterialId
;
413 nlassert(remap
[matId
]>=0);
419 // ***************************************************************************
420 void CMeshMRMSkinnedGeom::applyGeomorph(std::vector
<CMRMWedgeGeom
> &geoms
, float alphaLod
)
422 applyGeomorphWithVBHardPtr(geoms
, alphaLod
);
426 // ***************************************************************************
427 void CMeshMRMSkinnedGeom::applyGeomorphWithVBHardPtr(std::vector
<CMRMWedgeGeom
> &geoms
, float alphaLod
)
429 // no geomorphs? quit.
433 clamp(alphaLod
, 0.f
, 1.f
);
434 sint a
= (uint
)floor((256.f
*alphaLod
)+0.5f
);
438 // info from VBuffer.
439 uint8
*vertexPtr
= (uint8
*)_VBufferFinal
.getPackedVertices();
440 sint32 vertexSize
= sizeof(CPackedVertexBuffer::CPackedVertex
);
442 // use a faster method
443 applyGeomorphPosNormalUV0Int(geoms
, vertexPtr
, vertexPtr
, vertexSize
, a
, a1
);
447 // ***************************************************************************
448 void CMeshMRMSkinnedGeom::applyGeomorphPosNormalUV0(std::vector
<CMRMWedgeGeom
> &geoms
, uint8
*vertexPtr
, uint8
*vertexDestPtr
, sint32 vertexSize
, float a
, float a1
)
450 nlassert(vertexSize
==32);
453 // For all geomorphs.
454 uint nGeoms
= (uint
)geoms
.size();
455 CMRMWedgeGeom
*ptrGeom
= &(geoms
[0]);
456 uint8
*destPtr
= vertexDestPtr
;
457 for(; nGeoms
>0; nGeoms
--, ptrGeom
++, destPtr
+= vertexSize
)
459 // Consider the Pos/Normal/UV as an array of 8 float to interpolate.
460 float *start
= (float*)(vertexPtr
+ (ptrGeom
->Start
<<5));
461 float *end
= (float*)(vertexPtr
+ (ptrGeom
->End
<<5));
462 float *dst
= (float*)(destPtr
);
465 dst
[0]= start
[0] * a
+ end
[0]* a1
;
466 dst
[1]= start
[1] * a
+ end
[1]* a1
;
467 dst
[2]= start
[2] * a
+ end
[2]* a1
;
468 dst
[3]= start
[3] * a
+ end
[3]* a1
;
469 dst
[4]= start
[4] * a
+ end
[4]* a1
;
470 dst
[5]= start
[5] * a
+ end
[5]* a1
;
471 dst
[6]= start
[6] * a
+ end
[6]* a1
;
472 dst
[7]= start
[7] * a
+ end
[7]* a1
;
477 // ***************************************************************************
478 void CMeshMRMSkinnedGeom::applyGeomorphPosNormalUV0Int(std::vector
<CMRMWedgeGeom
> &geoms
, uint8
*vertexPtr
, uint8
*vertexDestPtr
, sint32 vertexSize
, sint a
, sint a1
)
480 // For all geomorphs.
481 uint nGeoms
= (uint
)geoms
.size();
482 CMRMWedgeGeom
*ptrGeom
= &(geoms
[0]);
483 uint8
*destPtr
= vertexDestPtr
;
484 for(; nGeoms
>0; nGeoms
--, ptrGeom
++, destPtr
+= vertexSize
)
486 // Consider the Pos/Normal/UV as an array of 8 float to interpolate.
487 sint16
*start
= (sint16
*)(vertexPtr
+ (ptrGeom
->Start
*vertexSize
));
488 sint16
*end
= (sint16
*)(vertexPtr
+ (ptrGeom
->End
*vertexSize
));
489 sint16
*dst
= (sint16
*)(destPtr
);
492 * This is slow but, we don't care because this method is called for debug purpose only (watch skin without skinning)
496 dst
[0]= (sint16
)(((sint
)(start
[0]) * a
+ (sint
)(end
[0]) * a1
)>>8);
497 dst
[1]= (sint16
)(((sint
)(start
[1]) * a
+ (sint
)(end
[1]) * a1
)>>8);
498 dst
[2]= (sint16
)(((sint
)(start
[2]) * a
+ (sint
)(end
[2]) * a1
)>>8);
499 dst
[3]= (sint16
)(((sint
)(start
[3]) * a
+ (sint
)(end
[3]) * a1
)>>8);
500 dst
[4]= (sint16
)(((sint
)(start
[4]) * a
+ (sint
)(end
[4]) * a1
)>>8);
501 dst
[5]= (sint16
)(((sint
)(start
[5]) * a
+ (sint
)(end
[5]) * a1
)>>8);
502 dst
[6]= (sint16
)(((sint
)(start
[6]) * a
+ (sint
)(end
[6]) * a1
)>>8);
503 dst
[7]= (sint16
)(((sint
)(start
[7]) * a
+ (sint
)(end
[7]) * a1
)>>8);
508 // ***************************************************************************
509 void CMeshMRMSkinnedGeom::initInstance(CMeshBaseInstance
*mbi
)
514 // ***************************************************************************
515 bool CMeshMRMSkinnedGeom::clip(const std::vector
<CPlane
> &pyramid
, const CMatrix
&worldMatrix
)
517 // Speed Clip: clip just the sphere.
518 CBSphere
localSphere(_BBox
.getCenter(), _BBox
.getRadius());
519 CBSphere worldSphere
;
521 // transform the sphere in WorldMatrix (with nearly good scale info).
522 localSphere
.applyTransform(worldMatrix
, worldSphere
);
524 // if out of only plane, entirely out.
525 for(sint i
=0;i
<(sint
)pyramid
.size();i
++)
527 // We are sure that pyramid has normalized plane normals.
528 // if SpherMax OUT return false.
529 float d
= pyramid
[i
]*worldSphere
.Center
;
530 if(d
>worldSphere
.Radius
)
534 // test if must do a precise clip, according to mesh size.
535 if( _PreciseClipping
)
539 // if out of only plane, entirely out.
540 for(sint i
=0;i
<(sint
)pyramid
.size();i
++)
542 // Transform the pyramid in Object space.
543 localPlane
= pyramid
[i
]*worldMatrix
;
544 // localPlane must be normalized, because worldMatrix mya have a scale.
545 localPlane
.normalize();
546 // if the box is not partially inside the plane, quit
547 if( !_BBox
.clipBack(localPlane
) )
556 // ***************************************************************************
557 inline sint
CMeshMRMSkinnedGeom::chooseLod(float alphaMRM
, float &alphaLod
)
559 // Choose what Lod to draw.
560 alphaMRM
*= _Lods
.size()-1;
561 sint numLod
= (sint
)ceil(alphaMRM
);
569 // Lerp beetween lod i-1 and lod i.
570 alphaLod
= alphaMRM
-(numLod
-1);
573 /// Ensure numLod is correct
574 if(numLod
>=(sint
)_Lods
.size())
576 numLod
= (sint
)_Lods
.size()-1;
584 // ***************************************************************************
585 void CMeshMRMSkinnedGeom::render(IDriver
*drv
, CTransformShape
*trans
, float polygonCount
, uint32 rdrFlags
, float globalAlpha
)
592 // get the meshMRM instance.
593 CMeshBaseInstance
*mi
= safe_cast
<CMeshBaseInstance
*>(trans
);
596 // get the result of the Load Balancing.
597 float alphaMRM
= _LevelDetail
.getLevelDetailFromPolyCount(polygonCount
);
601 sint numLod
= chooseLod(alphaMRM
, alphaLod
);
604 // Render the choosen Lod.
605 CLod
&lod
= _Lods
[numLod
];
606 if(lod
.RdrPass
.empty())
610 // get the skeleton model to which I am binded (else NULL).
611 CSkeletonModel
*skeleton
;
612 skeleton
= mi
->getSkeletonModel();
613 // The mesh must not be skinned for render()
614 nlassert(!(mi
->isSkinned() && skeleton
));
619 H_AUTO( NL3D_MeshMRMGeom_RenderNormal
);
624 // set the instance worldmatrix.
625 drv
->setupModelMatrix(trans
->getWorldMatrix());
630 // Geomorph the choosen Lod (if not the coarser mesh).
633 applyGeomorph(lod
.Geomorphs
, alphaLod
);
637 // force normalisation of normals..
638 bool bkupNorm
= drv
->isForceNormalize();
639 drv
->forceNormalize(true);
642 // Setup meshVertexProgram
650 * This is slow but, we don't care because this method is called for debug purpose only (watch skin without skinning)
653 getVertexBuffer (tmp
);
655 drv
->activeVertexBuffer(tmp
);
658 // Global alpha used ?
659 uint32 globalAlphaUsed
= rdrFlags
& IMeshGeom::RenderGlobalAlpha
;
660 uint8 globalAlphaInt
=(uint8
)NLMISC::OptFastFloor(globalAlpha
*255);
665 bool gaDisableZWrite
= (rdrFlags
& IMeshGeom::RenderGADisableZWrite
)?true:false;
668 for(uint i
=0;i
<lod
.RdrPass
.size();i
++)
670 CRdrPass
&rdrPass
= lod
.RdrPass
[i
];
672 if ( ( (mi
->Materials
[rdrPass
.MaterialId
].getBlend() == false) && (rdrFlags
& IMeshGeom::RenderOpaqueMaterial
) ) ||
673 ( (mi
->Materials
[rdrPass
.MaterialId
].getBlend() == true) && (rdrFlags
& IMeshGeom::RenderTransparentMaterial
) ) )
676 CMaterial
&material
=mi
->Materials
[rdrPass
.MaterialId
];
678 // Use a MeshBlender to modify material and driver.
679 CMeshBlender blender
;
680 blender
.prepareRenderForGlobalAlpha(material
, drv
, globalAlpha
, globalAlphaInt
, gaDisableZWrite
);
683 * This is slow but, we don't care because this method is called for debug purpose only (watch skin without skinning)
686 lod
.getRdrPassPrimitiveBlock (i
, block
);
689 drv
->activeIndexBuffer(block
);
690 drv
->renderTriangles(material
, 0, block
.getNumIndexes()/3);
692 // Resetup material/driver
693 blender
.restoreRender(material
, drv
, gaDisableZWrite
);
699 for(uint i
=0;i
<lod
.RdrPass
.size();i
++)
701 CRdrPass
&rdrPass
= lod
.RdrPass
[i
];
703 if ( ( (mi
->Materials
[rdrPass
.MaterialId
].getBlend() == false) && (rdrFlags
& IMeshGeom::RenderOpaqueMaterial
) ) ||
704 ( (mi
->Materials
[rdrPass
.MaterialId
].getBlend() == true) && (rdrFlags
& IMeshGeom::RenderTransparentMaterial
) ) )
707 CMaterial
&material
=mi
->Materials
[rdrPass
.MaterialId
];
710 * This is slow but, we don't care because this method is called for debug purpose only (watch skin without skinning)
713 lod
.getRdrPassPrimitiveBlock (i
, block
);
715 // Render with the Materials of the MeshInstance.
716 drv
->activeIndexBuffer(block
);
717 drv
->renderTriangles(material
, 0, block
.getNumIndexes()/3);
722 // bkup force normalisation.
723 drv
->forceNormalize(bkupNorm
);
728 // ***************************************************************************
729 void CMeshMRMSkinnedGeom::renderSkin(CTransformShape
*trans
, float alphaMRM
)
734 // ***************************************************************************
735 bool CMeshMRMSkinnedGeom::supportSkinGrouping() const
740 // ***************************************************************************
741 sint
CMeshMRMSkinnedGeom::renderSkinGroupGeom(CMeshMRMSkinnedInstance
*mi
, float alphaMRM
, uint remainingVertices
, uint8
*vbDest
)
743 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom
)
745 // since not tested in supportSkinGrouping(), must test _Lods.empty(): no lod, no draw
749 // get a ptr on scene
750 CScene
*ownerScene
= mi
->getOwnerScene();
751 // get a ptr on renderTrav
752 CRenderTrav
*renderTrav
= &ownerScene
->getRenderTrav();
753 // get a ptr on the driver
754 IDriver
*drv
= renderTrav
->getDriver();
760 sint numLod
= chooseLod(alphaMRM
, alphaLod
);
761 _LastLodComputed
= numLod
;
764 // Render the choosen Lod.
765 CLod
&lod
= _Lods
[numLod
];
766 if(lod
.RdrPass
.empty())
767 // return no vertices added
770 // If the Lod is too big to render in the VBufferHard
771 if(lod
.NWedges
>remainingVertices
)
775 // get the skeleton model to which I am skinned
776 CSkeletonModel
*skeleton
;
777 skeleton
= mi
->getSkeletonModel();
778 // must be skinned for renderSkin()
779 nlassert(mi
->isSkinned() && skeleton
);
784 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom_go
);
790 // Use RawSkin if possible: only if no morph, and only Vertex/Normal
791 updateRawSkinNormal(true, mi
, numLod
);
793 // NB: the skeleton matrix has already been setuped by CSkeletonModel
794 // NB: the normalize flag has already been setuped by CSkeletonModel
796 // applySkin with RawSkin.
798 nlassert(mi
->_RawSkinCache
);
800 H_AUTO( NL3D_RawSkinning
);
802 // RawSkin do all the job in optimized way: Skinning, copy to VBHard and Geomorph.
804 // skinning with normal, but no tangent space
805 applyRawSkinWithNormal (lod
, *(mi
->_RawSkinCache
), skeleton
, vbDest
, alphaLod
);
807 // Vertices are packed in RawSkin mode (ie no holes due to MRM!)
808 return (sint
)mi
->_RawSkinCache
->Geomorphs
.size() +
809 mi
->_RawSkinCache
->TotalSoftVertices
+
810 mi
->_RawSkinCache
->TotalHardVertices
;
813 // ***************************************************************************
814 void CMeshMRMSkinnedGeom::renderSkinGroupPrimitives(CMeshMRMSkinnedInstance
*mi
, uint baseVertex
, std::vector
<CSkinSpecularRdrPass
> &specularRdrPasses
, uint skinIndex
)
816 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpPrimitives
);
818 // get a ptr on scene
819 CScene
*ownerScene
= mi
->getOwnerScene();
820 // get a ptr on renderTrav
821 CRenderTrav
*renderTrav
= &ownerScene
->getRenderTrav();
822 // get a ptr on the driver
823 IDriver
*drv
= renderTrav
->getDriver();
826 // Get the lod choosen in renderSkinGroupGeom()
827 CLod
&lod
= _Lods
[_LastLodComputed
];
830 // must update primitive cache
831 updateShiftedTriangleCache(mi
, _LastLodComputed
, baseVertex
);
832 nlassert(mi
->_ShiftedTriangleCache
);
835 // Render Triangles with cache
837 for(uint i
=0;i
<lod
.RdrPass
.size();i
++)
839 CRdrPass
&rdrPass
= lod
.RdrPass
[i
];
842 CMaterial
&material
=mi
->Materials
[rdrPass
.MaterialId
];
844 // TestYoyo. Material Speed Test
845 /*if( material.getDiffuse()!=CRGBA(250, 251, 252) )
847 material.setDiffuse(CRGBA(250, 251, 252));
848 // Set all texture the same.
849 static CSmartPtr<ITexture> pTexFile= new CTextureFile("fy_hom_visage_c1_fy_e1.tga");
850 material.setTexture(0, pTexFile );
852 if(material.getShader()==CMaterial::Specular)
854 CSmartPtr<ITexture> tex= material.getTexture(0);
855 material.setShader(CMaterial::Normal);
856 material.setTexture(0, tex );
859 material.setTexture(1, NULL);
862 // If the material is a specular material, don't render it now!
863 if(material
.getShader()==CMaterial::Specular
)
865 // Add it to the rdrPass to sort!
866 CSkinSpecularRdrPass specRdrPass
;
867 specRdrPass
.SkinIndex
= skinIndex
;
868 specRdrPass
.RdrPassIndex
= i
;
869 // Get the handle of the specular Map as the sort Key
870 ITexture
*specTex
= material
.getTexture(1);
872 specRdrPass
.SpecId
= 0;
874 specRdrPass
.SpecId
= drv
->getTextureHandle( *specTex
);
875 // Append it to the list
876 specularRdrPasses
.push_back(specRdrPass
);
880 // Get the shifted triangles.
881 CShiftedTriangleCache::CRdrPass
&shiftedRdrPass
= mi
->_ShiftedTriangleCache
->RdrPass
[i
];
883 // Render with the Materials of the MeshInstance.
884 drv
->activeIndexBuffer(mi
->_ShiftedTriangleCache
->RawIndices
);
885 drv
->renderTriangles(material
, shiftedRdrPass
.Triangles
, shiftedRdrPass
.NumTriangles
);
891 // ***************************************************************************
892 void CMeshMRMSkinnedGeom::renderSkinGroupSpecularRdrPass(CMeshMRMSkinnedInstance
*mi
, uint rdrPassId
)
894 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpSpecularRdrPass
);
896 // get a ptr on scene
897 CScene
*ownerScene
= mi
->getOwnerScene();
898 // get a ptr on renderTrav
899 CRenderTrav
*renderTrav
= &ownerScene
->getRenderTrav();
900 // get a ptr on the driver
901 IDriver
*drv
= renderTrav
->getDriver();
904 // Get the lod choosen in renderSkinGroupGeom()
905 CLod
&lod
= _Lods
[_LastLodComputed
];
908 // _ShiftedTriangleCache must have been computed in renderSkinGroupPrimitives
909 nlassert(mi
->_ShiftedTriangleCache
);
912 // Render Triangles with cache
914 CRdrPass
&rdrPass
= lod
.RdrPass
[rdrPassId
];
917 CMaterial
&material
=mi
->Materials
[rdrPass
.MaterialId
];
919 // Get the shifted triangles.
920 CShiftedTriangleCache::CRdrPass
&shiftedRdrPass
= mi
->_ShiftedTriangleCache
->RdrPass
[rdrPassId
];
922 // Render with the Materials of the MeshInstance.
923 drv
->activeIndexBuffer(mi
->_ShiftedTriangleCache
->RawIndices
);
924 drv
->renderTriangles(material
, shiftedRdrPass
.Triangles
, shiftedRdrPass
.NumTriangles
);
928 // ***************************************************************************
929 void CMeshMRMSkinnedGeom::updateShiftedTriangleCache(CMeshMRMSkinnedInstance
*mi
, sint curLodId
, uint baseVertex
)
931 // if the instance has a cache, but not sync to us, delete it.
932 if( mi
->_ShiftedTriangleCache
&& (
933 mi
->_ShiftedTriangleCache
->MeshDataId
!= _MeshDataId
||
934 mi
->_ShiftedTriangleCache
->LodId
!= curLodId
||
935 mi
->_ShiftedTriangleCache
->BaseVertex
!= baseVertex
) )
937 mi
->clearShiftedTriangleCache();
940 // If the instance has not a valid cache, must create it.
941 if( !mi
->_ShiftedTriangleCache
)
943 mi
->_ShiftedTriangleCache
= new CShiftedTriangleCache
;
944 // Fill the cache Key.
945 mi
->_ShiftedTriangleCache
->MeshDataId
= _MeshDataId
;
946 mi
->_ShiftedTriangleCache
->LodId
= curLodId
;
947 mi
->_ShiftedTriangleCache
->BaseVertex
= baseVertex
;
949 // Build list of PBlock. From Lod, or from RawSkin cache.
950 static vector
<CIndexBuffer
*> pbList
;
952 nlassert(mi
->_RawSkinCache
);
953 pbList
.resize(mi
->_RawSkinCache
->RdrPass
.size());
954 for(uint i
=0;i
<pbList
.size();i
++)
956 pbList
[i
]= &mi
->_RawSkinCache
->RdrPass
[i
];
960 mi
->_ShiftedTriangleCache
->RdrPass
.resize((uint32
)pbList
.size());
962 // First pass, count number of triangles, and fill header info
965 for(i
=0;i
<pbList
.size();i
++)
967 mi
->_ShiftedTriangleCache
->RdrPass
[i
].NumTriangles
= pbList
[i
]->getNumIndexes()/3;
968 totalTri
+= pbList
[i
]->getNumIndexes()/3;
971 // Allocate triangles indices.
972 mi
->_ShiftedTriangleCache
->RawIndices
.setFormat(NL_SKINNED_MESH_MRM_INDEX_FORMAT
);
973 mi
->_ShiftedTriangleCache
->RawIndices
.setNumIndexes(totalTri
*3);
975 CIndexBufferReadWrite iba
;
976 mi
->_ShiftedTriangleCache
->RawIndices
.lock(iba
);
978 // Second pass, fill ptrs, and fill Arrays
980 for(i
=0;i
<pbList
.size();i
++)
982 CShiftedTriangleCache::CRdrPass
&dstRdrPass
= mi
->_ShiftedTriangleCache
->RdrPass
[i
];
983 dstRdrPass
.Triangles
= indexTri
*3;
986 uint numTris
= pbList
[i
]->getNumIndexes()/3;
989 uint nIds
= numTris
*3;
991 CIndexBufferRead ibaRead
;
992 pbList
[i
]->lock (ibaRead
);
993 #ifndef NL_SKINNED_MESH_MRM_INDEX16
994 nlassert(iba
.getFormat() == CIndexBuffer::Indices32
);
995 const uint32
*pSrcTri
= (const uint32
*) ibaRead
.getPtr();
996 uint32
*pDstTri
= (uint32
*) iba
.getPtr() + dstRdrPass
.Triangles
;
997 for(;nIds
>0;nIds
--,pSrcTri
++,pDstTri
++)
998 *pDstTri
= *pSrcTri
+ baseVertex
;
1000 nlassert(iba
.getFormat() == CIndexBuffer::Indices16
);
1001 const uint16
*pSrcTri
= (const uint16
*) ibaRead
.getPtr();
1002 uint16
*pDstTri
= (uint16
*) iba
.getPtr() + dstRdrPass
.Triangles
;
1003 for(;nIds
>0;nIds
--,pSrcTri
++,pDstTri
++)
1004 *pDstTri
= *pSrcTri
+ baseVertex
;
1009 indexTri
+= dstRdrPass
.NumTriangles
;
1015 // ***************************************************************************
1016 void CMeshMRMSkinnedGeom::serial(NLMISC::IStream
&f
)
1018 // because of complexity, serial is separated in save / load.
1027 // serial bones names
1028 f
.serialCont (_BonesName
);
1032 // Bones index are in skeleton model id list
1033 _BoneIdComputed
= false;
1035 // Must always recompute usage of parents of bones used.
1036 _BoneIdExtended
= false;
1039 // serial Basic info.
1040 // ==================
1042 f
.serial(_LevelDetail
.MaxFaceUsed
);
1043 f
.serial(_LevelDetail
.MinFaceUsed
);
1044 f
.serial(_LevelDetail
.DistanceFinest
);
1045 f
.serial(_LevelDetail
.DistanceMiddle
);
1046 f
.serial(_LevelDetail
.DistanceCoarsest
);
1047 f
.serial(_LevelDetail
.OODistanceDelta
);
1048 f
.serial(_LevelDetail
.DistancePow
);
1050 // Prepare the VBuffer.
1052 _VBufferFinal
.contReset();
1053 _VBufferFinal
.serial(f
);
1055 // serial Shadow Skin Information
1056 f
.serialCont (_ShadowSkin
.Vertices
);
1057 f
.serialCont (_ShadowSkin
.Triangles
);
1059 // resest the Lod arrays. NB: each Lod is empty, and ready to receive Lod data.
1060 // ==================
1066 f
.serialCont (_Lods
);
1070 // Inform that the mesh data has changed
1073 // Some runtime not serialized compilation
1078 // ***************************************************************************
1080 float CMeshMRMSkinnedGeom::getNumTriangles (float distance
)
1082 // NB: this is an approximation, but this is continious.
1083 return _LevelDetail
.getNumTriangles(distance
);
1086 // ***************************************************************************
1087 void CMeshMRMSkinnedGeom::computeBonesId (CSkeletonModel
*skeleton
)
1089 // Already computed ?
1090 if (!_BoneIdComputed
)
1092 // Get a pointer on the skeleton
1093 nlassert (skeleton
);
1096 // **** For each bones, compute remap
1097 std::vector
<uint
> remap
;
1098 skeleton
->remapSkinBones(_BonesName
, _BonesId
, remap
);
1101 // **** Remap the vertices, and compute Bone Spheres.
1103 // Find the Geomorph space: to process only real vertices, not geomorphed ones.
1106 for (lod
=0; lod
<_Lods
.size(); lod
++)
1108 nGeomSpace
= max(nGeomSpace
, (uint
)_Lods
[lod
].Geomorphs
.size());
1111 // Prepare Sphere compute
1112 static std::vector
<CAABBox
> boneBBoxes
;
1113 static std::vector
<bool> boneBBEmpty
;
1115 boneBBEmpty
.clear();
1116 boneBBoxes
.resize(_BonesId
.size());
1117 boneBBEmpty
.resize(_BonesId
.size(), true);
1120 // Remap the vertex, and compute the bone spheres. see CTransform::getSkinBoneSphere() doc.
1121 // for true vertices
1123 const uint vertexCount
= _VBufferFinal
.getNumVertices();
1124 CPackedVertexBuffer::CPackedVertex
*vertices
= _VBufferFinal
.getPackedVertices();
1125 for (vert
=nGeomSpace
; vert
<vertexCount
; vert
++)
1127 // get the vertex position.
1129 _VBufferFinal
.getPos (vertex
, vertices
[vert
]);
1133 for (weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
1136 if ((vertices
[vert
].Weights
[weight
]>0)||(weight
==0))
1139 uint srcId
= vertices
[vert
].Matrices
[weight
];
1140 nlassert (srcId
< remap
.size());
1142 vertices
[vert
].Matrices
[weight
] = remap
[srcId
];
1144 // if the boneId is valid (ie found)
1145 if(_BonesId
[srcId
]>=0)
1147 // transform the vertex pos in BoneSpace
1148 CVector p
= skeleton
->Bones
[_BonesId
[srcId
]].getBoneBase().InvBindPos
* vertex
;
1149 // extend the bone bbox.
1150 if(boneBBEmpty
[srcId
])
1152 boneBBoxes
[srcId
].setCenter(p
);
1153 boneBBEmpty
[srcId
]= false;
1157 boneBBoxes
[srcId
].extend(p
);
1167 _BonesSphere
.resize(_BonesId
.size());
1168 for(uint bone
=0;bone
<_BonesSphere
.size();bone
++)
1170 // If the bone is empty, mark with -1 in the radius.
1171 if(boneBBEmpty
[bone
])
1173 _BonesSphere
[bone
].Radius
= -1;
1177 _BonesSphere
[bone
].Center
= boneBBoxes
[bone
].getCenter();
1178 _BonesSphere
[bone
].Radius
= boneBBoxes
[bone
].getRadius();
1182 // **** Remap the vertex influence by lods
1183 for (lod
=0; lod
<_Lods
.size(); lod
++)
1185 // For each matrix used
1187 for (matrix
=0; matrix
<_Lods
[lod
].MatrixInfluences
.size(); matrix
++)
1190 nlassert (_Lods
[lod
].MatrixInfluences
[matrix
]<remap
.size());
1193 _Lods
[lod
].MatrixInfluences
[matrix
] = remap
[_Lods
[lod
].MatrixInfluences
[matrix
]];
1197 // **** Remap Shadow Vertices.
1198 for(vert
=0;vert
<_ShadowSkin
.Vertices
.size();vert
++)
1200 CShadowVertex
&v
= _ShadowSkin
.Vertices
[vert
];
1202 nlassert (v
.MatrixId
< remap
.size());
1203 v
.MatrixId
= remap
[v
.MatrixId
];
1207 _BoneIdComputed
= true;
1211 // Already extended ?
1212 if (!_BoneIdExtended
)
1214 nlassert (skeleton
);
1217 // the total bone Usage of the mesh.
1218 vector
<bool> boneUsage
;
1219 boneUsage
.resize(skeleton
->Bones
.size(), false);
1221 // for all Bones marked as valid.
1223 for(i
=0; i
<_BonesId
.size(); i
++)
1225 // if not a valid boneId, skip it.
1229 // mark him and his father in boneUsage.
1230 skeleton
->flagBoneAndParents(_BonesId
[i
], boneUsage
);
1233 // fill _BonesIdExt with bones of _BonesId and their parents.
1234 _BonesIdExt
.clear();
1235 for(i
=0; i
<boneUsage
.size();i
++)
1237 // if the bone is used by the mesh, add it to BoneIdExt.
1239 _BonesIdExt
.push_back(i
);
1245 _BoneIdExtended
= true;
1251 // ***************************************************************************
1252 void CMeshMRMSkinnedGeom::updateSkeletonUsage(CSkeletonModel
*sm
, bool increment
)
1254 // For all Bones used.
1255 for(uint i
=0; i
<_BonesIdExt
.size();i
++)
1257 uint boneId
= _BonesIdExt
[i
];
1258 // Some explicit Error.
1259 if(boneId
>=sm
->Bones
.size())
1260 nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId
);
1261 // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
1263 sm
->incBoneUsage(boneId
, CSkeletonModel::UsageNormal
);
1265 sm
->decBoneUsage(boneId
, CSkeletonModel::UsageNormal
);
1270 // ***************************************************************************
1271 void CMeshMRMSkinnedGeom::compileRunTime()
1273 _PreciseClipping
= _BBox
.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD
;
1275 // The Mesh must follow those restrictions, to support group skinning
1276 nlassert (_VBufferFinal
.getNumVertices() < NL3D_MESH_SKIN_MANAGER_MAXVERTICES
);
1278 // Support Shadow SkinGrouping if Shadow setuped, and if not too many vertices.
1279 _SupportShadowSkinGrouping
= !_ShadowSkin
.Vertices
.empty() &&
1280 NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT
==CVertexBuffer::PositionFlag
&&
1281 _ShadowSkin
.Vertices
.size() <= NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES
;
1285 // ***************************************************************************
1286 void CMeshMRMSkinnedGeom::profileSceneRender(CRenderTrav
*rdrTrav
, CTransformShape
*trans
, float polygonCount
, uint32 rdrFlags
)
1288 // if no _Lods, no draw
1292 // get the result of the Load Balancing.
1293 float alphaMRM
= _LevelDetail
.getLevelDetailFromPolyCount(polygonCount
);
1297 sint numLod
= chooseLod(alphaMRM
, alphaLod
);
1299 // Render the choosen Lod.
1300 CLod
&lod
= _Lods
[numLod
];
1302 // get the mesh instance.
1303 CMeshBaseInstance
*mi
= safe_cast
<CMeshBaseInstance
*>(trans
);
1305 // Profile all pass.
1307 for (uint i
=0;i
<lod
.RdrPass
.size();i
++)
1309 CRdrPass
&rdrPass
= lod
.RdrPass
[i
];
1310 // Profile with the Materials of the MeshInstance.
1311 if ( ( (mi
->Materials
[rdrPass
.MaterialId
].getBlend() == false) && (rdrFlags
& IMeshGeom::RenderOpaqueMaterial
) ) ||
1312 ( (mi
->Materials
[rdrPass
.MaterialId
].getBlend() == true) && (rdrFlags
& IMeshGeom::RenderTransparentMaterial
) ) )
1314 triCount
+= rdrPass
.getNumTriangle();
1322 rdrTrav
->Scene
->incrementProfileTriVBFormat(rdrTrav
->Scene
->BenchRes
.MeshMRMProfileTriVBFormat
,
1323 NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT
, triCount
);
1325 rdrTrav
->Scene
->BenchRes
.NumMeshMRMVBufferStd
++;
1326 rdrTrav
->Scene
->BenchRes
.NumMeshMRMRdrNormal
++;
1327 rdrTrav
->Scene
->BenchRes
.NumMeshMRMTriRdrNormal
+= triCount
;
1332 // ***************************************************************************
1333 bool CMeshMRMSkinnedGeom::getSkinBoneBBox(CSkeletonModel
*skeleton
, NLMISC::CAABBox
&bbox
, uint boneId
) const
1335 bbox
.setCenter(CVector::Null
);
1336 bbox
.setHalfSize(CVector::Null
);
1341 // get the bindpos of the wanted bone
1342 nlassert(boneId
<skeleton
->Bones
.size());
1343 const CMatrix
&invBindPos
= skeleton
->Bones
[boneId
].getBoneBase().InvBindPos
;
1346 // Find the Geomorph space: to process only real vertices, not geomorphed ones.
1349 for (lod
=0; lod
<_Lods
.size(); lod
++)
1351 nGeomSpace
= max(nGeomSpace
, (uint
)_Lods
[lod
].Geomorphs
.size());
1354 // Prepare BBox compute
1357 // Remap the vertex, and compute the wanted bone bbox
1358 // for true vertices
1359 const uint vertexCount
= _VBufferFinal
.getNumVertices();
1360 const CPackedVertexBuffer::CPackedVertex
*vertices
= _VBufferFinal
.getPackedVertices();
1361 for (uint vert
=nGeomSpace
; vert
<vertexCount
; vert
++)
1363 // get the vertex position.
1365 _VBufferFinal
.getPos (vertex
, vertices
[vert
]);
1369 for (weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
1372 if ((vertices
[vert
].Weights
[weight
]>0)||(weight
==0))
1374 // Check id is the wanted one
1375 if(vertices
[vert
].Matrices
[weight
]==boneId
)
1377 // transform the vertex pos in BoneSpace
1378 CVector p
= invBindPos
* vertex
;
1379 // extend the bone bbox.
1396 // return true if some influence found
1402 // ***************************************************************************
1403 // ***************************************************************************
1404 // Mesh Block Render Interface
1405 // ***************************************************************************
1406 // ***************************************************************************
1409 // ***************************************************************************
1410 bool CMeshMRMSkinnedGeom::supportMeshBlockRendering () const
1413 Yoyo: Don't Support It for MRM because too Slow!!
1414 The problem is that lock() unlock() on each instance, on the same VBHeap IS AS SLOWER AS
1417 TODO_OPTIMIZE: find a way to optimize MRM.
1422 // ***************************************************************************
1423 // ***************************************************************************
1425 // ***************************************************************************
1426 // ***************************************************************************
1430 // ***************************************************************************
1431 CMeshMRMSkinned::CMeshMRMSkinned()
1435 // ***************************************************************************
1437 bool CMeshMRMSkinned::isCompatible(const CMesh::CMeshBuild
&m
)
1439 /* Optimised shape for skinned object with MRM, 1 UV coordinates, 1 to 4 skinning weight and 256 matrices
1440 Tangeant space, vertex program, mesh block rendering and vertex buffer hard are not available. */
1443 if (m
.VertexFlags
!= NL3D_MESH_MRM_SKINNED_VERTEX_FORMAT
)
1447 if (m
.NumCoords
[0] != 2)
1451 if (!m
.BlendShapes
.empty())
1454 // Check number of vertices
1455 if (m
.Vertices
.size() > NL3D_MESH_SKIN_MANAGER_MAXVERTICES
)
1462 // ***************************************************************************
1463 void CMeshMRMSkinned::build (CMeshBase::CMeshBaseBuild
&mBase
, CMesh::CMeshBuild
&m
,
1464 const CMRMParameters
¶ms
)
1466 nlassert (isCompatible(m
));
1468 /// copy MeshBase info: materials ....
1469 CMeshBase::buildMeshBase (mBase
);
1471 // Then build the geom.
1472 _MeshMRMGeom
.build (m
, (uint
)mBase
.Materials
.size(), params
);
1474 // ***************************************************************************
1475 void CMeshMRMSkinned::build (CMeshBase::CMeshBaseBuild
&m
, const CMeshMRMSkinnedGeom
&mgeom
)
1477 /// copy MeshBase info: materials ....
1478 CMeshBase::buildMeshBase(m
);
1480 // Then copy the geom.
1481 _MeshMRMGeom
= mgeom
;
1485 // ***************************************************************************
1486 void CMeshMRMSkinned::optimizeMaterialUsage(std::vector
<sint
> &remap
)
1488 // For each material, count usage.
1489 vector
<bool> materialUsed
;
1490 materialUsed
.resize(CMeshBase::_Materials
.size(), false);
1491 for(uint lod
=0;lod
<getNbLod();lod
++)
1493 for(uint rp
=0;rp
<getNbRdrPass(lod
);rp
++)
1495 uint matId
= getRdrPassMaterial(lod
, rp
);
1497 materialUsed
[matId
]= true;
1501 // Apply it to meshBase
1502 CMeshBase::applyMaterialUsageOptim(materialUsed
, remap
);
1504 // Apply lut to meshGeom.
1505 _MeshMRMGeom
.applyMaterialRemap(remap
);
1509 // ***************************************************************************
1510 CTransformShape
*CMeshMRMSkinned::createInstance(CScene
&scene
)
1512 // Create a CMeshMRMSkinnedInstance, an instance of a mesh.
1513 //===============================================
1514 CMeshMRMSkinnedInstance
*mi
= (CMeshMRMSkinnedInstance
*)scene
.createModel(NL3D::MeshMRMSkinnedInstanceId
);
1517 // instanciate the material part of the MeshMRM, ie the CMeshBase.
1518 CMeshBase::instanciateMeshBase(mi
, &scene
);
1521 // do some instance init for MeshGeom
1522 _MeshMRMGeom
.initInstance(mi
);
1524 // init the FilterType
1525 mi
->initRenderFilterType();
1531 // ***************************************************************************
1532 bool CMeshMRMSkinned::clip(const std::vector
<CPlane
> &pyramid
, const CMatrix
&worldMatrix
)
1534 return _MeshMRMGeom
.clip(pyramid
, worldMatrix
);
1538 // ***************************************************************************
1539 void CMeshMRMSkinned::render(IDriver
*drv
, CTransformShape
*trans
, bool passOpaque
)
1542 uint32 mask
= (0-(uint32
)passOpaque
);
1544 // select rdrFlags, without ifs.
1545 rdrFlags
= mask
& (IMeshGeom::RenderOpaqueMaterial
| IMeshGeom::RenderPassOpaque
);
1546 rdrFlags
|= ~mask
& (IMeshGeom::RenderTransparentMaterial
);
1548 _MeshMRMGeom
.render(drv
, trans
, trans
->getNumTrianglesAfterLoadBalancing(), rdrFlags
, 1);
1552 // ***************************************************************************
1553 void CMeshMRMSkinned::serial(NLMISC::IStream
&f
)
1559 (void)f
.serialVersion(0);
1561 // serial Materials infos contained in CMeshBase.
1562 CMeshBase::serialMeshBase(f
);
1565 // serial the geometry.
1566 _MeshMRMGeom
.serial(f
);
1570 // ***************************************************************************
1571 float CMeshMRMSkinned::getNumTriangles (float distance
)
1573 return _MeshMRMGeom
.getNumTriangles (distance
);
1577 // ***************************************************************************
1578 const CMeshMRMSkinnedGeom
& CMeshMRMSkinned::getMeshGeom () const
1580 return _MeshMRMGeom
;
1584 // ***************************************************************************
1585 void CMeshMRMSkinned::computeBonesId (CSkeletonModel
*skeleton
)
1587 _MeshMRMGeom
.computeBonesId (skeleton
);
1590 // ***************************************************************************
1591 void CMeshMRMSkinned::updateSkeletonUsage (CSkeletonModel
*skeleton
, bool increment
)
1593 _MeshMRMGeom
.updateSkeletonUsage(skeleton
, increment
);
1596 // ***************************************************************************
1597 void CMeshMRMSkinned::changeMRMDistanceSetup(float distanceFinest
, float distanceMiddle
, float distanceCoarsest
)
1599 _MeshMRMGeom
.changeMRMDistanceSetup(distanceFinest
, distanceMiddle
, distanceCoarsest
);
1602 // ***************************************************************************
1603 IMeshGeom
*CMeshMRMSkinned::supportMeshBlockRendering (CTransformShape
*trans
, float &polygonCount
) const
1608 // ***************************************************************************
1609 void CMeshMRMSkinned::profileSceneRender(CRenderTrav
*rdrTrav
, CTransformShape
*trans
, bool passOpaque
)
1612 uint32 mask
= (0-(uint32
)passOpaque
);
1614 // select rdrFlags, without ifs.
1615 rdrFlags
= mask
& (IMeshGeom::RenderOpaqueMaterial
| IMeshGeom::RenderPassOpaque
);
1616 rdrFlags
|= ~mask
& (IMeshGeom::RenderTransparentMaterial
);
1618 _MeshMRMGeom
.profileSceneRender(rdrTrav
, trans
, trans
->getNumTrianglesAfterLoadBalancing(), rdrFlags
);
1623 // ***************************************************************************
1624 // ***************************************************************************
1625 // CMeshMRMSkinnedGeom RawSkin optimisation
1626 // ***************************************************************************
1627 // ***************************************************************************
1630 // ***************************************************************************
1631 void CMeshMRMSkinnedGeom::dirtMeshDataId()
1633 // see updateRawSkinNormal()
1638 // ***************************************************************************
1639 void CMeshMRMSkinnedGeom::updateRawSkinNormal(bool enabled
, CMeshMRMSkinnedInstance
*mi
, sint curLodId
)
1643 // if the instance cache is not cleared, must clear.
1644 mi
->clearRawSkinCache();
1648 // If the instance has no RawSkin, or has a too old RawSkin cache, must delete it, and recreate
1649 if ((mi
->_RawSkinCache
== NULL
) || (mi
->_RawSkinCache
->MeshDataId
!=_MeshDataId
))
1651 // first delete if too old.
1652 mi
->clearRawSkinCache();
1654 // Then recreate, and use _MeshDataId to verify that the instance works with same data.
1655 mi
->_RawSkinCache
= new CRawSkinnedNormalCache
;
1656 mi
->_RawSkinCache
->MeshDataId
= _MeshDataId
;
1657 mi
->_RawSkinCache
->LodId
= -1;
1661 /* If the instance rawSkin has a different Lod (or if -1), then must recreate it.
1662 NB: The lod may change each frame per instance, but suppose not so many change, so we can cache those data.
1664 if( mi
->_RawSkinCache
->LodId
!= curLodId
)
1666 H_AUTO( NL3D_CMeshMRMGeom_updateRawSkinNormal
);
1668 CRawSkinnedNormalCache
&skinLod
= *mi
->_RawSkinCache
;
1669 CLod
&lod
= _Lods
[curLodId
];
1673 // Clear the raw skin mesh.
1674 skinLod
.clearArrays();
1677 mi
->_RawSkinCache
->LodId
= curLodId
;
1679 // For each matrix influence.
1680 nlassert(NL3D_MESH_SKINNING_MAX_MATRIX
==4);
1682 // For each vertex, acknowledge if it is a src for geomorph.
1683 static vector
<uint8
> softVertices
;
1684 softVertices
.clear();
1685 softVertices
.resize( _VBufferFinal
.getNumVertices(), 0 );
1686 for(i
=0;i
<lod
.Geomorphs
.size();i
++)
1688 softVertices
[lod
.Geomorphs
[i
].Start
]= 1;
1689 softVertices
[lod
.Geomorphs
[i
].End
]= 1;
1692 // The remap from old index in _VBufferFinal to RawSkin vertices (without Geomorphs).
1693 static vector
<uint32
> vertexRemap
;
1694 vertexRemap
.resize( _VBufferFinal
.getNumVertices() );
1700 skinLod
.TotalSoftVertices
= 0;
1701 skinLod
.TotalHardVertices
= 0;
1707 for(uint j
=0;j
<lod
.InfluencedVertices
[i
].size();j
++)
1709 uint vid
= lod
.InfluencedVertices
[i
][j
];
1710 if(softVertices
[vid
])
1715 skinLod
.TotalSoftVertices
+= softSize
[i
];
1716 skinLod
.TotalHardVertices
+= hardSize
[i
];
1717 skinLod
.SoftVertices
[i
]= softSize
[i
];
1718 skinLod
.HardVertices
[i
]= hardSize
[i
];
1722 hardStart
[0]= skinLod
.TotalSoftVertices
;
1725 softStart
[i
]= softStart
[i
-1]+softSize
[i
-1];
1726 hardStart
[i
]= hardStart
[i
-1]+hardSize
[i
-1];
1731 uint softIdx
= softStart
[i
];
1732 uint hardIdx
= hardStart
[i
];
1733 for(uint j
=0;j
<lod
.InfluencedVertices
[i
].size();j
++)
1735 uint vid
= lod
.InfluencedVertices
[i
][j
];
1736 if(softVertices
[vid
])
1737 vertexRemap
[vid
]= softIdx
++;
1739 vertexRemap
[vid
]= hardIdx
++;
1744 // Resize the dest array.
1745 skinLod
.Vertices1
.resize((uint32
)lod
.InfluencedVertices
[0].size());
1746 skinLod
.Vertices2
.resize((uint32
)lod
.InfluencedVertices
[1].size());
1747 skinLod
.Vertices3
.resize((uint32
)lod
.InfluencedVertices
[2].size());
1748 skinLod
.Vertices4
.resize((uint32
)lod
.InfluencedVertices
[3].size());
1750 // Vertex buffer pointers
1751 const CPackedVertexBuffer::CPackedVertex
*vertices
= _VBufferFinal
.getPackedVertices();
1753 // 1 Matrix skinning.
1755 for(i
=0;i
<skinLod
.Vertices1
.size();i
++)
1757 // get the dest vertex.
1758 uint vid
= lod
.InfluencedVertices
[0][i
];
1760 rawIdx
= vertexRemap
[vid
];
1761 if(softVertices
[vid
])
1762 rawIdx
-= softStart
[0];
1764 rawIdx
+= softSize
[0]-hardStart
[0];
1767 const CPackedVertexBuffer::CPackedVertex
&vertex
= vertices
[vid
];
1768 skinLod
.Vertices1
[rawIdx
].MatrixId
[0]= vertex
.Matrices
[0];
1769 _VBufferFinal
.getPos (skinLod
.Vertices1
[rawIdx
].Vertex
, vertex
);
1770 vertex
.getNormal (skinLod
.Vertices1
[rawIdx
].Normal
);
1771 vertex
.getU (skinLod
.Vertices1
[rawIdx
].UV
.U
);
1772 vertex
.getV (skinLod
.Vertices1
[rawIdx
].UV
.V
);
1775 // 2 Matrix skinning.
1777 for(i
=0;i
<skinLod
.Vertices2
.size();i
++)
1779 // get the dest vertex.
1780 uint vid
= lod
.InfluencedVertices
[1][i
];
1782 rawIdx
= vertexRemap
[vid
];
1783 if(softVertices
[vid
])
1784 rawIdx
-= softStart
[1];
1786 rawIdx
+= softSize
[1]-hardStart
[1];
1788 const CPackedVertexBuffer::CPackedVertex
&vertex
= vertices
[vid
];
1789 skinLod
.Vertices2
[rawIdx
].MatrixId
[0]= vertex
.Matrices
[0];
1790 skinLod
.Vertices2
[rawIdx
].MatrixId
[1]= vertex
.Matrices
[1];
1791 _VBufferFinal
.getPos (skinLod
.Vertices2
[rawIdx
].Vertex
, vertex
);
1792 vertex
.getWeight (skinLod
.Vertices2
[rawIdx
].Weights
[0], 0);
1793 vertex
.getWeight (skinLod
.Vertices2
[rawIdx
].Weights
[1], 1);
1794 vertex
.getNormal (skinLod
.Vertices2
[rawIdx
].Normal
);
1795 vertex
.getU (skinLod
.Vertices2
[rawIdx
].UV
.U
);
1796 vertex
.getV (skinLod
.Vertices2
[rawIdx
].UV
.V
);
1799 // 3 Matrix skinning.
1801 for(i
=0;i
<skinLod
.Vertices3
.size();i
++)
1803 // get the dest vertex.
1804 uint vid
= lod
.InfluencedVertices
[2][i
];
1806 rawIdx
= vertexRemap
[vid
];
1807 if(softVertices
[vid
])
1808 rawIdx
-= softStart
[2];
1810 rawIdx
+= softSize
[2]-hardStart
[2];
1812 const CPackedVertexBuffer::CPackedVertex
&vertex
= vertices
[vid
];
1813 skinLod
.Vertices3
[rawIdx
].MatrixId
[0]= vertex
.Matrices
[0];
1814 skinLod
.Vertices3
[rawIdx
].MatrixId
[1]= vertex
.Matrices
[1];
1815 skinLod
.Vertices3
[rawIdx
].MatrixId
[2]= vertex
.Matrices
[2];
1816 _VBufferFinal
.getPos (skinLod
.Vertices3
[rawIdx
].Vertex
, vertex
);
1817 vertex
.getWeight (skinLod
.Vertices3
[rawIdx
].Weights
[0], 0);
1818 vertex
.getWeight (skinLod
.Vertices3
[rawIdx
].Weights
[1], 1);
1819 vertex
.getWeight (skinLod
.Vertices3
[rawIdx
].Weights
[2], 2);
1820 vertex
.getNormal (skinLod
.Vertices3
[rawIdx
].Normal
);
1821 vertex
.getU (skinLod
.Vertices3
[rawIdx
].UV
.U
);
1822 vertex
.getV (skinLod
.Vertices3
[rawIdx
].UV
.V
);
1825 // 4 Matrix skinning.
1827 for(i
=0;i
<skinLod
.Vertices4
.size();i
++)
1829 // get the dest vertex.
1830 uint vid
= lod
.InfluencedVertices
[3][i
];
1832 rawIdx
= vertexRemap
[vid
];
1833 if(softVertices
[vid
])
1834 rawIdx
-= softStart
[3];
1836 rawIdx
+= softSize
[3]-hardStart
[3];
1838 const CPackedVertexBuffer::CPackedVertex
&vertex
= vertices
[vid
];
1839 skinLod
.Vertices4
[rawIdx
].MatrixId
[0]= vertex
.Matrices
[0];
1840 skinLod
.Vertices4
[rawIdx
].MatrixId
[1]= vertex
.Matrices
[1];
1841 skinLod
.Vertices4
[rawIdx
].MatrixId
[2]= vertex
.Matrices
[2];
1842 skinLod
.Vertices4
[rawIdx
].MatrixId
[3]= vertex
.Matrices
[3];
1843 _VBufferFinal
.getPos (skinLod
.Vertices4
[rawIdx
].Vertex
, vertex
);
1844 vertex
.getWeight (skinLod
.Vertices4
[rawIdx
].Weights
[0], 0);
1845 vertex
.getWeight (skinLod
.Vertices4
[rawIdx
].Weights
[1], 1);
1846 vertex
.getWeight (skinLod
.Vertices4
[rawIdx
].Weights
[2], 2);
1847 vertex
.getWeight (skinLod
.Vertices4
[rawIdx
].Weights
[3], 3);
1848 vertex
.getNormal (skinLod
.Vertices4
[rawIdx
].Normal
);
1849 vertex
.getU (skinLod
.Vertices4
[rawIdx
].UV
.U
);
1850 vertex
.getV (skinLod
.Vertices4
[rawIdx
].UV
.V
);
1855 uint numGeoms
= (uint
)lod
.Geomorphs
.size();
1856 skinLod
.Geomorphs
.resize( numGeoms
);
1857 for(i
=0;i
<numGeoms
;i
++)
1859 // NB: don't add "numGeoms" to the index because RawSkin look in a TempArray in RAM, which start at 0...
1860 skinLod
.Geomorphs
[i
].Start
= vertexRemap
[lod
.Geomorphs
[i
].Start
];
1861 skinLod
.Geomorphs
[i
].End
= vertexRemap
[lod
.Geomorphs
[i
].End
];
1866 skinLod
.RdrPass
.resize(lod
.RdrPass
.size());
1867 for(i
=0;i
<skinLod
.RdrPass
.size();i
++)
1870 skinLod
.RdrPass
[i
].setFormat(NL_SKINNED_MESH_MRM_INDEX_FORMAT
);
1871 skinLod
.RdrPass
[i
].setNumIndexes(lod
.RdrPass
[i
].getNumTriangle()*3);
1872 const uint16
*srcTriPtr
= &(lod
.RdrPass
[i
].PBlock
[0]);
1873 CIndexBufferReadWrite ibaWrite
;
1874 skinLod
.RdrPass
[i
].lock (ibaWrite
);
1875 #ifndef NL_SKINNED_MESH_MRM_INDEX16
1876 nlassert(ibaWrite
.getFormat() == CIndexBuffer::Indices32
);
1877 uint32
*dstTriPtr
= (uint32
*) ibaWrite
.getPtr();
1878 uint32 numIndices
= lod
.RdrPass
[i
].PBlock
.size();
1879 for(uint j
=0;j
<numIndices
;j
++, srcTriPtr
++, dstTriPtr
++)
1881 uint vid
= (uint
)*srcTriPtr
;
1882 // If this index refers to a Geomorphed vertex, don't modify!
1886 *dstTriPtr
= vertexRemap
[vid
] + numGeoms
;
1889 nlassert(ibaWrite
.getFormat() == CIndexBuffer::Indices16
);
1890 uint16
*dstTriPtr
= (uint16
*) ibaWrite
.getPtr();
1891 uint32 numIndices
= (uint32
)lod
.RdrPass
[i
].PBlock
.size();
1892 for(uint j
=0;j
<numIndices
;j
++, srcTriPtr
++, dstTriPtr
++)
1894 uint vid
= (uint
)*srcTriPtr
;
1895 // If this index refers to a Geomorphed vertex, don't modify!
1899 *dstTriPtr
= (uint16
) (vertexRemap
[vid
] + numGeoms
);
1908 // ***************************************************************************
1909 // ***************************************************************************
1910 // CMeshMRMSkinnedGeom Shadow Skin Rendering
1911 // ***************************************************************************
1912 // ***************************************************************************
1915 // ***************************************************************************
1916 void CMeshMRMSkinnedGeom::setShadowMesh(const std::vector
<CShadowVertex
> &shadowVertices
, const std::vector
<uint32
> &triangles
)
1918 _ShadowSkin
.Vertices
= shadowVertices
;
1919 _ShadowSkin
.Triangles
= triangles
;
1920 // update flag. Support Shadow SkinGrouping if Shadow setuped, and if not too many vertices.
1921 _SupportShadowSkinGrouping
= !_ShadowSkin
.Vertices
.empty() &&
1922 NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT
==CVertexBuffer::PositionFlag
&&
1923 _ShadowSkin
.Vertices
.size() <= NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES
;
1926 // ***************************************************************************
1927 uint
CMeshMRMSkinnedGeom::getNumShadowSkinVertices() const
1929 return (uint
)_ShadowSkin
.Vertices
.size();
1932 // ***************************************************************************
1933 sint
CMeshMRMSkinnedGeom::renderShadowSkinGeom(CMeshMRMSkinnedInstance
*mi
, uint remainingVertices
, uint8
*vbDest
)
1935 uint numVerts
= (uint
)_ShadowSkin
.Vertices
.size();
1937 // if no verts, no draw
1941 // if no lods, there should be no verts, but still ensure no bug in skinning
1945 // If the Lod is too big to render in the VBufferHard
1946 if(numVerts
>remainingVertices
)
1950 // get the skeleton model to which I am skinned
1951 CSkeletonModel
*skeleton
;
1952 skeleton
= mi
->getSkeletonModel();
1953 // must be skinned for renderSkin()
1959 H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow
);
1965 // For all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
1966 // NB: take the best lod since the lower lods cannot use other Matrix than the higher one.
1967 static vector
<CMatrix3x4
> boneMat3x4
;
1968 CLod
&lod
= _Lods
[_Lods
.size()-1];
1969 computeBoneMatrixes3x4(boneMat3x4
, lod
.MatrixInfluences
, skeleton
);
1971 _ShadowSkin
.applySkin((CVector
*)vbDest
, boneMat3x4
);
1974 // How many vertices are added to the VBuffer ???
1978 // ***************************************************************************
1979 void CMeshMRMSkinnedGeom::renderShadowSkinPrimitives(CMeshMRMSkinnedInstance
*mi
, CMaterial
&castMat
, IDriver
*drv
, uint baseVertex
)
1983 if(_ShadowSkin
.Triangles
.empty())
1988 H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow
);
1990 // NB: the skeleton matrix has already been setuped by CSkeletonModel
1991 // NB: the normalize flag has already been setuped by CSkeletonModel
1993 // TODO_SHADOW: optim: Special triangle cache for shadow!
1994 static CIndexBuffer shiftedTris
;
1995 shiftedTris
.setPreferredMemory(CIndexBuffer::RAMVolatile
, false);
1996 if (shiftedTris
.getName().empty()) NL_SET_IB_NAME(shiftedTris
, "CMeshMRMSkinnedGeom::renderShadowSkinPrimitives::shiftedTris");
1997 //if(shiftedTris.getNumIndexes()<_ShadowSkin.Triangles.size())
1999 shiftedTris
.setFormat(NL_SKINNED_MESH_MRM_INDEX_FORMAT
);
2000 shiftedTris
.setNumIndexes((uint32
)_ShadowSkin
.Triangles
.size());
2003 CIndexBufferReadWrite iba
;
2004 shiftedTris
.lock(iba
);
2005 const uint32
*src
= &_ShadowSkin
.Triangles
[0];
2006 TSkinnedMeshMRMIndexType
*dst
= (TSkinnedMeshMRMIndexType
*) iba
.getPtr();
2007 for(uint n
= (uint
)_ShadowSkin
.Triangles
.size();n
>0;n
--, src
++, dst
++)
2009 *dst
= (TSkinnedMeshMRMIndexType
)(*src
+ baseVertex
);
2013 // Render Triangles with cache
2016 uint numTris
= (uint
)_ShadowSkin
.Triangles
.size()/3;
2018 // Render with the Materials of the MeshInstance.
2019 drv
->activeIndexBuffer(shiftedTris
);
2020 drv
->renderTriangles(castMat
, 0, numTris
);
2023 // ***************************************************************************
2024 bool CMeshMRMSkinnedGeom::intersectSkin(CMeshMRMSkinnedInstance
*mi
, const CMatrix
&toRaySpace
, float &dist2D
, float &distZ
, bool computeDist2D
)
2026 // no inst/verts/lod => no intersection
2027 if(!mi
|| _ShadowSkin
.Vertices
.empty() || _Lods
.empty())
2029 CSkeletonModel
*skeleton
= mi
->getSkeletonModel();
2033 // Compute skinning with all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
2034 // NB: take the best lod (_Lods.back()) since the lower lods cannot use other Matrix than the higher one.
2035 return _ShadowSkin
.getRayIntersection(toRaySpace
, *skeleton
, _Lods
.back().MatrixInfluences
, dist2D
, distZ
, computeDist2D
);
2039 // ***************************************************************************
2040 // ***************************************************************************
2041 // CMeshMRMSkinnedGeom::CPackedVertexBuffer
2042 // ***************************************************************************
2043 // ***************************************************************************
2045 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::serial(NLMISC::IStream
&f
)
2050 f
.serialCont (_PackedBuffer
);
2051 f
.serial (_DecompactScale
);
2054 // ***************************************************************************
2056 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::CPackedVertex::serial(NLMISC::IStream
&f
)
2070 for (i
=0; i
<NL3D_MESH_MRM_SKINNED_MAX_MATRIX
; i
++)
2072 f
.serial (Matrices
[i
]);
2073 f
.serial (Weights
[i
]);
2077 // ***************************************************************************
2079 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::CPackedVertex::setNormal (const CVector
&src
)
2082 pos
*= NL3D_MESH_MRM_SKINNED_NORMAL_FACTOR
;
2083 pos
.x
= (float)floor(pos
.x
+0.5f
);
2084 pos
.y
= (float)floor(pos
.y
+0.5f
);
2085 pos
.z
= (float)floor(pos
.z
+0.5f
);
2086 clamp (pos
.x
, -32768.f
, 32767.f
);
2087 clamp (pos
.y
, -32768.f
, 32767.f
);
2088 clamp (pos
.z
, -32768.f
, 32767.f
);
2094 // ***************************************************************************
2096 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::CPackedVertex::setPos (const NLMISC::CVector
&pos
, float scaleFactor
)
2099 _pos
/= scaleFactor
;
2100 _pos
.x
= (float)floor(_pos
.x
+0.5f
);
2101 _pos
.y
= (float)floor(_pos
.y
+0.5f
);
2102 _pos
.z
= (float)floor(_pos
.z
+0.5f
);
2103 clamp (_pos
.x
, -32768.f
, 32767.f
);
2104 clamp (_pos
.y
, -32768.f
, 32767.f
);
2105 clamp (_pos
.z
, -32768.f
, 32767.f
);
2111 // ***************************************************************************
2113 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::CPackedVertex::setUV (float _u
, float _v
)
2115 float u
= _u
* NL3D_MESH_MRM_SKINNED_UV_FACTOR
;
2116 float v
= _v
* NL3D_MESH_MRM_SKINNED_UV_FACTOR
;
2117 u
= (float)floor(u
+0.5f
);
2118 v
= (float)floor(v
+0.5f
);
2119 clamp (u
, -32768.f
, 32767.f
);
2120 clamp (v
, -32768.f
, 32767.f
);
2125 // ***************************************************************************
2127 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::CPackedVertex::setWeight (uint weightId
, float weight
)
2129 weight
= weight
* NL3D_MESH_MRM_SKINNED_WEIGHT_FACTOR
;
2130 weight
= (float)floor(weight
+0.5f
);
2131 clamp (weight
, 0.f
, 255.f
);
2132 Weights
[weightId
] = (uint8
)weight
;
2135 // ***************************************************************************
2137 void CMeshMRMSkinnedGeom::CPackedVertexBuffer::build (const CVertexBuffer
&buffer
, const std::vector
<CMesh::CSkinWeight
> &skinWeight
)
2139 const uint numVertices
= buffer
.getNumVertices();
2140 nlassert (numVertices
== skinWeight
.size());
2141 nlassert ((buffer
.getVertexFormat() & (CVertexBuffer::PositionFlag
|CVertexBuffer::NormalFlag
|CVertexBuffer::TexCoord0Flag
)) == (CVertexBuffer::PositionFlag
|CVertexBuffer::NormalFlag
|CVertexBuffer::TexCoord0Flag
));
2143 _PackedBuffer
.resize (numVertices
);
2146 _DecompactScale
= NL3D_MESH_MRM_SKINNED_DEFAULT_POS_SCALE
;
2148 CVertexBufferRead vba
;
2153 // Get the min max of the bbox
2154 CVector _min
= *vba
.getVertexCoordPointer(0);
2155 CVector _max
= _min
;
2159 for (i
=1; i
<numVertices
; i
++)
2162 const CVector
&vect
= *vba
.getVertexCoordPointer(i
);
2163 _min
.minof(_min
, vect
);
2164 _max
.maxof(_max
, vect
);
2168 float max_width
= std::max((float)fabs(_min
.x
), std::max((float)fabs(_min
.y
), (float)fabs(_min
.z
)));
2169 max_width
= std::max(max_width
, std::max((float)fabs(_max
.x
), std::max((float)fabs(_max
.y
), (float)fabs(_max
.z
))));
2170 _DecompactScale
= std::max(_DecompactScale
, max_width
/ 32767.f
);
2173 for (i
=0; i
<numVertices
; i
++)
2175 CPackedVertex
&vertex
= _PackedBuffer
[i
];
2178 vertex
.setPos (*vba
.getVertexCoordPointer(i
), _DecompactScale
);
2181 vertex
.setNormal (*vba
.getNormalCoordPointer(i
));
2184 const float *uv
= (const float*)vba
.getTexCoordPointer(i
, 0);
2185 vertex
.setUV (uv
[0], uv
[1]);
2190 for (j
=0; j
<NL3D_MESH_MRM_SKINNED_MAX_MATRIX
; j
++)
2192 vertex
.Matrices
[j
] = (uint8
)skinWeight
[i
].MatrixId
[j
];
2193 vertex
.setWeight (j
, skinWeight
[i
].Weights
[j
]);
2194 weightSum
+= (sint
)vertex
.Weights
[j
];
2198 weightSum
= 255 - weightSum
;
2200 // Add error to the first weight
2201 nlassert ((sint
)vertex
.Weights
[0] + weightSum
<= 255);
2202 nlassert ((sint
)vertex
.Weights
[0] + weightSum
> 0);
2203 vertex
.Weights
[0] += weightSum
;
2208 // ***************************************************************************
2210 void CMeshMRMSkinnedGeom::getVertexBuffer(CVertexBuffer
&output
) const
2212 output
.setVertexFormat (CVertexBuffer::PositionFlag
|CVertexBuffer::NormalFlag
|CVertexBuffer::TexCoord0Flag
);
2213 const uint numVertices
= _VBufferFinal
.getNumVertices();
2214 output
.setNumVertices (numVertices
);
2216 // Set all UV routing on 0
2218 for (i
=0; i
<CVertexBuffer::MaxStage
; i
++)
2219 output
.setUVRouting (i
, 0);
2221 CVertexBufferReadWrite vba
;
2223 const CPackedVertexBuffer::CPackedVertex
*vertex
= _VBufferFinal
.getPackedVertices();
2224 for (i
=0; i
<numVertices
; i
++)
2226 _VBufferFinal
.getPos(*vba
.getVertexCoordPointer(i
), vertex
[i
]);
2227 vertex
[i
].getNormal(*vba
.getNormalCoordPointer(i
));
2228 float *texCoord
= (float*)vba
.getTexCoordPointer(i
,0);
2229 vertex
[i
].getU(texCoord
[0]);
2230 vertex
[i
].getV(texCoord
[1]);
2234 // ***************************************************************************
2236 void CMeshMRMSkinnedGeom::getSkinWeights (std::vector
<CMesh::CSkinWeight
> &skinWeights
) const
2238 const uint vertexCount
= _VBufferFinal
.getNumVertices();
2239 skinWeights
.resize (vertexCount
);
2240 const CPackedVertexBuffer::CPackedVertex
*vertices
= _VBufferFinal
.getPackedVertices();
2242 for (i
=0; i
<vertexCount
; i
++)
2244 const CPackedVertexBuffer::CPackedVertex
&vertex
= vertices
[i
];
2248 for (j
=0; j
<NL3D_MESH_MRM_SKINNED_MAX_MATRIX
; j
++)
2250 skinWeights
[i
].MatrixId
[j
] = vertex
.Matrices
[j
];
2251 vertex
.getWeight (skinWeights
[i
].Weights
[j
], j
);
2257 // ***************************************************************************
2258 // ***************************************************************************
2259 // Old school Template skinning: SSE or not.
2260 // ***************************************************************************
2261 // ***************************************************************************
2264 // RawSkin Cache constants
2266 // The number of byte to process per block
2267 const uint NL_BlockByteL1
= 4096;
2269 // Number of vertices per block to process with 1 matrix.
2270 uint
CMeshMRMSkinnedGeom::NumCacheVertexNormal1
= NL_BlockByteL1
/ sizeof(CRawVertexNormalSkinned1
);
2271 // Number of vertices per block to process with 2 matrix.
2272 uint
CMeshMRMSkinnedGeom::NumCacheVertexNormal2
= NL_BlockByteL1
/ sizeof(CRawVertexNormalSkinned2
);
2273 // Number of vertices per block to process with 3 matrix.
2274 uint
CMeshMRMSkinnedGeom::NumCacheVertexNormal3
= NL_BlockByteL1
/ sizeof(CRawVertexNormalSkinned3
);
2275 // Number of vertices per block to process with 4 matrix.
2276 uint
CMeshMRMSkinnedGeom::NumCacheVertexNormal4
= NL_BlockByteL1
/ sizeof(CRawVertexNormalSkinned4
);
2279 /* Old School template: include the same file with define switching,
2280 Was used before to reuse same code for and without SSE.
2281 Useless now because SSE removed, but keep it for possible future work on it.
2283 #define ADD_MESH_MRM_SKINNED_TEMPLATE
2284 #include "mesh_mrm_skinned_template.cpp"