assimpAppMesh.cpp
Engine/source/ts/assimp/assimpAppMesh.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "ts/collada/colladaExtensions.h" 26#include "ts/assimp/assimpAppMesh.h" 27#include "ts/assimp/assimpAppNode.h" 28 29// assimp include files. 30#include <assimp/cimport.h> 31#include <assimp/scene.h> 32#include <assimp/postprocess.h> 33#include <assimp/types.h> 34 35bool AssimpAppMesh::fixedSizeEnabled = false; 36S32 AssimpAppMesh::fixedSize = 2; 37 38//------------------------------------------------------------------------------ 39 40AssimpAppMesh::AssimpAppMesh(const struct aiMesh* mesh, AssimpAppNode* node) 41 : mMeshData(mesh), appNode(node) 42{ 43 Con::printf("[ASSIMP] Mesh Created: %s", getName()); 44 45 // See if it's a skinned mesh 46 mIsSkinMesh = false; 47 for (U32 b = 0; b < mesh->mNumBones; b++) 48 if (mMeshData->mBones[b]->mNumWeights > 0) 49 { 50 mIsSkinMesh = true; 51 break; 52 } 53} 54 55const char* AssimpAppMesh::getName(bool allowFixed) 56{ 57 // Some exporters add a 'PIVOT' or unnamed node between the mesh and the 58 // actual object node. Detect this and return the object node name instead 59 // of the pivot node. 60 const char* nodeName = appNode->getName(); 61 if ( dStrEqual(nodeName, "null") || dStrEndsWith(nodeName, "PIVOT") ) 62 nodeName = appNode->getParentName(); 63 64 // If all geometry is being fixed to the same size, append the size 65 // to the name 66 return allowFixed && fixedSizeEnabled ? avar("%s %d", nodeName, fixedSize) : nodeName; 67} 68 69MatrixF AssimpAppMesh::getMeshTransform(F32 time) 70{ 71 return appNode->getNodeTransform(time); 72} 73 74void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset) 75{ 76 // After this function, the following are expected to be populated: 77 // points, normals, uvs, primitives, indices 78 // There is also colors and uv2s but those don't seem to be required. 79 points.reserve(mMeshData->mNumVertices); 80 uvs.reserve(mMeshData->mNumVertices); 81 normals.reserve(mMeshData->mNumVertices); 82 83 bool flipNormals = ColladaUtils::getOptions().invertNormals; 84 85 bool noUVFound = false; 86 for (U32 i = 0; i<mMeshData->mNumVertices; i++) 87 { 88 // Points and Normals 89 aiVector3D pt = mMeshData->mVertices[i]; 90 aiVector3D nrm; 91 if (mMeshData->HasNormals()) 92 nrm = mMeshData->mNormals[i]; 93 else 94 nrm.Set(0, 0, 0); 95 96 Point3F tmpVert; 97 Point3F tmpNormal; 98 99 tmpVert = Point3F(pt.x, pt.y, pt.z); 100 tmpNormal = Point3F(nrm.x, nrm.y, nrm.z); 101 if (flipNormals) 102 tmpNormal *= -1.0f; 103 104 objOffset.mulP(tmpVert); 105 106 points.push_back(tmpVert); 107 108 if (mMeshData->HasTextureCoords(0)) 109 { 110 uvs.push_back(Point2F(mMeshData->mTextureCoords[0][i].x, mMeshData->mTextureCoords[0][i].y)); 111 } 112 else 113 { 114 // I don't know if there's any solution to this issue. 115 // If it's not mapped, it's not mapped. 116 noUVFound = true; 117 uvs.push_back(Point2F(1, 1)); 118 } 119 120 // UV2s 121 if (mMeshData->HasTextureCoords(1)) 122 { 123 uv2s.push_back(Point2F(mMeshData->mTextureCoords[1][i].x, mMeshData->mTextureCoords[1][i].y)); 124 } 125 126 // Vertex Colors 127 if (mMeshData->HasVertexColors(0)) 128 { 129 LinearColorF vColor(mMeshData->mColors[0][i].r, 130 mMeshData->mColors[0][i].g, 131 mMeshData->mColors[0][i].b, 132 mMeshData->mColors[0][i].a); 133 colors.push_back(vColor.toColorI()); 134 } 135 136 //uvs.push_back(mModel->mVerts[i].texcoord); 137 normals.push_back(tmpNormal); 138 //edgeVerts.push_back(mModel->mVerts[i].edge); 139 } 140 141 U32 numFaces = mMeshData->mNumFaces; 142 //primitives.reserve(numFaces); 143 144 //Fetch the number of indices 145 U32 indicesCount = 0; 146 for (U32 i = 0; i < numFaces; i++) 147 { 148 indicesCount += mMeshData->mFaces[i].mNumIndices; 149 } 150 151 indices.reserve(indicesCount); 152 153 // Create TSMesh primitive 154 primitives.increment(); 155 TSDrawPrimitive& primitive = primitives.last(); 156 primitive.start = 0; 157 primitive.matIndex = (TSDrawPrimitive::Triangles | TSDrawPrimitive::Indexed) | (S32)mMeshData->mMaterialIndex; 158 primitive.numElements = indicesCount; 159 160 for ( U32 n = 0; n < mMeshData->mNumFaces; ++n) 161 { 162 const struct aiFace* face = &mMeshData->mFaces[n]; 163 if ( face->mNumIndices == 3 ) 164 { 165 U32 indexCount = face->mNumIndices; 166 for (U32 ind = 0; ind < indexCount; ind++) 167 { 168 U32 index = face->mIndices[ind]; 169 indices.push_back(index); 170 } 171 } 172 else 173 { 174 Con::printf("[ASSIMP] Non-Triangle Face Found. Indices: %d", face->mNumIndices); 175 } 176 } 177 178 U32 boneCount = mMeshData->mNumBones; 179 bones.setSize(boneCount); 180 181 // Count the total number of weights for all of the bones. 182 U32 totalWeights = 0; 183 U32 nonZeroWeights = 0; 184 for (U32 b = 0; b < boneCount; b++) 185 totalWeights += mMeshData->mBones[b]->mNumWeights; 186 187 // Assimp gives weights sorted by bone index. We need them in vertex order. 188 Vector<F32> tmpWeight; 189 Vector<S32> tmpBoneIndex; 190 Vector<S32> tmpVertexIndex; 191 tmpWeight.setSize(totalWeights); 192 tmpBoneIndex.setSize(totalWeights); 193 tmpVertexIndex.setSize(totalWeights); 194 195 for (U32 b = 0; b < boneCount; b++) 196 { 197 String name = mMeshData->mBones[b]->mName.C_Str(); 198 aiNode* nodePtr = AssimpAppNode::findChildNodeByName(mMeshData->mBones[b]->mName.C_Str(), appNode->mScene->mRootNode); 199 if (!nodePtr) 200 bones[b] = new AssimpAppNode(appNode->mScene, appNode->mNode); 201 else 202 bones[b] = new AssimpAppNode(appNode->mScene, nodePtr); 203 204 MatrixF boneTransform; 205 AssimpAppNode::assimpToTorqueMat(mMeshData->mBones[b]->mOffsetMatrix, boneTransform); 206 Point3F boneScale = boneTransform.getScale(); 207 Point3F bonePos = boneTransform.getPosition(); 208 if (boneScale != Point3F::One && ColladaUtils::getOptions().ignoreNodeScale) 209 { 210 Point3F scaleMult = Point3F::One / boneScale; 211 boneTransform.scale(scaleMult); 212 bonePos /= scaleMult; 213 } 214 215 bonePos *= ColladaUtils::getOptions().unit * ColladaUtils::getOptions().formatScaleFactor; 216 boneTransform.setPosition(bonePos); 217 218 initialTransforms.push_back(boneTransform); 219 220 //Weights 221 U32 numWeights = mMeshData->mBones[b]->mNumWeights; 222 223 for (U32 w = 0; w < numWeights; ++w) 224 { 225 aiVertexWeight* aiWeight = &mMeshData->mBones[b]->mWeights[w]; 226 227 if (aiWeight->mWeight > 0.0f) 228 { 229 tmpWeight[nonZeroWeights] = aiWeight->mWeight; 230 tmpVertexIndex[nonZeroWeights] = aiWeight->mVertexId; 231 tmpBoneIndex[nonZeroWeights] = b; 232 nonZeroWeights++; 233 } 234 } 235 } 236 237 weight.setSize(nonZeroWeights); 238 vertexIndex.setSize(nonZeroWeights); 239 boneIndex.setSize(nonZeroWeights); 240 241 // Copy the weights to our vectors in vertex order and 242 // normalize vertex weights (force weights for each vert to sum to 1) 243 U32 nextWeight = 0; 244 for (U32 i = 0; i < mMeshData->mNumVertices; ++i) 245 { 246 U32 vertStart = nextWeight; 247 F32 invTotalWeight = 0; 248 for (U32 ind = 0; ind < nonZeroWeights; ++ind) 249 { 250 if (tmpVertexIndex[ind] == i) 251 { 252 weight[nextWeight] = tmpWeight[ind]; 253 invTotalWeight += tmpWeight[ind]; 254 vertexIndex[nextWeight] = tmpVertexIndex[ind]; 255 boneIndex[nextWeight] = tmpBoneIndex[ind]; 256 nextWeight++; 257 } 258 } 259 260 // Now normalize the vertex weights 261 if (invTotalWeight > 0.0) 262 { 263 invTotalWeight = 1.0f / invTotalWeight; 264 for (U32 ind = vertStart; ind < nextWeight; ++ind) 265 weight[ind] *= invTotalWeight; 266 } 267 } 268 269 if ( noUVFound ) 270 Con::warnf("[ASSIMP] No UV Data for mesh."); 271} 272 273void AssimpAppMesh::lookupSkinData() 274{ // This function is intentionally left blank. The skin data - bones, weights and indexes are 275 // processed in lockMesh() with the rest of the mesh data. 276} 277 278F32 AssimpAppMesh::getVisValue(F32 t) 279{ 280 return 1.0f; 281} 282