跳转到内容

vex language reference

本页内容* 上下文 * 语句 * 内置函数 * 用户定义函数 + 注意事项 * 主(上下文)函数 + 用户界面编译指示 * 运算符 + 点运算符 + 比较运算 + 优先级表 + 运算符类型交互 * 数据类型 * 结构体 + 结构体函数 * Mantra专用类型 * 类型转换 + 变量类型转换 + 函数类型转换 * 注释 * 保留关键字

上下文

contexts

VEX程序是为特定上下文编写的。例如,控制对象表面颜色的着色器是为surface上下文编写的。确定光源照明的着色器是为light上下文编写的。创建或过滤通道数据的VEX程序是为chop上下文编写的。

上下文决定了哪些函数、语句和全局变量可用。

参见VEX上下文了解使用VEX的不同方式概述。

如果您正在为着色上下文(表面、置换、光源等)编写代码,还应阅读着色上下文特定信息

语句

statements

VEX支持类似C语言的常用语句。它还支持特定于着色的语句,如仅在特定上下文中可用的illuminancegather循环。

内置函数

built-in-functions

VEX包含一个大型的内置函数库。某些函数仅在特定上下文中可用。

参见VEX函数

用户定义函数

functions

函数的定义方式与C类似:指定返回类型、函数名称、带括号的参数列表,然后是代码块。

相同类型的参数可以在逗号分隔的列表中声明,无需重新声明类型。其他参数必须用分号分隔。

int test(int a, b; string c) {
if (a > b) {
printf(c);
}
}

您可以重载具有相同名称但不同参数签名和/或返回类型的函数。

可以使用可选的function关键字引入函数定义以避免类型歧义。

function int test(int a, b; string c) {
if (a > b) {
printf(c);
}
}
void print(basis b) {
printf("basis: { i: %s, j: %s, k: %s }\n", b.i, b.j, b.k);
}
void print(matrix m) {
printf("matrix: %s\n", m);
}
void print(bases b) {
printf("bases <%s> {\n", b.description);
printf(" "); print(b.m);
printf(" "); print(b.n);
printf(" "); print(b.o);
printf("}\n");
}
basis rotate(basis b; vector axis; float amount) {
matrix m = 1;
rotate(m, amount, axis);
basis result = b;
result.i *= m;
result.j *= m;
result.k *= m;
return result;
}
void rotate(basis b; vector axis; float amount) {
b = rotate(b, axis, amount);
}

注意事项

notes

  • 用户函数必须在被引用之前声明。
  • 函数由编译器自动内联,因此递归将不起作用。要编写递归算法,应改用着色器调用
  • 与RenderMan着色语言一样,用户函数的参数总是通过引用传递,因此在用户函数中的修改会影响调用该函数的变量。可以通过在参数前添加const关键字来强制着色参数为只读。为确保用户函数写入输出参数,可在其前添加export关键字。
  • 用户函数的数量没有限制。
  • 一个函数中可以有多个return语句。
  • 可以直接访问全局变量(与RenderMan着色语言不同,不需要用extern声明它们)。但是,建议避免访问全局变量,因为这会将函数限制在仅在一个上下文中工作(存在这些全局变量的地方)。相反,应将全局变量作为参数传递给函数。
  • 函数可以在函数内部定义(嵌套函数)。

主(上下文)函数

main-context-function

VEX程序必须包含一个返回类型为上下文名称的函数。这是程序的主函数,由mantra调用。编译器期望每个文件有一个上下文函数。

此函数应通过调用内置和/或用户定义的函数来完成计算所需信息和修改全局变量的工作。您不使用return语句从上下文函数返回值。请参阅特定上下文页面了解每个上下文中可用的全局变量。

上下文函数的参数(如果有)成为程序的用户界面,例如引用VEX程序的着色节点的参数。

如果存在与上下文函数参数同名的几何属性,则该属性会覆盖参数的值。这允许您将属性绘制到几何体上以控制VEX代码。

surface
noise_surf(vector clr = {1,1,1}; float frequency = 1;
export vector nml = {0,0,0})
{
Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N));
nml = normalize(N)*0.5 + 0.5;
}

注意 VEX对上下文函数的参数有特殊处理。可以使用与变量同名的几何属性覆盖参数的值。除了这种特殊情况外,参数在着色器范围内应被视为”const”。这意味着修改参数值是非法的。如果发生这种情况,编译器将生成错误。

您可以使用export关键字标记您希望修改原始几何体的参数。

用户界面编译指示

user-interface-pragmas Houdini从此程序生成的用户界面将是最小的,基本上只是变量名和基于数据类型的通用文本字段。例如,您可能希望指定frequency应该是一个具有特定范围的滑块,而clr应该被视为颜色(给它一个颜色选择器UI)。您可以使用用户界面编译器编译指示来实现这一点。

#pragma opname noise_surf
#pragma oplabel "噪波表面"
#pragma label clr "颜色"
#pragma label frequency "频率"
#pragma hint clr color
#pragma range frequency 0.1 10
surface noise_surf(vector clr = {1,1,1}; float frequency = 1;
export vector nml = {0,0,0})
{
Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N));
nml = normalize(N)*0.5 + 0.5;
}

运算符

operators

VEX具有标准C运算符和C优先级,但有以下差异。

乘法定义在两个向量或点之间。乘法执行逐元素乘法(而不是点积或叉积;参见crossdot)。

许多运算符为非标量数据类型定义(即向量乘以矩阵将用矩阵变换向量)。

在将两种不同类型与运算符组合的模糊情况下,结果具有第二个(右侧)值的类型,例如

int + vector = vector

点运算符

dot-operator 您可以使用点运算符(.)引用向量、矩阵或结构体的各个组件。

对于向量,组件名称是固定的。

  • .x.u引用vector2的第一个元素。
  • .x.r引用vectorvector4的第一个元素。
  • .y.v引用vector2的第二个元素。
  • .y.g引用vectorvector4的第二个元素。
  • .z.b引用vectorvector4的第三个元素。
  • .w.a引用vector4的第四个元素。

选择u,v/x,y,z/r,g,b字母是任意的;即使向量不包含点或颜色,也适用相同的字母。

对于矩阵,您可以使用一对字母:

  • .xx引用[0][0]元素
  • .zz引用[2][2]元素
  • .ax引用[3][0]元素

此外,点运算符可用于”混合”向量的组件。例如

  • v.zyx等同于set(v.z, v.y, v.x)
  • v4.bgab等同于set(v4.b, v4.g, v4.a, v4.b)

注意 您不能赋值给混合向量,只能从中读取。因此不能执行v.zyx = b,而必须执行v = b.zyx

比较运算

comparisons 比较运算符(==, !=, <, <=, >, >=)在运算符左侧与右侧类型相同时定义,仅适用于字符串、浮点和整数类型。运算结果为整数类型。

字符串匹配运算符(~=)仅在运算符两侧都是字符串时定义,等同于调用match函数。

逻辑(&&, ||, !)和位运算(& |, ^, ~)运算符仅对整数定义。

优先级表

precedence 表中位置越高的运算符优先级越高。

顺序运算符结合性描述
15()从左到右函数调用、表达式分组、结构成员。
13!从左到右逻辑非
13~从左到右按位取反
13+从左到右一元加(例如+5)
13-从左到右一元减(例如-5)
13++从左到右递增(例如x++)
13--从左到右递减(例如x--)
13(type)从左到右类型转换(例如(int)x)。
12*从左到右乘法
12/从左到右除法
12%从左到右取模
11+从左到右加法
11-从左到右减法
10<从左到右小于
10>从左到右大于
10<=从左到右小于等于
10>=从左到右大于等于
9==从左到右等于
9!=从左到右不等于
9~=从左到右字符串匹配
8&从左到右按位与
7^从左到右按位异或
6``从左到右
5&&从左到右逻辑与
4``
3?:从左到右三元条件(例如x ? "true" : "false")
2= += -= *= /= %= &= ```vex=“^= ```从右到左
1,从左到右参数分隔符

运算符类型交互

operator-type-interactions

  • 当您对floatint应用运算时,结果是运算符左侧的类型。即float * int = float,而int * float = int
  • 如果将向量与标量值(intfloat)相加、相乘、相除或相减,VEX返回相同大小的向量,运算按分量执行。例如:
{1.0, 2.0, 3.0} * 2.0 == {2.0, 4.0, 6.0}
  • 如果对不同大小的向量进行加、乘、除或减运算,VEX返回较大大小的向量。运算按分量执行。 重要:较小向量上的”缺失”分量填充为{0.0, 0.0, 0.0, 1.0}
{1.0, 2.0, 3.0} * {2.0, 3.0, 4.0, 5.0} == {2.0, 6.0, 12.0, 5.0}

如果您不期望这一点,可能会得到令人惊讶的结果,例如:

// vector2的第三个元素被视为0,
// 但第四个元素被视为1.0
{1.0, 2.0} + {1.0, 2.0, 3.0, 4.0} == {2.0, 4.0, 3.0, 5.0}

如果您要组合不同大小的向量,可能需要手动分解组件并进行运算,以获得预期结果而不出现意外。

数据类型

data-types

警告 默认情况下,VEX使用32位整数。如果您使用AttribCast SOP将几何属性转换为64位,VEX将在VEX代码中操作该属性时静默丢弃多余的位。

VEX引擎以32位或64位模式运行。在32位模式下,所有浮点数、向量和整数都是32位。在64位模式下,它们是64位。没有doublelong类型来允许混合精度数学。

您可以使用下划线分隔长数字。

类型定义示例
int整数值21, -3, 0x31, 0b1001, 0212, 1_000_000
float浮点标量值21.3, -3.2, 1.0, 0.000_000_1
vector2两个浮点值。您可能使用它来表示纹理坐标(尽管通常Houdini使用向量)或复数{0,0}, {0.3,0.5}
vector三个浮点值。您可以使用它来表示位置、方向、法线或颜色(RGB或HSV){0,0,0}, {0.3,0.5,-0.5}
vector4四个浮点值。您可以使用它来表示齐次坐标中的位置,或带alpha的颜色(RGBA)。它通常用于表示四元数。VEX中的四元数按x/y/z/w顺序排列,而不是w/x/y/z。这适用于四元数和具有齐次坐标的位置。{0,0,0,1}, {0.3,0.5,-0.5,0.2}
array值列表。有关更多信息,请参见