/src/assimp/code/PostProcessing/ScaleProcess.cpp
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2026, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | #include "ScaleProcess.h" |
42 | | |
43 | | #include <assimp/scene.h> |
44 | | #include <assimp/postprocess.h> |
45 | | #include <assimp/BaseImporter.h> |
46 | | |
47 | | namespace Assimp { |
48 | | |
49 | | // ------------------------------------------------------------------------------------------------ |
50 | 297 | ScaleProcess::ScaleProcess() : BaseProcess(), mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { |
51 | | // empty |
52 | 297 | } |
53 | | |
54 | | // ------------------------------------------------------------------------------------------------ |
55 | 0 | void ScaleProcess::setScale( ai_real scale ) { |
56 | 0 | mScale = scale; |
57 | 0 | } |
58 | | |
59 | | // ------------------------------------------------------------------------------------------------ |
60 | 0 | ai_real ScaleProcess::getScale() const { |
61 | 0 | return mScale; |
62 | 0 | } |
63 | | |
64 | | // ------------------------------------------------------------------------------------------------ |
65 | 218 | bool ScaleProcess::IsActive( unsigned int pFlags ) const { |
66 | 218 | return ( pFlags & aiProcess_GlobalScale ) != 0; |
67 | 218 | } |
68 | | |
69 | | // ------------------------------------------------------------------------------------------------ |
70 | 0 | void ScaleProcess::SetupProperties( const Importer* pImp ) { |
71 | | // User scaling |
72 | 0 | mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f ); |
73 | | |
74 | | // File scaling * Application Scaling |
75 | 0 | float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f ); |
76 | | |
77 | | // apply scale to the scale |
78 | | // helps prevent bugs with backward compatibility for anyone using normal scaling. |
79 | 0 | mScale *= importerScale; |
80 | 0 | } |
81 | | |
82 | | // ------------------------------------------------------------------------------------------------ |
83 | 0 | void ScaleProcess::Execute( aiScene* pScene ) { |
84 | 0 | if(mScale == 1.0f) { |
85 | 0 | return; // nothing to scale |
86 | 0 | } |
87 | | |
88 | 0 | ai_assert(mScale != 0 ); |
89 | 0 | ai_assert(nullptr != pScene ); |
90 | 0 | ai_assert(nullptr != pScene->mRootNode ); |
91 | |
|
92 | 0 | if ( nullptr == pScene ) { |
93 | 0 | return; |
94 | 0 | } |
95 | | |
96 | 0 | if ( nullptr == pScene->mRootNode ) { |
97 | 0 | return; |
98 | 0 | } |
99 | | |
100 | | // Process animations and update position transform to new unit system |
101 | 0 | for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) { |
102 | 0 | aiAnimation* animation = pScene->mAnimations[animationID]; |
103 | |
|
104 | 0 | for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) { |
105 | 0 | aiNodeAnim* anim = animation->mChannels[animationChannel]; |
106 | |
|
107 | 0 | for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) { |
108 | 0 | aiVectorKey& vectorKey = anim->mPositionKeys[posKey]; |
109 | 0 | vectorKey.mValue *= mScale; |
110 | 0 | } |
111 | 0 | } |
112 | 0 | } |
113 | |
|
114 | 0 | for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) { |
115 | 0 | aiMesh *mesh = pScene->mMeshes[meshID]; |
116 | | |
117 | | // Reconstruct mesh vertices to the new unit system |
118 | 0 | for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) { |
119 | 0 | aiVector3D& vertex = mesh->mVertices[vertexID]; |
120 | 0 | vertex *= mScale; |
121 | 0 | } |
122 | | |
123 | | // bone placement / scaling |
124 | 0 | for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) { |
125 | | // Reconstruct matrix by transform rather than by scale |
126 | | // This prevent scale values being changed which can |
127 | | // be meaningful in some cases |
128 | | // like when you want the modeller to see 1:1 compatibility. |
129 | 0 | aiBone* bone = mesh->mBones[boneID]; |
130 | |
|
131 | 0 | aiVector3D pos, scale; |
132 | 0 | aiQuaternion rotation; |
133 | |
|
134 | 0 | bone->mOffsetMatrix.Decompose( scale, rotation, pos); |
135 | |
|
136 | 0 | aiMatrix4x4 translation; |
137 | 0 | aiMatrix4x4::Translation( pos * mScale, translation ); |
138 | |
|
139 | 0 | aiMatrix4x4 scaling; |
140 | 0 | aiMatrix4x4::Scaling( aiVector3D(scale), scaling ); |
141 | |
|
142 | 0 | const aiMatrix4x4 RotMatrix = aiMatrix4x4(rotation.GetMatrix()); |
143 | |
|
144 | 0 | bone->mOffsetMatrix = translation * RotMatrix * scaling; |
145 | 0 | } |
146 | | |
147 | | |
148 | | // animation mesh processing |
149 | | // convert by position rather than scale. |
150 | 0 | for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) { |
151 | 0 | aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID]; |
152 | |
|
153 | 0 | for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) { |
154 | 0 | aiVector3D& vertex = animMesh->mVertices[vertexID]; |
155 | 0 | vertex *= mScale; |
156 | 0 | } |
157 | 0 | } |
158 | 0 | } |
159 | |
|
160 | 0 | traverseNodes( pScene->mRootNode ); |
161 | 0 | } |
162 | | |
163 | | // ------------------------------------------------------------------------------------------------ |
164 | 0 | void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) { |
165 | 0 | applyScaling( node ); |
166 | |
|
167 | 0 | for( size_t i = 0; i < node->mNumChildren; i++) { |
168 | | // recurse into the tree until we are done! |
169 | 0 | traverseNodes( node->mChildren[i], nested_node_id+1 ); |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | // ------------------------------------------------------------------------------------------------ |
174 | 0 | void ScaleProcess::applyScaling( aiNode *currentNode ) { |
175 | 0 | if ( nullptr != currentNode ) { |
176 | | // Reconstruct matrix by transform rather than by scale |
177 | | // This prevent scale values being changed which can |
178 | | // be meaningful in some cases |
179 | | // like when you want the modeller to |
180 | | // see 1:1 compatibility. |
181 | |
|
182 | 0 | aiVector3D pos, scale; |
183 | 0 | aiQuaternion rotation; |
184 | 0 | currentNode->mTransformation.Decompose( scale, rotation, pos); |
185 | |
|
186 | 0 | aiMatrix4x4 translation; |
187 | 0 | aiMatrix4x4::Translation( pos * mScale, translation ); |
188 | |
|
189 | 0 | aiMatrix4x4 scaling; |
190 | | |
191 | | // note: we do not use mScale here, this is on purpose. |
192 | 0 | aiMatrix4x4::Scaling( scale, scaling ); |
193 | |
|
194 | 0 | aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); |
195 | |
|
196 | 0 | currentNode->mTransformation = translation * RotMatrix * scaling; |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | } // Namespace Assimp |