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才行。
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}; // 顶层:冷色
}
你想想看,建筑不同高度用不同材质,这种逻辑在程序化生成里太常见了。我曾经用类似的方法,根据高度给建筑分段,每段赋予不同的纹理和细节密度,效果非常自然。
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编程的基石。你想想看,任何复杂的程序化生成逻辑,归根结底都是这些基础元素的组合。下一章我们会继续深入,看看函数、数组和字符串怎么用。但在此之前,我建议你打开Houdini,新建一个Attribute Wrangle节点,把今天学的代码都敲一遍。光看不练,等于白学。