目录
参考 https://www.cnblogs.com/vfxJerry/p/12108565.html
一,矩阵相关概念
vex内基于row行vector,vector*matrix==matrix*vector;
向量{x, y, z, w},w=1表示位置,w=0表示方向;
vector3 * matrix4*4, vector3自动转化为vector4(w=1);
注
- 3*3矩阵和4*4矩阵之间转换需注意;
- 创建起始矩阵应是单位矩阵,若为非单位矩阵最后一列应为(0,0,0,1);
- 矩阵本身即可包含位移、旋转、缩放,旋转和缩放会涉及中心点,所以先后顺序会影响结果;
- 顺序不影响,4*4中的前3*3矩阵中数值;
- 如先应用位移,顺序就会影响,4*4中的最后一行位移信息会不一样;
Houdini内主要矩阵类型
- Identity Matrix,单位矩阵保持不变ident();
- Translation Matrix,位移矩阵translate();
- Rotation Matrix,旋转矩阵rotate();
矩阵含义
注,可理解为创建新的坐标系相对于世界坐标系,即手搓矩阵,补位(第四列)应为(0,0,0,1);
//表示从世界原点变换到指定位置的坐标
//默认补位都是1
4@m = set(v@x_axis, v@y_axis, v@z_axis, v@P);
@m.xa = @m.ya = @m.za = 0;
设置矩阵值 setcomp
setcomp(@m, 0,0,3);
setcomp(@m, 0,1,3);
setcomp(@m, 0,2,3);
常用矩阵相关函数
ident(),单位矩阵;
translate(),位移矩阵;
rotate(),选择矩阵;
scale(),缩放矩阵;
invert(),反转矩阵;
transpose(),行列交换;
maketransform(),构建3*3/4*4矩阵;
cracktransform(),提取矩阵的位移、旋转或缩放信息;
instance(),实例(使用指定的位置和法线,类似copy);
lookat(),获取朝向矩阵;
slerp(),矩阵或四元数融合;
//变换
4@m=ident();
translate(@m, chv('trans'));
rotate(@m, ch('ang'),4); //x轴1,y轴2,z轴4
scale(@m, chv('scale'));
@P *= @m;
//以m2中心点旋转
matrix m1 = ident();
matrix m2 = detail(1,'xform');
rotate(m1, ch('ang1'), set(1,0,0));
rotate(m2, ch('ang2'), set(0,1,0));
@P *= m1*m2;
二,案例
参考:使用houdini绑定系统里的rigdoctor节点来提取矩阵_哔哩哔哩_bilibili
案例:源位置过渡到目标位置
vector P = point(1, 'P', chi('num'));
vector N = point(1, 'N', chi('num'));
matrix m1 = instance(P, N, chv('scale'));
//方法一,直接插值过渡
@P *= slerp(ident(), m1, ch('bias'));
//方法二,提取各个变换分量,分别插值过渡,最后在合并
vector t,r,s;
cracktransform(0,0,set(0,0,0),m1,t,r,s);
t = lerp(set(0,0,0),t,ch('bias'));
s = lerp(set(1,1,1),s,ch('bias'));
//旋转过渡类似 r = -lerp(set(0,0,0),r,ch('bias'));
vector4 q = eulertoquaternion(radians(r), 0);
vector4 ql = slerp(quaternion(set(0,0,0)),q,ch('bias'));
r = degrees(quaterniontoeuler(ql,0));
@P *= maketransform(0,0,t,r,s);
案例:交叉球去穿插
houdini矩阵使用案例矩阵去除干涉_哔哩哔哩_bilibili
//转化坐标系思路,以相交的切面为新坐标系或以每个球中心点为坐标系
//在copy球前的源点上,记录每个会相交点的坐标系矩阵
i[]@nearpts = nearpoints(0, @P, 1);
pop(@nearpts, 0);
matrix mat[];
foreach(int pt; i[]@nearpts){
vector P1 = point(0,"P",pt);
float pscale1 = point(0,"pscale",pt);
float len = length(@P-P1);
//lenx相交面的中心点到附件点的距离
if(len < @pscale + pscale1){
float lenx = len/2 + (pow(@pscale,2)-pow(pscale1,2))/(2*len);
vector x = normalize(P1-@P);
vector y = set(0,1,0);
vector z = normalize(cross(x,y));
vector pos = @P+x*lenx;
matrix m = set(x,y,z,pos);
m.xa = m.ya = m.za = 0;
append(mat, m);
}
}
4[]@mat = mat;
//在copy后的球上,应用矩阵
foreach(matrix m; 4[]@mat){
@P *= invert(m);
if(@P.x>0){
//@Cd = 0;
@P.x = 0;
}
@P *= m;
}
案例:相机投射
//投射平面变换到相机位置,并-Z轴偏移
matrix cam_matrix = optransform(chsop('path')); //提取obj层级的变换
@P *= cam_matrix;
//1号端口为相交模型
vector cam_pos = set(0,0,0)*cam_matrix;
vector dir = @P-cam_pos;
vector p, uvw;
int prim = intersect(1, cam_pos, dir, p, uvw);
if(prim>-1){
@P=p;
@Cd = primuv(1, 'Cd', prim, uvw);
}
else
@Cd = 0;
案例:路径运动并旋转
//获取路径参考点的信息
vector x = normalize(point(1, 'tangentu', 0));
vector z = normalize(cross(set(0,1,0), x));
vector y = normalize(cross(x, z));
vector pos = point(1, 'P', 0);
注,方法一与以下其他方法,旋转位置会有偏差;
- 方法一,是先将所有轴都设置(对齐)为指定的 x/y/z 轴,在旋转y轴;
- 其他方法都是,先将y轴设置(对齐)为指定y轴,在旋转y轴(或先旋转在对齐);
//方法一,手搓矩阵 //先调整坐标系,在原地旋转,位移 matrix m = set(x, y, z, set(0,0,0)); m.xa = m.ya = m.za = 0; rotate(m, radians(@Frame*20), y); translate(m, pos); @P *= m;
//方法二,四元数或矩阵,也是原地旋转,在位移 //注,可将rot设置为orient属性,在使用copy节点 vector4 rot1 = dihedral(set(0,1,0), y); vector4 rot2 = quaternion(radians(set(0,1,0)*@Frame*20)); vector4 rot = qmultiply(rot1, rot2); //先rot2,在rot1 @P = qrotate(rot, @P); @P += pos;
vector4 rot1 = dihedral(set(0,1,0), y); vector4 rot2 = quaternion(radians(y*@Frame*20)); vector4 rot = qmultiply(rot2, rot1); //先rot1,在rot2 @P = qrotate(rot, @P); @P += pos;
vector4 q = dihedral(set(0,1,0), y); matrix m = ident(); rotate(m, radians(@Frame*20), y); translate(m, pos); @P = qrotate(q, @P); @P*=m;
//方法三,maketransform函数,也是原地旋转,在位移 //pr只是调整坐标系 vector4 q = dihedral(set(0,1,0), y); vector pr = degrees(quaterniontoeuler(q, 0)); vector rot = set(0,1,0)*@Frame*20; @P = qrotate(q, @P); matrix m = maketransform(0,0,0,rot,1,0,pr); //沿新坐标系的y轴旋转 translate(m, pos); @P *= m;
//方法四,instance函数 //此函数是先计算orient参数,在计算rotate参数,有先后顺序不可写反 vector4 rot1 = dihedral(set(0,1,0), y); vector4 rot2 = quaternion(radians(set(0,1,0)*@Frame*20)); matrix m = instance(pos, 0, 1, rot1, rot2, 0); @P *= m;
vector4 rot1 = dihedral(set(0,1,0), y); vector4 rot2 = quaternion(radians(y*@Frame*20)); matrix m = instance(pos, 0, 1, rot2, rot1, 0); @P *= m;
vector4 rot1 = dihedral(set(0,1,0), y); vector4 rot2 = quaternion(radians(set(0,1,0)*@Frame*20)); vector4 orient = qmultiply(rot1, rot2); //先rot2,在rot1 matrix m = instance(pos, 0, 1, 0, orient, 0); @P *= m;