Ticket #1012: collada_import_fixes-12092011.patch
File collada_import_fixes-12092011.patch, 8.2 KB (added by , 12 years ago) |
---|
-
source/collada/PMDConvert.cpp
252 252 // guaranteed by ReduceInfluences; necessary for avoiding 253 253 // out-of-bounds writes to the VertexBlend 254 254 255 if (vertexInfluences[i].GetPairCount() == 0) 256 { 257 // Blender exports some models with vertices that have no influences, 258 // which I've not found details about in the COLLADA spec, however, 259 // it seems to work OK to treat these vertices the same as if they 260 // were only influenced by the bind-shape matrix (see comment below), 261 // so we use the same special case here. 262 influences.bones[0] = (uint8)jointCount; 263 influences.weights[0] = 1.0f; 264 } 265 255 266 for (size_t j = 0; j < vertexInfluences[i].GetPairCount(); ++j) 256 267 { 257 uint32 jointIdx = vertexInfluences[i].GetPair(j)->jointIndex; 258 REQUIRE(jointIdx <= 0xFF, "sensible number of joints (<256)"); // because we only have a u8 to store them in 268 if (vertexInfluences[i].GetPair(j)->jointIndex == -1) 269 { 270 // This is a special case we must handle, according to the COLLADA spec: 271 // "An index of -1 into the array of joints refers to the bind shape" 272 // which basically means when skinning the vertex it's relative to the 273 // bind-shape transform instead of an animated bone. Since our skinning 274 // is in world space, we will have already applied the bind-shape transform, 275 // so we don't have to worry about that, though we DO have to apply the 276 // world space transform of the model for the indicated vertex. 277 // 278 // To indicate this special case, we use a bone ID set to the total number 279 // of bones in the model, which will have a special "bone matrix" reserved 280 // that contains the world space transform of the model during skinning. 281 // (see http://trac.wildfiregames.com/ticket/1012) 282 influences.bones[j] = (uint8)jointCount; 283 influences.weights[j] = vertexInfluences[i].GetPair(j)->weight; 284 } 285 else 286 { 287 uint32 jointIdx = vertexInfluences[i].GetPair(j)->jointIndex; 288 REQUIRE(jointIdx < 0xFF, "sensible number of joints (<255)"); // because we only have a u8 to store them in 259 289 260 // Find the joint on the skeleton, after checking it really exists261 FCDSceneNode* joint = NULL;262 if (jointIdx < controllerInstance.GetJointCount())263 joint = controllerInstance.GetJoint(jointIdx);290 // Find the joint on the skeleton, after checking it really exists 291 FCDSceneNode* joint = NULL; 292 if (jointIdx < controllerInstance.GetJointCount()) 293 joint = controllerInstance.GetJoint(jointIdx); 264 294 265 // Complain on error 266 if (! joint) 267 { 268 if (! hasComplainedAboutNonexistentJoints) 295 // Complain on error 296 if (! joint) 269 297 { 270 Log(LOG_WARNING, "Vertexes influenced by nonexistent joint"); 271 hasComplainedAboutNonexistentJoints = true; 298 if (! hasComplainedAboutNonexistentJoints) 299 { 300 Log(LOG_WARNING, "Vertexes influenced by nonexistent joint"); 301 hasComplainedAboutNonexistentJoints = true; 302 } 303 continue; 272 304 } 273 continue;274 }275 305 276 // Store into the VertexBlend 277 int boneId = skeleton.GetBoneID(joint->GetName().c_str()); 278 if (boneId < 0) 279 { 280 // The relevant joint does exist, but it's not a recognised 281 // bone in our chosen skeleton structure 282 Log(LOG_ERROR, "Vertex influenced by unrecognised bone '%s'", joint->GetName().c_str()); 283 continue; 306 // Store into the VertexBlend 307 int boneId = skeleton.GetBoneID(joint->GetName().c_str()); 308 if (boneId < 0) 309 { 310 // The relevant joint does exist, but it's not a recognised 311 // bone in our chosen skeleton structure 312 Log(LOG_ERROR, "Vertex influenced by unrecognised bone '%s'", joint->GetName().c_str()); 313 continue; 314 } 315 316 influences.bones[j] = (uint8)boneId; 317 influences.weights[j] = vertexInfluences[i].GetPair(j)->weight; 284 318 } 285 286 influences.bones[j] = (uint8)boneId;287 influences.weights[j] = vertexInfluences[i].GetPair(j)->weight;288 319 } 289 320 290 321 boneWeights.push_back(influences); … … 522 553 /** 523 554 * Applies world-space transform to vertex data and transforms Collada's right-handed 524 555 * Y-up / Z-up coordinates to the game's left-handed Y-up coordinate system 556 * 557 * TODO: Maybe we should use FCDocumentTools::StandardizeUpAxisAndLength in addition 558 * to this, so we'd only have one up-axis case to worry about, but it doesn't seem to 559 * correctly adjust the prop points in Y_UP models. 525 560 */ 526 561 static void TransformStaticModel(float* position, float* normal, size_t vertexCount, 527 562 const FMMatrix44& transform, bool yUp) … … 563 598 /** 564 599 * Applies world-space transform to vertex data and transforms Collada's right-handed 565 600 * Y-up / Z-up coordinates to the game's left-handed Y-up coordinate system 601 * 602 * TODO: Maybe we should use FCDocumentTools::StandardizeUpAxisAndLength in addition 603 * to this, so we'd only have one up-axis case to worry about, but it doesn't seem to 604 * correctly adjust the prop points in Y_UP models. 566 605 */ 567 606 static void TransformSkinnedModel(float* position, float* normal, size_t vertexCount, 568 607 std::vector<BoneTransform>& bones, std::vector<PropPoint>& propPoints, -
source/graphics/Model.cpp
84 84 size_t numBlends = modeldef->GetNumBlends(); 85 85 86 86 // allocate matrices for bone transformations 87 m_BoneMatrices = (CMatrix3D*)rtl_AllocateAligned(sizeof(CMatrix3D) * (numBones + numBlends), 16); 87 // (one extra matrix is used for the special case of bind-shape relative weighting) 88 m_BoneMatrices = (CMatrix3D*)rtl_AllocateAligned(sizeof(CMatrix3D) * (numBones + numBlends + 1), 16); 88 89 for (size_t i = 0; i < numBones + numBlends; ++i) 89 90 { 90 91 m_BoneMatrices[i].SetIdentity(); … … 398 399 m_BoneMatrices[i] = m_BoneMatrices[i] * m_InverseBindBoneMatrices[i]; 399 400 } 400 401 402 // Note: there is a special case of joint influence, in which the vertex 403 // is influenced by the bind-shape transform instead of a particular bone, 404 // which we indicate with the blending bone ID set to the total number 405 // of bones. But since we're skinning in world space, we use the model's 406 // world space transform and store that matrix in this special index. 407 // (see http://trac.wildfiregames.com/ticket/1012) 408 m_BoneMatrices[m_pModelDef->GetNumBones()] = m_Transform; 409 401 410 m_pModelDef->BlendBoneMatrices(m_BoneMatrices); 402 411 } 403 412 } -
source/graphics/ModelDef.cpp
209 209 for (size_t i = 0; i < m_NumBlends; ++i) 210 210 { 211 211 const SVertexBlend& blend = m_pBlends[i]; 212 CMatrix3D& boneMatrix = boneMatrices[m_NumBones + i]; 212 CMatrix3D& boneMatrix = boneMatrices[m_NumBones + 1 + i]; 213 214 // Note: there is a special case of joint influence, in which the vertex 215 // is influenced by the bind-shape matrix instead of a particular bone, 216 // which we indicate by setting the bone ID set to the total number 217 // of bones. It should be blended with the world space transform and we 218 // have already set up this matrix in boneMatrices. 219 // (see http://trac.wildfiregames.com/ticket/1012) 220 213 221 boneMatrix.Blend(boneMatrices[blend.m_Bone[0]], blend.m_Weight[0]); 214 222 boneMatrix.AddBlend(boneMatrices[blend.m_Bone[1]], blend.m_Weight[1]); 215 223 for (size_t j = 2; j < SVertexBlend::SIZE && blend.m_Bone[j] != 0xFF; ++j) … … 301 309 } 302 310 if (j >= blends.size()) 303 311 blends.push_back(blend); 304 mdef->m_pBlendIndices[i] = mdef->m_NumBones + j; 312 // This index is offset by one to allow the special case of a 313 // weighted influence relative to the bind-shape rather than 314 // a particular bone. See comment in BlendBoneMatrices. 315 mdef->m_pBlendIndices[i] = mdef->m_NumBones + j + 1; 305 316 } 306 317 } 307 318