当前位置:网站首页>[opengl] bone animation blending effect
[opengl] bone animation blending effect
2022-07-03 14:42:00 【ZJU_ fish1996】
This article mainly discusses the blending effect of two bone animation transitions .

In the game , Animation is often cut into multiple segments (clip), Build the final performance effect through combination and splicing . To ensure a smooth transition when switching actions , Make the whole movement more smooth , You need to mix the front and back actions through interpolation .
Concept introduction
Before discussing specific hybrid calculations , I think it is still necessary to clarify some details of the whole animation system .
One of the problems that needs to be discussed is : What data should be maintained when animation runs , And how to convert into the final rendering process . In the original bone animation demo in , I actually store the skin matrix of each bone in each frame , As a bone animation demonstration, it is more than enough .
But for practical applications , There are at least two problems here : First, the animation data frame by frame is generally the result of baking , stay dcc Animation data in the tool is generally keyframes + Curve type storage , Real time interpolation itself is not time consuming , And it can compress the bandwidth , So animation is often compressed and stored ;
Second, in addition to playing animation , Sometimes we need to do some post-processing for the action —— For example, animation blending discussed in this article , Another example is the effect of reverse dynamics , At this time, only skin matrix is not conducive to operation , We should according to our actual needs , Stored as local transformation matrix or global ( Model space ) Transformation matrix . Specially , If stored as a local transformation matrix , In the process of solving, there are steps to constantly find the parent node multiplication matrix , Arranging the order of bones reasonably here can avoid repeated operations .
Another issue to consider is , Whether the mixing should affect the playback length of the action ? Let's assume the action A The length is ta frame ,B by tb frame , The number of mixed frames is tc, So action A,B After mixing , The total frame length should be ta+tb, still ta+tb+tc, Or between the two ?
To address this issue , I think the friendly design is : The mixing time should not affect the original playback length , Mixing this function itself is only for better performance , It should not destroy the original system . Then there must be an action here “ sacrifice ” Part of the posture . A common idea is to make the target move before tc Convert frame to transition frame , The matrix of each frame and the last frame of the source action are interpolated according to the current time .
Concrete realization
For better mixing operation , We can modify the data stored in the animation to that in the model space transform value , Instead of the final skin matrix . So-called transform That is, store the translation, rotation, and zoom respectively , Then according to RST Construct the matrix :
struct STransform
{
QVector3D position = QVector3D(0, 0, 0);
QVector3D scale = QVector3D(1, 1, 1);
QQuaternion rotation = QQuaternion(0, 0, 0, 1);
};
In the actual interpolation operation , We also aim at every bone Translation of model space 、 rotate 、 The zoom Interpolate separately ( Because there is no scaling of bones in the project , Scaling interpolation is not calculated in actual engineering )
Switch to the new action , When we detect that new actions need to be mixed , According to the current action localtime, Sampling action transform value , As caching :
void CAnimationEngine::PlayAnimation(Object* obj, const string& path)
{
if(m_animators.find(path) == m_animators.end())
{
return;
}
int frame = -1;
string oldPath;
// check need blend, save cache pose
if(m_events.find(obj) != m_events.end() && m_animators.find(m_events[obj].m_path) != m_animators.end())
{
if(g_animParam.m_nBlendFrame)
{
oldPath = m_events[obj].m_path;
frame = min(m_animators[oldPath].GetFrameNum(), static_cast<int>(m_events[obj].m_time * FRAME_PER_MS));
}
}
m_events[obj] = SEvent(path, g_animParam.m_bLoop, g_animParam.m_nBlendFrame, g_animParam.m_eBlendCurve, g_animParam.m_fSpeed);
if(!oldPath.empty())
{
CAnimator& animator = m_animators[oldPath];
m_events[obj].m_cachePose = animator.GetTransform(frame);
}
}
Next , In the code that updates the bone animation , We translate the sampling action and cache action under the current frame number 、 Rotate and interpolate respectively , Mix weights in time t Company , Contains linear blending (t), And nonlinear mixing (3 * t * t - 2 * t * t).
After interpolation , We reconstruct the global transformation matrix of the model space , And multiply the inverse matrix of the binding matrix to construct the skin matrix , Pass to shader .
bool CAnimationEngine::UpdateAnimation(Object* obj, QOpenGLShaderProgram* program)
{
// ...
if (event.m_blendFrame > 0 && frame <= event.m_blendFrame && event.m_cachePose.size() > 0)
{
vector<QMatrix4x4> final;
float ratio = static_cast<float>(frame + 1) / (event.m_blendFrame + 1);
if (event.m_eBlendCurve == EBlendCurve::Smooth)
{
ratio = ratio * ratio * (-2 * ratio + 3);
}
for(int i = 0;i < size; i++)
{
STransform& transform = animator.GetTransform(frame, i);
QQuaternion quat = QQuaternion::slerp(event.m_cachePose[i].rotation, transform.rotation, ratio);
QVector3D trans = Lerp(event.m_cachePose[i].position, transform.position, ratio);
QMatrix4x4& invBindPose = CAnimationEngine::Inst()->GetBone(i)->m_invBindPose;
QMatrix4x4 mat;
mat.translate(trans);
mat.rotate(quat);
mat = mat * invBindPose;
final.push_back(mat);
}
program->setUniformValueArray(location,final.data(), size);
}
else
{
// ...
}
// ...
return true;
}
边栏推荐
- Use of form text box (I) select text
- Recent learning summary
- Solr series of full-text search engines - basic principles of full-text search
- Preliminary summary of structure
- tonybot 人形机器人 查看端口并对应端口 0701
- Zzuli:1046 product of odd numbers
- Talking about part of data storage in C language
- Zzuli:1054 monkeys eat peaches
- C language fcntl function
- 556. The next larger element III
猜你喜欢
Frequently asked questions: PHP LDAP_ add(): Add: Undefined attribute type in
Bibit pharmaceutical rushed to the scientific innovation board: annual revenue of 970000, loss of 137million, proposed to raise 2billion
Talking about part of data storage in C language
Adc128s022 ADC Verilog design and Implementation
分布式事务(Seata) 四大模式详解
C language fcntl function
基因家族特征分析 - 染色体定位分析
Rasterization: a practical implementation (2)
Amazon, express, lazada, shopee, eBay, wish, Wal Mart, Alibaba international, meikeduo and other cross-border e-commerce platforms evaluate how Ziyang account can seize traffic by using products in th
pyQt界面制作(登录+跳转页面)
随机推荐
Sword finger offer 28 Symmetric binary tree
DDK for XP
Stop asking yourself if you are suitable for software testing
retrofit
Zzuli:1053 sine function
Use of constraintlayout
ZABBIX saves the page blank after adding calculated items
动态获取权限
Luogu p5194 [usaco05dec]scales s solution
Tonybot humanoid robot infrared remote control play 0630
Zzuli: sum of 1051 square roots
Awvs batch operation script
2021-10-16 initial programming
Bibit pharmaceutical rushed to the scientific innovation board: annual revenue of 970000, loss of 137million, proposed to raise 2billion
Sendmail can't send mail and it's too slow to send. Solve it
Luogu p5018 [noip2018 popularization group] symmetric binary tree problem solution
Luogu p3065 [usaco12dec]first! G problem solution
tonybot 人形机器人 定距移动 代码编写玩法
Special research report on the market of lithium battery electrolyte industry in China (2022 Edition)
Zhonggan micro sprint technology innovation board: annual revenue of 240million, net loss of 17.82 million, proposed to raise 600million