目录
一,概述
在Houdini内有多个节点可编写Vex表达式或Vex代码片段(snippet),如Geometry节点AttributeWrangle,Dynamic节点GeometryWrangle、Gas Field Wrangle、及particle dynamics nodes;Vex表达式可在point, particle, edge, primitive, voxel(依赖节点类型)上运行,还可读取节点参数和几何体属性,及设置特殊变量来更改输入几何体的值;Python与之类似,但是使用python语言编写;
出于性能的原因,Houdini正朝向通过对属性操作来修改几何体的方向发展,而不是使用HScript表达式操作局部变量和外部通道引用;
- 相对于HScript,Vex运行更快,可自动支持线程和并行计算;
- 直接处理属性,会更容易使用;局部变量的命名可能与底层属性的名称不一致,且节点与节点之间也可能不一致;
- 使用HScript表达式,获取属性(没有映射局部变量的)会变得非常麻烦,如point(opinputpath(".",0), $PT, "my_var", 0)),但Vex表达式,会简单的多,如@my_var;由于在Houdini里经常围绕属性,所以Vex会方便的多;
- 相对于使用HScript的外部引用而言,对于将属性信息向下传递及并行处理会更加友好;
- 当前,compiled SOP blocks可支持Vex操作,不支持编译使用局部变量的HScript表达式;
- Vex已有大多数HScript 表达式函数的等价物,且更易用于数组和字符串处理,如类似Python的数组/字符串切片和类似Python的字典;
随着处理的几何体越大、越复杂,线程和并行处理对于性能变得越来越重要;VEX会被越来越广泛地用于替换HScript表达式;
二,语法
VEX有一个语境(Context)的概念,一些函数仅仅在特定的语境下有效,如在SOP context内访问几何体信息的函数;VEX snippet可用于编写VEX代码片段,运行在CVEX语境下;
语法要点
- 每个语句必需已封号(;)结尾;
- //和/*...*/可引用注释;
- 三角函数如sin、cos使用弧度radians,而不是degrees;
- 矢量属性分量使用@v.x,而不是$VX;
- rand应用于矢量变量时,将产生矢量noise;
1,声明属性
在使用属性前,应指定属性的类型和默认值;
- 如属性已存在,忽略默认值;不存在,则使用默认值;
- 在声明属性类型后,即可省略类型符号;
float @mass = 1;
vector @up = {0, 1, 0};
//报错,必需是合法的constant,即是确定的常数值
float @mass = 1 / area; // Error
vector @up = set(0, 1, 0); // Error
可使用简写数据类型模式:
- 此时使用表达式不必是constant;
- 数组不简写,不可赋初值;
f@mass = 1;
v@up = {0, 1, 0};
f@mass = 1 / area;
v@up = set(0, 1, 0);
int @arr[] = {1, 2}; //报错
i[]@arr = {1, 2};
int arr[] = {1, 2};
2,访问Geometry属性和信息
在snippet内,可使用@attrib_name,来读取或写入属性值,如@P;
- 在Volume Wrangle内,@volume_name可读取和写入指定的volume;
- 当写入@attrib_name时,若属性不存在时,则会创建此属性,但Volume Wrangle不会创建新的volume;
- Houdini提供了一些可在snippet内使用的类属性的变量,如@elemnum(表示当前元素的编号),@numelem(表示元素的总数);
- 一些节点可能提供了额外的类属性的变量,如Volume Wrangle,可使用@center(表示volume的中心点);
- Houdini会使用适当的Vex数据类型来转换一些常用属性,如@P、@v等会自动转换属性类型;对访问不同端口输入的属性@opinputn_name,自动转换不起作用;
- 默认@是浮点类型,可手动在@前添加指定的类型的符号(只需首次指定类型);
VEX Type | Syntax |
int | i@name |
float | f@name |
vector2 (2 floats) | u@name |
vector (3 floats) | v@name |
vector4 (4 floats) | p@name |
matrix2 (2×2 floats) | 2@name |
matrix3 (3×3 floats) | 3@name |
matrix (4×4 floats) | 4@name |
string | s@name |
array | type[]@name |
dict | d@name |
VEX Type | Attribute names |
vector (3 floats) | @P, @accel, @Cd, @N, @scale, @force, @rest, @torque, @up, @uv, @v,@center, @dPdx, @dPdy, @dPdz |
vector4 (4 floats) | @backtrack, @orient, @rot |
int | @id, @nextid, @pstate, @elemnum, @numelem, @ptnum, @primnum, @vtxnum, @numpt, @numprim, @numvtx, @group_*, @ix, @iy, @iz, @resx, @resy, @resz |
string | @name, @instance |
访问其他端口输入的属性
如节点不止一个输入端口,可通过添加前缀opinputinputnum_(inputnum从0开始)来访问不同输入的属性,如v@opinput1_P,即读取相同元素编号下1号端口的P属性;默认使用相同元素编号,但可在节点参数“Attribute to Match”来使用指定的属性匹配;
3,访问参数值parameter
在snippet内,可使用参数的内部名字作为变量名,来读取或写入节点上的参数值;
- 在参数编辑器内,鼠标悬停在参数名上可显示该参数的内部名;
- 访问用户创建的参数值,可使用函数chf/chv等函数;
4,访问全局变量
不像Hscript表达式,vex无法使用像$F来访问全局变量;在vop中,可从全局节点连接全局变量如Time、Frame;如下为可直接使用的隐式全局变量;
Implicit Variables | Explaining |
@Time | 相当于$T |
@Frame | 相当于$FF |
@SimTime | 相当于$ST(仅在DOP Context) |
@SimFrame | 相当于$SF(仅在DOP Context) |
@TimeInc | 相当于1/$FPS |
5,设置Geometry属性
可使用@语法,设置几何体属性,这是在snippet中优先使用的方法;逻辑上在VEX function中,有三个不同的有效geometry;
- input geometry,如使用point(0, ...)来读取输入几何体点属性;
- 不会被@attrb_name或setpointattrib(0, ...)所做的修改;
- current geometry,当前正在运行的point/prim,直接使用@attrb_name来读取或修改属性;
- output geometry,如使用setpointattrib(0, ...)写入几何体点属性;
- 将覆盖任何@attrb_name所做的修改;
//属性a值仍为0
@a=2;
@a=point(0,"a",@ptnum); //读取输入的属性,不涉及@a=2的设置
//属性a值仍为2
@a = 1;
setpointattrib(0,"a",@ptnum,2); //设置输出几何体的属性,会覆盖其他设置
@a = 3;
@a=point(0,"a",@ptnum);
6,索引变量
在循环过程中,知道当前元素编号和元素总数是非常有用的;
Indexing Variables | Explaining |
@elemnum | 当前元素编号(泛型); |
@numelem | 元素总数(泛型); |
@ptnum | 当前点号; 如使用在vertex,表示本身对应的point, 如使用在prim,则表示prim上第0号vertex的point; |
@primnum | 当前面号; 如使用在vertex,表示本身对应的prim; 如使用在point,则表示包含该point的prim(-1表示没有prim,如有多个prim包含该point返回其中任意一个prim); |
@vtxnum | 当前顶点号; 如使用在point,表示本身对应的vertex(-1表示没有vertex,如有多个vertex包含该point返回其中任意一个vertex); 如使用在prim,则表示prim上第0号vertex; linear vertex number是从0到vertex总数-1,不同于vertex’s primitive index;vertexprim表示获取linear vertex number对应的primnum; vertexprimindex表示将linear vertex number转化为vertex’s primitive index; primvertexcount表示获取prim的vertex总数; |
@numpt | 当前点总数; |
@numprim | 当前面总数; |
@numvtx | 使用在detail表示当前顶点总数,其他则表示当前prim顶点总数; |
7,创建几何体
可使用特定节点创建几何体,如attribwrangle;使用绑定变量(如@attrib_name)设置属性比函数setattrib更快,仅当在其他元素上设置属性时使用函数setattrib;
Functions | Explaining |
addpoint | 创建点 |
addprim | 创建面 |
addvertex | 创建顶点 |
setattrib | 设置属性值 |
setprimvertex | 将顶点重连到点 |
removepoint | 移除点 |
removeprim | 移除面 |
setpointgroup | 添加或移除点到/从组 |
setprimgroup | 添加或移除面到/从组 |
setprimintrinsic | 设置一个可写入的面固有属性 |
8,访问组
- 特定虚拟属性@group_groupname,可获取或设置组;
- 值为1或非0值,表示当前元素在组内;值为0,则表示从组内移除;
9,Includes
在代码片段内的任何#include指令将自动从被生成的函数内移出;确定一个参数是否用于属性绑定,是通过在预处理后简单的代码扫描完成的;此预处理仅在代码片段上完成,但并不处理任何#include文件;可能会被依赖于#includes的#ifdef指令混淆;
10,Tips
- 在多行编辑器内,可按Ctrl+Enter提交更改和更新houdini;
- VEX片段在每一帧运行,或在模拟网络内每步幅运行;
- 可使用return语句,提前退出VEX片段;
Code | Problem |
force += 2 | Syntax error, unexpected '}', expecting ';' Each statement must end with a semicolon (;) |
@v += force; | SRead-only expression given for read/write parameter Particle nodes cannot modify particle attributes. |
x = { 0, @y, 0}; | Syntax error, unexpected identifier, expecting '}'. You cannot have varying arguments to the {} vector constructor. Use set() instead: x = set(0, @y, 0);. |
x = set(0, $F, 0); | Doesn't animate. While $F will be evaluated, VOP networks are not time dependent so it won’t animate. Use @Frame instead. |
三,使用属性操作函数
添加属性函数:
addpointattrib(0, "Cd", {0, 0, 0});
addvertexattrib(0, "Cd", {0, 0, 0});
addprimattrib(0, "Cd", {0, 0, 0});
adddetailattrib(0, "Cd", {0, 0, 0});
设置属性函数:
setpointattrib(0, "Cd", 0, {0, 0, 0});
setvertexattrib(0, "Cd", 0, {0, 0, 0});
setprimattrib(0, "Cd", 0, 0, {0, 0, 0});
setdetailattrib(0, "Cd", {0, 0, 0});
获取属性函数:
vector c1 = point(1, "Cd", @ptnum);
vector c2 = prim(1, "Cd", 0);
vector c3 = vertex(1, "Cd", 0);
vector c4 = detail(1, "Cd", 0);
内在属性
- intrinsic内在属性,只有prim、detail层级上会存在;
- 读取内在属性primintrinsic(),设置内在属性setprimintrinsic();
四,snippet、inline
在snippet中,其内的代码会封装在一个函数中,然后在调用;
- 输入的值可作为变量访问和设置,每个输入均对应一个输出(可将鼠标悬停在输入或输出上),也可重命名输入变量;
- 最佳访问几何体属性的方法,是连入Bind节点以使用变量;
- 可在不连入时,使用@语法,但默认@语法是只读属性,Bindings to Export参数有匹配的名字,才可写入;
- 可使用函数ch,来使用节点上的参数;
- 可直接读取和写入全局变量,但不建议使用,会产生未知的错误;
注,当有同名变量连入时,使用同名的@语法,不起作用;
在Inline中,是直接写入代码,不用在调用;
- 可输入多达64个任意类型数据,多达32个任意输出;
- 无需对输入或输出,写入变量声明;声明的任何变量,都应以$开头(全局变量除外);
- 全局变量(如P、N等)也无需连入,也无需开头$;
- 不建议给输入变量赋值,会引起未知错误;