目录
一,四元数相关概念
四元数
- //VEX内获得四元数
- vector4 quaternion(matrix3 rotations) //仅应用矩阵的旋转信息
- vector4 quaternion(float angle, vector axis)
- vector4 quaternion(vector angleaxis) //方向为旋转轴,大小为旋转角度
-
- vector4 eulertoquaternion(vector rotations, int order)
注,数学运算,如绕某向量 K=(
,
,
) 旋转
,则四元数为:
- (x,y,z) = (
,
,
) *
![]()
- w =
![]()
- 且满足条件:
+
+
+
=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));
二,案例
参考:使用houdini绑定系统里的rigdoctor节点来提取矩阵_哔哩哔哩_bilibili
案例:沿面中心翻转
- //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;

案例:路径导弹
- //方法一
- 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;

案例:RBD刚体还原过渡
注,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);

案例:拉直螺旋线
- //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<npoints(0); j++){
- vector pos2 = point(0, 'P', j);
- pos2 = qrotate(rot, pos2-pos0);
- setpointattrib(0, 'P', j, pos2+pos0);
- }
- //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; }

案例:卷曲螺旋线
- //point层级,for循环在上一循环基础上循环,也可solver(SOP)
- int num = chi('num');
- if(@ptnum < num){
- vector pivot = point(0, 'P', num);
- vector prepos = point(0, 'P', num-1);
- vector nextpos = point(0, 'P', num+1);
- float ang = ch('ang')*pow(point(0, 'curveu', num)+0.01,-0.8);
-
- vector axis = normalize(cross(set(0,1,0), nextpos-pivot));
- vector4 rot1 = quaternion(ang, axis);
- vector4 rot2 = dihedral(prepos-pivot, pivot-nextpos);
- vector4 rot = qmultiply(rot1, rot2);
-
- @P -= pivot;
- @P = qrotate(rot, @P);
- @P += pivot;
- }
- vector pos[] = array();
- for(int i=0; i<@numpt; i++){
- pos[i] = point(0, 'P', i);
- }
-
- for(int i=0; i<chi('num'); i++){
- vector pivot = point(0, 'P', i);
- vector prepos = point(0, 'P', i-1);
- vector nextpos = point(0, 'P', i+1);
- float ang = ch('ang')*pow(point(0, 'curveu', i)+0.01,-0.8);
-
- vector axis = normalize(cross(set(0,1,0), nextpos-pivot));
- vector4 rot1 = quaternion(ang, axis);
- vector4 rot2 = dihedral(prepos-pivot, pivot-nextpos);
- vector4 rot = qmultiply(rot1, rot2);
-
- for(int j=0; j
- pos[j] -= pivot;
- pos[j] = qrotate(rot, pos[j]);
- pos[j] += pivot;
- }
- }
-
- for(int i=0; i<chi('num'); i++){
- setpointattrib(0, 'P', i, pos[i]);
- }
- //point层级,当前点位置与后一个点位置的旋转并卷曲信息
- vector pivot = point(0, 'P', @ptnum+1);
- vector pos2 = point(0, 'P', @ptnum+2);
- vector4 rot1 = dihedral(@P-pivot, pivot-pos2);
-
- vector axis = normalize(cross(set(0,1,0), pos2-pivot));
- float ang = ch('ang')*pow(@curveu+0.01,-0.8);
- vector4 rot2 = quaternion(ang, axis);
-
- vector4 rot = qmultiply(rot2, rot1);
-
- p@srot = slerp(set(0,0,0,1), rot, clamp(@Frame-101*@curveu,0,1));
- //point层级,此节点之前使用sort节点反向点号
- 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, 'srot', i));
- pos -= pivot;
- pos = qrotate(prerot, pos);
- pos += prepos;
- prepos = pos;
- @P = pos;
- }
- //使用rigdoctor可提取原模型本身旋转后的位移信息
- if(@ptnum<@Frame){
- vector pivot = point(0, 'P', @ptnum+1);
- vector pos2 = point(0, 'P', @ptnum+2);
- vector4 rot1 = dihedral(@P-pivot, pivot-pos2);
-
- vector axis1 = point(0, 'tangentv', @ptnum+1);
- vector axis2 = point(0, 'tangentv', @ptnum+2);
- vector4 axisrot = dihedral(axis2, axis1);
-
- vector axis = normalize(cross(set(0,1,0), pos2-pivot));
- float ang = ch('ang')*pow(1-@curveu+0.01,-0.5);
- vector4 rot2 = quaternion(ang, axis);
-
- vector4 rot = qmultiply(axisrot, rot1);
- rot = qmultiply(rot, rot2);
-
- matrix3 m = qconvert(rot);
-
- 4@localtransform *= m;
- }


- //针对原曲线不在同一平面,卷曲后也不再同一平面的问题修正
- for(int i=0; i<chi('num'); i++){
- vector pivot = point(0, 'P', i);
- vector prepos = point(0, 'P', i-1);
- vector nextpos = point(0, 'P', i+1);
- float ang = ch('ang')*pow(point(0, 'curveu', i)+0.01,-0.8);
-
- vector N = point(0, 'N', i);
- vector preN = point(0, 'N', i-1);
- vector4 prerot = dihedral(preN, N);
-
- vector axis = normalize(cross(N, nextpos-pivot));
- vector4 rot1 = quaternion(ang, axis);
- vector4 rot2 = dihedral(prepos-pivot, pivot-nextpos);
- vector4 rot = qmultiply(rot1, rot2);
-
- for(int j=0; j<i; j++){
- pos[j] -= pivot;
- pos[j] = qrotate(rot, pos[j]);
- pos[j] = qrotate(prerot, pos[j]);
- pos[j] += pivot;
- }
- }
-
- for(int i=0; i<chi('num'); i++){
- setpointattrib(0, 'P', i, pos[i]);
- }
