看了几个关于关键帧提取和关键帧插值的论文,有几篇讲到了四元数插值这个概念
关于欧拉角到四元数的转换,请看:刚体运动研究方法——欧拉角四元数
接下来介绍四元数的插值公式以及matlab实现
插值公式可以从论文论文理解——从运动捕获数据中提取关键帧中找到,在这里再写一遍


这里的 t 代表的是在夹角的哪一部分插值,从下图可以看出来,图中的ang=θ

话不多说,上代码(matlab实现):
网上摘取的,地方忘记了,并且经过了一个小小的修改
SlepInsert.m
function r= SlerpInsert(p,q,t)
%球面线性插值
%程序考虑了p、q点乘结果为负的情况
%返回的插值结果是r
w0=p(1);x0=p(2);y0=p(3);z0=p(4);
w1=q(1);x1=q(2);y1=q(3);z1=q(4);
%用点乘计算两个四元数夹角的cos值
cosOmega=w0*w1+x0*x1+y0*y1+z0*z1;
%如果点乘为负,则反转一个四元数以取得短的4D弧
if(cosOmega<0.0)
w1=-w1;
x1=-x1;
y1=-y1;
z1=-z1;
cosOmega=-cosOmega;
end
%检查他们是否接近,以避免除零
m=size(t,2);%火啊去插值精度,即需要分别在哪一部分插值
for i=1:m
if cosOmega>0.99999999 %cos=1的时候就是夹角为0,重合
k0=1.0-t(i);
k1=t(i);
else
%用三角公式sin?+cos?=1计算sin值
sinOmega=sqrt(1.0-cosOmega*cosOmega);
%通过sin和cos计算角度
omega=atan2(sinOmega,cosOmega) %计算点(cosOmega,sinOmega)与x轴正向的夹角
%计算分母的倒数,这样就只需要一次除法
oneOverSinOmega=1.0/sinOmega;
%计算插值变量
k0=sin((1.0-t(i))*omega)*oneOverSinOmega;
k1=sin(t(i)*omega)*oneOverSinOmega;
end
%插值
w=w0*k0+w1*k1;
x=x0*k0+x1*k1;
y=y0*k0+y1*k1;
z=z0*k0+z1*k1;
r(i,1)=w; r(i,2)=x; r(i,3)=y; r(i,4)=z;
end
SerpInsertTest.m
clear
clc
q=[1 2 3 4];
p=[1 3 6 8];
t=0:0.5:2*pi;
r=SlerpInsert(p,q,t);结果:
r =
1.0000 3.0000 6.0000 8.0000
1.0000 2.5000 4.5000 6.0000
1.0000 2.0000 3.0000 4.0000
1.0000 1.5000 1.5000 2.0000
1.0000 1.0000 0 0
1.0000 0.5000 -1.5000 -2.0000
1.0000 0 -3.0000 -4.0000
1.0000 -0.5000 -4.5000 -6.0000
1.0000 -1.0000 -6.0000 -8.0000
1.0000 -1.5000 -7.5000 -10.0000
1.0000 -2.0000 -9.0000 -12.0000
1.0000 -2.5000 -10.5000 -14.0000
1.0000 -3.0000 -12.0000 -16.0000
按照论文思想就是酱紫啦,如果需要在OpenGL里面实现的话,请参考网络里面的大牛们的文章。