rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 Open Asset Import Library (assimp)
|
nuclear@0
|
3 ----------------------------------------------------------------------
|
nuclear@0
|
4
|
nuclear@0
|
5 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
6 All rights reserved.
|
nuclear@0
|
7
|
nuclear@0
|
8 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
9 with or without modification, are permitted provided that the
|
nuclear@0
|
10 following conditions are met:
|
nuclear@0
|
11
|
nuclear@0
|
12 * Redistributions of source code must retain the above
|
nuclear@0
|
13 copyright notice, this list of conditions and the
|
nuclear@0
|
14 following disclaimer.
|
nuclear@0
|
15
|
nuclear@0
|
16 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
17 copyright notice, this list of conditions and the
|
nuclear@0
|
18 following disclaimer in the documentation and/or other
|
nuclear@0
|
19 materials provided with the distribution.
|
nuclear@0
|
20
|
nuclear@0
|
21 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
22 contributors may be used to endorse or promote products
|
nuclear@0
|
23 derived from this software without specific prior
|
nuclear@0
|
24 written permission of the assimp team.
|
nuclear@0
|
25
|
nuclear@0
|
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
37
|
nuclear@0
|
38 ----------------------------------------------------------------------
|
nuclear@0
|
39 */
|
nuclear@0
|
40
|
nuclear@0
|
41 /** Implementation of the LimitBoneWeightsProcess post processing step */
|
nuclear@0
|
42
|
nuclear@0
|
43 #include "AssimpPCH.h"
|
nuclear@0
|
44 #include "LimitBoneWeightsProcess.h"
|
nuclear@0
|
45
|
nuclear@0
|
46
|
nuclear@0
|
47 using namespace Assimp;
|
nuclear@0
|
48
|
nuclear@0
|
49
|
nuclear@0
|
50 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
51 // Constructor to be privately used by Importer
|
nuclear@0
|
52 LimitBoneWeightsProcess::LimitBoneWeightsProcess()
|
nuclear@0
|
53 {
|
nuclear@0
|
54 mMaxWeights = AI_LMW_MAX_WEIGHTS;
|
nuclear@0
|
55 }
|
nuclear@0
|
56
|
nuclear@0
|
57 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
58 // Destructor, private as well
|
nuclear@0
|
59 LimitBoneWeightsProcess::~LimitBoneWeightsProcess()
|
nuclear@0
|
60 {
|
nuclear@0
|
61 // nothing to do here
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
65 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
66 bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const
|
nuclear@0
|
67 {
|
nuclear@0
|
68 return (pFlags & aiProcess_LimitBoneWeights) != 0;
|
nuclear@0
|
69 }
|
nuclear@0
|
70
|
nuclear@0
|
71 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
72 // Executes the post processing step on the given imported data.
|
nuclear@0
|
73 void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
nuclear@0
|
74 {
|
nuclear@0
|
75 DefaultLogger::get()->debug("LimitBoneWeightsProcess begin");
|
nuclear@0
|
76 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
nuclear@0
|
77 ProcessMesh( pScene->mMeshes[a]);
|
nuclear@0
|
78
|
nuclear@0
|
79 DefaultLogger::get()->debug("LimitBoneWeightsProcess end");
|
nuclear@0
|
80 }
|
nuclear@0
|
81
|
nuclear@0
|
82 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
83 // Executes the post processing step on the given imported data.
|
nuclear@0
|
84 void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
|
nuclear@0
|
85 {
|
nuclear@0
|
86 // get the current value of the property
|
nuclear@0
|
87 this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
|
nuclear@0
|
88 }
|
nuclear@0
|
89
|
nuclear@0
|
90 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
91 // Unites identical vertices in the given mesh
|
nuclear@0
|
92 void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
|
nuclear@0
|
93 {
|
nuclear@0
|
94 if( !pMesh->HasBones())
|
nuclear@0
|
95 return;
|
nuclear@0
|
96
|
nuclear@0
|
97 // collect all bone weights per vertex
|
nuclear@0
|
98 typedef std::vector< std::vector< Weight > > WeightsPerVertex;
|
nuclear@0
|
99 WeightsPerVertex vertexWeights( pMesh->mNumVertices);
|
nuclear@0
|
100
|
nuclear@0
|
101 // collect all weights per vertex
|
nuclear@0
|
102 for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 const aiBone* bone = pMesh->mBones[a];
|
nuclear@0
|
105 for( unsigned int b = 0; b < bone->mNumWeights; b++)
|
nuclear@0
|
106 {
|
nuclear@0
|
107 const aiVertexWeight& w = bone->mWeights[b];
|
nuclear@0
|
108 vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight));
|
nuclear@0
|
109 }
|
nuclear@0
|
110 }
|
nuclear@0
|
111
|
nuclear@0
|
112 unsigned int removed = 0, old_bones = pMesh->mNumBones;
|
nuclear@0
|
113
|
nuclear@0
|
114 // now cut the weight count if it exceeds the maximum
|
nuclear@0
|
115 bool bChanged = false;
|
nuclear@0
|
116 for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
|
nuclear@0
|
117 {
|
nuclear@0
|
118 if( vit->size() <= mMaxWeights)
|
nuclear@0
|
119 continue;
|
nuclear@0
|
120
|
nuclear@0
|
121 bChanged = true;
|
nuclear@0
|
122
|
nuclear@0
|
123 // more than the defined maximum -> first sort by weight in descending order. That's
|
nuclear@0
|
124 // why we defined the < operator in such a weird way.
|
nuclear@0
|
125 std::sort( vit->begin(), vit->end());
|
nuclear@0
|
126
|
nuclear@0
|
127 // now kill everything beyond the maximum count
|
nuclear@0
|
128 unsigned int m = vit->size();
|
nuclear@0
|
129 vit->erase( vit->begin() + mMaxWeights, vit->end());
|
nuclear@0
|
130 removed += m-vit->size();
|
nuclear@0
|
131
|
nuclear@0
|
132 // and renormalize the weights
|
nuclear@0
|
133 float sum = 0.0f;
|
nuclear@0
|
134 for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it)
|
nuclear@0
|
135 sum += it->mWeight;
|
nuclear@0
|
136 for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it)
|
nuclear@0
|
137 it->mWeight /= sum;
|
nuclear@0
|
138 }
|
nuclear@0
|
139
|
nuclear@0
|
140 if (bChanged) {
|
nuclear@0
|
141 // rebuild the vertex weight array for all bones
|
nuclear@0
|
142 typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone;
|
nuclear@0
|
143 WeightsPerBone boneWeights( pMesh->mNumBones);
|
nuclear@0
|
144 for( unsigned int a = 0; a < vertexWeights.size(); a++)
|
nuclear@0
|
145 {
|
nuclear@0
|
146 const std::vector<Weight>& vw = vertexWeights[a];
|
nuclear@0
|
147 for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it)
|
nuclear@0
|
148 boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight));
|
nuclear@0
|
149 }
|
nuclear@0
|
150
|
nuclear@0
|
151 // and finally copy the vertex weight list over to the mesh's bones
|
nuclear@0
|
152 std::vector<bool> abNoNeed(pMesh->mNumBones,false);
|
nuclear@0
|
153 bChanged = false;
|
nuclear@0
|
154
|
nuclear@0
|
155 for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
nuclear@0
|
156 {
|
nuclear@0
|
157 const std::vector<aiVertexWeight>& bw = boneWeights[a];
|
nuclear@0
|
158 aiBone* bone = pMesh->mBones[a];
|
nuclear@0
|
159
|
nuclear@0
|
160 // ignore the bone if no vertex weights were removed there
|
nuclear@0
|
161
|
nuclear@0
|
162 // FIX (Aramis, 07|22|08)
|
nuclear@0
|
163 // NO! we can't ignore it in this case ... it is possible that
|
nuclear@0
|
164 // the number of weights did not change, but the weight values did.
|
nuclear@0
|
165
|
nuclear@0
|
166 // if( bw.size() == bone->mNumWeights)
|
nuclear@0
|
167 // continue;
|
nuclear@0
|
168
|
nuclear@0
|
169 // FIX (Aramis, 07|21|08)
|
nuclear@0
|
170 // It is possible that all weights of a bone have been removed.
|
nuclear@0
|
171 // This would naturally cause an exception in &bw[0].
|
nuclear@0
|
172 if ( bw.empty() )
|
nuclear@0
|
173 {
|
nuclear@0
|
174 abNoNeed[a] = bChanged = true;
|
nuclear@0
|
175 continue;
|
nuclear@0
|
176 }
|
nuclear@0
|
177
|
nuclear@0
|
178 // copy the weight list. should always be less weights than before, so we don't need a new allocation
|
nuclear@0
|
179 ai_assert( bw.size() <= bone->mNumWeights);
|
nuclear@0
|
180 bone->mNumWeights = (unsigned int) bw.size();
|
nuclear@0
|
181 ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
|
nuclear@0
|
182 }
|
nuclear@0
|
183
|
nuclear@0
|
184 if (bChanged) {
|
nuclear@0
|
185 // the number of new bones is smaller than before, so we can reuse the old array
|
nuclear@0
|
186 aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur;
|
nuclear@0
|
187
|
nuclear@0
|
188 for (std::vector<bool>::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) {
|
nuclear@0
|
189 if (*iter) {
|
nuclear@0
|
190 delete *ppcSrc;
|
nuclear@0
|
191 --pMesh->mNumBones;
|
nuclear@0
|
192 }
|
nuclear@0
|
193 else *ppcCur++ = *ppcSrc;
|
nuclear@0
|
194 ++ppcSrc;
|
nuclear@0
|
195 }
|
nuclear@0
|
196 }
|
nuclear@0
|
197
|
nuclear@0
|
198 if (!DefaultLogger::isNullLogger()) {
|
nuclear@0
|
199 char buffer[1024];
|
nuclear@0
|
200 ::sprintf(buffer,"Removed %i weights. Input bones: %i. Output bones: %i",removed,old_bones,pMesh->mNumBones);
|
nuclear@0
|
201 DefaultLogger::get()->info(buffer);
|
nuclear@0
|
202 }
|
nuclear@0
|
203 }
|
nuclear@0
|
204 }
|