2014-10-11 86 views
3

tl; dr:當動畫模型時,每個關節都正確移動,但不是相對於其父關節。帶親子問題的骨骼動畫

enter image description here

我正在使用內置IQE裝載機和渲染在Lua定製骨骼動畫系統。幾乎所有的事情都在這一點上發揮作用,除了骨骼似乎在動畫時脫節。每個關節都可以正確翻譯,旋轉和縮放,但不會考慮父母的位置,從而產生一些可怕的問題。

在參考IQM規範和演示時,我不能爲了我的生活找出問題所在。我的Lua代碼(據我所知)與參考C++相同。

計算基地聯合矩陣:

local base = self.active_animation.base 
local inverse_base = self.active_animation.inverse_base 

for i, joint in ipairs(self.data.joint) do 
    local pose = joint.pq 

    local pos = { pose[1], pose[2], pose[3] } 
    local rot = matrix.quaternion(pose[4], pose[5], pose[6], pose[7]) 
    local scale = { pose[8], pose[9], pose[10] } 

    local m = matrix.matrix4x4() 
    m = m:translate(pos) 
    m = m:rotate(rot) 
    m = m:scale(scale) 

    local inv = m:invert() 

    if joint.parent > 0 then 
     base[i] = base[joint.parent] * m 
     inverse_base[i] = inv * inverse_base[joint.parent] 
    else 
     base[i] = m 
     inverse_base[i] = inv 
    end 
end 

計算動畫幀矩陣

local buffer = {} 
local base = self.active_animation.base 
local inverse_base = self.active_animation.inverse_base 
for k, pq in ipairs(self.active_animation.frame[self.active_animation.current_frame].pq) do 
    local joint = self.data.joint[k] 
    local pose = pq 

    local pos = { pose[1], pose[2], pose[3] } 
    local rot = matrix.quaternion(pose[4], pose[5], pose[6], pose[7]) 
    local scale = { pose[8], pose[9], pose[10] } 

    local m = matrix.matrix4x4() 
    m = m:translate(pos) 
    m = m:rotate(rot) 
    m = m:scale(scale) 

    local f = matrix.matrix4x4() 

    if joint.parent > 0 then 
     f = base[joint.parent] * m * inverse_base[k] 
    else 
     f = m * inverse_base[k] 
    end 

    table.insert(buffer, f:to_vec4s()) 
end 

完整的代碼here作進一步檢查。相關代碼位於/libs/iqe.lua中,在函數IQE:buffer()和IQE:send_frame()的底部。此代碼在LOVE遊戲框架的自定義版本上運行,幷包含Windows二進制文件(和批處理文件)。

最後說明:我們的矩陣代碼已經針對其他實現和多個測試進行了驗證。

回答

3

父母骨骼的變化應該會影響孩子的轉變。事實上,這是通過指定特定骨骼在其父框架中的轉換來實現的。所以,骨骼的轉換通常是在它們的本地座標系統中指定的,這取決於它的父代。如果父母中的任何一個轉化了,這種轉變會影響所有的孩子,即使他們的地方轉化沒有改變。

在你的情況,你一次緩存每個節點的所有絕對(相對於根,準確地說)轉換。然後使用緩存更新每個節點的本地變換,並且不更新緩存。那麼,如果更新孩子使用緩存而不是真正的父變換,節點的局部變換的變化會如何影響孩子?

還有一個問題。你爲什麼要做以下事情?

f = base[joint.parent] * m * inverse_base[k] 

我的意思是,它通常將只是:

f = base[joint.parent] * m 

我想,記錄在動畫轉換爲絕對的(相對於根,要準確)。這很奇怪。通常每個轉換都是局部的。檢查這個問題,因爲這會增加很多問題。

更重要的是,我沒有看到任何需要緩存的東西在你的情況下(除inverse_base,通常不需要)。

更改IQE:send_frame()功能如下:

local buffer = {} 
local transforms = {} 
local inverse_base = self.active_animation.inverse_base 
for k, pq in ipairs(self.active_animation.frame[self.active_animation.current_frame].pq) do 
    local joint = self.data.joint[k] 
    local pose = pq 

    local pos = { pose[1], pose[2], pose[3] } 
    local rot = matrix.quaternion(pose[4], pose[5], pose[6], pose[7]) 
    local scale = { pose[8], pose[9], pose[10] } 

    local m = matrix.matrix4x4() 
    m = m:translate(pos) 
    m = m:rotate(rot) 
    m = m:scale(scale) 

    local f = matrix.matrix4x4() 

    if joint.parent > 0 then 
     transforms[k] = transforms[joint.parent] * m 
     f = transforms[k] * inverse_base[k] 
    else 
     f = m * inverse_base[k] 
     transforms[k] = m 
    end 

    table.insert(buffer, f:to_vec4s()) 
end 

這工作對我好。嘗試擺脫的inverse_base,你將能夠從你的IQE刪除所有動畫相關的代碼:緩衝()函數

附:通常,所有節點都通過遍歷樹來更新。但是,您通過查看列表來更新節點。你應該知道,你必須保證某種程度上,對於任何節點來說,它都是孩子們追求的節點。

+0

首先我想說的非常感謝你的幫助!當我測試你的代碼時,它幾乎可以工作!無論如何,比我的代碼好多了!我用我的一個動畫「blah」得到了這個奇怪的錯誤,我想知道這是否是因爲我解析列表的方式,這可能會導致一些骨頭在被他們的孩子使用之前不能正確更新? https://dl.dropboxusercontent.com/u/12958391/misc/mk2.png – Karai17 2014-10-11 18:00:40

+0

我看過「blah」動畫,看起來腿的最頂層父變換是錯誤的。我不確定,但也許這個問題涉及這個奇怪的* inverse_base *。 嘗試重寫代碼而不乘以* inverse_base [k] * 並調整您正在使用的導出工具的設置。 – Podgorskiy 2014-10-11 19:01:09

+0

你曾經說過一些骨頭在被孩子使用之前可能不會被更新。如果是這樣,它肯定會破壞動畫。查看我之前寫過的帖子稿。 – Podgorskiy 2014-10-11 19:06:22