3、VEX基础语法(上):变量与数据类型、运算符、条件判断与循环

各位好,欢迎来到VEX编程的第一课。说实话,很多刚接触Houdini的朋友一看到VEX就头大,觉得这是另一门编程语言。但我想告诉你,VEX其实没那么可怕。它本质上就是C语言的一个变种,语法简洁,逻辑直接。今天我们就从最基础的东西开始,把地基打牢。

3.1 变量与数据类型:int、float、vector

变量是什么?说白了就是给数据起个名字,方便我们后面反复使用。VEX是强类型语言,每个变量在声明时就必须指定类型。我刚开始学的时候老忘记这点,结果编译报错报得我怀疑人生。

3.1.1 整数类型(int)

int就是整数,不带小数点。比如点云的数量、循环的次数、开关的状态,这些都用int。

int count = 10;
int id = @ptnum;  // 获取当前点的序号

嗯,这里要注意:VEX里用@ptnum@primnum这些属性时,它们本身就是int类型。我在项目中遇到过有人试图把@ptnum直接当float用,结果数值被截断,排查了半天才发现问题。

3.1.2 浮点类型(float)

float就是带小数点的数。位置偏移、缩放比例、颜色通道值,这些都用float。

float height = 3.5;
float randomVal = rand(@ptnum);  // 生成0~1之间的随机数

我个人习惯在写VEX时,所有涉及除法的地方都显式写成float,比如float result = 1.0 / 3.0;。为什么?因为int除以int在VEX里结果是int,会丢掉小数部分。你想想看,如果两个整数相除得到0,后面再乘什么东西都白搭。

3.1.3 向量类型(vector)

vector是VEX里最常用的复合类型,它包含三个float分量,分别用.x、.y、.z访问。位置、方向、颜色、法线,这些全是vector。

vector pos = @P;           // 点的位置
vector color = {1, 0, 0};  // 红色
vector up = {0, 1, 0};     // 向上的方向

我曾经犯过一个低级错误:把vector当颜色用时,忘记分量范围是0~1,直接写了个vector col = {255, 128, 64};,结果颜色完全不对。后来才反应过来,VEX里颜色是归一化的,255要除以255才行。

小技巧:VEX里可以用set()函数快速创建vector:vector v = set(1.0, 2.0, 3.0);。我个人更推荐这种方式,可读性更好。

3.2 运算符与表达式

运算符就是用来操作数据的符号。VEX的运算符和C语言几乎一模一样,如果你写过C,这部分可以快速过。但有几个坑我得提醒你。

3.2.1 算术运算符

运算符含义示例
+a + b
-a - b
*a * b
/a / b
%取模(余数)a % b

取模运算在程序化生成里特别有用。比如你想让一排柱子每隔3个换一种颜色,就可以用@ptnum % 3来判断。

3.2.2 比较运算符与逻辑运算符

比较运算符返回的是int类型,1表示真,0表示假。逻辑运算符用于组合多个条件。

int result = (a > b) && (c != d);  // 两个条件同时成立
int flag = (x == 0) || (y == 0);   // 至少一个条件成立

这里有个细节:VEX里==是比较,=是赋值。我见过太多人把这两个搞混,结果条件永远为真,因为赋值表达式返回的是被赋的值,非零即为真。嗯,写代码时一定要瞪大眼睛。

3.3 条件判断:if-else

条件判断让程序有了「决策能力」。在建筑生成中,我们经常要根据高度、位置、随机值来决定不同的处理方式。

3.3.1 基本if-else结构

if (@ptnum % 2 == 0) {
    @Cd = {1, 0, 0};  // 偶数点染红色
} else {
    @Cd = {0, 0, 1};  // 奇数点染蓝色
}

这段代码很简单:根据点序号奇偶性赋予不同颜色。我在做建筑立面时,经常用这种逻辑来区分窗框和玻璃。

3.3.2 多分支判断

float h = @P.y;
if (h < 1.0) {
    @Cd = {0.8, 0.6, 0.4};  // 底层:暖色
} else if (h < 3.0) {
    @Cd = {0.6, 0.8, 0.6};  // 中层:绿色
} else {
    @Cd = {0.4, 0.6, 0.8};  // 顶层:冷色
}

你想想看,建筑不同高度用不同材质,这种逻辑在程序化生成里太常见了。我曾经用类似的方法,根据高度给建筑分段,每段赋予不同的纹理和细节密度,效果非常自然。

注意:VEX里if-else的代码块必须用花括号{}括起来,即使只有一行代码也不能省略。这和Python不一样,别偷懒。

3.4 循环:for与while

循环就是重复执行某段代码。在程序化生成中,循环用来创建重复结构,比如一排窗户、一圈柱子、一层层楼板。

3.4.1 for循环

for循环适合已知循环次数的情况。语法是:for(初始化; 条件; 步进)

// 在X轴上创建一排点,间距1个单位
for (int i = 0; i < 10; i++) {
    vector pos = set(i, 0, 0);
    addpoint(0, pos);
}

这段代码会在原点右侧生成10个点。我在做建筑骨架时,经常用for循环生成楼层:for (int floor = 0; floor < numFloors; floor++),然后每层再嵌套一个循环生成窗户。

3.4.2 while循环

while循环适合不知道具体次数,但知道终止条件的情况。

int i = 0;
while (i < 10) {
    // 做点什么
    i++;
}

说实话,在VEX里while用得比for少。因为大多数时候我们处理的是点云或图元,用foreach循环更直接。但while在处理动态条件时很有用,比如「一直向外扩散,直到碰到障碍物」这种逻辑。

3.4.3 循环的坑

我曾经在VEX里写了一个死循环,结果Houdini直接卡死,只能强制结束进程。为什么会这样?因为循环条件永远为真,程序跳不出来。所以写循环时一定要确保条件最终会变为假,或者用break手动跳出。

// 安全的写法:设置最大迭代次数
int maxIter = 100;
int i = 0;
while (i < maxIter) {
    // 处理逻辑
    if (someCondition) break;  // 满足条件提前退出
    i++;
}
避坑指南:在VEX的Wrangle节点里,循环次数不要太大。因为VEX是逐点/逐面执行的,如果每个点都循环1000次,几万个点就是几千万次运算,性能会急剧下降。我一般把循环上限控制在100以内。

知识体系总览

下面这张图帮你梳理本章的核心内容,方便你快速回顾。

VEX基础语法(上) 变量与数据类型 int 整数 float 浮点 vector 向量 运算符与表达式 算术运算符 比较运算符 逻辑运算符 条件判断 if-else 多分支 循环结构 for循环 while循环 循环控制 核心:变量存数据 → 运算符做计算 → 条件/循环控制流程

好了,这一章的内容就到这里。变量、运算符、条件判断、循环,这四个东西是VEX编程的基石。你想想看,任何复杂的程序化生成逻辑,归根结底都是这些基础元素的组合。下一章我们会继续深入,看看函数、数组和字符串怎么用。但在此之前,我建议你打开Houdini,新建一个Attribute Wrangle节点,把今天学的代码都敲一遍。光看不练,等于白学。


专注资料整理