Houdini使用Python,Vex,C++创建相同表现的SOP并比较差异

it2025-03-16  26

目标

官方文档《HDK: The Many Ways to Create a SOP》展示了如何使用6种方式去创建同一种表现的SOP。 其实概括来讲还是三种渠道:Python节点;Vex节点;使用HDK通过C++创建一个包含新的SOP节点的插件。 只不过,在这个文档中,Python方式又包括了:原始版本;使用numpy模块的加速版本;使用内联C++代码的版本。而HDK的C++代码又包括了:普通使用HDK接口的版本;调用HOM模块的版本。因此总共是6个方式。

本篇的目标自己实践一下它们,并比较它们在性能方面的差异。

表现

表现上,都是让顶点随着时间进行正弦波动。我的实验中采用了一个100*100的网格作为输入:

随后可以在节点的信息中看到cook时间:

实践

1. Python_普通

逻辑比较直白,就是遍历所有的顶点,依照自己的位置和时间做正弦计算,随后设置位置。 代码见 HDK: HOM/SOP_HOMWave.py 时间:49.82ms

2. Python_numpy

由于numpy模块的sin函数的参数可以是个数组,因此所有顶点可以只调用一次numpy的sin函数一起处理,这样更快。 代码见 HDK: HOM/SOP_HOMWaveNumpy.py 时间:1.8ms

3. Python_内联C++代码

这个版本使用了inlinecpp模块。这个模块我想应该是SideFX自己所写的,因为我在“inlinecpp.py”文件中看到了很多Houdini的内容。

inlinecpp模块提供机制可以让Python内联C++代码,调用HDK的接口做操作。 代码见 HDK: HOM/SOP_HOMWaveInlinecpp.py 时间:0.47ms

4. C++_普通调用HDK

代码见 HDK: SOP/SOP_CPPWave.C

其文件也可以在HDK目录里找到\toolkit\samples\SOP\SOP_CPPWave.C。

在之前的博客《研究HDK(Houdini Development Kit):使用CMake自动生成VS工程》中,我为“SOP_Star”这个范例生成了工程。为了方便,我直接将SOP_CPPWave的头文件,源文件拷贝过来,然后替换原有的代码。随后要注意修改生成的目标文件的名字以做区分: 将SOP_Star改为SOP_CPPWave: 然后生成dll文件

SOP_Star.vcxproj -> C:\Users\admin\Documents\houdini18.0\dso\SOP_CPPWave.dll

重启Houdini后可以使用这个节点: 时间0.18ms

5. C++_调用HOM模块

HOM模块其实就是Houdini里的Python所使用的模块。和之前的“Python内联C++代码”相反,这里相当于C++调用本来给Python的模块。

代码见 HDK: HOM/SOP_HOMWave.C

和上一步一样,修改工程里的代码和生成的dll的名字。

重启Houdini后可以使用这个节点: 时间:3.3ms

6. Vex

Vex只需要一行代码: 时间:0.04ms

比较

效率

我的实验得到的效率排名为:

方式时间Python_普通49.82msC++_调用HOM模块3.3msPython_numpy1.8msPython_内联C++代码0.47msC++_普通调用HDK0.18msVex0.04ms

官方的实验数据为: 官方做实验时输入的数据应该和我不一个数量级,所以时间上也不在一个数量级上。但是排名上区别不大,所以能得到很多相同的结论。 (区别最大的是,官方实验中“Vex”和“Python内联C++”的版本性能相似,但在我的实验中有10倍的差别。不过考虑到官方的数据计算量应该更大,所以我觉得官方的结果应该更准确。)

从这个实验数据中可以得到的结论有:

1.

Vex,C++普通调用HDK,Python内联C++代码 这三者拥有最高的效率。

Vex可以达到接近于原生C++的效率,归功于它实际上自动提供了下面的优化:

以线程的方式进行求值计算(Vex SOP可以自动多线程)使用SSE,Altivec 等其他向量指令集基于输入参数的运行时优化
2.

python节点:使用numpy模块的版本明显比不使用的版本快。这是因为它不用在一个python循环中遍历所有的点了。

3.

“Python_普通”版本是最慢的版本,比C++或者Vex版本要慢多了。因为他在迭代所有的点的过程中,必须持续地为 HOM_Point 对象来 分配/清理 内存。

维护性

考虑到维护性,Vex和Python一定会胜出,因为他们都是脚本语言,不需要重新build。(官方文档还提到:It’s marginally easier to create a VEX SOP since you can build an HDA directly from the command line,即可以在命令行中使用Vex创建SOP?此种方法有待后续试验。)


另外,在Python使用内联C++代码要比纯使用C++更好维护一些,因为:

你可以直接在编辑器内指定参数,而不是使用C++的PRM_Templates你可以用python做大部分的内容,只留最慢的部分给C++Houdini编辑器会帮你自动编译C++代码你改变代码后不需要重启Houdini如果代码会导致崩溃,inlinecpp经常会阻拦崩溃并且显示追踪到的错误信息的栈(需要将“catch_crashes”设为True或者“debug”设为“True”)

易用性

Though VEX is fairly easy to use, VEX is designed around algorithms that apply across many elements simultaneously. This makes it very good and efficient at running over all points or primitives, but less effective if you have a very serial algorithm.

尽管Vex使用非常简单,但Vex被设计为围绕算法、并行计算的。这导致它在遍历所有的点或者图元时非常优秀且高效(因为可以并行)。但是如果你想实现一个顺序执行的算法( a very serial algorithm),则效率就不会那么高。


使用Python写一个SOP节点可以使用无穷无尽的模块。在某些方面,这种灵活性带来的优点价值要超过其本身低效这一缺点,例如:

从XML文件中导入几何体在网络连接中变换一个几何体基于USB或者手柄来对一个几何体变形。

总结

速度上:C++ >= Vex >> Python Python最慢没有异议。 而对于C++和Vex,如果是很并行的计算,那么Vex很高效(在我的实验中Vex超过了C++),但是如果考虑到一些顺序执行的、前后有依赖关系的一系列运算,还是C++要快。


方便性:Vex = Python >> C++ C++修改后需要编译,而其他两者是脚本语言,写完就可以执行。


功能性:Python ≈ C++ >> Vex 我这里的“功能性”指能做的事情。毫无疑问,“Vex”能做的其他二者都能做,所以Vex的功能性实际上是最低的。而Python和C++的比较则需要讨论:

理论上,Python可以内联C++代码,而C++中也可以调用HOM模块。所以二者在Houdini的功能上应该是一样的。但是,在Python中内联的C++代码毕竟是个字符串,肯定没有在VS这种IDE中写代码舒服,当代码比较多的时候会更加不方便。(但也并非全是坏处,正如上一部分【维护性】中所讨论的)而在C++中调用HOM模块也只是Houdini相关的,而Python一个优势就是有很多第三方库。也就是说,对于HDK底层的功能,C++更方便处理;而Python可以使用无穷无尽的模块。

看来,他们都在一个方面上有明显的缺点。在使用时,还是需要根据实际情况选择。

最新回复(0)