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/mrm_builder.h"
20 #include "nel/3d/mrm_parameters.h"
22 using namespace NLMISC
;
33 // ***************************************************************************
34 // ***************************************************************************
36 // ***************************************************************************
37 // ***************************************************************************
40 // ***************************************************************************
41 static bool findElement(vector
<sint
> &array
, sint elt
)
43 return find(array
.begin(), array
.end(), elt
) != array
.end();
45 // ***************************************************************************
46 static bool deleteElement(vector
<sint
> &array
, sint elt
)
49 vector
<sint
>::iterator it
=array
.begin();
51 while( (it
=find(array
.begin(), array
.end(), elt
)) != array
.end() )
52 found
=true, array
.erase(it
);
55 // Do not use remove<> since it desn't modify size ... (???)
56 // This doesn't seem to work.
57 //return remove(array.begin(), array.end(), elt)!=array.end();
61 // ***************************************************************************
62 // ***************************************************************************
64 // ***************************************************************************
65 // ***************************************************************************
68 // ***************************************************************************
69 bool CMRMBuilder::vertexHasOneWedge(sint numvertex
)
71 CMRMVertex
&vert
= TmpVertices
[numvertex
];
72 for(sint attId
=0;attId
<NumAttributes
;attId
++)
75 for(sint i
=0;i
<(sint
)vert
.SharedFaces
.size();i
++)
77 sint w
= TmpFaces
[vert
.SharedFaces
[i
]].getAssociatedWedge(attId
, numvertex
);
78 if(numwedge
>=0 && numwedge
!=w
) return false;
84 // ***************************************************************************
85 bool CMRMBuilder::vertexHasOneMaterial(sint numvertex
)
88 CMRMVertex
&vert
= TmpVertices
[numvertex
];
89 for(sint i
=0;i
<(sint
)vert
.SharedFaces
.size();i
++)
91 sint m
= TmpFaces
[vert
.SharedFaces
[i
]].MaterialId
;
92 if(matId
>=0 && matId
!=m
) return false;
97 // ***************************************************************************
98 bool CMRMBuilder::vertexContinue(sint numvertex
)
100 return vertexHasOneWedge(numvertex
) && vertexHasOneMaterial(numvertex
);
102 // ***************************************************************************
103 bool CMRMBuilder::vertexClosed(sint numvertex
)
105 CMRMVertex
&vert
= TmpVertices
[numvertex
];
106 map
<CMRMEdge
, sint
> EdgeShare
;
109 for(i
=0;i
<(sint
)vert
.SharedFaces
.size();i
++)
111 CMRMFaceBuild
&f
=TmpFaces
[vert
.SharedFaces
[i
]];
112 EdgeShare
[f
.getEdge(0)]= 0;
113 EdgeShare
[f
.getEdge(1)]= 0;
114 EdgeShare
[f
.getEdge(2)]= 0;
117 for(i
=0;i
<(sint
)vert
.SharedFaces
.size();i
++)
119 CMRMFaceBuild
&f
=TmpFaces
[vert
.SharedFaces
[i
]];
120 EdgeShare
[f
.getEdge(0)]++;
121 EdgeShare
[f
.getEdge(1)]++;
122 EdgeShare
[f
.getEdge(2)]++;
125 for(i
=0;i
<(sint
)vert
.SharedFaces
.size();i
++)
127 CMRMFaceBuild
&f
=TmpFaces
[vert
.SharedFaces
[i
]];
128 sint v0
= f
.Corner
[0].Vertex
;
129 sint v1
= f
.Corner
[1].Vertex
;
130 sint v2
= f
.Corner
[2].Vertex
;
131 if(EdgeShare
[f
.getEdge(0)]<2 && (v0
==numvertex
|| v1
==numvertex
)) return false;
132 if(EdgeShare
[f
.getEdge(1)]<2 && (v1
==numvertex
|| v2
==numvertex
)) return false;
133 if(EdgeShare
[f
.getEdge(2)]<2 && (v0
==numvertex
|| v2
==numvertex
)) return false;
137 // ***************************************************************************
138 float CMRMBuilder::getDeltaFaceNormals(sint numvertex
)
140 // return a positive value of Somme(|DeltaNormals|) / NNormals.
141 CMRMVertex
&vert
= TmpVertices
[numvertex
];
143 CVector
refNormal(0.f
, 0.f
, 0.f
);
144 sint nfaces
=(sint
)vert
.SharedFaces
.size();
145 for(sint i
=0;i
<nfaces
;i
++)
148 CVector
&v0
= TmpVertices
[TmpFaces
[i
].Corner
[0].Vertex
].Current
;
149 CVector
&v1
= TmpVertices
[TmpFaces
[i
].Corner
[1].Vertex
].Current
;
150 CVector
&v2
= TmpVertices
[TmpFaces
[i
].Corner
[2].Vertex
].Current
;
151 normal
= (v1
-v0
)^(v2
-v0
);
156 delta
+=(1-refNormal
*normal
);
161 return delta
/(nfaces
-1);
163 // ***************************************************************************
164 bool CMRMBuilder::edgeContinue(const CMRMEdge
&edge
)
168 CMRMVertex
&Vertex1
=TmpVertices
[v0
];
170 // build list sharing edge.
171 vector
<sint
> deletedFaces
;
173 for(i
=0;i
<(sint
)Vertex1
.SharedFaces
.size();i
++)
175 sint numFace
= Vertex1
.SharedFaces
[i
];
176 if(TmpFaces
[numFace
].hasVertex(v1
))
177 deletedFaces
.push_back(numFace
);
181 // test if faces have same material.
182 for(i
=0;i
<(sint
)deletedFaces
.size();i
++)
185 m
= TmpFaces
[deletedFaces
[i
]].MaterialId
;
186 if(matId
>=0 && matId
!=m
) return false;
190 // test if faces have same wedge (for all att).
191 for(sint attId
=0;attId
<NumAttributes
;attId
++)
193 sint numwedge1
=-1,numwedge2
=-1;
194 for(i
=0;i
<(sint
)deletedFaces
.size();i
++)
197 w
= TmpFaces
[deletedFaces
[i
]].getAssociatedWedge(attId
, v0
);
198 if(numwedge1
>=0 && numwedge1
!=w
) return false;
200 w
= TmpFaces
[deletedFaces
[i
]].getAssociatedWedge(attId
, v1
);
201 if(numwedge2
>=0 && numwedge2
!=w
) return false;
208 // ***************************************************************************
209 bool CMRMBuilder::edgeNearUniqueMatFace(const CMRMEdge
&edge
)
213 CMRMVertex
&Vertex1
=TmpVertices
[v0
];
215 // build list sharing edge.
216 vector
<sint
> deletedFaces
;
218 for(i
=0;i
<(sint
)Vertex1
.SharedFaces
.size();i
++)
220 sint numFace
= Vertex1
.SharedFaces
[i
];
221 if(TmpFaces
[numFace
].hasVertex(v1
))
222 deletedFaces
.push_back(numFace
);
225 // test if faces are not isolated OneMaterial faces.
226 for(i
=0;i
<(sint
)deletedFaces
.size();i
++)
228 CMRMFaceBuild
&f
=TmpFaces
[deletedFaces
[i
]];
229 if( !edgeContinue(f
.getEdge(0)) &&
230 !edgeContinue(f
.getEdge(1)) &&
231 !edgeContinue(f
.getEdge(2)))
238 // ***************************************************************************
239 float CMRMBuilder::computeEdgeCost(const CMRMEdge
&edge
)
243 // more expensive is the edge, later it will collapse.
246 // **** standard cost
248 // compute size of the edge.
249 float cost
=(TmpVertices
[v1
].Current
-TmpVertices
[v2
].Current
).norm();
251 // compute "curvature" of the edge.
252 float faceCost
= (getDeltaFaceNormals(v1
)+getDeltaFaceNormals(v2
));
253 // totally plane faces (faceCost==0) must be collapsed with respect to size (and not random if cost==0).
254 // else we may have Plane Mesh (like flags) that will collapse in a very ugly way.
255 faceCost
= max(faceCost
, 0.01f
);
257 // modulate size with curvature.
260 // Like H.Hope, add a weight on discontinuities..
261 if( !vertexContinue(v1
) && !vertexContinue(v2
) )
263 // Nb: don't do this on discontinuities edges, unless the unique material face will collapse (pffiou!!).
264 if( edgeContinue(edge
) || edgeNearUniqueMatFace(edge
) )
268 // **** Interface Sewing cost
269 if(_HasMeshInterfaces
)
271 // if the 2 vertices come from a Sewing Interface mesh (must be a real interface id)
272 sint meshSewingId
= TmpVertices
[v1
].InterfaceLink
.InterfaceId
;
273 if( meshSewingId
>=0 && TmpVertices
[v2
].InterfaceLink
.InterfaceId
>=0 )
275 // if the 2 vertices come from the same Sewing Interface mesh
276 if( meshSewingId
== TmpVertices
[v2
].InterfaceLink
.InterfaceId
)
278 // Then the edge is one of the sewing interface mesh. must do special things for it
279 CMRMSewingMesh
&sewingMesh
= _SewingMeshes
[meshSewingId
];
282 // get the sewing edge id
284 sewingEdge
.v0
= TmpVertices
[v1
].InterfaceLink
.InterfaceVertexId
;
285 sewingEdge
.v1
= TmpVertices
[v2
].InterfaceLink
.InterfaceVertexId
;
286 // if the current sewing lod want to collapse this edge
287 sint collapseId
= sewingMesh
.mustCollapseEdge(_CurrentLodComputed
, sewingEdge
, dummy
);
290 // Then set a negative priority (ie will collapse as soon as possible). from -N to -1.
291 // NB: sort them according to collapseId
292 cost
= (float)(-sewingMesh
.getNumCollapseEdge(_CurrentLodComputed
) + collapseId
);
296 // This edge must not collapse at this Lod, set an infinite priority (hope will never collapse).
302 /* The edge is between 2 interfaces but not the same. If we collide it we'll have holes!
303 This problem arise if space beetween interfaces is small. eg: if we setup an interface beetween
304 hair and head, and another one beetween head and torso, then we'll have this problem in the
306 The solution is to make a big big cost to hope we'll never collide them (else Holes...)!!
307 Don't use FLT_MAX to still have a correct order if we don't have choice...
320 // ***************************************************************************
321 // ***************************************************************************
323 // ***************************************************************************
324 // ***************************************************************************
327 // ***************************************************************************
328 bool CMRMBuilder::faceShareWedges(CMRMFaceBuild
*face
, sint attribId
, sint numVertex1
, sint numVertex2
)
330 sint numWedge1
= face
->getAssociatedWedge(attribId
, numVertex1
);
331 sint numWedge2
= face
->getAssociatedWedge(attribId
, numVertex2
);
332 if(numWedge1
<0) return false;
333 if(numWedge2
<0) return false;
335 CMRMAttribute
&w1
= TmpAttributes
[attribId
][numWedge1
];
336 CMRMAttribute
&w2
= TmpAttributes
[attribId
][numWedge2
];
337 return w1
.Shared
&& w2
.Shared
&& w1
.NbSharedFaces
>0 && w2
.NbSharedFaces
>0;
341 // ***************************************************************************
342 void CMRMBuilder::insertFaceIntoEdgeList(CMRMFaceBuild
&f
)
347 len
= computeEdgeCost(f
.getEdge(0));
348 f
. It0
= EdgeCollapses
.insert( TEdgeMap::value_type( len
, CMRMEdgeFace(f
.getEdge(0),&f
) ) );
352 len
= computeEdgeCost(f
.getEdge(1));
353 f
. It1
= EdgeCollapses
.insert( TEdgeMap::value_type( len
, CMRMEdgeFace(f
.getEdge(1),&f
) ) );
357 len
= computeEdgeCost(f
.getEdge(2));
358 f
. It2
= EdgeCollapses
.insert( TEdgeMap::value_type( len
, CMRMEdgeFace(f
.getEdge(2),&f
) ) );
361 // ***************************************************************************
362 void CMRMBuilder::removeFaceFromEdgeList(CMRMFaceBuild
&f
)
365 EdgeCollapses
.erase(f
.It0
);
367 EdgeCollapses
.erase(f
.It1
);
369 EdgeCollapses
.erase(f
.It2
);
374 // ***************************************************************************
375 struct CTmpVertexWeight
380 bool operator==(const CTmpVertexWeight
&o
) const
382 return MatrixId
==o
.MatrixId
;
385 bool operator<(const CTmpVertexWeight
&o
) const
387 return Weight
>o
.Weight
;
393 // ***************************************************************************
394 CMesh::CSkinWeight
CMRMBuilder::collapseSkinWeight(const CMesh::CSkinWeight
&sw1
, const CMesh::CSkinWeight
&sw2
, float interValue
) const
396 // If fast interpolation.
402 // else, must blend a skinWeight: must identify matrix which exist in the 2 sws, and add new ones.
405 static vector
<CTmpVertexWeight
> sws
;
406 sws
.reserve(NL3D_MESH_SKINNING_MAX_MATRIX
* 2);
409 // For all weights of sw1.
411 for(i
=0; i
<NL3D_MESH_SKINNING_MAX_MATRIX
; i
++)
414 vw
.MatrixId
= sw1
.MatrixId
[i
];
415 vw
.Weight
= sw1
.Weights
[i
]*(1-interValue
);
416 // if this weight is not null.
419 // add it to the list.
422 // For skinning reduction.
428 // For all weights of sw1.
429 for(i
=0; i
<NL3D_MESH_SKINNING_MAX_MATRIX
; i
++)
432 vw
.MatrixId
= sw2
.MatrixId
[i
];
433 vw
.Weight
= sw2
.Weights
[i
]*(interValue
);
434 // if this weight is not null.
437 // add it or add influence to the matrix.
438 vector
<CTmpVertexWeight
>::iterator it
= find(sws
.begin(), sws
.end(), vw
);
442 it
->Weight
+= vw
.Weight
;
444 // For skinning reduction.
450 // Then keep just the best.
451 // sort by Weight decreasing order.
452 sort(sws
.begin(), sws
.end());
454 // clamp the result to the wanted max matrix.
456 switch(_SkinReduction
)
458 case CMRMParameters::SkinReductionMin
:
459 nbMatsOut
= min(nbMats1
, nbMats2
);
461 case CMRMParameters::SkinReductionMax
:
462 nbMatsOut
= max(nbMats1
, nbMats2
);
464 case CMRMParameters::SkinReductionBest
:
465 nbMatsOut
= min( (uint
)sws
.size(), (uint
)NL3D_MESH_SKINNING_MAX_MATRIX
);
471 nbMatsOut
= min(nbMatsOut
, (uint
)sws
.size());
472 nlassert(nbMatsOut
<=NL3D_MESH_SKINNING_MAX_MATRIX
);
475 // Then output the result to the skinWeight, normalizing.
477 for(i
= 0; i
<nbMatsOut
; i
++)
479 sumWeight
+= sws
[i
].Weight
;
482 CMesh::CSkinWeight ret
;
483 // Fill only needed matrix (other are rested in CMesh::CSkinWeight ctor).
484 for(i
= 0; i
<nbMatsOut
; i
++)
486 ret
.MatrixId
[i
]= sws
[i
].MatrixId
;
487 ret
.Weights
[i
]= sws
[i
].Weight
/ sumWeight
;
493 // ***************************************************************************
494 sint
CMRMBuilder::collapseEdge(const CMRMEdge
&edge
)
502 // 0. collapse the vertices.
503 //==========================
505 // edge.Vertex1 kept, but morphed.
506 // edge.Vertex2 deleted, and must know on which vertex it collapse.
507 CMRMVertex
&Vertex1
=TmpVertices
[edgeV1
], &Vertex2
=TmpVertices
[edgeV2
];
509 // Interpolation choice.
510 // Default is to interpolate vertex 0 to the middle of the edge.
513 // **** If at least one vertex of the edge is on a mesh sewing interface, must change InterValue
514 if( _HasMeshInterfaces
&& (Vertex1
.InterfaceLink
.InterfaceId
>=0 || Vertex2
.InterfaceLink
.InterfaceId
>=0) )
516 // If this is an edge of a mesh sewing interface
517 if(Vertex1
.InterfaceLink
.InterfaceId
==Vertex2
.InterfaceLink
.InterfaceId
)
519 // Then the edge is one of the sewing interface mesh. must do special things for it
520 CMRMSewingMesh
&sewingMesh
= _SewingMeshes
[Vertex1
.InterfaceLink
.InterfaceId
];
522 // get the sewing edge id
524 sewingEdge
.v0
= Vertex1
.InterfaceLink
.InterfaceVertexId
;
525 sewingEdge
.v1
= Vertex2
.InterfaceLink
.InterfaceVertexId
;
527 // Get the edge in the sewing mesh which is said to be collapsed
529 sint collapseId
= sewingMesh
.mustCollapseEdge(_CurrentLodComputed
, sewingEdge
, vertToCollapse
);
533 // if it is v0 which must collapse, then InterValue=1
534 if(vertToCollapse
==(uint
)sewingEdge
.v0
)
542 // This should not happens. But it is still possible if this edge don't want to collapse but if their
543 // is no more choice. Take a default value
549 // must collapse to the vertex on the sewing interface (as if it was open)
550 if(Vertex1
.InterfaceLink
.InterfaceId
>=0)
552 // NB: it is possible that both vertices are on a different sewing interface... still collapse (must have to)
557 // Then Vertex2 is on a sewing interface, collapse to it
562 // **** Else, on special cases, it is much more efficient to interpolate at start or at end of edge.
565 // If one vertex is "open", ie his shared faces do not represent a closed Fan, then interpolate to this one,
566 // so the mesh has the same silhouette.
567 bool vc1
= vertexClosed(edgeV1
);
568 bool vc2
= vertexClosed(edgeV2
);
569 if(!vc1
&& vc2
) InterValue
=0;
570 else if(vc1
&& !vc2
) InterValue
=1;
573 // Do the same test but with vertex continue: it is preferable to not move the boundaries
574 // of a material, or a mapping.
575 bool vc1
= vertexContinue(edgeV1
);
576 bool vc2
= vertexContinue(edgeV2
);
577 if(!vc1
&& vc2
) InterValue
=0;
578 if(vc1
&& !vc2
) InterValue
=1;
581 /*BENCH_TotalCollapses++;
583 BENCH_MiddleCollapses++;*/
585 // Collapse the Vertex.
586 //========================
587 Vertex1
.Current
= Vertex1
.Current
*(1-InterValue
) + Vertex2
.Current
*InterValue
;
588 for (i
= 0; i
< (sint
)Vertex1
.BSCurrent
.size(); ++i
)
589 Vertex1
.BSCurrent
[i
] = Vertex1
.BSCurrent
[i
]*(1-InterValue
) + Vertex2
.BSCurrent
[i
]*InterValue
;
590 Vertex2
.CollapsedTo
= edgeV1
;
592 Vertex1
.CurrentSW
= collapseSkinWeight(Vertex1
.CurrentSW
, Vertex2
.CurrentSW
, InterValue
);
593 if( _HasMeshInterfaces
)
594 Vertex1
.InterfaceLink
= InterValue
<0.5f
? Vertex1
.InterfaceLink
: Vertex2
.InterfaceLink
;
596 // \todo yoyo: TODO_BUG: Don't know why, but vertices may point on deleted faces.
597 // Temp: we destroy here thoses face from SharedFaces...
598 for(i
=0;i
<(sint
)Vertex1
.SharedFaces
.size();i
++)
600 sint numFace
= Vertex1
.SharedFaces
[i
];
601 if(TmpFaces
[numFace
].Deleted
)
602 deleteElement(Vertex1
.SharedFaces
, numFace
), i
--;
604 for(i
=0;i
<(sint
)Vertex2
.SharedFaces
.size();i
++)
606 sint numFace
= Vertex2
.SharedFaces
[i
];
607 if(TmpFaces
[numFace
].Deleted
)
608 deleteElement(Vertex2
.SharedFaces
, numFace
), i
--;
612 // Build Neighbor faces.
613 vector
<sint
> neighboorFaces
;
614 for(i
=0;i
<(sint
)Vertex1
.SharedFaces
.size();i
++)
616 sint numFace
= Vertex1
.SharedFaces
[i
];
617 if(!findElement(neighboorFaces
, numFace
))
618 neighboorFaces
.push_back(numFace
);
620 for(i
=0;i
<(sint
)Vertex2
.SharedFaces
.size();i
++)
622 sint numFace
= Vertex2
.SharedFaces
[i
];
623 if(!findElement(neighboorFaces
, numFace
))
624 neighboorFaces
.push_back(numFace
);
627 // Build faces which will be destroyed (may 1 or 2, maybe more for non conventionnal meshes).
628 vector
<sint
> deletedFaces
;
629 for(i
=0;i
<(sint
)Vertex1
.SharedFaces
.size();i
++)
631 sint numFace
= Vertex1
.SharedFaces
[i
];
632 nlassert(!TmpFaces
[numFace
].Deleted
);
633 if(TmpFaces
[numFace
].hasVertex(edgeV2
))
634 deletedFaces
.push_back(numFace
);
638 // 1. Collapse the wedges.
639 //========================
641 // For ALL Attributes.
642 for(sint attId
=0;attId
<NumAttributes
;attId
++)
644 // a/ Stock the wedge interpolation in each destroyed face.
645 //------------------------------------------------------
646 for(i
=0;i
<(sint
)deletedFaces
.size();i
++)
648 CMRMFaceBuild
&face
= TmpFaces
[deletedFaces
[i
]];
650 CVectorH
&w0
= TmpAttributes
[attId
][ face
.getAssociatedWedge(attId
, edgeV1
) ].Current
;
651 CVectorH
&w1
= TmpAttributes
[attId
][ face
.getAssociatedWedge(attId
, edgeV2
) ].Current
;
653 CVectorH
&itp
= face
.InterpolatedAttribute
;
654 itp
.x
= w0
.x
*(1-InterValue
) + w1
.x
*InterValue
;
655 itp
.y
= w0
.y
*(1-InterValue
) + w1
.y
*InterValue
;
656 itp
.z
= w0
.z
*(1-InterValue
) + w1
.z
*InterValue
;
657 itp
.w
= w0
.w
*(1-InterValue
) + w1
.w
*InterValue
;
659 for (j
= 0; j
< (sint
)face
.BSInterpolated
.size(); ++j
)
661 CVectorH
&w0
= TmpAttributes
[attId
][face
.getAssociatedWedge(attId
, edgeV1
)].BSCurrent
[j
];
662 CVectorH
&w1
= TmpAttributes
[attId
][face
.getAssociatedWedge(attId
, edgeV2
)].BSCurrent
[j
];
663 CVectorH
&itb
= face
.BSInterpolated
[j
];
664 itb
.x
= w0
.x
*(1-InterValue
) + w1
.x
*InterValue
;
665 itb
.y
= w0
.y
*(1-InterValue
) + w1
.y
*InterValue
;
666 itb
.z
= w0
.z
*(1-InterValue
) + w1
.z
*InterValue
;
667 itb
.w
= w0
.w
*(1-InterValue
) + w1
.w
*InterValue
;
672 // b/ Build wedge list to be modify.
673 //----------------------------------
676 for(i
=0;i
<(sint
)neighboorFaces
.size();i
++)
678 CMRMFaceBuild
&face
= TmpFaces
[neighboorFaces
[i
]];
681 numWedge
= face
.getAssociatedWedge(attId
, edgeV1
);
682 if(numWedge
>=0 && !findElement(wedges
, numWedge
))
683 wedges
.push_back(numWedge
);
685 numWedge
= face
.getAssociatedWedge(attId
, edgeV2
);
686 if(numWedge
>=0 && !findElement(wedges
, numWedge
))
687 wedges
.push_back(numWedge
);
691 // c/ Count numFaces which point on those wedges. (- deleted faces).
692 //------------------------------------------------------------------
694 for(i
=0;i
<(sint
)wedges
.size();i
++)
696 sint numWedge
= wedges
[i
];
697 CMRMAttribute
&wedge
= TmpAttributes
[attId
][numWedge
];
699 wedge
.NbSharedFaces
=0;
702 // Count total ref count.
703 for(j
=0;j
<(sint
)neighboorFaces
.size();j
++)
705 if(TmpFaces
[neighboorFaces
[j
]].hasWedge(attId
, numWedge
))
706 wedge
.NbSharedFaces
++;
709 // Minus deleted faces.
710 for(j
=0;j
<(sint
)deletedFaces
.size();j
++)
712 if(TmpFaces
[deletedFaces
[j
]].hasWedge(attId
, numWedge
))
714 wedge
.NbSharedFaces
--;
716 wedge
.InterpolatedFace
=deletedFaces
[j
];
722 // d/ Collapse wedge following 3 possibles cases.
723 //-----------------------------------------------
726 for(i
=0;i
<(sint
)wedges
.size();i
++)
728 sint numWedge
= wedges
[i
];
729 CMRMAttribute
&wedge
= TmpAttributes
[attId
][numWedge
];
731 // if wedge not shared...
734 // We've got an "exterior wedge" which lost no corner => do not merge it nor delete it.
735 // Leave it as the same value (extrapolate it may not be a good solution).
739 // if wedge dissapears, notify.
740 if(wedge
.NbSharedFaces
==0)
742 wedge
.CollapsedTo
=-2;
743 // Do not change his value. (as specified in Hope article).
747 CMRMFaceBuild
&face
= TmpFaces
[wedge
.InterpolatedFace
];
749 // Must interpolate it.
750 wedge
.Current
= face
.InterpolatedAttribute
;
751 wedge
.BSCurrent
= face
.BSInterpolated
;
753 // Must merge the wedge of the second vertex on first
754 // ONLY IF 2 interpolated wedges are shared and NbSharedFaces!=0.
755 if( numWedge
==face
.getAssociatedWedge(attId
, edgeV2
) &&
756 faceShareWedges(&face
, attId
, edgeV1
, edgeV2
) )
758 wedge
.CollapsedTo
= face
.getAssociatedWedge(attId
, edgeV1
);
766 // 3. collapse faces.
767 //===================
769 // delete face shared by edge.
770 for(i
=0;i
<(sint
)deletedFaces
.size();i
++)
772 sint numFace
= deletedFaces
[i
];
773 TmpFaces
[numFace
].Deleted
=true;
775 // release edges from list.
776 removeFaceFromEdgeList(TmpFaces
[numFace
]);
778 TmpFaces
[numFace
].invalidAllIts(EdgeCollapses
);
781 // delete from vertex1 and 2 the deleted faces.
782 deleteElement( Vertex1
.SharedFaces
, numFace
);
783 deleteElement( Vertex2
.SharedFaces
, numFace
);
787 // must ref correctly the faces.
788 for(i
=0;i
<(sint
)neighboorFaces
.size();i
++)
790 CMRMFaceBuild
&face
=TmpFaces
[neighboorFaces
[i
]];
793 if(face
.Corner
[0].Vertex
==edgeV2
) face
.Corner
[0].Vertex
=edgeV1
;
794 if(face
.Corner
[1].Vertex
==edgeV2
) face
.Corner
[1].Vertex
=edgeV1
;
795 if(face
.Corner
[2].Vertex
==edgeV2
) face
.Corner
[2].Vertex
=edgeV1
;
796 // nb: doesn't matter if deletedFaces are modified...
799 for(sint attId
=0;attId
<NumAttributes
;attId
++)
802 newWedge
= TmpAttributes
[attId
][ face
.Corner
[0].Attributes
[attId
] ].CollapsedTo
;
803 if(newWedge
>=0) face
.Corner
[0].Attributes
[attId
]= newWedge
;
804 newWedge
= TmpAttributes
[attId
][ face
.Corner
[1].Attributes
[attId
] ].CollapsedTo
;
805 if(newWedge
>=0) face
.Corner
[1].Attributes
[attId
]= newWedge
;
806 newWedge
= TmpAttributes
[attId
][ face
.Corner
[2].Attributes
[attId
] ].CollapsedTo
;
807 if(newWedge
>=0) face
.Corner
[2].Attributes
[attId
]= newWedge
;
811 /* Those ones are updated in collapseEdges(): they are removed from the edgeCollapseList,
812 then they are re-inserted with good Vertex indices.
817 // The vertex1 has now the shared env of vertex2.
818 Vertex1
.SharedFaces
.insert(Vertex1
.SharedFaces
.end(), Vertex2
.SharedFaces
.begin(),
819 Vertex2
.SharedFaces
.end());
822 return (sint
)deletedFaces
.size();
826 // ***************************************************************************
827 sint
CMRMBuilder::followVertex(sint i
)
829 CMRMVertex
&vert
=TmpVertices
[i
];
830 if(vert
.CollapsedTo
>=0)
831 return followVertex(vert
.CollapsedTo
);
835 // ***************************************************************************
836 sint
CMRMBuilder::followWedge(sint attribId
, sint i
)
838 CMRMAttribute
&wedge
= TmpAttributes
[attribId
][i
];
839 if(wedge
.CollapsedTo
>=0)
840 return followWedge(attribId
, wedge
.CollapsedTo
);
846 // ***************************************************************************
847 // ***************************************************************************
848 // Mesh Level method.
849 // ***************************************************************************
850 // ***************************************************************************
853 // ***************************************************************************
854 CMRMBuilder::CMRMBuilder()
858 _HasMeshInterfaces
= false;
861 // ***************************************************************************
862 void CMRMBuilder::init(const CMRMMesh
&baseMesh
)
869 for(attId
=0;attId
<NL3D_MRM_MAX_ATTRIB
;attId
++)
871 TmpAttributes
[attId
].clear();
874 EdgeCollapses
.clear();
878 NumAttributes
= baseMesh
.NumAttributes
;
879 TmpVertices
.resize(baseMesh
.Vertices
.size());
880 for(attId
=0;attId
<NumAttributes
;attId
++)
882 TmpAttributes
[attId
].resize(baseMesh
.Attributes
[attId
].size());
884 TmpFaces
.resize(baseMesh
.Faces
.size());
888 for(i
=0;i
<(sint
)baseMesh
.Vertices
.size();i
++)
890 TmpVertices
[i
].Current
= TmpVertices
[i
].Original
= baseMesh
.Vertices
[i
];
891 TmpVertices
[i
].BSCurrent
.resize(baseMesh
.BlendShapes
.size());
892 for(uint32 j
= 0; j
<baseMesh
.BlendShapes
.size() ;++j
)
893 TmpVertices
[i
].BSCurrent
[j
]= baseMesh
.BlendShapes
[j
].Vertices
[i
];
895 TmpVertices
[i
].CurrentSW
= TmpVertices
[i
].OriginalSW
= baseMesh
.SkinWeights
[i
];
896 if(_HasMeshInterfaces
)
897 TmpVertices
[i
].InterfaceLink
= baseMesh
.InterfaceLinks
[i
];
899 for(attId
=0;attId
<NumAttributes
;attId
++)
901 for(i
=0;i
<(sint
)baseMesh
.Attributes
[attId
].size();i
++)
903 TmpAttributes
[attId
][i
].Current
= TmpAttributes
[attId
][i
].Original
=
904 baseMesh
.Attributes
[attId
][i
];
905 TmpAttributes
[attId
][i
].BSCurrent
.resize(baseMesh
.BlendShapes
.size());
906 for(uint32 j
= 0; j
<baseMesh
.BlendShapes
.size() ;++j
)
907 TmpAttributes
[attId
][i
].BSCurrent
[j
]= baseMesh
.BlendShapes
[j
].Attributes
[attId
][i
];
910 for(i
=0;i
<(sint
)baseMesh
.Faces
.size();i
++)
912 TmpFaces
[i
]= baseMesh
.Faces
[i
];
913 TmpFaces
[i
].BSInterpolated
.resize(baseMesh
.BlendShapes
.size());
917 // Create vertices sharedFaces.
918 for(i
=0;i
<(sint
)TmpFaces
.size();i
++)
920 CMRMFaceBuild
&face
= TmpFaces
[i
];
922 TmpVertices
[face
.Corner
[0].Vertex
].SharedFaces
.push_back(i
);
923 TmpVertices
[face
.Corner
[1].Vertex
].SharedFaces
.push_back(i
);
924 TmpVertices
[face
.Corner
[2].Vertex
].SharedFaces
.push_back(i
);
929 for(i
=0;i
<(sint
)TmpFaces
.size();i
++)
931 CMRMFaceBuild
&f
= TmpFaces
[i
];
932 // At start, valid all edges.
936 insertFaceIntoEdgeList(f
);
939 // ***************************************************************************
940 void CMRMBuilder::collapseEdges(sint nWantedFaces
)
944 sint nCurrentFaces
=(sint
)TmpFaces
.size();
945 sint bug0
=0,bug2
=0,bug3
=0;
947 while(nCurrentFaces
>nWantedFaces
)
950 EdgeIt
= EdgeCollapses
.begin();
952 if(EdgeIt
== EdgeCollapses
.end())
955 // 0. Look if edge already deleted
956 //================================
957 CMRMEdge edge
=(*EdgeIt
).second
;
959 // Is it valid?? (ie his vertices exist yet??).
960 if(TmpVertices
[ edge
.v0
].CollapsedTo
>=0
961 || TmpVertices
[ edge
.v1
].CollapsedTo
>=0)
963 // \todo yoyo: TODO_BUG: potential bug here...
964 CMRMFaceBuild
&f
= *(EdgeIt
->second
.Face
);
965 nlassert(f
.validEdgeIt(EdgeIt
->second
));
966 f
.invalidEdgeIt(EdgeIt
->second
, EdgeCollapses
);
967 EdgeCollapses
.erase(EdgeIt
);
971 // \todo yoyo: TODO_BUG: potential bug here...
972 // If a mesh is "open" it will crash if a "hole collapse"...
975 CMRMFaceBuild
&f
= *(EdgeIt
->second
.Face
);
976 nlassert(f
.validEdgeIt(EdgeIt
->second
));
977 f
.invalidEdgeIt(EdgeIt
->second
, EdgeCollapses
);
978 EdgeCollapses
.erase(EdgeIt
);
984 // 1. else, OK, collapse it!!
985 //===========================
986 sint vertexCollapsed
= edge
.v0
;
987 nCurrentFaces
-= collapseEdge(edge
);
990 // 2. Must reorder all his neighborhood.
991 //======================================
992 CMRMVertex
&vert
=TmpVertices
[vertexCollapsed
];
994 // we delete from list modified edges, and we re-add them with their new value.
995 for(i
=0;i
<(sint
)vert
.SharedFaces
.size();i
++)
997 CMRMFaceBuild
&f
= TmpFaces
[vert
.SharedFaces
[i
]];
998 removeFaceFromEdgeList(f
);
999 insertFaceIntoEdgeList(f
);
1004 // ***************************************************************************
1005 void CMRMBuilder::saveCoarserMesh(CMRMMesh
&coarserMesh
)
1009 coarserMesh
.Vertices
.clear();
1010 coarserMesh
.SkinWeights
.clear();
1011 coarserMesh
.InterfaceLinks
.clear();
1012 for(attId
=0;attId
<NL3D_MRM_MAX_ATTRIB
;attId
++)
1014 coarserMesh
.Attributes
[attId
].clear();
1016 coarserMesh
.Faces
.clear();
1017 coarserMesh
.NumAttributes
= NumAttributes
;
1022 for(i
=0;i
<(sint
)TmpVertices
.size();i
++)
1024 CMRMVertex
&vert
=TmpVertices
[i
];
1025 if(vert
.CollapsedTo
==-1) // if exist yet.
1027 vert
.CoarserIndex
=index
;
1028 coarserMesh
.Vertices
.push_back(vert
.Current
);
1030 coarserMesh
.SkinWeights
.push_back(vert
.CurrentSW
);
1031 if(_HasMeshInterfaces
)
1032 coarserMesh
.InterfaceLinks
.push_back(vert
.InterfaceLink
);
1037 vert
.CoarserIndex
=-1; // indicate that this vertex no more exist and is to be geomorphed to another.
1043 for(attId
=0;attId
<NumAttributes
;attId
++)
1046 for(i
=0;i
<(sint
)TmpAttributes
[attId
].size();i
++)
1048 CMRMAttribute
&wedge
= TmpAttributes
[attId
][i
];
1049 if(wedge
.CollapsedTo
==-1) // if exist yet.
1051 wedge
.CoarserIndex
=index
;
1052 coarserMesh
.Attributes
[attId
].push_back(wedge
.Current
);
1055 else if(wedge
.CollapsedTo
==-2) // else if totaly destroyed.
1057 // Insert this wedge in the coarser mesh.
1058 // NB: the coarser mesh faces do not use it anymore, but FinerMesh use it
1059 // for geomorph (LODMesh.CoarserFaces may point to it).
1060 // NB: look at buildFinalMRM(), it works fine for all cases.
1061 wedge
.CoarserIndex
=index
;
1062 coarserMesh
.Attributes
[attId
].push_back(wedge
.Current
);
1066 wedge
.CoarserIndex
=-1; // indicate that this wedge no more exist and is to be geomorphed to another.
1072 for(i
=0;i
<(sint
)TmpFaces
.size();i
++)
1074 CMRMFaceBuild
&face
=TmpFaces
[i
];
1079 newFace
.MaterialId
= face
.MaterialId
;
1080 for(sint j
=0;j
<3;j
++)
1083 newFace
.Corner
[j
].Vertex
= TmpVertices
[face
.Corner
[j
].Vertex
].CoarserIndex
;
1084 nlassert(newFace
.Corner
[j
].Vertex
>=0);
1086 for(attId
=0;attId
<NumAttributes
;attId
++)
1088 sint oldidx
= face
.Corner
[j
].Attributes
[attId
];
1089 newFace
.Corner
[j
].Attributes
[attId
]= TmpAttributes
[attId
][oldidx
].CoarserIndex
;
1090 nlassert(newFace
.Corner
[j
].Attributes
[attId
]>=0);
1095 coarserMesh
.Faces
.push_back(newFace
);
1102 // ***************************************************************************
1103 void CMRMBuilder::makeLODMesh(CMRMMeshGeom
&lodMesh
)
1105 sint i
,j
,attId
,index
,coidx
;
1107 // for all faces of this mesh, find target in the coarser mesh.
1108 for(i
=0;i
<(sint
)lodMesh
.CoarserFaces
.size();i
++)
1110 CMRMFace
&face
= lodMesh
.CoarserFaces
[i
];
1116 // The index is yet the index in the finer mesh.
1117 index
= face
.Corner
[j
].Vertex
;
1118 // the index in the coarser mesh is vert.CoarserIndex.
1119 coidx
= TmpVertices
[index
].CoarserIndex
;
1120 // but if this vertex is collapsed, must find the good index (yet in the finer mesh)
1123 // find to which we must collapse.
1124 index
= followVertex(index
);
1125 // and so we have the coarser index. this one must be valid.
1126 coidx
= TmpVertices
[index
].CoarserIndex
;
1129 // update corner of CoarserFace.
1130 face
.Corner
[j
].Vertex
= coidx
;
1133 // Do exactly same thing for all attributes.
1134 for(attId
=0;attId
<NumAttributes
;attId
++)
1136 index
= face
.Corner
[j
].Attributes
[attId
];
1137 coidx
= TmpAttributes
[attId
][index
].CoarserIndex
;
1140 index
= followWedge(attId
, index
);
1141 coidx
= TmpAttributes
[attId
][index
].CoarserIndex
;
1144 face
.Corner
[j
].Attributes
[attId
]= coidx
;
1151 // ***************************************************************************
1152 // Transform source blend shapes to source blend shapes modified (just calculate new vertex/attr position)
1153 /*void CMRMBuilder::computeBsVerticesAttributes(vector<CMRMMesh> &srcBsMeshs, vector<CMRMMesh> &bsMeshsMod)
1155 sint i, j, k, attId;
1157 bsMeshsMod.resize (srcBsMeshs.size());
1158 for (k = 0; k < (sint)srcBsMeshs.size(); ++k)
1160 CMRMMesh &rBsMesh = srcBsMeshs[k];
1161 CMRMMesh &rBsMeshMod = bsMeshsMod[k];
1163 // Calculate modified vertices with the linear equation back tracking help
1164 rBsMeshMod.Vertices.resize (rBsMesh.Vertices.size());
1165 for (i = 0; i < (sint)rBsMesh.Vertices.size(); ++i)
1167 CLinearEquation &LinEq = TmpVertices[i].CurrentLinEq;
1168 rBsMeshMod.Vertices[i] = CVector(0.0f, 0.0f, 0.0f);
1169 for (j = 0; j < (sint)LinEq.Elts.size(); ++j)
1171 rBsMeshMod.Vertices[i] += LinEq.Elts[j].factor * rBsMesh.Vertices[LinEq.Elts[j].index];
1176 rBsMeshMod.NumAttributes = NumAttributes;
1177 for (attId = 0; attId < NumAttributes; attId++)
1179 rBsMeshMod.Attributes[attId].resize (rBsMesh.Attributes[attId].size());
1180 for (i = 0; i < (sint)rBsMesh.Attributes[attId].size(); ++i)
1182 CLinearEquation &LinEq = TmpAttributes[attId][i].CurrentLinEq;
1183 rBsMeshMod.Attributes[attId][i] = CVectorH(0.0f, 0.0f, 0.0f, 0.0f);
1184 for (j = 0; j < (sint)LinEq.Elts.size(); ++j)
1186 rBsMeshMod.Attributes[attId][i].x += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].x;
1187 rBsMeshMod.Attributes[attId][i].y += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].y;
1188 rBsMeshMod.Attributes[attId][i].z += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].z;
1189 rBsMeshMod.Attributes[attId][i].w += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].w;
1196 // ***************************************************************************
1197 // Transform source Blend Shape Meshes Modified into coarser blend shape mesh (compact vertices)
1198 void CMRMBuilder::makeCoarserBS (vector
<CMRMBlendShape
> &csBsMeshs
)
1201 sint32 nSizeVert
, nSizeAttr
, attId
;
1203 // Calculate size of vertices array
1205 for (i
= 0; i
< TmpVertices
.size(); ++i
)
1206 if(TmpVertices
[i
].CoarserIndex
> nSizeVert
)
1207 nSizeVert
= TmpVertices
[i
].CoarserIndex
;
1210 for (k
= 0; k
< csBsMeshs
.size(); ++k
)
1212 CMRMBlendShape
&rBsCoarserMesh
= csBsMeshs
[k
];
1214 rBsCoarserMesh
.Vertices
.resize (nSizeVert
);
1215 rBsCoarserMesh
.NumAttributes
= NumAttributes
;
1218 for(i
= 0; i
< TmpVertices
.size(); ++i
)
1220 CMRMVertex
&vert
= TmpVertices
[i
];
1221 if (vert
.CoarserIndex
!= -1)
1223 rBsCoarserMesh
.Vertices
[vert
.CoarserIndex
] = vert
.BSCurrent
[k
];
1227 for (attId
= 0; attId
< NumAttributes
; attId
++)
1229 // Calculate size of attribute attId array
1231 for(i
= 0; i
< TmpAttributes
[attId
].size(); i
++)
1232 if (TmpAttributes
[attId
][i
].CoarserIndex
> nSizeAttr
)
1233 nSizeAttr
= TmpAttributes
[attId
][i
].CoarserIndex
;
1236 rBsCoarserMesh
.Attributes
[attId
].resize (nSizeAttr
);
1238 for (i
= 0; i
< TmpAttributes
[attId
].size(); i
++)
1240 CMRMAttribute
&wedge
= TmpAttributes
[attId
][i
];
1241 if (wedge
.CoarserIndex
!= -1)
1243 rBsCoarserMesh
.Attributes
[attId
][wedge
.CoarserIndex
] = wedge
.BSCurrent
[k
];
1250 // ***************************************************************************
1251 void CMRMBuilder::makeFromMesh(const CMRMMesh
&baseMesh
, CMRMMeshGeom
&lodMesh
, CMRMMesh
&coarserMesh
, sint nWantedFaces
)
1253 // Init Tmp values in MRM builder.
1256 // compute MRM too next tgt face.
1257 collapseEdges(nWantedFaces
);
1259 // save the coarser mesh.
1260 saveCoarserMesh(coarserMesh
);
1261 // Build coarser BlendShapes.
1262 coarserMesh
.BlendShapes
.resize(baseMesh
.BlendShapes
.size());
1263 makeCoarserBS(coarserMesh
.BlendShapes
);
1265 // build the lodMesh (baseMesh, with vertex/Attributes collapse infos).
1267 makeLODMesh(lodMesh
);
1269 // end for this level.
1274 // ***************************************************************************
1275 // ***************************************************************************
1276 // Global MRM Level method.
1277 // ***************************************************************************
1278 // ***************************************************************************
1281 // ***************************************************************************
1282 void CMRMBuilder::buildAllLods(const CMRMMesh
&baseMesh
, std::vector
<CMRMMeshGeom
> &lodMeshs
,
1283 uint nWantedLods
, uint divisor
)
1285 sint nFaces
= (sint
)baseMesh
.Faces
.size();
1288 CMRMMesh srcMesh
= baseMesh
;
1290 // coarsest LOD will have those number of faces.
1291 nBaseFaces
=nFaces
/divisor
;
1292 nBaseFaces
=max(nBaseFaces
,4);
1294 // must have at least 2 LOD to be really intersting. But the rest of the process work too with only one Lod!!
1295 nlassert(nWantedLods
>=1);
1296 lodMeshs
.resize(nWantedLods
);
1298 // If only one lod asked, must init some Tmp Global values (like NumAttributes)
1301 _CurrentLodComputed
= 0;
1305 // must fill all LODs, from end to start. do not proces last lod since it will be the coarsest mesh.
1306 for(i
=nWantedLods
-1;i
>0;i
--)
1310 // for sewing computing
1311 _CurrentLodComputed
= i
;
1314 nbWantedFaces
= nBaseFaces
+ (nFaces
-nBaseFaces
) * (i
-1)/(nWantedLods
-1);
1315 nbWantedFaces
=max(nbWantedFaces
,4);
1320 makeFromMesh(srcMesh
, lodMeshs
[i
], csMesh
, nbWantedFaces
);
1322 // next mesh to process is csMesh.
1325 // the first lodMedsh gets the coarsest mesh.
1326 lodMeshs
[0]= srcMesh
;
1330 // ***************************************************************************
1331 void CMRMBuilder::buildFinalMRM(std::vector
<CMRMMeshGeom
> &lodMeshs
, CMRMMeshFinal
&finalMRM
)
1335 sint nLods
= (sint
)lodMeshs
.size();
1340 finalMRM
.NumAttributes
= NumAttributes
;
1341 finalMRM
.Skinned
= _Skinned
;
1342 CMRMMeshFinal::CWedge::NumAttributesToCompare
= NumAttributes
;
1343 CMRMMeshFinal::CWedge::CompareSkinning
= _Skinned
;
1344 finalMRM
.Lods
.resize(nLods
);
1347 // Build Wedges, and faces index.
1350 for(lodId
=0; lodId
<nLods
; lodId
++)
1352 CMRMMeshGeom
&lodMesh
= lodMeshs
[lodId
];
1353 CMRMMeshGeom
&lodMeshPrec
= lodMeshs
[lodId
==0?0:lodId
-1];
1354 // for all face corner.
1355 for(i
=0; i
<(sint
)lodMesh
.Faces
.size();i
++)
1357 // The current face.
1358 CMRMFace
&face
= lodMesh
.Faces
[i
];
1359 // the current face, but which points to the prec LOD vertices/attributes.
1360 CMRMFace
&faceCoarser
= lodMesh
.CoarserFaces
[i
];
1364 CMRMCorner
&corner
= face
.Corner
[j
];
1365 CMRMCorner
&cornerCoarser
= faceCoarser
.Corner
[j
];
1366 // start and end wedge (geomorph), maybe same.
1367 CMRMMeshFinal::CWedge wedgeStart
;
1368 CMRMMeshFinal::CWedge wedgeEnd
;
1370 // fill wedgeStart with values from lodMesh.
1371 wedgeStart
.Vertex
= lodMesh
.Vertices
[corner
.Vertex
];
1373 wedgeStart
.VertexSkin
= lodMesh
.SkinWeights
[corner
.Vertex
];
1374 for(attId
=0; attId
<NumAttributes
; attId
++)
1376 wedgeStart
.Attributes
[attId
]= lodMesh
.Attributes
[attId
][corner
.Attributes
[attId
]];
1379 // if geomorph possible (ie not lod 0).
1382 // fill wedgeEnd with values from coarser lodMesh.
1383 wedgeEnd
.Vertex
= lodMeshPrec
.Vertices
[cornerCoarser
.Vertex
];
1385 wedgeEnd
.VertexSkin
= lodMeshPrec
.SkinWeights
[cornerCoarser
.Vertex
];
1386 for(attId
=0; attId
<NumAttributes
; attId
++)
1388 wedgeEnd
.Attributes
[attId
]= lodMeshPrec
.Attributes
[attId
][cornerCoarser
.Attributes
[attId
]];
1394 wedgeEnd
= wedgeStart
;
1397 // find/insert wedge, and get Ids. NB: if start/end same, same indices.
1398 sint wedgeStartId
= finalMRM
.findInsertWedge(wedgeStart
);
1399 sint wedgeEndId
= finalMRM
.findInsertWedge(wedgeEnd
);
1401 // store in TmpCorner.
1402 corner
.WedgeStartId
= wedgeStartId
;
1403 corner
.WedgeEndId
= wedgeEndId
;
1407 // Here, the number of wedge indicate the max number of wedge this LOD needs.
1408 finalMRM
.Lods
[lodId
].NWedges
= (sint
)finalMRM
.Wedges
.size();
1412 // Count NBWedges necessary for geomorph, and compute Dest geomorph wedges ids.
1414 // the number of geomorph required for one LOD.
1416 // the number of geomorph required for all LOD (max of sglmGeom).
1417 sint sglmGeomMax
= 0;
1419 // Do not process lod 0, since no geomorph.
1420 for(lodId
=1; lodId
<nLods
; lodId
++)
1422 CMRMMeshGeom
&lodMesh
= lodMeshs
[lodId
];
1424 // reset the GeomMap, the one which indicate if we have already inserted a geomorph.
1428 // for all face corner.
1429 for(i
=0; i
<(sint
)lodMesh
.Faces
.size();i
++)
1431 // The current face.
1432 CMRMFace
&face
= lodMesh
.Faces
[i
];
1436 CMRMCorner
&corner
= face
.Corner
[j
];
1438 // if not same wedge Ids, this is a geomorphed wedge.
1439 if(corner
.WedgeStartId
!= corner
.WedgeEndId
)
1441 // search if it exist yet in the set.
1443 geom
.Start
= corner
.WedgeStartId
;
1444 geom
.End
= corner
.WedgeEndId
;
1445 sint geomDest
= sglmGeom
;
1446 // if don't find this geom in the set, then it is a new one.
1447 TGeomMap::const_iterator it
= _GeomMap
.find(geom
);
1448 if(it
== _GeomMap
.end())
1450 _GeomMap
.insert( make_pair(geom
, geomDest
) );
1454 geomDest
= it
->second
;
1456 // store this Geom Id in the corner.
1457 corner
.WedgeGeomId
= geomDest
;
1463 sglmGeomMax
= max(sglmGeomMax
, sglmGeom
);
1467 // inform the finalMRM.
1468 finalMRM
.NGeomSpace
= sglmGeomMax
;
1471 // decal all wedges/ face index.
1473 // insert an empty space for dest geomorph.
1474 finalMRM
.Wedges
.insert(finalMRM
.Wedges
.begin(), sglmGeomMax
, CMRMMeshFinal::CWedge());
1476 // Parse all faces corner of All lods, and decal Start/End Wedge index.
1477 for(lodId
=0; lodId
<nLods
; lodId
++)
1479 CMRMMeshGeom
&lodMesh
= lodMeshs
[lodId
];
1481 // for all face corner.
1482 for(i
=0; i
<(sint
)lodMesh
.Faces
.size();i
++)
1484 // The current face.
1485 CMRMFace
&face
= lodMesh
.Faces
[i
];
1489 CMRMCorner
&corner
= face
.Corner
[j
];
1492 corner
.WedgeStartId
+= sglmGeomMax
;
1493 corner
.WedgeEndId
+= sglmGeomMax
;
1497 // increment too the number of wedge required for this Lod.
1498 finalMRM
.Lods
[lodId
].NWedges
+= sglmGeomMax
;
1504 // Parse all faces corner of All lods, and build Faces/Geomorphs..
1505 for(lodId
=0; lodId
<nLods
; lodId
++)
1507 CMRMMeshGeom
&lodMesh
= lodMeshs
[lodId
];
1508 CMRMMeshFinal::CLod
&lodDest
= finalMRM
.Lods
[lodId
];
1510 // alloc final faces of this LOD.
1511 lodDest
.Faces
.resize(lodMesh
.Faces
.size());
1513 // reset the GeomMap, the one which indicate if we have already inserted a geomorph.
1516 // for all face corner.
1517 for(i
=0; i
<(sint
)lodMesh
.Faces
.size();i
++)
1519 // The current face.
1520 CMRMFace
&face
= lodMesh
.Faces
[i
];
1522 CMRMMeshFinal::CFace
&faceDest
= lodDest
.Faces
[i
];
1523 // fill good material.
1524 faceDest
.MaterialId
= face
.MaterialId
;
1529 CMRMCorner
&corner
= face
.Corner
[j
];
1531 // if not same wedge Ids, this is a geomorphed wedge.
1532 if(corner
.WedgeStartId
!= corner
.WedgeEndId
)
1534 // geomorph, so point to geomorphed wedge.
1535 faceDest
.WedgeId
[j
]= corner
.WedgeGeomId
;
1537 // Build the geomorph, add it to the list (if not yet inserted).
1539 geom
.Start
= corner
.WedgeStartId
;
1540 geom
.End
= corner
.WedgeEndId
;
1541 // if don't find this geom in the set, then it is a new one.
1542 TGeomMap::const_iterator it
= _GeomMap
.find(geom
);
1543 if(it
== _GeomMap
.end())
1545 // mark it as inserted.
1546 _GeomMap
.insert( make_pair(geom
, corner
.WedgeGeomId
) );
1547 // and we must insert this geom in the array.
1548 nlassert( corner
.WedgeGeomId
==(sint
)lodDest
.Geomorphs
.size() );
1549 lodDest
.Geomorphs
.push_back(geom
);
1554 // no geomorph, so just point to good wedge.
1555 faceDest
.WedgeId
[j
]= corner
.WedgeStartId
;
1562 // process all wedges, and compute NSkinMatUsed, skipping geomorphs.
1564 // NB: this works because weights are sorted from biggest to lowest.
1567 for(i
=finalMRM
.NGeomSpace
; i
<(sint
)finalMRM
.Wedges
.size();i
++)
1569 CMRMMeshFinal::CWedge
&wedge
= finalMRM
.Wedges
[i
];
1570 for(j
=0; j
<NL3D_MESH_SKINNING_MAX_MATRIX
; j
++)
1572 if(wedge
.VertexSkin
.Weights
[j
]==0)
1576 wedge
.NSkinMatUsed
= j
;
1580 // Blend Shape Stuff
1581 finalMRM
.MRMBlendShapesFinals
.resize (lodMeshs
[0].BlendShapes
.size());
1582 for (lodId
= 0; lodId
< nLods
; ++lodId
)
1584 CMRMMeshGeom
&lodMesh
= lodMeshs
[lodId
];
1585 CMRMMeshGeom
&lodMeshPrec
= lodMeshs
[lodId
==0?0:lodId
-1];
1587 // for all face corner.
1588 for (i
= 0; i
< (sint
)lodMesh
.Faces
.size(); ++i
)
1590 // The current face.
1591 CMRMFace
&face
= lodMesh
.Faces
[i
];
1592 // the current face, but which points to the prec LOD vertices/attributes.
1593 CMRMFace
&faceCoarser
= lodMesh
.CoarserFaces
[i
];
1595 for (j
= 0; j
< 3; ++j
)
1597 CMRMCorner
&corner
= face
.Corner
[j
];
1598 CMRMCorner
&cornerCoarser
= faceCoarser
.Corner
[j
];
1600 sint startDestIndex
= corner
.WedgeStartId
;
1602 for (sint k
= 0; k
< (sint
)finalMRM
.MRMBlendShapesFinals
.size(); ++k
)
1604 CMRMMeshFinal::CMRMBlendShapeFinal
&rBSFinal
= finalMRM
.MRMBlendShapesFinals
[k
];
1606 rBSFinal
.Wedges
.resize (finalMRM
.Wedges
.size());
1607 // Fill WedgeStart used by this corner.
1608 rBSFinal
.Wedges
[startDestIndex
].Vertex
= lodMesh
.BlendShapes
[k
].Vertices
[corner
.Vertex
];
1609 for (attId
= 0; attId
< NumAttributes
; ++attId
)
1611 rBSFinal
.Wedges
[startDestIndex
].Attributes
[attId
] = lodMesh
.BlendShapes
[k
].Attributes
[attId
][corner
.Attributes
[attId
]];
1614 // If geomorph, must fill the end too
1615 if(lodId
>0 && corner
.WedgeStartId
!= corner
.WedgeEndId
)
1617 sint endDestIndex
= corner
.WedgeEndId
;
1619 rBSFinal
.Wedges
[endDestIndex
].Vertex
= lodMeshPrec
.BlendShapes
[k
].Vertices
[cornerCoarser
.Vertex
];
1620 for (attId
= 0; attId
< NumAttributes
; ++attId
)
1622 rBSFinal
.Wedges
[endDestIndex
].Attributes
[attId
] = lodMeshPrec
.BlendShapes
[k
].Attributes
[attId
][cornerCoarser
.Attributes
[attId
]];
1634 // ***************************************************************************
1635 // ***************************************************************************
1636 // Interface to MeshBuild Part.
1637 // ***************************************************************************
1638 // ***************************************************************************
1642 // ***************************************************************************
1643 sint
CMRMBuilder::findInsertAttributeInBaseMesh(CMRMMesh
&baseMesh
, sint attId
, sint vertexId
, const CVectorH
&att
)
1645 // find this attribute in the map.
1647 key
.VertexId
= vertexId
;
1649 TAttributeMap::iterator it
= _AttributeMap
[attId
].find(key
);
1651 // if attribute not found in the map, then insert a new one.
1652 if(it
==_AttributeMap
[attId
].end())
1654 sint idx
= (sint
)baseMesh
.Attributes
[attId
].size();
1655 // insert into the array.
1656 baseMesh
.Attributes
[attId
].push_back(att
);
1657 // insert into the map.
1658 _AttributeMap
[attId
].insert(make_pair(key
, idx
));
1663 // return the one found.
1669 // ***************************************************************************
1670 sint
CMRMBuilder::findInsertNormalInBaseMesh(CMRMMesh
&baseMesh
, sint attId
, sint vertexId
, const CVector
&normal
)
1675 return findInsertAttributeInBaseMesh(baseMesh
, attId
, vertexId
, att
);
1679 // ***************************************************************************
1680 sint
CMRMBuilder::findInsertColorInBaseMesh(CMRMMesh
&baseMesh
, sint attId
, sint vertexId
, CRGBA col
)
1687 return findInsertAttributeInBaseMesh(baseMesh
, attId
, vertexId
, att
);
1691 // ***************************************************************************
1692 sint
CMRMBuilder::findInsertUvwInBaseMesh(CMRMMesh
&baseMesh
, sint attId
, sint vertexId
, const NLMISC::CUVW
&uvw
)
1699 return findInsertAttributeInBaseMesh(baseMesh
, attId
, vertexId
, att
);
1703 // ***************************************************************************
1704 CRGBA
CMRMBuilder::attToColor(const CVectorH
&att
) const
1708 tmp
= att
.x
; clamp(tmp
, 0, 255);
1709 ret
.R
= (uint8
)(uint
)tmp
;
1710 tmp
= att
.y
; clamp(tmp
, 0, 255);
1711 ret
.G
= (uint8
)(uint
)tmp
;
1712 tmp
= att
.z
; clamp(tmp
, 0, 255);
1713 ret
.B
= (uint8
)(uint
)tmp
;
1714 tmp
= att
.w
; clamp(tmp
, 0, 255);
1715 ret
.A
= (uint8
)(uint
)tmp
;
1721 // ***************************************************************************
1722 NLMISC::CUVW
CMRMBuilder::attToUvw(const CVectorH
&att
) const
1724 return CUVW(att
.x
, att
.y
, att
.z
);
1728 // ***************************************************************************
1729 uint32
CMRMBuilder::buildMrmBaseMesh(const CMesh::CMeshBuild
&mbuild
, CMRMMesh
&baseMesh
)
1734 // build the supported VertexFormat.
1735 uint32 retVbFlags
= CVertexBuffer::PositionFlag
;
1738 // reset the baseMesh.
1739 baseMesh
= CMRMMesh();
1741 for(attId
=0; attId
<NL3D_MRM_MAX_ATTRIB
;attId
++)
1742 _AttributeMap
[attId
].clear();
1745 // Compute number of attributes used by the MeshBuild.
1746 // ========================
1748 if(mbuild
.VertexFlags
& CVertexBuffer::NormalFlag
)
1750 baseMesh
.NumAttributes
++;
1751 retVbFlags
|= CVertexBuffer::NormalFlag
;
1753 if(mbuild
.VertexFlags
& CVertexBuffer::PrimaryColorFlag
)
1755 baseMesh
.NumAttributes
++;
1756 retVbFlags
|= CVertexBuffer::PrimaryColorFlag
;
1758 if(mbuild
.VertexFlags
& CVertexBuffer::SecondaryColorFlag
)
1760 baseMesh
.NumAttributes
++;
1761 retVbFlags
|= CVertexBuffer::SecondaryColorFlag
;
1763 for(k
=0; k
<CVertexBuffer::MaxStage
;k
++)
1765 uint flag
=CVertexBuffer::TexCoord0Flag
<<k
;
1766 if(mbuild
.VertexFlags
& flag
)
1768 baseMesh
.NumAttributes
++;
1772 nlassert(baseMesh
.NumAttributes
<=NL3D_MRM_MAX_ATTRIB
);
1775 // Fill basics: Vertices and Faces materials / index to vertices.
1776 // ========================
1777 // Just copy vertices.
1778 baseMesh
.Vertices
= mbuild
.Vertices
;
1779 // Just copy SkinWeights.
1781 baseMesh
.SkinWeights
= mbuild
.SkinWeights
;
1782 // Just copy InterfaceLinks
1783 if(_HasMeshInterfaces
)
1784 baseMesh
.InterfaceLinks
= mbuild
.InterfaceLinks
;
1786 nFaces
= (sint
)mbuild
.Faces
.size();
1787 baseMesh
.Faces
.resize(nFaces
);
1788 for(i
=0; i
<nFaces
; i
++)
1790 // copy material Id.
1791 baseMesh
.Faces
[i
].MaterialId
= mbuild
.Faces
[i
].MaterialId
;
1792 // Copy Vertex index.
1795 baseMesh
.Faces
[i
].Corner
[j
].Vertex
= mbuild
.Faces
[i
].Corner
[j
].Vertex
;
1799 // Resolve attributes discontinuities and Fill attributes of the baseMesh.
1800 // ========================
1802 for(i
=0; i
<nFaces
; i
++)
1806 const CMesh::CCorner
&srcCorner
= mbuild
.Faces
[i
].Corner
[j
];
1807 CMRMCorner
&destCorner
= baseMesh
.Faces
[i
].Corner
[j
];
1810 // For all activated attributes in mbuild, find/insert the attribute in the baseMesh.
1811 // NB: 2 attributes are said to be different if they have not the same value OR if they don't lie
1812 // on the same vertex. This is very important for MRM computing.
1813 if(mbuild
.VertexFlags
& CVertexBuffer::NormalFlag
)
1815 destCorner
.Attributes
[attId
]= findInsertNormalInBaseMesh(baseMesh
, attId
, destCorner
.Vertex
, srcCorner
.Normal
);
1818 if(mbuild
.VertexFlags
& CVertexBuffer::PrimaryColorFlag
)
1820 destCorner
.Attributes
[attId
]= findInsertColorInBaseMesh(baseMesh
, attId
, destCorner
.Vertex
, srcCorner
.Color
);
1823 if(mbuild
.VertexFlags
& CVertexBuffer::SecondaryColorFlag
)
1825 destCorner
.Attributes
[attId
]= findInsertColorInBaseMesh(baseMesh
, attId
, destCorner
.Vertex
, srcCorner
.Specular
);
1828 for(k
=0; k
<CVertexBuffer::MaxStage
;k
++)
1830 if(mbuild
.VertexFlags
& (CVertexBuffer::TexCoord0Flag
<<k
))
1832 destCorner
.Attributes
[attId
]= findInsertUvwInBaseMesh(baseMesh
, attId
, destCorner
.Vertex
, srcCorner
.Uvws
[k
]);
1841 // End. clear Tmp infos.
1842 // ========================
1844 for(attId
=0; attId
<NL3D_MRM_MAX_ATTRIB
;attId
++)
1845 _AttributeMap
[attId
].clear();
1852 // ***************************************************************************
1853 CMesh::CSkinWeight
CMRMBuilder::normalizeSkinWeight(const CMesh::CSkinWeight
&sw
) const
1856 static vector
<CTmpVertexWeight
> sws
;
1857 sws
.reserve(NL3D_MESH_SKINNING_MAX_MATRIX
);
1860 // For all weights of sw1.
1862 for(i
=0; i
<NL3D_MESH_SKINNING_MAX_MATRIX
; i
++)
1864 CTmpVertexWeight vw
;
1865 vw
.MatrixId
= sw
.MatrixId
[i
];
1866 vw
.Weight
= sw
.Weights
[i
];
1867 // if this weight is not null.
1870 // add it to the list.
1876 // sort by Weight decreasing order.
1877 sort(sws
.begin(), sws
.end());
1880 // Then output the result to the skinWeight, normalizing.
1882 for(i
= 0; i
<nbMats
; i
++)
1884 sumWeight
+= sws
[i
].Weight
;
1887 CMesh::CSkinWeight ret
;
1888 // Fill only needed matrix (other are rested in CMesh::CSkinWeight ctor).
1889 for(i
= 0; i
<nbMats
; i
++)
1891 ret
.MatrixId
[i
]= sws
[i
].MatrixId
;
1892 ret
.Weights
[i
]= sws
[i
].Weight
/ sumWeight
;
1899 // ***************************************************************************
1900 void CMRMBuilder::normalizeBaseMeshSkin(CMRMMesh
&baseMesh
) const
1904 for(uint i
=0; i
<baseMesh
.SkinWeights
.size(); i
++)
1906 baseMesh
.SkinWeights
[i
]= normalizeSkinWeight(baseMesh
.SkinWeights
[i
]);
1912 // ***************************************************************************
1913 void CMRMBuilder::buildMeshBuildMrm(const CMRMMeshFinal
&finalMRM
, CMeshMRMGeom::CMeshBuildMRM
&mbuild
, uint32 vbFlags
, uint32 nbMats
, const CMesh::CMeshBuild
&mb
)
1918 // reset the mbuild.
1919 mbuild
= CMeshMRMGeom::CMeshBuildMRM();
1922 bool useFormatExt
= false;
1923 // Check whether there are texture coordinates with more than 2 compnents, which force us to use an extended vertex format
1924 for (k
= 0; k
< CVertexBuffer::MaxStage
; ++k
)
1927 (vbFlags
& (CVertexBuffer::TexCoord0Flag
<< k
))
1928 && mb
.NumCoords
[k
] != 2)
1930 useFormatExt
= true;
1935 uint numTexCoordUsed
= 0;
1938 for (k
= 0; k
< CVertexBuffer::MaxStage
; ++k
)
1940 if (vbFlags
& (CVertexBuffer::TexCoord0Flag
<< k
))
1942 numTexCoordUsed
= k
;
1948 // setup standard format
1949 mbuild
.VBuffer
.setVertexFormat(vbFlags
);
1951 else // setup extended format
1953 mbuild
.VBuffer
.clearValueEx();
1954 if (vbFlags
& CVertexBuffer::PositionFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Position
, CVertexBuffer::Float3
);
1955 if (vbFlags
& CVertexBuffer::NormalFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Normal
, CVertexBuffer::Float3
);
1956 if (vbFlags
& CVertexBuffer::PrimaryColorFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::PrimaryColor
, CVertexBuffer::UChar4
);
1957 if (vbFlags
& CVertexBuffer::SecondaryColorFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::SecondaryColor
, CVertexBuffer::UChar4
);
1958 if (vbFlags
& CVertexBuffer::WeightFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Weight
, CVertexBuffer::Float4
);
1959 if (vbFlags
& CVertexBuffer::PaletteSkinFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::PaletteSkin
, CVertexBuffer::UChar4
);
1960 if (vbFlags
& CVertexBuffer::FogFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Fog
, CVertexBuffer::Float1
);
1962 for (k
= 0; k
< CVertexBuffer::MaxStage
; ++k
)
1964 if (vbFlags
& (CVertexBuffer::TexCoord0Flag
<< k
))
1966 switch(mb
.NumCoords
[k
])
1969 mbuild
.VBuffer
.addValueEx((CVertexBuffer::TValue
) (CVertexBuffer::TexCoord0
+ k
), CVertexBuffer::Float2
);
1972 mbuild
.VBuffer
.addValueEx((CVertexBuffer::TValue
) (CVertexBuffer::TexCoord0
+ k
), CVertexBuffer::Float3
);
1980 mbuild
.VBuffer
.initEx();
1983 // Copy the UVRouting
1984 for (i
=0; i
<CVertexBuffer::MaxStage
; i
++)
1986 mbuild
.VBuffer
.setUVRouting (i
, mb
.UVRouting
[i
]);
1989 // Setup the VertexBuffer.
1990 // ========================
1992 mbuild
.VBuffer
.setNumVertices((uint32
)finalMRM
.Wedges
.size());
1993 // Setup SkinWeights.
1995 mbuild
.SkinWeights
.resize(finalMRM
.Wedges
.size());
1997 CVertexBufferReadWrite vba
;
1998 mbuild
.VBuffer
.lock (vba
);
2001 for(i
=0; i
<(sint
)finalMRM
.Wedges
.size(); i
++)
2003 const CMRMMeshFinal::CWedge
&wedge
= finalMRM
.Wedges
[i
];
2006 vba
.setVertexCoord(i
, wedge
.Vertex
);
2008 // seutp attributes.
2011 // For all activated attributes in mbuild, retriev the attribute from the finalMRM.
2012 if(vbFlags
& CVertexBuffer::NormalFlag
)
2014 vba
.setNormalCoord(i
, wedge
.Attributes
[attId
] );
2017 if(vbFlags
& CVertexBuffer::PrimaryColorFlag
)
2019 vba
.setColor(i
, attToColor(wedge
.Attributes
[attId
]) );
2022 if(vbFlags
& CVertexBuffer::SecondaryColorFlag
)
2024 vba
.setSpecular(i
, attToColor(wedge
.Attributes
[attId
]) );
2027 for(k
=0; k
<CVertexBuffer::MaxStage
;k
++)
2029 if(vbFlags
& (CVertexBuffer::TexCoord0Flag
<<k
))
2031 switch(mb
.NumCoords
[k
])
2034 vba
.setTexCoord(i
, k
, (CUV
) attToUvw(wedge
.Attributes
[attId
]) );
2038 CUVW uvw
= attToUvw(wedge
.Attributes
[attId
]);
2039 vba
.setValueFloat3Ex((CVertexBuffer::TValue
) (CVertexBuffer::TexCoord0
+ k
), i
, uvw
.U
, uvw
.V
, uvw
.W
);
2050 // Setup SkinWeights.
2053 mbuild
.SkinWeights
[i
]= wedge
.VertexSkin
;
2059 // ========================
2061 mbuild
.Lods
.resize(finalMRM
.Lods
.size());
2063 for(i
=0; i
<(sint
)finalMRM
.Lods
.size(); i
++)
2065 const CMRMMeshFinal::CLod
&srcLod
= finalMRM
.Lods
[i
];
2066 CMeshMRMGeom::CLod
&destLod
= mbuild
.Lods
[i
];
2071 // Copy NWedges infos.
2072 destLod
.NWedges
= srcLod
.NWedges
;
2073 // Copy Geomorphs infos.
2074 destLod
.Geomorphs
= srcLod
.Geomorphs
;
2077 // Reorder faces by rdrpass.
2080 // First count the number of faces used by this LOD for each material
2081 vector
<sint
> matCount
;
2082 // resize, and reset to 0.
2084 matCount
.resize(nbMats
, 0);
2085 // For each face of this Lods, incr the mat face counter.
2086 for(j
= 0; j
<(sint
)srcLod
.Faces
.size(); j
++)
2088 sint matId
= srcLod
.Faces
[j
].MaterialId
;
2090 nlassert(matId
<(sint
)nbMats
);
2091 // increment the refcount of this material by this LOD.
2095 // Then for each material not empty, create a rdrPass, and ref it for this material.
2096 vector
<sint
> rdrPassIndex
; // material to rdrPass map.
2097 rdrPassIndex
.resize(nbMats
);
2098 for(j
=0; j
<(sint
)nbMats
; j
++)
2101 rdrPassIndex
[j
]= -1;
2104 // map material to rdrPass.
2105 sint idRdrPass
= (sint
)destLod
.RdrPass
.size();
2106 rdrPassIndex
[j
]= idRdrPass
;
2107 // create a rdrPass.
2108 destLod
.RdrPass
.push_back(CMeshMRMGeom::CRdrPass());
2109 // assign the good materialId to this rdrPass.
2110 destLod
.RdrPass
[idRdrPass
].MaterialId
= j
;
2111 // reserve the array of faces of this rdrPass.
2112 destLod
.RdrPass
[idRdrPass
].PBlock
.reserve(3*matCount
[j
]);
2116 // Then for each face, add it to the good rdrPass of this Lod.
2117 for(j
= 0; j
<(sint
)srcLod
.Faces
.size(); j
++)
2119 sint matId
= srcLod
.Faces
[j
].MaterialId
;
2120 sint idRdrPass
= rdrPassIndex
[matId
];
2121 // add this face to the good rdrPass.
2122 sint w0
= srcLod
.Faces
[j
].WedgeId
[0];
2123 sint w1
= srcLod
.Faces
[j
].WedgeId
[1];
2124 sint w2
= srcLod
.Faces
[j
].WedgeId
[2];
2125 CIndexBuffer
&ib
= destLod
.RdrPass
[idRdrPass
].PBlock
;
2126 uint index
= ib
.getNumIndexes();
2127 ib
.setNumIndexes(index
+3);
2128 CIndexBufferReadWrite ibaWrite
;
2130 ibaWrite
.setTri(index
, w0
, w1
, w2
);
2134 // Build skin info for this Lod.
2136 for(j
=0; j
<NL3D_MESH_SKINNING_MAX_MATRIX
; j
++)
2138 destLod
.InfluencedVertices
[j
].clear();
2140 destLod
.MatrixInfluences
.clear();
2143 // This is the set which tell what wedge has already been inserted.
2144 set
<uint
> wedgeInfSet
;
2146 // First, build the list of vertices influenced by this Lod.
2147 for(j
= 0; j
<(sint
)srcLod
.Faces
.size(); j
++)
2151 sint wedgeId
= srcLod
.Faces
[j
].WedgeId
[k
];
2152 // If it is a geomorph
2153 if(wedgeId
<finalMRM
.NGeomSpace
)
2155 // add the start and end to the list (if not here). NB: wedgeId is both the id
2156 // of the dest wedge, and the id of the geomorph.
2157 sint wedgeStartId
= destLod
.Geomorphs
[wedgeId
].Start
;
2158 sint wedgeEndId
= destLod
.Geomorphs
[wedgeId
].End
;
2159 uint nMatUsedStart
= finalMRM
.Wedges
[wedgeStartId
].NSkinMatUsed
;
2160 uint nMatUsedEnd
= finalMRM
.Wedges
[wedgeEndId
].NSkinMatUsed
;
2162 // if insertion in the set work, add to the good array.
2163 if( wedgeInfSet
.insert(wedgeStartId
).second
)
2164 destLod
.InfluencedVertices
[nMatUsedStart
-1].push_back(wedgeStartId
);
2165 if( wedgeInfSet
.insert(wedgeEndId
).second
)
2166 destLod
.InfluencedVertices
[nMatUsedEnd
-1].push_back(wedgeEndId
);
2170 uint nMatUsed
= finalMRM
.Wedges
[wedgeId
].NSkinMatUsed
;
2172 // just add this wedge to the list (if not here).
2173 // if insertion in the set work, add to the array.
2174 if( wedgeInfSet
.insert(wedgeId
).second
)
2175 destLod
.InfluencedVertices
[nMatUsed
-1].push_back(wedgeId
);
2180 // Optimisation: for better cache, sort the destLod.InfluencedVertices in increasing order.
2181 for(j
=0; j
<NL3D_MESH_SKINNING_MAX_MATRIX
; j
++)
2183 sort(destLod
.InfluencedVertices
[j
].begin(), destLod
.InfluencedVertices
[j
].end());
2187 // Then Build the MatrixInfluences array, for all thoses Influenced Vertices only.
2188 // This is the map MatrixId -> MatrixInfId.
2189 map
<uint
, uint
> matrixInfMap
;
2191 // For all influenced vertices, flags matrix they use.
2193 for(iSkinMat
= 0; iSkinMat
<NL3D_MESH_SKINNING_MAX_MATRIX
; iSkinMat
++)
2195 for(j
= 0; j
<(sint
)destLod
.InfluencedVertices
[iSkinMat
].size(); j
++)
2197 uint wedgeId
= destLod
.InfluencedVertices
[iSkinMat
][j
];
2199 // take the original wedge.
2200 const CMRMMeshFinal::CWedge
&wedge
= finalMRM
.Wedges
[wedgeId
];
2201 // For all matrix with not null influence...
2202 for(k
= 0; k
<NL3D_MESH_SKINNING_MAX_MATRIX
; k
++)
2204 float matWeight
= wedge
.VertexSkin
.Weights
[k
];
2206 // This check the validity of skin weights sort. If false, problem before in the algo.
2207 if((uint
)k
<iSkinMat
+1)
2209 nlassert( matWeight
>0 );
2213 nlassert( matWeight
==0 );
2215 // if not null influence.
2218 uint matId
= wedge
.VertexSkin
.MatrixId
[k
];
2220 // search/insert the matrixInfId.
2221 map
<uint
, uint
>::iterator it
= matrixInfMap
.find(matId
);
2222 if( it
==matrixInfMap
.end() )
2224 uint matInfId
= (uint
)destLod
.MatrixInfluences
.size();
2225 matrixInfMap
.insert( make_pair(matId
, matInfId
) );
2226 // create the new MatrixInfluence.
2227 destLod
.MatrixInfluences
.push_back(matId
);
2238 // Indicate Skinning.
2239 mbuild
.Skinned
= _Skinned
;
2243 bool useTgSpace
= mb
.MeshVertexProgram
!= NULL
? mb
.MeshVertexProgram
->needTangentSpace() : false;
2245 // Construct Blend Shapes
2246 //// mbuild <- finalMRM
2247 mbuild
.BlendShapes
.resize (finalMRM
.MRMBlendShapesFinals
.size());
2248 for (k
= 0; k
< (sint
)mbuild
.BlendShapes
.size(); ++k
)
2250 CBlendShape
&rBS
= mbuild
.BlendShapes
[k
];
2251 sint32 nNbVertVB
= (sint32
)finalMRM
.Wedges
.size();
2252 bool bIsDeltaPos
= false;
2253 rBS
.deltaPos
.resize (nNbVertVB
, CVector(0.0f
,0.0f
,0.0f
));
2254 bool bIsDeltaNorm
= false;
2255 rBS
.deltaNorm
.resize (nNbVertVB
, CVector(0.0f
,0.0f
,0.0f
));
2256 bool bIsDeltaUV
= false;
2257 rBS
.deltaUV
.resize (nNbVertVB
, CUV(0.0f
,0.0f
));
2258 bool bIsDeltaCol
= false;
2259 rBS
.deltaCol
.resize (nNbVertVB
, CRGBAF(0.0f
,0.0f
,0.0f
,0.0f
));
2260 bool bIsDeltaTgSpace
= false;
2263 rBS
.deltaTgSpace
.resize(nNbVertVB
, CVector::Null
);
2266 rBS
.VertRefs
.resize (nNbVertVB
, 0xffffffff);
2268 for (i
= 0; i
< nNbVertVB
; i
++)
2270 const CMRMMeshFinal::CWedge
&rWedgeRef
= finalMRM
.Wedges
[i
];
2271 const CMRMMeshFinal::CWedge
&rWedgeTar
= finalMRM
.MRMBlendShapesFinals
[k
].Wedges
[i
];
2273 CVector delta
= rWedgeTar
.Vertex
- rWedgeRef
.Vertex
;
2276 if (delta
.norm() > 0.001f
)
2278 rBS
.deltaPos
[i
] = delta
;
2279 rBS
.VertRefs
[i
] = i
;
2284 if (vbFlags
& CVertexBuffer::NormalFlag
)
2286 attr
= rWedgeRef
.Attributes
[attId
];
2287 CVector NormRef
= CVector(attr
.x
, attr
.y
, attr
.z
);
2288 attr
= rWedgeTar
.Attributes
[attId
];
2289 CVector NormTar
= CVector(attr
.x
, attr
.y
, attr
.z
);
2290 delta
= NormTar
- NormRef
;
2291 if (delta
.norm() > 0.001f
)
2293 rBS
.deltaNorm
[i
] = delta
;
2294 rBS
.VertRefs
[i
] = i
;
2295 bIsDeltaNorm
= true;
2300 if (vbFlags
& CVertexBuffer::PrimaryColorFlag
)
2302 attr
= rWedgeRef
.Attributes
[attId
];
2303 CRGBAF RGBARef
= CRGBAF(attr
.x
/255.0f
, attr
.y
/255.0f
, attr
.z
/255.0f
, attr
.w
/255.0f
);
2304 attr
= rWedgeTar
.Attributes
[attId
];
2305 CRGBAF RGBATar
= CRGBAF(attr
.x
/255.0f
, attr
.y
/255.0f
, attr
.z
/255.0f
, attr
.w
/255.0f
);
2306 CRGBAF deltaRGBA
= RGBATar
- RGBARef
;
2307 if ((deltaRGBA
.R
*deltaRGBA
.R
+ deltaRGBA
.G
*deltaRGBA
.G
+
2308 deltaRGBA
.B
*deltaRGBA
.B
+ deltaRGBA
.A
*deltaRGBA
.A
) > 0.0001f
)
2310 rBS
.deltaCol
[i
] = deltaRGBA
;
2311 rBS
.VertRefs
[i
] = i
;
2317 if (vbFlags
& CVertexBuffer::SecondaryColorFlag
)
2318 { // Nothing to do !
2322 // Do that only for the UV0
2323 if (vbFlags
& CVertexBuffer::TexCoord0Flag
)
2325 attr
= rWedgeRef
.Attributes
[attId
];
2326 CUV UVRef
= CUV(attr
.x
, attr
.y
);
2327 attr
= rWedgeTar
.Attributes
[attId
];
2328 CUV UVTar
= CUV(attr
.x
, attr
.y
);
2329 CUV deltaUV
= UVTar
- UVRef
;
2330 if ((deltaUV
.U
*deltaUV
.U
+ deltaUV
.V
*deltaUV
.V
) > 0.0001f
)
2332 rBS
.deltaUV
[i
] = deltaUV
;
2333 rBS
.VertRefs
[i
] = i
;
2341 attr
= rWedgeRef
.Attributes
[attId
];
2342 CVector TgSpaceRef
= CVector(attr
.x
, attr
.y
, attr
.z
);
2343 attr
= rWedgeTar
.Attributes
[attId
];
2344 CVector TgSpaceTar
= CVector(attr
.x
, attr
.y
, attr
.z
);
2345 delta
= TgSpaceTar
- TgSpaceRef
;
2346 if (delta
.norm() > 0.001f
)
2348 rBS
.deltaTgSpace
[i
] = delta
;
2349 rBS
.VertRefs
[i
] = i
;
2350 bIsDeltaTgSpace
= true;
2355 } // End of all vertices added in blend shape
2357 // Delete unused items and calculate the number of vertex used (blended)
2359 sint32 nNbVertUsed
= nNbVertVB
;
2361 for (j
= 0; j
< nNbVertVB
; ++j
)
2363 if (rBS
.VertRefs
[j
] == 0xffffffff) // Is vertex UNused
2371 rBS
.VertRefs
[nDstPos
] = rBS
.VertRefs
[j
];
2372 rBS
.deltaPos
[nDstPos
] = rBS
.deltaPos
[j
];
2373 rBS
.deltaNorm
[nDstPos
] = rBS
.deltaNorm
[j
];
2374 rBS
.deltaUV
[nDstPos
] = rBS
.deltaUV
[j
];
2375 rBS
.deltaCol
[nDstPos
] = rBS
.deltaCol
[j
];
2378 rBS
.deltaTgSpace
[nDstPos
] = rBS
.deltaTgSpace
[j
];
2386 rBS
.deltaPos
.resize (nNbVertUsed
);
2388 rBS
.deltaPos
.resize (0);
2391 rBS
.deltaNorm
.resize (nNbVertUsed
);
2393 rBS
.deltaNorm
.resize (0);
2396 rBS
.deltaUV
.resize (nNbVertUsed
);
2398 rBS
.deltaUV
.resize (0);
2401 rBS
.deltaCol
.resize (nNbVertUsed
);
2403 rBS
.deltaCol
.resize (0);
2405 if (bIsDeltaTgSpace
)
2406 rBS
.deltaTgSpace
.resize (nNbVertUsed
);
2408 rBS
.deltaTgSpace
.resize (0);
2411 rBS
.VertRefs
.resize (nNbVertUsed
);
2416 // ***************************************************************************
2417 void CMRMBuilder::buildMeshBuildMrm(const CMRMMeshFinal
&finalMRM
, CMeshMRMSkinnedGeom::CMeshBuildMRM
&mbuild
, uint32 vbFlags
, uint32 nbMats
, const CMesh::CMeshBuild
&mb
)
2422 // reset the mbuild.
2423 mbuild
= CMeshMRMSkinnedGeom::CMeshBuildMRM();
2426 bool useFormatExt
= false;
2427 // Check whether there are texture coordinates with more than 2 compnents, which force us to use an extended vertex format
2428 for (k
= 0; k
< CVertexBuffer::MaxStage
; ++k
)
2431 (vbFlags
& (CVertexBuffer::TexCoord0Flag
<< k
))
2432 && mb
.NumCoords
[k
] != 2)
2434 useFormatExt
= true;
2439 uint numTexCoordUsed
= 0;
2442 for (k
= 0; k
< CVertexBuffer::MaxStage
; ++k
)
2444 if (vbFlags
& (CVertexBuffer::TexCoord0Flag
<< k
))
2446 numTexCoordUsed
= k
;
2452 // setup standard format
2453 mbuild
.VBuffer
.setVertexFormat(vbFlags
);
2455 else // setup extended format
2457 mbuild
.VBuffer
.clearValueEx();
2458 if (vbFlags
& CVertexBuffer::PositionFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Position
, CVertexBuffer::Float3
);
2459 if (vbFlags
& CVertexBuffer::NormalFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Normal
, CVertexBuffer::Float3
);
2460 if (vbFlags
& CVertexBuffer::PrimaryColorFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::PrimaryColor
, CVertexBuffer::UChar4
);
2461 if (vbFlags
& CVertexBuffer::SecondaryColorFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::SecondaryColor
, CVertexBuffer::UChar4
);
2462 if (vbFlags
& CVertexBuffer::WeightFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Weight
, CVertexBuffer::Float4
);
2463 if (vbFlags
& CVertexBuffer::PaletteSkinFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::PaletteSkin
, CVertexBuffer::UChar4
);
2464 if (vbFlags
& CVertexBuffer::FogFlag
) mbuild
.VBuffer
.addValueEx(CVertexBuffer::Fog
, CVertexBuffer::Float1
);
2466 for (k
= 0; k
< CVertexBuffer::MaxStage
; ++k
)
2468 if (vbFlags
& (CVertexBuffer::TexCoord0Flag
<< k
))
2470 switch(mb
.NumCoords
[k
])
2473 mbuild
.VBuffer
.addValueEx((CVertexBuffer::TValue
) (CVertexBuffer::TexCoord0
+ k
), CVertexBuffer::Float2
);
2476 mbuild
.VBuffer
.addValueEx((CVertexBuffer::TValue
) (CVertexBuffer::TexCoord0
+ k
), CVertexBuffer::Float3
);
2484 mbuild
.VBuffer
.initEx();
2487 // Copy the UVRouting
2488 for (i
=0; i
<CVertexBuffer::MaxStage
; i
++)
2490 mbuild
.VBuffer
.setUVRouting (i
, mb
.UVRouting
[i
]);
2493 // Setup the VertexBuffer.
2494 // ========================
2496 mbuild
.VBuffer
.setNumVertices((uint32
)finalMRM
.Wedges
.size());
2498 CVertexBufferReadWrite vba
;
2499 mbuild
.VBuffer
.lock (vba
);
2501 // Setup SkinWeights.
2503 mbuild
.SkinWeights
.resize(finalMRM
.Wedges
.size());
2506 for(i
=0; i
<(sint
)finalMRM
.Wedges
.size(); i
++)
2508 const CMRMMeshFinal::CWedge
&wedge
= finalMRM
.Wedges
[i
];
2511 vba
.setVertexCoord(i
, wedge
.Vertex
);
2513 // seutp attributes.
2516 // For all activated attributes in mbuild, retrieve the attribute from the finalMRM.
2517 if(vbFlags
& CVertexBuffer::NormalFlag
)
2519 vba
.setNormalCoord(i
, wedge
.Attributes
[attId
] );
2522 if(vbFlags
& CVertexBuffer::PrimaryColorFlag
)
2524 vba
.setColor(i
, attToColor(wedge
.Attributes
[attId
]) );
2527 if(vbFlags
& CVertexBuffer::SecondaryColorFlag
)
2529 vba
.setSpecular(i
, attToColor(wedge
.Attributes
[attId
]) );
2532 for(k
=0; k
<CVertexBuffer::MaxStage
;k
++)
2534 if(vbFlags
& (CVertexBuffer::TexCoord0Flag
<<k
))
2536 switch(mb
.NumCoords
[k
])
2539 vba
.setTexCoord(i
, k
, (CUV
) attToUvw(wedge
.Attributes
[attId
]) );
2543 CUVW uvw
= attToUvw(wedge
.Attributes
[attId
]);
2544 vba
.setValueFloat3Ex((CVertexBuffer::TValue
) (CVertexBuffer::TexCoord0
+ k
), i
, uvw
.U
, uvw
.V
, uvw
.W
);
2555 // Setup SkinWeights.
2558 mbuild
.SkinWeights
[i
]= wedge
.VertexSkin
;
2564 // ========================
2566 mbuild
.Lods
.resize(finalMRM
.Lods
.size());
2568 for(i
=0; i
<(sint
)finalMRM
.Lods
.size(); i
++)
2570 const CMRMMeshFinal::CLod
&srcLod
= finalMRM
.Lods
[i
];
2571 CMeshMRMSkinnedGeom::CLod
&destLod
= mbuild
.Lods
[i
];
2576 // Copy NWedges infos.
2577 destLod
.NWedges
= srcLod
.NWedges
;
2578 // Copy Geomorphs infos.
2579 destLod
.Geomorphs
= srcLod
.Geomorphs
;
2582 // Reorder faces by rdrpass.
2585 // First count the number of faces used by this LOD for each material
2586 vector
<sint
> matCount
;
2587 // resize, and reset to 0.
2589 matCount
.resize(nbMats
, 0);
2590 // For each face of this Lods, incr the mat face counter.
2591 for(j
= 0; j
<(sint
)srcLod
.Faces
.size(); j
++)
2593 sint matId
= srcLod
.Faces
[j
].MaterialId
;
2595 nlassert(matId
<(sint
)nbMats
);
2596 // increment the refcount of this material by this LOD.
2600 // Then for each material not empty, create a rdrPass, and ref it for this material.
2601 vector
<sint
> rdrPassIndex
; // material to rdrPass map.
2602 rdrPassIndex
.resize(nbMats
);
2603 for(j
=0; j
<(sint
)nbMats
; j
++)
2606 rdrPassIndex
[j
]= -1;
2609 // map material to rdrPass.
2610 sint idRdrPass
= (sint
)destLod
.RdrPass
.size();
2611 rdrPassIndex
[j
]= idRdrPass
;
2612 // create a rdrPass.
2613 destLod
.RdrPass
.push_back(CMeshMRMSkinnedGeom::CRdrPass());
2614 // assign the good materialId to this rdrPass.
2615 destLod
.RdrPass
[idRdrPass
].MaterialId
= j
;
2616 // reserve the array of faces of this rdrPass.
2617 destLod
.RdrPass
[idRdrPass
].PBlock
.reserve(3*matCount
[j
]);
2621 // Then for each face, add it to the good rdrPass of this Lod.
2622 for(j
= 0; j
<(sint
)srcLod
.Faces
.size(); j
++)
2624 sint matId
= srcLod
.Faces
[j
].MaterialId
;
2625 sint idRdrPass
= rdrPassIndex
[matId
];
2626 // add this face to the good rdrPass.
2627 sint w0
= srcLod
.Faces
[j
].WedgeId
[0];
2628 sint w1
= srcLod
.Faces
[j
].WedgeId
[1];
2629 sint w2
= srcLod
.Faces
[j
].WedgeId
[2];
2630 destLod
.RdrPass
[idRdrPass
].PBlock
.push_back (w0
);
2631 destLod
.RdrPass
[idRdrPass
].PBlock
.push_back (w1
);
2632 destLod
.RdrPass
[idRdrPass
].PBlock
.push_back (w2
);
2636 // Build skin info for this Lod.
2638 for(j
=0; j
<NL3D_MESH_SKINNING_MAX_MATRIX
; j
++)
2640 destLod
.InfluencedVertices
[j
].clear();
2642 destLod
.MatrixInfluences
.clear();
2645 // This is the set which tell what wedge has already been inserted.
2646 set
<uint
> wedgeInfSet
;
2648 // First, build the list of vertices influenced by this Lod.
2649 for(j
= 0; j
<(sint
)srcLod
.Faces
.size(); j
++)
2653 sint wedgeId
= srcLod
.Faces
[j
].WedgeId
[k
];
2654 // If it is a geomorph
2655 if(wedgeId
<finalMRM
.NGeomSpace
)
2657 // add the start and end to the list (if not here). NB: wedgeId is both the id
2658 // of the dest wedge, and the id of the geomorph.
2659 sint wedgeStartId
= destLod
.Geomorphs
[wedgeId
].Start
;
2660 sint wedgeEndId
= destLod
.Geomorphs
[wedgeId
].End
;
2661 uint nMatUsedStart
= finalMRM
.Wedges
[wedgeStartId
].NSkinMatUsed
;
2662 uint nMatUsedEnd
= finalMRM
.Wedges
[wedgeEndId
].NSkinMatUsed
;
2664 // if insertion in the set work, add to the good array.
2665 if( wedgeInfSet
.insert(wedgeStartId
).second
)
2666 destLod
.InfluencedVertices
[nMatUsedStart
-1].push_back(wedgeStartId
);
2667 if( wedgeInfSet
.insert(wedgeEndId
).second
)
2668 destLod
.InfluencedVertices
[nMatUsedEnd
-1].push_back(wedgeEndId
);
2672 uint nMatUsed
= finalMRM
.Wedges
[wedgeId
].NSkinMatUsed
;
2674 // just add this wedge to the list (if not here).
2675 // if insertion in the set work, add to the array.
2676 if( wedgeInfSet
.insert(wedgeId
).second
)
2677 destLod
.InfluencedVertices
[nMatUsed
-1].push_back(wedgeId
);
2682 // Optimisation: for better cache, sort the destLod.InfluencedVertices in increasing order.
2683 for(j
=0; j
<NL3D_MESH_SKINNING_MAX_MATRIX
; j
++)
2685 sort(destLod
.InfluencedVertices
[j
].begin(), destLod
.InfluencedVertices
[j
].end());
2689 // Then Build the MatrixInfluences array, for all thoses Influenced Vertices only.
2690 // This is the map MatrixId -> MatrixInfId.
2691 map
<uint
, uint
> matrixInfMap
;
2693 // For all influenced vertices, flags matrix they use.
2695 for(iSkinMat
= 0; iSkinMat
<NL3D_MESH_SKINNING_MAX_MATRIX
; iSkinMat
++)
2697 for(j
= 0; j
<(sint
)destLod
.InfluencedVertices
[iSkinMat
].size(); j
++)
2699 uint wedgeId
= destLod
.InfluencedVertices
[iSkinMat
][j
];
2701 // take the original wedge.
2702 const CMRMMeshFinal::CWedge
&wedge
= finalMRM
.Wedges
[wedgeId
];
2703 // For all matrix with not null influence...
2704 for(k
= 0; k
<NL3D_MESH_SKINNING_MAX_MATRIX
; k
++)
2706 float matWeight
= wedge
.VertexSkin
.Weights
[k
];
2708 // This check the validity of skin weights sort. If false, problem before in the algo.
2709 if((uint
)k
<iSkinMat
+1)
2711 nlassert( matWeight
>0 );
2715 nlassert( matWeight
==0 );
2717 // if not null influence.
2720 uint matId
= wedge
.VertexSkin
.MatrixId
[k
];
2722 // search/insert the matrixInfId.
2723 map
<uint
, uint
>::iterator it
= matrixInfMap
.find(matId
);
2724 if( it
==matrixInfMap
.end() )
2726 uint matInfId
= (uint
)destLod
.MatrixInfluences
.size();
2727 matrixInfMap
.insert( make_pair(matId
, matInfId
) );
2728 // create the new MatrixInfluence.
2729 destLod
.MatrixInfluences
.push_back(matId
);
2740 // Indicate Skinning.
2741 mbuild
.Skinned
= _Skinned
;
2745 bool useTgSpace
= mb
.MeshVertexProgram
!= NULL
? mb
.MeshVertexProgram
->needTangentSpace() : false;
2747 // Construct Blend Shapes
2748 //// mbuild <- finalMRM
2749 mbuild
.BlendShapes
.resize (finalMRM
.MRMBlendShapesFinals
.size());
2750 for (k
= 0; k
< (sint
)mbuild
.BlendShapes
.size(); ++k
)
2752 CBlendShape
&rBS
= mbuild
.BlendShapes
[k
];
2753 sint32 nNbVertVB
= (sint32
)finalMRM
.Wedges
.size();
2754 bool bIsDeltaPos
= false;
2755 rBS
.deltaPos
.resize (nNbVertVB
, CVector(0.0f
,0.0f
,0.0f
));
2756 bool bIsDeltaNorm
= false;
2757 rBS
.deltaNorm
.resize (nNbVertVB
, CVector(0.0f
,0.0f
,0.0f
));
2758 bool bIsDeltaUV
= false;
2759 rBS
.deltaUV
.resize (nNbVertVB
, CUV(0.0f
,0.0f
));
2760 bool bIsDeltaCol
= false;
2761 rBS
.deltaCol
.resize (nNbVertVB
, CRGBAF(0.0f
,0.0f
,0.0f
,0.0f
));
2762 bool bIsDeltaTgSpace
= false;
2765 rBS
.deltaTgSpace
.resize(nNbVertVB
, CVector::Null
);
2768 rBS
.VertRefs
.resize (nNbVertVB
, 0xffffffff);
2770 for (i
= 0; i
< nNbVertVB
; i
++)
2772 const CMRMMeshFinal::CWedge
&rWedgeRef
= finalMRM
.Wedges
[i
];
2773 const CMRMMeshFinal::CWedge
&rWedgeTar
= finalMRM
.MRMBlendShapesFinals
[k
].Wedges
[i
];
2775 CVector delta
= rWedgeTar
.Vertex
- rWedgeRef
.Vertex
;
2778 if (delta
.norm() > 0.001f
)
2780 rBS
.deltaPos
[i
] = delta
;
2781 rBS
.VertRefs
[i
] = i
;
2786 if (vbFlags
& CVertexBuffer::NormalFlag
)
2788 attr
= rWedgeRef
.Attributes
[attId
];
2789 CVector NormRef
= CVector(attr
.x
, attr
.y
, attr
.z
);
2790 attr
= rWedgeTar
.Attributes
[attId
];
2791 CVector NormTar
= CVector(attr
.x
, attr
.y
, attr
.z
);
2792 delta
= NormTar
- NormRef
;
2793 if (delta
.norm() > 0.001f
)
2795 rBS
.deltaNorm
[i
] = delta
;
2796 rBS
.VertRefs
[i
] = i
;
2797 bIsDeltaNorm
= true;
2802 if (vbFlags
& CVertexBuffer::PrimaryColorFlag
)
2804 attr
= rWedgeRef
.Attributes
[attId
];
2805 CRGBAF RGBARef
= CRGBAF(attr
.x
/255.0f
, attr
.y
/255.0f
, attr
.z
/255.0f
, attr
.w
/255.0f
);
2806 attr
= rWedgeTar
.Attributes
[attId
];
2807 CRGBAF RGBATar
= CRGBAF(attr
.x
/255.0f
, attr
.y
/255.0f
, attr
.z
/255.0f
, attr
.w
/255.0f
);
2808 CRGBAF deltaRGBA
= RGBATar
- RGBARef
;
2809 if ((deltaRGBA
.R
*deltaRGBA
.R
+ deltaRGBA
.G
*deltaRGBA
.G
+
2810 deltaRGBA
.B
*deltaRGBA
.B
+ deltaRGBA
.A
*deltaRGBA
.A
) > 0.0001f
)
2812 rBS
.deltaCol
[i
] = deltaRGBA
;
2813 rBS
.VertRefs
[i
] = i
;
2819 if (vbFlags
& CVertexBuffer::SecondaryColorFlag
)
2820 { // Nothing to do !
2824 // Do that only for the UV0
2825 if (vbFlags
& CVertexBuffer::TexCoord0Flag
)
2827 attr
= rWedgeRef
.Attributes
[attId
];
2828 CUV UVRef
= CUV(attr
.x
, attr
.y
);
2829 attr
= rWedgeTar
.Attributes
[attId
];
2830 CUV UVTar
= CUV(attr
.x
, attr
.y
);
2831 CUV deltaUV
= UVTar
- UVRef
;
2832 if ((deltaUV
.U
*deltaUV
.U
+ deltaUV
.V
*deltaUV
.V
) > 0.0001f
)
2834 rBS
.deltaUV
[i
] = deltaUV
;
2835 rBS
.VertRefs
[i
] = i
;
2843 attr
= rWedgeRef
.Attributes
[attId
];
2844 CVector TgSpaceRef
= CVector(attr
.x
, attr
.y
, attr
.z
);
2845 attr
= rWedgeTar
.Attributes
[attId
];
2846 CVector TgSpaceTar
= CVector(attr
.x
, attr
.y
, attr
.z
);
2847 delta
= TgSpaceTar
- TgSpaceRef
;
2848 if (delta
.norm() > 0.001f
)
2850 rBS
.deltaTgSpace
[i
] = delta
;
2851 rBS
.VertRefs
[i
] = i
;
2852 bIsDeltaTgSpace
= true;
2857 } // End of all vertices added in blend shape
2859 // Delete unused items and calculate the number of vertex used (blended)
2861 sint32 nNbVertUsed
= nNbVertVB
;
2863 for (j
= 0; j
< nNbVertVB
; ++j
)
2865 if (rBS
.VertRefs
[j
] == 0xffffffff) // Is vertex UNused
2873 rBS
.VertRefs
[nDstPos
] = rBS
.VertRefs
[j
];
2874 rBS
.deltaPos
[nDstPos
] = rBS
.deltaPos
[j
];
2875 rBS
.deltaNorm
[nDstPos
] = rBS
.deltaNorm
[j
];
2876 rBS
.deltaUV
[nDstPos
] = rBS
.deltaUV
[j
];
2877 rBS
.deltaCol
[nDstPos
] = rBS
.deltaCol
[j
];
2880 rBS
.deltaTgSpace
[nDstPos
] = rBS
.deltaTgSpace
[j
];
2888 rBS
.deltaPos
.resize (nNbVertUsed
);
2890 rBS
.deltaPos
.resize (0);
2893 rBS
.deltaNorm
.resize (nNbVertUsed
);
2895 rBS
.deltaNorm
.resize (0);
2898 rBS
.deltaUV
.resize (nNbVertUsed
);
2900 rBS
.deltaUV
.resize (0);
2903 rBS
.deltaCol
.resize (nNbVertUsed
);
2905 rBS
.deltaCol
.resize (0);
2907 if (bIsDeltaTgSpace
)
2908 rBS
.deltaTgSpace
.resize (nNbVertUsed
);
2910 rBS
.deltaTgSpace
.resize (0);
2913 rBS
.VertRefs
.resize (nNbVertUsed
);
2918 // ***************************************************************************
2919 void CMRMBuilder::buildBlendShapes (CMRMMesh
& baseMesh
,
2920 std::vector
<CMesh::CMeshBuild
*> &bsList
, uint32 VertexFlags
)
2922 uint32 i
, j
, k
, m
, destIndex
;
2925 vector
<CMRMBlendShape
> &bsMeshes
= baseMesh
.BlendShapes
;
2927 bsMeshes
.resize (bsList
.size());
2929 for (i
= 0; i
< bsList
.size(); ++i
)
2931 // Construct a blend shape like a mrm mesh
2932 nlassert (baseMesh
.Vertices
.size() == bsList
[i
]->Vertices
.size());
2933 bsMeshes
[i
].Vertices
.resize (baseMesh
.Vertices
.size());
2934 bsMeshes
[i
].Vertices
= bsList
[i
]->Vertices
;
2936 bsMeshes
[i
].NumAttributes
= baseMesh
.NumAttributes
;
2937 for (j
= 0; j
< (uint32
)bsMeshes
[i
].NumAttributes
; ++j
)
2938 bsMeshes
[i
].Attributes
[j
].resize(baseMesh
.Attributes
[j
].size());
2940 // For all corners parse the faces (given by the baseMesh) and construct blend shape mrm meshes
2941 for (j
= 0; j
< baseMesh
.Faces
.size(); ++j
)
2942 for (k
= 0; k
< 3; ++k
)
2944 const CMesh::CCorner
&srcCorner
= bsList
[i
]->Faces
[j
].Corner
[k
];
2945 CMRMCorner
&neutralCorner
= baseMesh
.Faces
[j
].Corner
[k
];
2949 if (VertexFlags
& CVertexBuffer::NormalFlag
)
2951 destIndex
= neutralCorner
.Attributes
[attId
];
2952 vh
.x
= srcCorner
.Normal
.x
;
2953 vh
.y
= srcCorner
.Normal
.y
;
2954 vh
.z
= srcCorner
.Normal
.z
;
2956 bsMeshes
[i
].Attributes
[attId
].operator[](destIndex
) = vh
;
2959 if (VertexFlags
& CVertexBuffer::PrimaryColorFlag
)
2961 destIndex
= neutralCorner
.Attributes
[attId
];
2962 vh
.x
= srcCorner
.Color
.R
;
2963 vh
.y
= srcCorner
.Color
.G
;
2964 vh
.z
= srcCorner
.Color
.B
;
2965 vh
.w
= srcCorner
.Color
.A
;
2966 bsMeshes
[i
].Attributes
[attId
].operator[](destIndex
) = vh
;
2969 if (VertexFlags
& CVertexBuffer::SecondaryColorFlag
)
2971 destIndex
= neutralCorner
.Attributes
[attId
];
2972 vh
.x
= srcCorner
.Specular
.R
;
2973 vh
.y
= srcCorner
.Specular
.G
;
2974 vh
.z
= srcCorner
.Specular
.B
;
2975 vh
.w
= srcCorner
.Specular
.A
;
2976 bsMeshes
[i
].Attributes
[attId
].operator[](destIndex
) = vh
;
2979 for (m
= 0; m
< CVertexBuffer::MaxStage
; ++m
)
2981 if (VertexFlags
& (CVertexBuffer::TexCoord0Flag
<<m
))
2983 destIndex
= neutralCorner
.Attributes
[attId
];
2984 vh
.x
= srcCorner
.Uvws
[m
].U
;
2985 vh
.y
= srcCorner
.Uvws
[m
].V
;
2986 vh
.z
= srcCorner
.Uvws
[m
].W
;
2988 bsMeshes
[i
].Attributes
[attId
].operator[](destIndex
) = vh
;
2997 // ***************************************************************************
2998 void CMRMBuilder::compileMRM(const CMesh::CMeshBuild
&mbuild
, std::vector
<CMesh::CMeshBuild
*> &bsList
,
2999 const CMRMParameters
¶ms
, CMeshMRMGeom::CMeshBuildMRM
&mrmMesh
,
3000 uint numMaxMaterial
)
3004 vector
<CMRMMeshGeom
> lodMeshs
;
3005 CMRMMeshFinal finalMRM
;
3006 vector
<CMRMMeshFinal
> finalBsMRM
;
3010 nlassert(params
.DistanceFinest
>=0);
3011 nlassert(params
.DistanceMiddle
> params
.DistanceFinest
);
3012 nlassert(params
.DistanceCoarsest
> params
.DistanceMiddle
);
3015 // Copy some parameters.
3016 _SkinReduction
= params
.SkinReduction
;
3019 _Skinned
= ((mbuild
.VertexFlags
& CVertexBuffer::PaletteSkinFlag
)==CVertexBuffer::PaletteSkinFlag
);
3020 // Skinning is OK only if SkinWeights are of same size as vertices.
3021 _Skinned
= _Skinned
&& ( mbuild
.Vertices
.size()==mbuild
.SkinWeights
.size() );
3023 // MeshInterface setuped ?
3024 _HasMeshInterfaces
= buildMRMSewingMeshes(mbuild
, params
.NLods
, params
.Divisor
);
3026 // from mbuild, build an internal MRM mesh representation.
3027 // vbFlags returned is the VBuffer format supported by CMRMBuilder.
3028 // NB: skinning is removed because skinning is made in software in CMeshMRMGeom.
3029 vbFlags
= buildMrmBaseMesh(mbuild
, baseMesh
);
3031 // Construct all blend shapes in the same way we have constructed the basemesh mrm
3032 buildBlendShapes (baseMesh
, bsList
, vbFlags
);
3034 // If skinned, must ensure that skin weights have weights in ascending order.
3037 normalizeBaseMeshSkin(baseMesh
);
3040 // from this baseMesh, builds all LODs of the MRM, with geomorph info. NB: vertices/wedges are duplicated.
3041 buildAllLods ( baseMesh
, lodMeshs
, params
.NLods
, params
.Divisor
);
3043 // From this array of LOD, build a finalMRM, by regrouping identical vertices/wedges, and compute index geomorphs.
3044 buildFinalMRM(lodMeshs
, finalMRM
);
3046 // From this finalMRM, build output: a CMeshBuildMRM.
3047 buildMeshBuildMrm(finalMRM
, mrmMesh
, vbFlags
, numMaxMaterial
, mbuild
);
3049 // Copy degradation control params.
3050 mrmMesh
.DistanceFinest
= params
.DistanceFinest
;
3051 mrmMesh
.DistanceMiddle
= params
.DistanceMiddle
;
3052 mrmMesh
.DistanceCoarsest
= params
.DistanceCoarsest
;
3056 // ***************************************************************************
3057 void CMRMBuilder::compileMRM(const CMesh::CMeshBuild
&mbuild
, std::vector
<CMesh::CMeshBuild
*> &bsList
,
3058 const CMRMParameters
¶ms
, CMeshMRMSkinnedGeom::CMeshBuildMRM
&mrmMesh
,
3059 uint numMaxMaterial
)
3063 vector
<CMRMMeshGeom
> lodMeshs
;
3064 CMRMMeshFinal finalMRM
;
3065 vector
<CMRMMeshFinal
> finalBsMRM
;
3069 nlassert(params
.DistanceFinest
>=0);
3070 nlassert(params
.DistanceMiddle
> params
.DistanceFinest
);
3071 nlassert(params
.DistanceCoarsest
> params
.DistanceMiddle
);
3074 // Copy some parameters.
3075 _SkinReduction
= params
.SkinReduction
;
3078 _Skinned
= ((mbuild
.VertexFlags
& CVertexBuffer::PaletteSkinFlag
)==CVertexBuffer::PaletteSkinFlag
);
3079 // Skinning is OK only if SkinWeights are of same size as vertices.
3080 _Skinned
= _Skinned
&& ( mbuild
.Vertices
.size()==mbuild
.SkinWeights
.size() );
3082 // MeshInterface setuped ?
3083 _HasMeshInterfaces
= buildMRMSewingMeshes(mbuild
, params
.NLods
, params
.Divisor
);
3085 // from mbuild, build an internal MRM mesh representation.
3086 // vbFlags returned is the VBuffer format supported by CMRMBuilder.
3087 // NB: skinning is removed because skinning is made in software in CMeshMRMGeom.
3088 vbFlags
= buildMrmBaseMesh(mbuild
, baseMesh
);
3090 // Construct all blend shapes in the same way we have constructed the basemesh mrm
3091 buildBlendShapes (baseMesh
, bsList
, vbFlags
);
3093 // If skinned, must ensure that skin weights have weights in ascending order.
3096 normalizeBaseMeshSkin(baseMesh
);
3099 // from this baseMesh, builds all LODs of the MRM, with geomorph info. NB: vertices/wedges are duplicated.
3100 buildAllLods ( baseMesh
, lodMeshs
, params
.NLods
, params
.Divisor
);
3102 // From this array of LOD, build a finalMRM, by regrouping identical vertices/wedges, and compute index geomorphs.
3103 buildFinalMRM(lodMeshs
, finalMRM
);
3105 // From this finalMRM, build output: a CMeshBuildMRM.
3106 buildMeshBuildMrm(finalMRM
, mrmMesh
, vbFlags
, numMaxMaterial
, mbuild
);
3108 // Copy degradation control params.
3109 mrmMesh
.DistanceFinest
= params
.DistanceFinest
;
3110 mrmMesh
.DistanceMiddle
= params
.DistanceMiddle
;
3111 mrmMesh
.DistanceCoarsest
= params
.DistanceCoarsest
;
3115 // ***************************************************************************
3116 // ***************************************************************************
3117 // MRM Interface system
3118 // ***************************************************************************
3119 // ***************************************************************************
3121 // ***************************************************************************
3122 bool CMRMBuilder::buildMRMSewingMeshes(const CMesh::CMeshBuild
&mbuild
, uint nWantedLods
, uint divisor
)
3124 nlassert(nWantedLods
>=1);
3125 nlassert(divisor
>=1);
3126 if(mbuild
.Interfaces
.empty())
3128 // must have same size
3129 if(mbuild
.InterfaceLinks
.size()!=mbuild
.Vertices
.size())
3132 // **** For each interface, MRM-ize it and store.
3133 _SewingMeshes
.resize(mbuild
.Interfaces
.size());
3134 for(uint i
=0;i
<mbuild
.Interfaces
.size();i
++)
3136 _SewingMeshes
[i
].build(mbuild
.Interfaces
[i
], nWantedLods
, divisor
);