2011-06-25 18 views
9

Tôi gặp một số vấn đề khi tạo mô hình COLLADA đã tải. Tôi đã viết trình phân tích cú pháp của riêng mình và bây giờ tôi cũng muốn viết thường trình vẽ của riêng mình. Vấn đề ist, rằng ngay sau khi tôi kích hoạt các hình ảnh động trên mô hình của tôi, bàn tay, chân và đầu được kéo dài ra khỏi nguồn gốc của mô hình. (Trình tải được thực hiện dựa trên hướng dẫn tại đây: COLLADA Tutorial)Các vấn đề về hoạt hình COLLADA Model

Điều đầu tiên tôi làm trong chức năng vẽ của mô hình là thiết lập ma trận khớp (không phải là ma trận thế giới!) Với các mục tiêu đã cho từ khối đọc, Nếu tôi ví dụ đọc một kênh như:

<channel source="#some_sampler" target="some_joint/transform(3)(2)"/> 

tôi sẽ thay đổi thành phần ma trận (3) (2) từ jointMatrix của doanh với sid = "chuyển hóa" trong bước đầu tiên này:

if(mCurrentAnimations_.size() > 0) { 
    unsigned currentFrame = GEAR::Root::getSingleton().getFrameEvent().frame; 
    bool updateTime = false; 
    if(currentFrame != mLastFrameUpdate_) { 
     if(timeSinceLastFrame < 1.0f) 
      updateTime = true; 
     mLastFrameUpdate_ = currentFrame; 
    } 

    /**************************************************** 
    * If we have an active animation,     * 
    * we animate it in each of it's defined channels * 
    ***************************************************/ 
    std::list<DAEAnimation*>::iterator it = mCurrentAnimations_.begin(); 
    while(it != mCurrentAnimations_.end()) { 
     for(int c = 0; c < (*it)->animation->channels.size(); ++c) { 
      // update the time of the channelanimation if requested 
      if(updateTime) { 
       (*it)->channelStates[c].elapsedTime += timeSinceLastFrame; 
      } 

      GEAR::COLLADA::Channel* channel = (*it)->animation->channels[c]; 
      // read the two indices depending on the time we're 
      int firstKeyframeTimeIndex = 0; 
      int secondKeyframeTimeIndex = 0; 
      for(int i = 0; i < channel->sampler->inputSource->mFloatArray_->mCount_; ++i) { 
       float time = channel->sampler->inputSource->mFloatArray_->mFloats_[i]; 
       if(firstKeyframeTimeIndex == secondKeyframeTimeIndex && time > (*it)->channelStates[c].elapsedTime && i > 0) { 
        firstKeyframeTimeIndex = i-1; 
        secondKeyframeTimeIndex = i; 
        break; 
       } 
       if(firstKeyframeTimeIndex == secondKeyframeTimeIndex && i == channel->sampler->inputSource->mFloatArray_->mCount_-1) { 
        (*it)->channelStates[c].elapsedTime = 0.0f; 
        firstKeyframeTimeIndex = i; 
        secondKeyframeTimeIndex = 0; 
        break; 
       } 
      } 
      // look what kind of TargetAccessor we have 
      if(channel->targetAccessor != NULL && channel->targetAccessor->type == GEAR::MATRIX_ACCESSOR) { 
       // ok we have to read 1 value for first and second index 
       float firstValue = channel->sampler->outputSource->mFloatArray_->mFloats_[firstKeyframeTimeIndex]; 
       float secondValue = channel->sampler->outputSource->mFloatArray_->mFloats_[secondKeyframeTimeIndex]; 

       float firstTime = channel->sampler->inputSource->mFloatArray_->mFloats_[firstKeyframeTimeIndex]; 
       float secondTime = channel->sampler->inputSource->mFloatArray_->mFloats_[secondKeyframeTimeIndex]; 
       float interpolateValue = 1.0f/(secondTime - firstTime) * (secondTime - (*it)->channelStates[c].elapsedTime); 
       // now we calculate an linear interpolated value 
       float value = (secondValue*interpolateValue) + (firstValue*(1.0-interpolateValue)); 

       // now we have to write this value to the Joint's Matrix 
       int entry = ((COLLADA::MatrixTargetAccessor*)channel->targetAccessor)->firstAccessor*4+((COLLADA::MatrixTargetAccessor*)channel->targetAccessor)->secondAccessor; 
       channel->targetJoint->matrix->jointSpaceMatrix.entries[entry] = channel->targetJoint->matrix->matrix.entries[entry] + value; 
      } 
     } 
     ++it; 
    } 
} 

Sau khi tham gia tMatrices được sửa đổi theo tất cả các kênh, tôi tính toán lại worldMatrices của doanh bằng cách gọi hàm sau vào thư mục gốc phần:

void 
COLLADA::Joint::recalcWorldSpaceTransMat() { 
    GEAR::Mat4 parentMat; 
    if(parent != NULL) 
     parentMat = parent->worldSpaceTransformationMatrix; 
    // @todo Here we have to test against NULL! 
    if(matrix != NULL) 
     this->worldSpaceTransformationMatrix = parentMat * matrix->jointSpaceMatrix; 
    else { 
     this->worldSpaceTransformationMatrix = parentMat; 
    } 
    //std::cout << "Joint " << sid << " recalculated\n"; 
    for(int i = 0; i < mChildJoints_.size(); ++i) 
     mChildJoints_[i]->recalcWorldSpaceTransMat(); 
} 

Bây giờ tất cả mọi thứ nên được sẵn sàng để vẽ mô hình của tôi chiều rộng phần cuối cùng sau chức năng vẽ của tôi:

for(int i = 0; i < mSubMeshes_.size(); ++i) { 
    for(int k = 0; k < mSubMeshes_[i]->mSubMeshes_.size(); ++k) { 
     // first we animate it 
     GEAR::DAESubMesh* submesh = mSubMeshes_[i]->mSubMeshes_[k]; 
     submesh->buffer->lock(true); 
     { 
      for(unsigned v = 0; v < submesh->buffer->getNumVertices(); ++v) { 
       // get the array of joints, which influence the current vertex 
       DAEVertexInfo* vertexInfo = submesh->vertexInfo[v]; 
       GEAR::Vec3 vertex; // do not init the vertex with any value! 
       float totalWeight = 0.0f; 
       for(int j = 0; j < vertexInfo->joints.size(); ++j) { 
        Mat4& invBindPoseMatrix = vertexInfo->joints[j]->joint->invBindPoseMatrix; 
        Mat4& transMat = vertexInfo->joints[j]->joint->worldSpaceTransformationMatrix; 
        totalWeight += vertexInfo->joints[j]->weight; 
        vertex += (transMat*invBindPoseMatrix*(submesh->skin->bindShapeMatrix*vertexInfo->vertex))*vertexInfo->joints[j]->weight; 
       } 
       if(totalWeight != 1.0f) { 
        float normalizedWeight = 1.0f/totalWeight; 
        vertex *= normalizedWeight; 
       } 
       submesh->buffer->bufferVertexPos(v, vertex); 
      } 
     } 
     submesh->buffer->unlock(); 

     mSubMeshes_[i]->mSubMeshes_[k]->buffer->draw(GEAR::TRIANGLES, 0, mSubMeshes_[i]->mSubMeshes_[k]->buffer->getNumVertices()); 
    } 
} 

Bây giờ vấn đề đặt ra là, mà đầu ra trông giống như sau: enter image description here

tôi chắc chắn phải có thói quen nạp dữ liệu thực hiện đúng, bởi vì các hình ảnh động chung của người đàn ông đi bộ là có thể nhìn thấy, nhưng lưới bị biến dạng: enter image description here

Như tôi đã nói, khi tôi bỏ ghi chú dòng:

channel->targetJoint->matrix->jointSpaceMatrix.entries[entry] = channel->targetJoint->matrix->matrix.entries[entry] + value; 

Các hình ảnh động bị vô hiệu hóa và mô hình được hiển thị trong đó là tư thế tiêu chuẩn: enter image description here

Bây giờ ngoài khi tôi thêm một bình thường đến 3 cột đầu tiên của jointMatrices như thế này trước khi tôi tính toán lại worldMatrix của doanh:

GEAR::Vec3 row1(matrix->jointSpaceMatrix.entries[0], matrix->jointSpaceMatrix.entries[1], matrix->jointSpaceMatrix.entries[2]); 
row1.normalize(); 
matrix->jointSpaceMatrix.entries[0] = row1.x; 
matrix->jointSpaceMatrix.entries[1] = row1.y; 
matrix->jointSpaceMatrix.entries[2] = row1.z; 
GEAR::Vec3 row2(matrix->jointSpaceMatrix.entries[4], matrix->jointSpaceMatrix.entries[5], matrix->jointSpaceMatrix.entries[6]); 
row2.normalize(); 
matrix->jointSpaceMatrix.entries[4] = row2.x; 
matrix->jointSpaceMatrix.entries[5] = row2.y; 
matrix->jointSpaceMatrix.entries[6] = row2.z; 
GEAR::Vec3 row3(matrix->jointSpaceMatrix.entries[8], matrix->jointSpaceMatrix.entries[9], matrix->jointSpaceMatrix.entries[10]); 
row3.normalize(); 
matrix->jointSpaceMatrix.entries[8] = row3.x; 
matrix->jointSpaceMatrix.entries[9] = row3.y; 
matrix->jointSpaceMatrix.entries[10] = row3.z; 

Sự cố vẫn tồn tại, nhưng lần này ở đầu ra khác. Người đàn ông bây giờ trông giống như một người ngoài hành tinh: D, nhưng điều này làm giảm tỷ lệ: enter image description here

Tôi không chính xác bây giờ, cho dù tôi đã thực hiện bình thường đúng cách. Sự bình thường này có thực sự cần thiết không? Nó không được mô tả trong hướng dẫn và tôi cũng không thể tìm thấy bất cứ điều gì liên quan.

Sau khi tất cả tôi đã được xem xét việc thực hiện nội suy trong mã từ trang hướng dẫn. VÀ: Chúng không sử dụng bất kỳ quaternion nào để intrpolate ma trận lỗ. Những gì họ làm là như sau (mà không làm việc cho tôi):

 Mat4 temp; 

    for (int i = 0; i < 16; ++i) 
     temp.entries[i] = interpolatef(matrix->jointSpaceMatrixStart.entries[i],matrix->jointSpaceMatrixFinish.entries[i],matrix->delta); 

    Vec3 forward,up,right,translation; 
    forward = Vec3(temp.entries[8], temp.entries[9], temp.entries[10]); 
    up= Vec3(temp.entries[4], temp.entries[5], temp.entries[6]); 
    right = Vec3(temp.entries[0], temp.entries[1], temp.entries[2]); 

    forward.normalize(); 
    up.normalize(); 
    right.normalize(); 

    temp.entries[8] = forward.x; temp.entries[9] = forward.y; temp.entries[10] = forward.z; 
    temp.entries[4] = up.x; temp.entries[5] = up.y; temp.entries[6] = up.z; 
    temp.entries[0] = right.x; temp.entries[1] = right.y; temp.entries[2] = right.z; 

    matrix->jointSpaceMatrix = GEAR::Mat4(temp); 

Sau đó, tôi sử dụng quaternion trong cách tiếp cận khác như vậy (cũng không hoạt động đối với tôi):

 // wat we need for interpolation: rotMatStart, rotMatFinish, delta 

    // create rotation matrices from our 2 given matrices 
    GEAR::Mat4 rotMatStart = matrix->jointSpaceMatrixStart; 
    rotMatStart.setTranslationPart(GEAR::VEC3_ZERO); 
    GEAR::Mat4 rotMatFinish = matrix->jointSpaceMatrixFinish; 
    rotMatFinish.setTranslationPart(GEAR::VEC3_ZERO); 

    rotMatStart.transpose(); 
    rotMatFinish.transpose(); 

    // create Quaternions, which represent these 2 matrices 
    float w = GEAR::Tools::sqr(1.0 + rotMatStart.entries[0] + rotMatStart.entries[5] + rotMatStart.entries[10])/2.0; 
    float w4 = (4.0 * w); 
    float x = (rotMatStart.entries[6] - rotMatStart.entries[9])/w4 ; 
    float y = (rotMatStart.entries[8] - rotMatStart.entries[2])/w4 ; 
    float z = (rotMatStart.entries[1] - rotMatStart.entries[4])/w4 ; 
    GEAR::Quaternion rotQuadStart(x, y, z, w); 
    rotQuadStart.normalize(); 
    w = GEAR::Tools::sqr(1.0 + rotMatFinish.entries[0] + rotMatFinish.entries[5] + rotMatFinish.entries[10])/2.0; 
    w4 = (4.0 * w); 
    x = (rotMatFinish.entries[6] - rotMatFinish.entries[9])/w4 ; 
    y = (rotMatFinish.entries[8] - rotMatFinish.entries[2])/w4 ; 
    z = (rotMatFinish.entries[1] - rotMatFinish.entries[4])/w4 ; 
    GEAR::Quaternion rotQuadFinish(x, y, z, w); 
    rotQuadFinish.normalize(); 

    // create the interpolated rotation matrix 
    GEAR::Quaternion slerpedRotQuat = slerp(rotQuadStart, rotQuadFinish, matrix->delta); 
    slerpedRotQuat.normalize(); 
    GEAR::Mat4 rotMat; 
    slerpedRotQuat.createMatrix(rotMat); 

    // interpolate the translation part 
    GEAR::Vec3 transVecStart(0.0,0.0,0.0); 
    matrix->jointSpaceMatrixStart.getTranslatedVector3D(transVecStart); 
    GEAR::Vec3 transVecFinish(0.0,0.0,0.0); 
    matrix->jointSpaceMatrixFinish.getTranslatedVector3D(transVecFinish); 

    GEAR::Mat4 transMat; 
    transMat.setTranslation(transVecFinish*matrix->delta + (transVecStart*(1.0f-matrix->delta))); 
    // now write the resulting Matrix back to the Joint 
    matrix->jointSpaceMatrix = transMat * rotMat; 

Nó cũng sẽ không làm việc cho tôi. Không có gì có vẻ hiệu quả. Tôi thực sự không có ý tưởng gì đang xảy ra với điều này.


Bây giờ sau 2 ngày, tôi nhận nó làm việc nhờ vào câu trả lời của datenwolf

Tôi muốn thông báo tất cả làm thế nào tôi nhận nó làm việc. Bây giờ tất cả mọi thứ có vẻ rõ ràng và nó chỉ là một bước nhỏ tất cả các thời gian. Bây giờ chúng ta bắt đầu với phần hoạt hình. Tôi lặp qua tất cả các kênh và tiết kiệm thời gian bắt đầu và các giá trị kết thúc cũng như giá trị đồng bằng nội suy trong phạm vi 0,0 1,0 đến doanh, kênh sinh động:

if(mCurrentAnimations_.size() > 0) { 
    unsigned currentFrame = GEAR::Root::getSingleton().getFrameEvent().frame; 
    bool updateTime = false; 
    if(currentFrame != mLastFrameUpdate_) { 
     if(timeSinceLastFrame < 1.0f) 
      updateTime = true; 
     mLastFrameUpdate_ = currentFrame; 
    } 

    /**************************************************** 
    * If we have an active animation,     * 
    * we animate it in each of it's defined channels * 
    ***************************************************/ 
    std::list<DAEAnimation*>::iterator it = mCurrentAnimations_.begin(); 
    while(it != mCurrentAnimations_.end()) { 
     for(int c = 0; c < (*it)->animation->channels.size(); ++c) { 
      // update the time of the channelanimation if requested 
      if(updateTime) { 
       (*it)->channelStates[c].elapsedTime += timeSinceLastFrame; 
      } 

      GEAR::COLLADA::Channel* channel = (*it)->animation->channels[c]; 
      // read the two indices depending on the time we're 
      int firstIndex = 0; 
      int secondIndex = 1; 
      for(int i = 0; i < channel->sampler->inputSource->mFloatArray_->mCount_; ++i) { 
       float time = channel->sampler->inputSource->mFloatArray_->mFloats_[i]; 
       if(time > (*it)->channelStates[c].elapsedTime) { 
        firstIndex = i-1; 
        secondIndex = i; 
        if(firstIndex == -1) // set to last frame 
         firstIndex = channel->sampler->inputSource->mFloatArray_->mCount_ - 1; 
        break; 
       } 
       else if(i == channel->sampler->inputSource->mFloatArray_->mCount_ - 1) { 
        (*it)->channelStates[c].elapsedTime -= channel->sampler->inputSource->mFloatArray_->mFloats_[i]; 
        firstIndex = 0; 
        secondIndex = 1; 
        break; 
       } 
      } 
      // look what kind of TargetAccessor we have 
      if(channel->targetAccessor != NULL && channel->targetAccessor->type == GEAR::MATRIX_ACCESSOR) { 
       /************************************************************************ 
       * Matrix accessors, which are read from a COLLADA <channel> block  * 
       * will always target one matrix component they animate.    * 
       * Such accessors are for example:          * 
       * <channel source"#someSource" target="someJoint/transform(0)(2)"/> * 
       *                  * 
       * @TODO:                * 
       * In a pre processing step, we have to group all channels, which  * 
       * operate on the same joint. In order to accelerate the processing of * 
       * grouped channels, we have to expand the number of keyframes of all * 
       * channels to the maximum of all channels.        * 
       ************************************************************************/ 
       unsigned entry = ((COLLADA::MatrixTargetAccessor*)channel->targetAccessor)->index; 
       float firstTime = channel->sampler->inputSource->mFloatArray_->mFloats_[firstIndex]; 
       float secondTime = channel->sampler->inputSource->mFloatArray_->mFloats_[secondIndex]; 
       // in case of matrix accessor, we write the startMatrix and the endMatrix to the Joints accessor, who finally will do the animation interpolation 
       channel->targetJoint->matrix->interpolationRequired = true; 
       // write out the start and end value to the jointSpaceMatrix 
       // this matrix will later be interpolated 
       channel->targetJoint->matrix->jointSpaceMatrixStart.entries[entry] = channel->sampler->outputSource->mFloatArray_->mFloats_[firstIndex]; 
       channel->targetJoint->matrix->jointSpaceMatrixFinish.entries[entry] = channel->sampler->outputSource->mFloatArray_->mFloats_[secondIndex]; 
       // the delta value is in the range [0.0,1.0] 
       channel->targetJoint->matrix->delta = 1.0f/(secondTime - firstTime) * (secondTime - (*it)->channelStates[c].elapsedTime); 
      } 
     } 
     ++it; 
    } 
} 

Như bạn có thể thấy, đây là không suy gì cả. Chúng tôi chỉ đơn giản là bộ nhớ đệm các giá trị bắt đầu và kết thúc và một đồng bằng cho tất cả các khớp hoạt hình (và chúng tôi cũng thiết lập một lá cờ trên mỗi khớp đã sửa đổi)

Bây giờ sau khi tất cả các hoạt ảnh được thực hiện, chúng tôi gọi hàm nội suy() trên tất cả khớp gốc:

for(int i = 0; i < mSourceModel_->mVisualSceneLibrary_.mVisualScenes_.size(); ++i) { 
    for(int v = 0; v < mSourceModel_->mVisualSceneLibrary_.mVisualScenes_[i]->mSkeleton_.size(); ++v) { 
     if(mSourceModel_->mVisualSceneLibrary_.mVisualScenes_[i]->mSkeleton_[v]->mRootJoint_ != NULL) { 
      /************************************************************************************ 
      * Now we have constructed all jointSpaceMatrixces for the start and the end and * 
      * we're ready to interpolate them and to also recalculate the joint's    * 
      * worldSpaceMatrix.                * 
      ***********************************************************************************/ 
      mSourceModel_->mVisualSceneLibrary_.mVisualScenes_[i]->mSkeleton_[v]->mRootJoint_->interpolateMatrices(); 
     } 
    } 
} 

Điều này không mới, nhưng phần thú vị bây giờ là triển khai nội suy. Không có gì qith Quaternions tại tất cả:

void COLLADA::Joint::interpolateMatrices() { 
if(matrix != NULL && matrix->interpolationRequired) { 

    for (unsigned i = 0; i < 16; ++i) 
     matrix->jointSpaceMatrix.entries[i] = interpolatef(matrix->jointSpaceMatrixStart.entries[i],matrix->jointSpaceMatrixFinish.entries[i],matrix->delta); 

    Vec3 forward,up,right,translation; 
    forward = Vec3(matrix->jointSpaceMatrix.entries[8], matrix->jointSpaceMatrix.entries[9], matrix->jointSpaceMatrix.entries[10]); 
    up= Vec3(matrix->jointSpaceMatrix.entries[4], matrix->jointSpaceMatrix.entries[5], matrix->jointSpaceMatrix.entries[6]); 
    right = Vec3(matrix->jointSpaceMatrix.entries[0], matrix->jointSpaceMatrix.entries[1], matrix->jointSpaceMatrix.entries[2]); 

    forward.normalize(); 
    up.normalize(); 
    right.normalize(); 

    matrix->jointSpaceMatrix.entries[8] = forward.x; matrix->jointSpaceMatrix.entries[9] = forward.y; matrix->jointSpaceMatrix.entries[10] = forward.z; 
    matrix->jointSpaceMatrix.entries[4] = up.x; matrix->jointSpaceMatrix.entries[5] = up.y; matrix->jointSpaceMatrix.entries[6] = up.z; 
    matrix->jointSpaceMatrix.entries[0] = right.x; matrix->jointSpaceMatrix.entries[1] = right.y; matrix->jointSpaceMatrix.entries[2] = right.z; 

    matrix->jointSpaceMatrix.entries[15] = 1.0f; // this component is always 1.0! In some files, this is exported the wrong way, which causes bugs! 
} 
/******************************************************** 
* After the interpolation is finished,     * 
* we have to recalculate the joint's worldSpaceMatrix. * 
********************************************************/ 
GEAR::Mat4 parentMat; 
if(parent != NULL) 
    parentMat = parent->worldSpaceTransformationMatrix; 
if(matrix != NULL) 
    worldSpaceTransformationMatrix = (parentMat * matrix->jointSpaceMatrix); 
else 
    worldSpaceTransformationMatrix = parentMat; 
skinningMatrix = worldSpaceTransformationMatrix*invBindPoseMatrix; 

// also interpolate and recalculate all childs 
for(unsigned k = 0; k < mChildJoints_.size(); ++k) 
    mChildJoints_[k]->interpolateMatrices(); 

}

Như bạn có thể thấy chúng tôi chỉ đơn giản là intrpolate tất cả các giá trị của ma trận và sau đó chúng ta chuẩn hóa 3 cột trên của ma trận. Sau đó, chúng tôi tính toán lại ngay lập tức worldSpaceMatrix cho phần khớp đó, cũng như ma trận tạo lớp hoàn chỉnh để lưu hiệu suất. Bây giờ chúng ta gần như hoàn chỉnh với tất cả. Điều cuối cùng cần làm là để thực sự animate đỉnh và sau đó để vẽ lưới:

for(int i = 0; i < mSubMeshes_.size(); ++i) { 
    for(int k = 0; k < mSubMeshes_[i]->mSubMeshes_.size(); ++k) { 
     // first we animate it 
     GEAR::DAESubMesh* submesh = mSubMeshes_[i]->mSubMeshes_[k]; 
     submesh->buffer->lock(true); 
     { 
      for(unsigned v = 0; v < submesh->buffer->getNumVertices(); ++v) { 
       // get the array of joints, which influence the current vertex 
       DAEVertexInfo* vertexInfo = submesh->vertexInfo[v]; 
       GEAR::Vec3 vertex; // do not init the vertex with any value! 
       float totalWeight = 0.0f; 
       for(int j = 0; j < vertexInfo->joints.size(); ++j) { 
        totalWeight += vertexInfo->joints[j]->weight; 
        vertex += ((vertexInfo->joints[j]->joint->skinningMatrix*(vertexInfo->vertex))*vertexInfo->joints[j]->weight); 
       } 
       // since it isn't guaranteed that the total weight is exactly 1.0, we have no normalize it 
       // @todo this should be moved to the parser 
       if(totalWeight != 1.0f) { 
        float normalizedWeight = 1.0f/totalWeight; 
        vertex *= normalizedWeight; 
       } 
       submesh->buffer->bufferVertexPos(v, vertex); 
      } 
     } 
     submesh->buffer->unlock(); 

     mSubMeshes_[i]->mSubMeshes_[k]->buffer->draw(GEAR::TRIANGLES, 0, mSubMeshes_[i]->mSubMeshes_[k]->buffer->getNumVertices()); 
    } 
} 

Tất cả trong tất cả đó là gần giống như đoạn code tôi bắt đầu với. Nhưng bây giờ mọi thứ rõ ràng hơn nhiều đối với tôi và tôi cũng có thể bắt đầu hỗ trợ < dịch >, <xoay> và < quy mô > hoạt ảnh. Hãy nhìn vào thực hiện của tôi tại gear3d.de (tải về thân cây SVN)

Tôi hy vọng điều này sẽ giúp một số người ngoài kia thực hiện giải pháp riêng của họ về chủ đề tuyệt vời này :)

+1

+1; một câu hỏi tốt bằng văn bản với mã thiết yếu nhất định và mô tả chính xác về sai và kết quả chính xác mong đợi. – datenwolf

Trả lời

4

Nhìn vào những hình ảnh tôi có ấn tượng, rằng ma trận chung của bạn không được chuẩn hóa, nghĩa là phần trên bên trái 3 × 3 nâng cấp lưới của bạn. Hãy thử những gì sẽ xảy ra nếu bạn bình thường hóa các vectơ 3 cột trên bên trái.

Nếu điều này làm giảm vấn đề, nó cần phải được điều tra, phần nào của hệ thống hoạt ảnh gây ra điều này.

+0

Cảm ơn câu trả lời của bạn và sự giúp đỡ của bạn. Bây giờ tôi đã thử nghiệm sự bình thường hóa, nhưng tôi không chính xác bây giờ cho dù tôi đã thực hiện nó đúng cách. Andy –

+0

@Andy: Việc bình thường hóa chỉ là một thử nghiệm để thu hẹp vấn đề. Cuối cùng, bạn sẽ phải có được nội suy hoạt hình chính xác. Tôi đã đọc một bình luận ở đó rằng bạn đang thực hiện nội suy tuyến tính. Khi các ma trận nội suy (xoay vòng) thì đây thường không phải là cách tiếp cận đúng. – datenwolf

+0

Bạn có ý tưởng nào về điều này không? Tôi đã thử gần như mọi kết hợp mà không có kết quả tốt. Tôi không biết bạn là ai quen thuộc với COLLADA. Trong COLLADA bạn có các hoạt ảnh được chia thành các Nguồn chứa bất kỳ dữ liệu nào như giá trị thời gian, giá trị chuyển đổi và giá trị nội suy, mẫu có chứa tham chiếu đến nguồn và kênh chứa tham chiếu đến mẫu và tham chiếu đến khớp. Các tham chiếu đến các khớp xác định, thành phần nào để tạo hiệu ứng động. Trong trường hợp của tôi, tất cả các thành phần ma trận mục tiêu tham chiếu. Đây là lý do tại sao tôi chỉ nội suy một thành phần ma trận. –

1

Trong trường hợp của tôi, tất cả các thành phần ma trận mục tiêu tham chiếu. Đây là lý do tại sao tôi chỉ nội suy một thành phần ma trận.

Bạn không bao giờ nội suy ma trận. Bao giờ.

Cách này thường được xử lý là, khi tải dữ liệu hoạt ảnh, bạn phân tách mỗi ma trận thành một quaternion và vị trí (và tỷ lệ, nếu bạn đang làm động quy mô). Quaternions được sử dụng bởi vì chúng nhỏ, dễ nội suy, và dễ dàng chuẩn hóa sau khi nội suy.Không giống như các ma trận lớn, khó nội suy và khó chỉnh sửa sau đó.

Lưu ý rằng ở trên thường được thực hiện dưới dạng bước xử lý trước trong công cụ. Công cụ tải hoạt ảnh Collada, chuyển đổi thành quaternions và vị trí, sau đó ghi chúng ra một định dạng tệp để đọc sau này.

Vì vậy, bạn sau đó nội suy các quaternions (cảm thấy tự do để sử dụng LERP cho nội suy động), khi cần thiết, với một bình thường nhanh chóng sau đó. Các vị trí chỉ cần cập nhật nếu các vị trí thực sự thay đổi tương ứng với bù đắp gốc. Bạn soạn những người đó lại thành ma trận và tiếp tục như bình thường.

Đơn giản và dễ dàng.

+0

Cảm ơn bạn đã trả lời câu hỏi này. Tôi bây giờ đã thực hiện nó bằng cách sử dụng quaternions, nhưng cho đến bây giờ mà không có một kết quả tốt. Trong đoạn mã trên, tôi đã thêm một vài điều bổ sung vào nội suy. Sẽ rất tuyệt nếu bạn nhìn vào nó. –

+2

@Nicol Trong pha trộn đỉnh, độ chính xác của ma trận nội suy thường có thể chấp nhận được (và ma trận bảng màu là tiêu chuẩn defacto cho pha trộn theo thời gian thực), vì vậy "bao giờ" của bạn hơi sai. Rõ ràng (quaternion, dịch thuật) cặp có nhược điểm của họ, quá. Một sự thay thế rất tốt cho việc tạo bảng màu ma trận là làm trắng da hai quaternion, làm giảm các hiện tượng kết hợp đỉnh thông thường với chi phí thời gian chạy không nhiều và không có vấn đề thiếu-phối hợp-hệ thống độc lập của các cặp (quaternion, translation). –

+0

@Christian Rau: Ngay cả khi bạn có thể sống với các hiện vật nội suy mà không cần chuẩn hóa, quaternions vẫn được ưu tiên, vì chúng nhỏ hơn, nén dễ dàng hơn nhiều và thậm chí nội suy nhanh hơn (4 giá trị thay vì 9). Không có lý do gì để trực tiếp nội suy ma trận. –

Các vấn đề liên quan