VEX —— Matrix

目录

一,矩阵相关概念

矩阵含义

设置矩阵值 setcomp

常用矩阵相关函数

二,案例

案例:源位置过渡到目标位置

案例:交叉球去穿插

案例:相机投射

案例:路径运动并旋转


参考 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;

<think>嗯,用户想知道Houdini中Point Wrangle节点内transform操作的执行优先级。我之前学过的关于Copy to Points的引用里提到过参数优先级的问题,比如transform可能比orient优先级高。所以,可能Point Wrangle里的操作顺序也很重要。 首先,Point Wrangle处理每个点的时候是按照代码顺序来的,所以每一步操作都会覆盖前面的结果。比如先平移再旋转的话,旋转是基于平移后的位置进行的。用户可能需要了解各个变换的顺序对最终结果的影响。 然后,Houdini中参数的优先级问题,比如在Copy to Points时,transform属性可能比orient优先级高,导致orient无效。类似地,Point Wrangle里如果有多个变换属性,比如N、transform、p@orient等,它们的执行顺序应该根据Houdini的内部优先级来决定。比如,transform矩阵可能比单独的旋转属性优先级更高,所以如果有同时设置的话,transform会被最后应用。 另外,用户提供的引用3中的代码示例,里面通过循环处理点的位置,逐步修改P属性。这说明在Point Wrangle里,每一步的setpointattrib都是直接修改属性,所以后面的操作会覆盖前面的。如果有多个变换步骤,比如先位移再旋转,代码中的顺序会影响最终结果。 还要注意Houdini的坐标系和矩阵乘法顺序。比如,矩阵变换通常是先缩放,再旋转,最后平移,但如果是行矩阵还是列矩阵会影响乘法的顺序。在Point Wrangle中,如果用户自己构造变换矩阵,需要注意乘法的顺序,比如M = T * R * S,这样会先缩放,再旋转,最后平移。 总结下来,Point Wrangle内的transform执行顺序主要看代码的书写顺序,而不同属性(如transform矩阵和orient四元数)之间的优先级需要参考Houdini的官方文档或者测试确定。此外,矩阵乘法顺序和坐标系也是关键因素。需要告诉用户正确的操作顺序和属性优先级,避免出现预期外的结果。</think>### Houdini Point Wrangle节点transform执行优先级解析 在Houdini中,Point Wrangle节点的transform操作执行顺序遵循特定的优先级规则,以下分步骤说明: 1. **基础执行逻辑** - 在Point Wrangle中,所有操作按代码书写顺序逐行执行 - 每个点的属性修改会立即生效,后续操作基于前序结果进行 - 示例代码: ```c @P += {1,0,0}; // 先执行X轴平移 @P *= 0.5; // 再执行缩放 ``` 2. **属性优先级层级** - 当同时存在多种transform属性时,按以下顺序生效: ```markdown 1. 直接修改`@P`属性 (最高优先级) 2. transform矩阵属性 `3@transform` 3. 四元数旋转 `4@orient` 4. 位移/旋转/缩放分离属性 `@scale`, `@rot`, `@trans` (最低优先级) ``` - 引用示例中transform参数优先级高于orient的特性与此一致[^1] 3. **矩阵运算顺序** - 当使用`matrix3`或`matrix`类型时,注意Houdini采用行向量右乘规则: ```c matrix m = ident(); rotate(m, radians(ch("rot")), {0,1,0}); // Y轴旋转 translate(m, {1,0,0}); // X轴位移 @P *= m; // 先旋转后位移 ``` - 矩阵乘法顺序与常规相反:`M = T * R * S` 4. **常见执行场景** - **叠加变换**:通过分步操作实现复合效果 ```c // 先缩放后旋转 @P *= chv("scale"); matrix3 rotm = ident(); rotate(rotm, radians(ch("angle")), {0,0,1}); @P *= rotm; ``` - **强制覆盖**:使用`setpointattrib()`直接指定最终值 ```c vector newpos = @P * chv("scale") + chv("offset"); setpointattrib(0, "P", @ptnum, newpos); ``` 5. **调试建议** - 使用`printf()`输出中间值验证执行顺序 - 在Geometry Spreadsheet中观察属性变化时序 - 引用代码示例中通过数组缓存中间值的做法值得参考[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值