TA笔记:Houdini基础1

概念认知

我觉得其实上来做什么教程还是太具象了,我想最开始最应该了解的是软件本身对数据操作的理念或者说思路。就我的感觉而言,Houdini是一款很贴近程序员思维的软件,那抓住抽象的概念反而才是关键所在。

术语缩写与基础概念

下述内容引用自SideFX社区中关于术语缩写讨论的页面[1]

Object = Object type nodes in an Object type folder. These Object nodes allow you build transform constraint hierarchies. Geometry type Object nodes contain SOP nodes that construct and modify geometry that inherit any transforms at the object level.

SOPs = Surface OPerators or geometry nodes that are inside an object folder. These are used to construct and modify geometry. Any kind of geometry from polygons to volumes.

DOPs = Dynamic OPerators or simulation/solver nodes that are used to construct simulations. Simulations read in geometry from SOPs and passes this data in to the DOP solvers.

SHOP = SHading Operators are materials that represent a shader to apply to geometry. Some are hard coded with vex and others are folders that you can dive in to and modify the VOPs inside.

VOPs = Vector OPerators inside VOP network nodes are used for everything from building shaders to modifying geometry, volumes, pixels, and more.

VEX = Vector Expression Language. The code language used to write shaders. VOPs are wrappers around VEX code snippets.

CVEX = Context agnostic Vector Expression Language. This has replaced all the VEX specific contexts throughout Houdini. It is a generalized language that uses the same environment and functions anywhere inside Houdini.

COPs = Composite OPerators in composite type folders. Used in image compositing operations.

ROPs = Render OPerators in side ROP Output directories which are used to create render output dependency graphs for automating output of any type of data and for triggering external processes like rendering. Commonly used to generate sequences of geometry, simulation data and trigger Render tasks that generates sequences of images to disk.

CHOPs = CHannel OPerators used to create and modify any type of raw channel data from motion to audio and everything in between. Most users safely ignore the CHOP context, and so can you, for now. Put it on the "get to it later" list when learning Houdini. But definitely keep it on the list.

P.S. 有这样一篇名为《像学习语言一样学习Houdini》的文章[2],可惜的是他只是列举了一些热点术语词汇,并没有对每个概念做出详细说明

不太严谨地说,VEX是最基础的(在应用层面不可再分的)操作指令,VOP是可视化的VEX,在VOP中创建的任何节点链都可以在VEX中完成,但并非在 VEX 中编写的所有内容都可以在 VOP 中复制。VOP的设计目的是读取模拟中某一点的几何属性,然后添加、乘以或减少与几何相关的变量[3],而SOP、CHOP这些则是更上层的(我意思是VOP较之于其他OP显得底层,其他OP会用到VOP的东西)。

VOP生成的VEX可能有冗余

操作概念

各种操作的本质就是处理特定的数据

Houdini 的域(/obj/shop/rop 等)是 Houdini 场景内部的逻辑组织结构,它们存在于 .hip 文件中,用于组织和管理不同类型的数据和节点。 可以把 .hip 文件理解为一个数据库,而各个域则是这个数据库中的不同表,它们存储着不同类型的数据。

  • /obj (Object): 这是 Houdini 中最主要的域,用于组织场景中的几何体、变换和其他对象。 在 /obj 域中,你可以创建、编辑和组织各种几何体,例如球体、立方体、曲线等等。 这些几何体及其相关的变换信息都存储在 .hip 文件中,构成场景的主要内容。 /obj 域下的节点结构通常是层次化的,你可以创建父对象和子对象来组织复杂的场景。
  • /shop (Shader): 这个域用于管理材质、着色器和其他与渲染相关的资源。 你创建的材质球、着色器网络等都存储在 .hip 文件的 /shop 域中。 当渲染场景时,Houdini 会读取 /shop 域中的数据来确定如何渲染各个对象。
  • /mat (Material): /mat 域更直接地与材质本身相关联,它通常包含材质的实际定义,而 /shop 则管理这些材质的组织和网络。
  • /rop (Render): 这个域包含渲染相关的节点,例如渲染器、输出节点等。在这里设置的渲染参数、选择的渲染器以及输出路径等信息,当点击渲染按钮时,Houdini 会读取 /rop 域中的数据来执行渲染操作。
  • /out (Output): 这个域用于存放最终的渲染输出结果,它本身并不直接参与场景的构建,但它是渲染流程的最终目的地。
  • /geo (Geometry): 这个域用于存储和操作几何数据,与 /obj 域中的几何数据有所不同,它更适合于一些特定的几何处理流程。
  • /ch (Channels): /ch 域并非一个独立的域,而是 Houdini 中用于存储和访问节点属性的通道系统。 所有域中的节点都拥有各种通道,用于控制节点的行为和属性。

subnet则类似于编程的函数(但是ai说subnet可以并行计算),是一种对一组节点组成的操作封装重用的结构。

为什么要在域介绍之后提这个?因为Subnet可以存在于任何一个域中,并且Subnet内部可以包含来自其他域的节点,但Subnet本身仍然属于它被创建的域。 Subnet本质上是一个容器,它组织和封装了一组节点,从而简化复杂的网络结构。

数据概念

Houdini 场景的最底层是各种不同类型的数据,如几何数据(点、线、面)、属性数据(颜色、大小、速度等)、通道数据(动画曲线)、动力学数据(粒子、流体)等等。VEX或者VOP可以操作大部分数据,各类运算符(OP)也可以操作一部分(通常是特定类型的)数据,如CHOP (Channel Operators)可以操作动画曲线、音频波形,DOP可以操作粒子位置、速度、力等。基于这些数据的组合,会形成一些新的、逻辑上的数据。

例如,多个图元可以构成一个更复杂的几何体;几何数据、属性数据和材质数据组合在一起可以构成一个具有视觉外观和物理属性的物体;通道数据可以驱动几何体的动画;动力学数据可以模拟物体的运动和行为。 这些组合形成的"新的数据"通常是更高层次的抽象,它们仍然基于底层的数据类型。

官方文档[4]说的数据分类一共四类:

  • 全局变量,例如$F(当前帧号)和$T(当前时间(以秒为单位))
  • 几何属性,通过@attributename引用,例如可以使用@pscale获取当前点的scale属性的值,并且可以只访问指定通道,例如
  • 局部变量,例如@ptnum表示当前正在处理的点的索引号。
  • 环境变量,例如$HIP(包含场景文件的目录)

当然要是从数据作用域来看的话,其实不太好划分。抓住数据流动的概念去看,一个节点产生的数据会流向下游节点(节点级数据在网络中流动),但是这些数据本身不会在网络间互通,但是可以有选择性地输出(一般通过OUT节点)

一些概念辨析

Point与Vertex的区别:Point可以表示空间坐标(三维位置,@p),而Vertex则是Polygon的组成,是对Point的索引,并且每个 Vertex 都必须对应一个 Point。这意味着,一个Point可以对应多个Vertex,或者说多个Vertex可以引用同一个Point来共享同一个空间位置(从而提高效率并减少数据冗余)

但是话又说回来了,Points更像是一个结构体,存有各种数据,其中包括了@P,但是不止这个。

  • Add
  • scatter
  • generate points
  • points from volume

Primitive与Polygon与Polygon Mesh的区别

基础操作

数据传递

带着上述认知再回来看教程,很多效果把内在逻辑抽象出来看,其实就是在给定条件下的数据交互。一些数据可能会作为完成目标效果的参数/条件,所以需要关注点在于:

  1. 获取和计算相关的数据(这还隐含着一件事情,即可能需要上游操作计算和暴露出当前依赖的数据)
  2. 将相关数据解析为合适处理的形式
  3. 根据数据计算目标效果的算法
  4. 计算结果反馈回去(暴露给下游)

我为什么强调是基础操作呢,因为很多步基础操作构成了一步逻辑上有明显意图的逻辑操作。就好比在数据结构领域,"为链表第x个节点后面插入一个节点"是一步逻辑操作,但是实际执行起来会由多个基础操作构成:顺序遍历链表找到第x个;保存第x个节点的后继;新申请一个节点并写入数据;第x个节点指向新申请的;新申请的指向第x个节点的后继;清除保存后继的引用。

因为理解了怎么获取加工和输出数据,之后才能完成更上层的逻辑操作:比如说以CGWiki的Houdini栏目的入门内容[5]的第二节为例:


如何把球体的信息(input2)传递给平面(input1),这个问题本质就是要去找到一种操作(或者说一种节点)可以把流入这个节点的多股数据按某种方式产生联系。

由这个思路主导去理解,可以发现Attribute Transfer节点能把一个输入流中的属性按某种依据迁移/匹配到另一个输入流里。在这里可以依据的有Detail/Primitives/Points和Vertices。其中Points是根据目标点与源点之间的距离计算邻近性,并进行加权平均。

加权平均是指:基于点属性进行传递时根据距离邻近性来计算目标点上的属性值(并不会建立点与点之间的一一对应关系,而是根据空间中附近的点的位置信息加权平均来的)

除了Attribute Transfer之外,还有其他传递数据的方法,比如说可以

  • Group Transfer
  • Attribute Transfer by UV

  • Cd是Color Diffuse
  • P是Position
  • N是Normal

点操作

不使用旧式的Point Sop,而是使用VEX或VOP代替

Point VOP 的设计初衷就是对每个点进行独立的计算和操作。所以设计好一个Point VOP意味着会对输入的每个点都执行一遍。如下所示

不过这里没有if,但是compare节点加上n-way switch可以等价if的

如果使用VEX直接操作就是使用Point Wrangler节点,代码是

复制代码
@P.y = sin( @ptnum * @Frame * 0.002 );

显然VEX更加简洁、灵活甚至直观。

参数提升

  • 将局部变量的值"提升"到全局属性
  • 将低级别几何体(例如点)的属性提升到高级别几何体(例如图元或细节属性)

例如vertex提升到point,由于一个点有多个vertex对应,方式使用average

具体表现为,某个属性由B提升到A之后,需要去Info的对应位置A栏目下找到,而非原先的B

Group

本节可以细看一篇CSDN博客的内容[6]

Group相当于是一个bool,标识是否属于某个组,可以类比为Layer这种概念。

因为在VEX中使用的方式就是比如下面这种:

js 复制代码
// @primnum表示当前正在处理的图元(primitive)的索引号(索引号从0开始计数)
// 选择偶数的图元标记到名为groupname1的组里
if(@primnum % 2 == 0)
	@group_groupname1 = 1;

在使用@group_groupname1的时候,如果没有名为groupname1的组就会创建,而且这是一个01值(或者说布尔值),那它就是类似于一种"标记"

  • 只视作0或非0两类值
  • base group里面输入!*创建空组
  • 使用@group_xxx而不赋予任何值创建空组
  • group可以转Attribute,只需创建Attribute时从指定的Group创建即可

小节总结

More of VEX

我本来是打算好好做点笔记的,但是说实话在GitHub发现的一个VEX教程[7]还蛮棒的,看这个得了。


  • .vfl是拓展名
  • 获取属性的方法:关于VEX的属性的Houdini官方文档
  • 获取参数的方法:ch*();函数家族
  • 参数≠属性(见本节的"补充"小节)
  • 自定义函数(内置的 VEX 函数有例外)的参数都是引用传递(函数内部修改会造成输入的参数变量值更改)
  • 使用@访问未声明的Houdini默认属性,会被声明并默认当作浮点类型,所以必须前置类型标识,如v@color1是vector3类型
  • ch*("../{path}")查找当前节点父级节点下节点(一般用来访问上游节点的属性)

ch更像是一种暴露参数到编辑器的手段,一个用于在 Houdini 中访问节点参数和属性值的函数

完全可以通过path和parameters组合得到具体参数的访问路径,如上图所示的是Translate的xyz三个周对应的参数名


  • VEX不直接支持递归,不过显然可以栈模拟(反正数组不是定长的)
  • VEX 的数组在声明时不需要指定长度,并且长度可以在运行时改变
  • 当然有些内容不必存放在数组里,比如"具有某种作用的点"或者"在遍历中被选中的点",直接加个属性赋值就可以了,相当于一个大的Dictionary<int,T>,其中键总是点序号,T是Houdini支持的类型

设置数据

c 复制代码
// 复制现有点的属性和组成员关系到新点
int addpoint(int geohandle, int point_number);
// 在指定位置创建新点
int addpoint(int geohandle, vector pos);
  • geohandle: 几何体的句柄。通常为 0geoself,表示当前几何体。
  • point_number: 要复制属性的现有点的编号
  • 返回值:新创建点的编号,失败则返回 -1

vector用花括号表示,如

c 复制代码
addpoint(0, {0, 1, 0});

类似地,addprim可以基于点添加图元.

但是{}只能初始化字面量,任何需要变量/函数等运行时获取到的须使用set()set返回值推导自输入参数。

根据对Houdini关于Set的文档示例的观察,可以理解为:接收set()返回值的参数类型决定了函数如何处理参数,一般有如下原则:

  • 返回T[]T接收则取首元素
  • 接收元素维度小于输出则只取输出的对应部分(适用于vector或matrix)
  • 接收元素的维度大于输出则没数据的补0(适用于T[]、vector或matrix)
  • 输入类型等于输出类型则返回原值
  • 输入类型不等于输出类型则会尝试隐式类型转换(这意味着会可能会发生float->int的去除小数部分)
  1. 参数≠属性:
特性 参数 (Parameters) 属性 (Attributes)
作用范围 节点本身 几何体 (点、图元、细节级别)
定义位置 节点属性面板 通过节点操作或 VEX 代码附加到几何体上
访问方式 ch() 函数家族 VEX 函数 (例如 point(), prim(), detail())
数据类型 各种数据类型 各种数据类型
主要作用 控制节点行为 描述几何体特性

以汽车为例:

  • 参数: 汽车的参数类似于发动机的排量、变速箱类型、车身颜色等,这些是汽车本身固有的属性,在制造时就已确定。
  • 属性: 汽车的属性类似于汽车的速度、位置、油量等,这些属性会随着汽车的运行而变化。

其余速记

很多都是看教程的笔记

范围内点选择nearpoint

调整球体范围,可以做爆炸效果

这是物体逐点和目标比较,另一种写法是目标位置往外搜,这种方式下Run Over是Detail(Only Once),只运行一次即可。

Run Over Points的话能多线程,Detail不行


根据拓扑结构找相邻:neighbours函数,返回值是表示邻居点的序号数组int[],

数组内元素顺序无规律,但是对于相同的拓扑结构,多次运行的结果是一样的

非VEX部分

点云

Point Clouds, PC,即点云,是一种三维数据表示形式。内含有多个点,每个点至少有一个三维坐标数据,但是也可以拥有额外的自定义数据,例如点的颜色。

点云数据的产生方式一般有如下几种:

  • Scatter SOP:在指定的几何体表面上随机散布点,可以控制点的密度、分布以及其他属性,以及使用不同的分布模式(例如均匀分布、泊松分布等)。
  • Convert SOP (Convert to Points):可以将任何多边形网格或曲线转换为点云。经过转换,每个顶点都会变成一个点
  • Trace SOP:沿着指定的几何体表面生成点(创建沿着曲线或表面分布的点云)
  • 源自模拟数据(粒子或者流体)
  • 来自体积数据

典型的点云操作是这样的:

c 复制代码
string filename = "my_pointcloud.pc";
string Pchannel = "P";	// 要查询的通道
vector P = {0, 0, 0}; // 查询点的位置
float radius = 1.0;	//搜索半径
int maxpoints = 100;	// 最大返回结果数目

int handle = pcopen(filename, Pchannel, P, radius, maxpoints);

if (handle >= 0) {
    while (pciterate(handle)) {
        int pNum = -1;
        pcimport(handle, "point.number", pNum);
        if (pNum != -1){
			vector pos = point(0, 'P', pNum);		// 获取点属性
		}
    }
    pcclose(handle);
} else {
    printf("Error opening point cloud file.\n");
}

pcopen是基于点的位置寻找待处理数据的,其返回值是一个句柄,指向一次查询的结果(符合条件的点)

  • pciterate:返回01,相当于表示是否还有剩余未遍历的点。要注意的是,该函数相对于隐式切换上下文,使待处理的点指向 pcopen(handle) 函数找到的下一个点。(迭代完毕会主动关闭点云文件)
  • pcimport则是针对当前处理的点(也就是在pciterate内)导入指定属性
  • pcnumfound(int handle)返回 pcopen 函数打开的点云搜索中找到的点数。
  • pcclose,就如同fopen会有对应的fclose,这里pc打开的句柄也要手动释放

额外地:

c 复制代码
int pcimport(int handle, string channel_name, <type>&value)

通道名只有两个可以传入:point.number(点序号)和point.distance


但是又有一个问题就是,上述操作仍未涉及自定义属性的读取,而这依靠另外的函数:

操作建议

本节内容提炼自引用部分或者网络论坛,由于来源众多且源头未必可考究,故不做引用脚注

学习资源

entagma

B站Up:落于ivi
Vimeo的Houdini教程
VFXDoc // 从VFX到Shader到Texture到Script,东西很多)
SideFX - Houdini VEX官方文档 // 还有比啃官方文档更快的途径了吗
GitHub - VEX tutorial // 这个还是很值得看的,可以作为语法速查(是的这就是参考[7])

参考

1\] [SideFX Community - pop sop dop? what do these mean?](https://www.sidefx.com/forum/topic/43515/?page=1) \[2\] [Learning Houdini like a language](https://www.mikelyndon.online/posts/learning-houdini-like-a-language) \[3\] [Kate Xagoraris - An Intro to VOPs](https://www.katexagoraris.com/an-intro-to-vops) \[4\] [SideFX Docs - Expression - variables and attributes](https://www.sidefx.com/docs/houdini/network/expressions.html#variables-and-attributes) \[5\] [CGWiki - 关于Houdini的子栏目](https://tokeru.com/cgwiki/HoudiniGettingStarted.html) \[6\] [CSDN - Houdini 组(group)的详细讲解](https://blog.csdn.net/weixin_43940314/article/details/129466469) \[7\] [GitHub - VEX tutorial](https://github.com/jtomori/vex_tutorial) \[?\] [知乎 - Houdini SOP \& VEX入门笔记(1)](https://zhuanlan.zhihu.com/p/70266411) \[9\] [Github - VEX for artists](https://github.com/kiryha/Houdini/wiki/vex-for-artists)

相关推荐
星轨初途5 小时前
【C/C++底层修炼】拆解动态内存管理:四大动态内存函数、六大错误与柔性数组
c语言·开发语言·c++·经验分享·笔记·柔性数组
妄汐霜14 小时前
小白学习笔记(spring框架的aop和tx)
笔记·学习
sheeta199816 小时前
LeetCode 每日一题笔记 日期:2025.03.24 题目:2906.构造乘积矩阵
笔记·leetcode·矩阵
Heartache boy17 小时前
野火STM32_HAL库版课程笔记-ADC多通道采集热敏、光敏、反射传感器(轮询)
笔记·stm32·单片机
yoothey17 小时前
Java字节流与字符流核心笔记(问答+考点复盘)
java·开发语言·笔记
老师好,我是刘同学18 小时前
force与deposit在SystemVerilog中的区别详解
笔记
Theodore_102219 小时前
深度学习(11):偏差与方差诊断、学习曲线
人工智能·笔记·深度学习·神经网络·机器学习·计算机视觉
2401_8357925420 小时前
Linux复习笔记
linux·服务器·笔记
C羊驼20 小时前
C语言学习笔记(十五):预处理
c语言·经验分享·笔记·学习·算法