VEX —— Quaternion|Euler Angle

目录

一,四元数相关概念

四元数

欧拉角

常用四元数相关函数

相互转换

二,案例

案例:沿面中心翻转

案例:路径导弹

案例:RBD刚体还原过渡

案例:拉直螺旋线


一,四元数相关概念

四元数

  • 在vex内四元数为((x,y,z),w);
//VEX内获得四元数
vector4 quaternion(matrix3 rotations) //仅应用矩阵的旋转信息
​vector4 quaternion(float angle, vector axis)
vector4 quaternion(vector angleaxis) //方向为旋转轴,大小为旋转角度

vector4  eulertoquaternion(vector rotations, int order)

注,数学运算,如绕某向量 K=(K_{x}K_{y}K_{z}) 旋转\theta,则四元数为:

  • (x,y,z)  =  (K_{x}K_{y}K_{z}) *  \sin \frac{\theta }{2} 
  • w =  \cos \frac{\theta }{2} 
  • 且满足条件:x^{2}+y^{2}+z^{2}+w^{2}=1

欧拉角

由环绕三个轴旋转的角度组成的矢量表示

  • 绕著x轴的旋转(Roll),绕著交点线的旋转(Pitch),绕著z轴的旋转(Yaw);
  • 任何旋转矩阵都是由三个基本旋转矩阵复合而成的;
  • 不同旋转顺序,结果不同,默认旋转顺序XYZ;
//VEX内获得欧拉角
vector  quaterniontoeuler(vector4 orient, int order)

注,可使用Transform节点应用欧拉角;

常用四元数相关函数

dihedral()

quaternion()

qrotate()

qmultiply()

qinvert()

qdistance()

qconvert()

eulertoquaternion()

quaterniontoeuler()

slerp()

相互转换

//矩阵转四元数
matrix m = detail(1, 'xform');
vector4 q = quaternion(matrix3(m));
//四元数转矩阵
vector4 q = quaternion(ch('ang'), chv('axis'));
matrix3 m = qconvert(q);
//欧拉角转矩阵或四元数
v@euler_angle = degrees(chv('ang'));
vector4 q = eulertoquaternion(@euler_angle);
matrix3 m = qconvert(q);
//四元数或矩阵,获取欧拉角
matrix m = detail(1, 'xform');
vector4 q = quaternion(matrix3(m));
v@euler_angle = degrees(quaterniontoeuler(q, 0));

二,案例

  • 设置旋转,dihedral,quaternion,orient(可用于copy);
  • 合并旋转,qmultiply
  • 应用旋转,qrotate

案例:沿面中心翻转

//point层级,并获取所属面的其他点
int pts[] = primpoints(0, @primnum);
vector pos0 = point(0, 'P', pts[0]);
vector pos1 = point(0, 'P', pts[1]);
vector pos2 = point(0, 'P', pts[2]);
vector pos3 = point(0, 'P', pts[3]);
//方法一,先归到中心点旋转,在还原
vector center = (pos0+pos1+pos2+pos3)/4;
vector axis = normalize(pos1-pos0);

@P -= center;

float ang = @Time;
vector4 q = quaternion(ang, axis);
@P = qrotate(q,@P);

@P += center;

//方法二,使用maketransform
vector pivot = (pos0+pos1+pos2+pos3)/4;
vector axis = normalize(pos1-pos0);

//直接绕axis旋转
float ang = @Time;
vector4 q_r = quaternion(ang, axis);
vector r = degrees(quaterniontoeuler(q_r, 0));

@P *= maketransform(0,0,0,r,1,pivot,0);

//绕x轴旋转,中心点旋转偏移到axis
float ang = @Time;
vector dir = set(1,0,0);
vector r = dir * degrees(ang);
vector4 q_pr = dihedral(dir, axis);
vector pr = degrees(quaterniontoeuler(q_pr, 0));

@P *= maketransform(0,0,0,r,1,pivot,pr);
//方法三,使用函数instance
vector pivot = (pos0+pos1+pos2+pos3)/4;
vector axis = normalize(pos1-pos0);

float ang = @Time;
vector4 orient = quaternion(ang, axis);
@P *= instance(pivot,0,1,0,orient,pivot);
//方法二,手搓矩阵(即将本身或局部坐标系恢复到世界坐标系,旋转后,在还原到原坐标系)
vector center = (pos0+pos1+pos2+pos3)/4;
vector xaxis = normalize(pos1-pos0);
vector yaxis = normalize(prim(0,'N',@primnum));
vector zaxis = normalize(cross(xaxis, yaxis));

matrix m = set(xaxis, yaxis, zaxis, center);
m.xa = m.ya = m.za = 0;
@P *= invert(m);

float ang = @Time;
vector4 q = quaternion(ang, set(1,0,0));
@P = qrotate(q, @P);

@P *= m;

VEX —— Quaternion|Euler Angle_第1张图片

案例:路径导弹

//方法一
vector tangentu = -primuv(1, 'tangentu', 0, ch('u'));
vector tangentv = primuv(1, 'tangentv', 0, ch('u'));
vector pos = primuv(1, 'P', 0, ch('u'));

vector4 rot1 = dihedral(set(1,0,0), tangentu);
vector4 rot2 = quaternion(@Time*10, set(1,0,0));
vector4 rot = qmultiply(rot1, rot2);

//如不是pack物体
@P = qrotate(rot, @P) + pos;

//如是pack物体,使用以下代码
@P = pos;
matrix3 m = qconvert(rot);
setprimintrinsic(0, "transform", 0, m);
//方法二
vector x_axis = -primuv(1, 'tangentu', 0, ch('u'));
vector y_axis = primuv(1, 'tangentv', 0, ch('u'));
vector z_axis = cross(x_axis, y_axis);
vector pos = primuv(1, 'P', 0, ch('u'));

matrix m = set(normalize(x_axis), normalize(y_axis), normalize(z_axis), pos);
vector4 q = quaternion(@Time*10, set(1,0,0));

@P = qrotate(q, @P);
@P *= m;

VEX —— Quaternion|Euler Angle_第2张图片

案例:RBD刚体还原过渡

  • RBD刚体的中心和质心(rest信息)的区别;

注,pack对象intrinsic属性

  • transform,存储旋转信息,使用setprimintrinsic函数设置;
  • packedfulltransform,存储所有的变换信息(只读);
//DOP内部还原的原始位置为rest,注意设置input端口
//直接用rbdbulletsolver(SOP),原始位置还是originP
float bias = chramp('bias', fit(@Frame-@offset*10,75,125,0,1));
matrix3 cm = primintrinsic(0, 'transform', @ptnum);
matrix3 blend = slerp(cm, 3@m, pow(bias,2));
setprimintrinsic(0, 'transform', @ptnum, blend);
v@P = lerp(@P, v@rest, bias);
float bias = chramp('bias', fit(@Frame-@offset*10,75,125,0,1));
matrix fm = getpackedtransform(0, @ptnum);
vector t = cracktransform(0, 0, 0, 0, 4@fm);
translate(4@fm, -t);
translate(4@fm, v@rest);
matrix blend = slerp(fm, 4@fm, bias);
setpackedtransform(0, @ptnum, blend);

VEX —— Quaternion|Euler Angle_第3张图片

案例:拉直螺旋线

  • 原理1:以0号点为中心旋转1号点及后续所有点到Y轴上,在以1号点为中心旋转2号点及后续所有点到Y轴上,依次类推;可使用solver或循环(在旋转一次的基础在旋转,容易理解);
  • 原理2,每层循环记录上次循环的上一个拉直点(prepos);每层循环先移动到原点旋转Y轴,在加上prepos;
  • 原理3,每个点依次旋转到前点和前前点的方向上,最后对齐到Y轴;
  • for等循环体内的point()始终都是读取输入端口的属性,setpointattrib始终会在输出时设置;
//solver节点内,detail层级
int i = @Frame;
vector pos0 = point(0, 'P', i-1);
vector pos1 = point(0, 'P', i);
vector4 rot = dihedral(pos1-pos0, set(0,1,0));

vector pos = qrotate(rot, pos1-pos0);
setpointattrib(0, 'P', i, pos+pos0);
    
for(int j=i+1; j
//point层级(也可是detail层级),每层循环互不关联
vector prepos = 0;

for(int i=1; i< @Frame; i++){
    vector pivot  = point(0, 'P', i-1);
    vector pos = point(0, 'P', i);    
    vector4 rot = dihedral(pos-pivot, set(0,1,0));    
    
    if(@ptnum>=i){
        vector mpos = qrotate(rot, @P-pivot);
        //@P=mpos+prepos; //会对下一循环影响
        setpointattrib(0, 'P', @ptnum, mpos+prepos);
     }
    
     prepos = qrotate(rot, pos-pivot)+prepos;
}
//detail层级
vector pos[] = array();
for(int i=0; i<@numpt; i++){
    pos[i] = point(0, 'P', i);
}

for(int i=1; i<@Frame; i++){
    vector4 rot = dihedral(pos[i]-pos[i-1], set(0,1,0));      
    for(int j=i; j<@numpt; j++){
        pos[j] = qrotate(rot, pos[j]-pos[i-1]);
        pos[j] += pos[i-1];
    }
}

for(int i=0; i<@numpt; i++){
    setpointattrib(0, 'P', i, pos[i]);
}

//point层级,当前点位置与前一个点位置对齐
vector pos1 = point(0, 'P', @ptnum-1);
vector pos2 = point(0, 'P', @ptnum-2);
vector4 rot = dihedral(@P-pos1, pos1-pos2);
if(@ptnum==1)
    rot = dihedral(@P, set(0,1,0));
p@rot = rot;

vector4 rot1 = set(0,0,0,1);
p@rot = slerp(rot1, p@rot, ch('val'));
//point层级,每个点都是相当于先对齐前一个点,在对齐前前点...,直到最后对齐Y轴
vector prepos = 0;
vector4 prerot = set(0,0,0,1);

for(int i=0; i<=@ptnum; i++){
    vector pos = point(0, 'P', i);
    vector pivot = point(0, 'P', i-1);
    prerot = qmultiply(prerot, point(0, 'rot', i));
    pos -= pivot;
    pos = qrotate(prerot, pos);
    pos += prepos;
    prepos = pos;
    @P = pos;
}

VEX —— Quaternion|Euler Angle_第4张图片

你可能感兴趣的:(#,VEX,Houdini)