2010-11-23 12 views
7

मैं अपने कार्यक्रम में एनीमेशन जोड़ने की कोशिश कर रहा हूं।ओपनजीएल कंकाल एनीमेशन

मेरे पास ब्लेंडर में कंकाल एनीमेशन के साथ मानव मॉडल बनाया गया है, और मैं मॉडल चलने के लिए कीफ्रेम के माध्यम से छोड़ सकता हूं।

अब मैंने मॉडल को एक एक्सएमएल (ओजीआर 3 डी) प्रारूप में निर्यात किया है, और इस एक्सएमएल फ़ाइल में मैं एक विशिष्ट समय पर प्रत्येक हड्डी को आवंटित रोटेशन, अनुवाद और स्केल देख सकता हूं (टी = 0.00000, टी = 0.00040, ... आदि)

मैंने जो किया है वह पाया गया है कि प्रत्येक हड्डी को कौन सा शिखर दिया जाता है। अब मुझे लगता है कि मुझे बस इतना करना है कि इन शीर्षकों में से प्रत्येक को हड्डी के लिए परिभाषित परिवर्तन लागू करें। क्या यह सही दृष्टिकोण है?

मेरी ओपन ड्रा() फ़ंक्शन में (किसी न किसी छद्म कोड):

for (Bone b : bones){ 
    gl.glLoadIdentity(); 

    List<Vertex> v= b.getVertices(); 
    rotation = b.getRotation(); 
    translation = b.getTranslation(); 
    scale = b.getScale(); 

    gl.glTranslatef(translation); 
    gl.glRotatef(rotation); 
    gl.glScalef(scale); 

    gl.glDrawElements(v); 
} 

उत्तर

5

कोने आमतौर पर एक से अधिक हड्डी से प्रभावित होते हैं - यह लगता है कि आप रैखिक मिश्रण skinning के बाद कर रहे हैं। सी में मेरे कोड के ++ दुर्भाग्य से, लेकिन उम्मीद है कि यह आप के विचार दे देंगे: गुजर कि वास्तविक दुनिया कार्यान्वयन आमतौर पर मेरी जानकारी के अनुसार करने के लिए GPU पर बात की इस तरह करते हैं

void Submesh::skin(const Skeleton_CPtr& skeleton) 
{ 
    /* 
    Linear Blend Skinning Algorithm: 

    P = (\sum_i w_i * M_i * M_{0,i}^{-1}) * P_0/(sum i w_i) 

    Each M_{0,i}^{-1} matrix gets P_0 (the rest vertex) into its corresponding bone's coordinate frame. 
    We construct matrices M_n * M_{0,n}^-1 for each n in advance to avoid repeating calculations. 
    I refer to these in the code as the 'skinning matrices'. 
    */ 

    BoneHierarchy_CPtr boneHierarchy = skeleton->bone_hierarchy(); 
    ConfiguredPose_CPtr pose = skeleton->get_pose(); 
    int boneCount = boneHierarchy->bone_count(); 

    // Construct the skinning matrices. 
    std::vector<RBTMatrix_CPtr> skinningMatrices(boneCount); 
    for(int i=0; i<boneCount; ++i) 
    { 
     skinningMatrices[i] = pose->bones(i)->absolute_matrix() * skeleton->to_bone_matrix(i); 
    } 

    // Build the vertex array. 
    RBTMatrix_Ptr m = RBTMatrix::zeros();  // used as an accumulator for \sum_i w_i * M_i * M_{0,i}^{-1} 

    int vertCount = static_cast<int>(m_vertices.size()); 
    for(int i=0, offset=0; i<vertCount; ++i, offset+=3) 
    { 
     const Vector3d& p0 = m_vertices[i].position(); 
     const std::vector<BoneWeight>& boneWeights = m_vertices[i].bone_weights(); 
     int boneWeightCount = static_cast<int>(boneWeights.size()); 

     Vector3d p; 
     if(boneWeightCount != 0) 
     { 
      double boneWeightSum = 0; 

      for(int j=0; j<boneWeightCount; ++j) 
      { 
       int boneIndex = boneWeights[j].bone_index(); 
       double boneWeight = boneWeights[j].weight(); 
       boneWeightSum += boneWeight; 
       m->add_scaled(skinningMatrices[boneIndex], boneWeight); 
      } 

      // Note: This is effectively p = m*p0 (if we think of p0 as (p0.x, p0.y, p0.z, 1)). 
      p = m->apply_to_point(p0); 
      p /= boneWeightSum; 

      // Reset the accumulator matrix ready for the next vertex. 
      m->reset_to_zeros(); 
     } 
     else 
     { 
      // If this vertex is unaffected by the armature (i.e. no bone weights have been assigned to it), 
      // use its rest position as its real position (it's the best we can do). 
      p = p0; 
     } 

     m_vertArray[offset] = p.x; 
     m_vertArray[offset+1] = p.y; 
     m_vertArray[offset+2] = p.z; 
    } 
} 

void Submesh::render() const 
{ 
    glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); 
    glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT); 

    glEnableClientState(GL_VERTEX_ARRAY); 
    glVertexPointer(3, GL_DOUBLE, 0, &m_vertArray[0]); 

    if(m_material->uses_texcoords()) 
    { 
     glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
     glTexCoordPointer(2, GL_DOUBLE, 0, &m_texCoordArray[0]); 
    } 

    m_material->apply(); 

    glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertIndices.size()), GL_UNSIGNED_INT, &m_vertIndices[0]); 

    glPopAttrib(); 
    glPopClientAttrib(); 
} 

नोट।

1

आपका कोड मानता है कि प्रत्येक हड्डी में एक स्वतंत्र परिवर्तन मैट्रिक्स होता है (आप प्रत्येक लूप पुनरावृत्ति की शुरुआत में अपने मैट्रिक्स को रीसेट करते हैं)। लेकिन हकीकत में, हड्डियां एक पदानुक्रमित संरचना बनाती हैं जिसे आप अपना प्रतिपादन करते समय संरक्षित रखना चाहिए। इस बात पर विचार करें कि जब आपकी ऊपरी भुजा घूमती है तो आपका अग्रसर घूमता है, क्योंकि यह संलग्न होता है। अग्रसर का अपना घूर्णन हो सकता है, लेकिन ऊपरी भुजा के साथ घुमाए जाने के बाद इसे लागू किया जाता है।

कंकाल का प्रतिपादन फिर से किया जाता है। यहां कुछ छद्म कोड है:

function renderBone(Bone b) { 
    setupTransformMatrix(b); 
    draw(b); 
    foreach c in b.getChildren() 
     renderBone(c); 
} 

main() { 
    gl.glLoadIdentity(); 
    renderBone(rootBone); 
} 

मुझे उम्मीद है कि इससे मदद मिलती है।

संबंधित मुद्दे