Ticket #1012: collada_import_fixes-12092011.patch

File collada_import_fixes-12092011.patch, 8.2 KB (added by historic_bruno, 12 years ago)
  • source/collada/PMDConvert.cpp

     
    252252                    // guaranteed by ReduceInfluences; necessary for avoiding
    253253                    // out-of-bounds writes to the VertexBlend
    254254
     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
    255266                for (size_t j = 0; j < vertexInfluences[i].GetPairCount(); ++j)
    256267                {
    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
    259289
    260                     // Find the joint on the skeleton, after checking it really exists
    261                     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);
    264294
    265                     // Complain on error
    266                     if (! joint)
    267                     {
    268                         if (! hasComplainedAboutNonexistentJoints)
     295                        // Complain on error
     296                        if (! joint)
    269297                        {
    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;
    272304                        }
    273                         continue;
    274                     }
    275305
    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;
    284318                    }
    285 
    286                     influences.bones[j] = (uint8)boneId;
    287                     influences.weights[j] = vertexInfluences[i].GetPair(j)->weight;
    288319                }
    289320
    290321                boneWeights.push_back(influences);
     
    522553    /**
    523554     * Applies world-space transform to vertex data and transforms Collada's right-handed
    524555     *  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.
    525560     */
    526561    static void TransformStaticModel(float* position, float* normal, size_t vertexCount,
    527562        const FMMatrix44& transform, bool yUp)
     
    563598    /**
    564599     * Applies world-space transform to vertex data and transforms Collada's right-handed
    565600     *  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.
    566605     */
    567606    static void TransformSkinnedModel(float* position, float* normal, size_t vertexCount,
    568607        std::vector<BoneTransform>& bones, std::vector<PropPoint>& propPoints,
  • source/graphics/Model.cpp

     
    8484        size_t numBlends = modeldef->GetNumBlends();
    8585
    8686        // 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);
    8889        for (size_t i = 0; i < numBones + numBlends; ++i)
    8990        {
    9091            m_BoneMatrices[i].SetIdentity();
     
    398399            m_BoneMatrices[i] = m_BoneMatrices[i] * m_InverseBindBoneMatrices[i];
    399400        }
    400401
     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
    401410        m_pModelDef->BlendBoneMatrices(m_BoneMatrices);
    402411    }
    403412}
  • source/graphics/ModelDef.cpp

     
    209209    for (size_t i = 0; i < m_NumBlends; ++i)
    210210    {
    211211        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
    213221        boneMatrix.Blend(boneMatrices[blend.m_Bone[0]], blend.m_Weight[0]);
    214222        boneMatrix.AddBlend(boneMatrices[blend.m_Bone[1]], blend.m_Weight[1]);
    215223        for (size_t j = 2; j < SVertexBlend::SIZE && blend.m_Bone[j] != 0xFF; ++j)
     
    301309                }
    302310                if (j >= blends.size())
    303311                    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;
    305316            }
    306317        }
    307318