当前位置:网站首页>[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;
}
边栏推荐
- 【7.3】146. LRU缓存机制
- Find the sum of the elements of each row of the matrix
- Talking about part of data storage in C language
- Common shortcut keys in PCB
- Table of mathematical constants by q779
- 1017 a divided by B (20 points)
- 556. The next larger element III
- Protobuf and grpc
- Pyqt interface production (login + jump page)
- Tonybot humanoid robot starts for the first time 0630
猜你喜欢
To improve efficiency or increase costs, how should developers understand pair programming?
556. The next larger element III
分布式事务(Seata) 四大模式详解
retrofit
Code writing and playing method of tonybot humanoid robot at fixed distance
puzzle(016.4)多米诺效应
dllexport和dllimport
Tailing rushes to the scientific and Technological Innovation Board: it plans to raise 1.3 billion, and Xiaomi Changjiang is the shareholder
Why is this error reported when modifying records in the database
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
随机推荐
[combinatorics] permutation and combination (set combination, one-to-one correspondence model analysis example)
Zzuli:1053 sine function
C language DUP function
Zzuli: cumulative sum of 1050 factorials
The mail function of LNMP environment cannot send mail
Zhejiang University Edition "C language programming (4th Edition)" topic set reference ideas set
7-28 monkeys choose King (Joseph problem)
FPGA blocking assignment and non blocking assignment
Output student grades
Luogu p4047 [jsoi2010] tribal division solution
Niuke: crossing the river
洛谷P3065 [USACO12DEC]First! G 题解
7-10 stack of hats (25 points) (C language solution)
动态获取权限
Get permissions dynamically
关于敏捷的一些概念
556. 下一个更大元素 III : 简单构造模拟题
Ultra simple mobile map development
PHP GD image upload bypass
ShowMeBug入驻腾讯会议,开启专业级技术面试时代