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

source code of qtquick3d/src/3rdparty/assimp/src/code/PostProcessing/ScaleProcess.cpp