【Houdini翻译教程】Points and Verts and Prims
关于houdini中的point,vertex以及primitive的区别与联系
原英文教程地址:https://www.tokeru.com/cgwiki/index.php?title=Points_and_Verts_and_Prims
翻译人:PB_zz
原英文教程与本人的翻译教程都是免费分享的,请勿进行盗用贩卖等行为。
“Points! points! points! houdini玩家满脑子里都是这玩意。”这像是Marcia会说的话。如果你是从maya转职houdini的玩家的话,你可能会奇怪为啥他会这样说。你还可能对点points,顶点verticies(简写为verts),基本初始体primitives(简写为prims,有些人错误地直接把它完全认为是面了)等概念感到困惑,这些玩意是啥?它们的区别又是啥?别担心,为师将为你答疑解惑。
译者注:顶点vertex的复数为verticies或者vertexes。 实际上,primitives并不是一定指面polygon。primitive本身翻译成中文的意思是“原始的,原始人,初始体,图元”。而houdini中的primitive指的是组成一个物体的最小元素,基本初始体。Primitive其实有很多种,本文最后会介绍。而在操作polygon模型的时候,它才是指面。具体的说明可以查阅一下帮助文档(In Houdini, primitives refer to a unit of geometry, lower-level than an object but above points. Houdini supports several different types of primitives)。但在本文内它大多数时候就是指多边形面,所以为了方便叙述和理解,在它的类型为面时直接简写成面了,不过你要记得它并不等同于面。
Short Answer - don't worry about it, just use points(简单粗暴的应对-别担心,不管怎样用points就对了)
嗯哼,几乎所有houdini里的东西都能识别你在点层级的操作,从这个角度来看,你反正在点上秀操作就行了,管它那么多干啥子。 哦?你想知道更多?可以的小伙子,我就喜欢你这种打破砂锅问到底的家伙...
A point(一个点)
在houdini中一个点的概念是和数学中点的概念差不多的。它是空间里的一个位置,没有任何与它联结的区域(area)或者维度(dimension)或者相连着的其它什么玩意。作为一个最基础的属性,一个点会存储好它的位置信息(@P)。
译者注:在数学上,欧氏几何中,点是空间中只有位置,没有大小的图形。在空间中作为1个0维的对象。
如果你原先学过maya,那么一个点有些类似于一个粒子(particle)。不过在maya里,粒子是被藏在particleShape节点里的,而houdini则与它大不相同,在houdini中,points是被当作顶级类的成员。进一步说,一个点是能存储额外属性(attributes)的,比如颜色(colour)和速度(velocity)等,甚至是一些从数学与物理角度上来说是不合理的属性,比如法线(normal)和大小(scale)。你可能会奇怪,一个无维度的点怎么会有法线或者区域呢?
让为师来告诉你答案,虽然houdini中点的概念是来自于数学上的点,但我们又不是数学家,我们可以在houdini中肆意妄为,做任何想做的事情!比如,你可以用点来代表水的水花,并且试着渲染它们。在数学上来说这是说不通的没错,它们是无限小的,看不见的东西。但对于houdini和mantra渲染器而言,它们将点看成是半径0.1的球体。如果你的点有@pscale属性,houdini和mantra渲染器就会将其当作点的半径。如果你的点有@v属性,那么它们就会将其视为一个速度向量。@Cd则是点的颜色...
所以说houdini中的点有些像是maya中的粒子,你可以让它带上各种属性。
Creating points(创建点)
想要在houdini中创建点有许多的方式。Add节点可能是最简单的一种方法了,相信你们都会用:

同时它还能将任意的多边形,曲面或曲线(poly, nurbs or curve)转换为点,只要你勾选了“delete geometry but keep the points”选项就行:

有些初始几何体sop节点(box,grid等)有选项可以直接生成点。其它的模型,就用上边提到的add节点的那个功能生成点就行了。还有另外一些节点,比如scatter,generate points,points from volume等等,也有生成点的功能,可以自行去探索。
Why points?(为何推荐用点?)
Maya玩家可能对此感到不解,那么顶点vertices呢?其它工具呢?为啥这么看重点层级呢?回答是,houdini中的绝大多数工具都是和点兼容的,这意味着你不管搞啥都能和点联系到一起,你可以高枕无忧地秀各种操作。而maya有许多低级组件(low-level components) (例如vertices, curve cv's, particles, lattice points, cluster handles, subdiv points等),这意味着一个设计来用于处理顶点verts的工具可能就无法用于处理curve cvs或者particles。但在houdini中,如果你当前捣鼓的东西不是个点,你特么也能把它转化成点,不管它之前是如何被创造出来的。能对最底层的东西随意操作不就完事了吗?何必捣鼓各种各样类型的乱七八糟玩意,而且还不互通。
Shade sails and verts and prims(帆和顶点和面)
我找了一些帆的图片来更好地说明。
译者注:作者中间有些介绍帆的文字,实在没啥用......就不翻了。
如下图,这些地方就是点(point),顶点(vertex)和面(primitive):

再看看下面这张图片,我用红色数字标出的是点point,用绿色数字标的是顶点verts,用黄色数字标的是面prims:

所以每个面都有4个顶点(三角形的话是3个),而point是面连接处的公共点。拿正方体来说的话,就是有6个面,4*6=24个顶点,8个点。
实际上,在houdini中你最经常操作的对象都是点,偶尔调戏面,很少用到顶点,它们主要用来将面连接到点上,一旦连接完成,你就可以无视顶点了。甚至你都不需要手动来连接,很多工具能帮你完成这个步骤。但是多了解这些背后的知识还是挺好的。
所以顶点是连接点与面的桥梁。
Visualising points and verts and prims(在houdini视窗中直观地感受点,顶点和面)
如果你还没养成关注你项目中模型的点/顶点/面的习惯,说明你使用houdini的时间并不长。
因为点和面是你经常要操作的对象,你可以像下图一样打开点序号和面序号在视图中的显示:

顶点序号同样能显示出来,但是你需要在显示设置里打开它。按键盘上的快捷键D,调出显示设置面板,勾选Markers->vertices->numbers前面的按钮,再按D关闭显示设置,你的顶点序号就能在视图中看到啦:

如下图,spreadsheet面板中这些玩意的序号一般是放在第一列的:

首先我们看到的是点的属性,可以看到当前模型有6个点。点序号(也就是vex语言中会用到的@ptnum)在第一列,位置属性(@P)也在列表里。
切换到面,显示该模型有2个面,序号为0和1(@primnum),并没有其它属性。
最后看下顶点,有8个顶点,但是第一列的序号表示方式比较奇怪,另外还有一列point number。
这种 "x:y z" 格式表示的意思是 "prim:vertex point".
例如0:2 4表示的是序号为0的面,顶点序号为2,它处于第4个点的位置上。

Attributes and interpolation(属性和插值算法)

如上图,我给一个grid上的每个点的颜色属性@Cd赋予了随机颜色值。你可以看到,houdini使用一种传统的游戏引擎风格的颜色混合方式,在每个面的内表面上使用颜色@Cd的插值进行着色,同时在面与面之间也进行颜色插值混合。如果一个点被4个面共享,那么这个点的颜色值也会被这四个面共享,然后进行混合。
那如果我们把随机颜色给与顶点呢?

如上图,我们只得到了每个面内自身的颜色混合,而面与面之间的颜色并没有进行混合。这是为啥子捏?还记得吗,顶点是属于每个面自身的边角点,所以它们的颜色是不与其他面共享的,就好像每个面没有连接在一起,被分裂开了一样:

最后我们来看看,如果把随机颜色赋予面呢?如下图所示,每个面的整块颜色都被定好了,面与面之间也没有空间做插值了,所以你可以看到这样的色块效果:

Normals(法线)
另一个类似的情况是法线,如果你能认真思考下就能明白,虽然一开始你可能转不过弯来。

如上图中,第一个立方体没有法线,第二个的点上有法线信息,第三个的顶点上有法线信息,第四个则是面上有法线。似乎只有顶点法线的情况看起来是正确的。为什么呢?
第一个立方体虽然没有法线信息,但是显然显卡需要法线信息来着色并显示图像给你看,因此它自动计算每个点的法线,并对其进行插值。
第二个有点法线,但是效果看起来比较像前一个。因为点法线会在顶点和面之间进行插值,所以它看起来也像早期3D游戏引擎的效果。
第三个的是顶点法线。这意味着每个面的角落顶点都有自己的法线信息,不会有什么插值计算,所以看起来是正常锐利边缘平整表面的样子。
第四个作者说他自己都没搞懂为啥是这样,猜测和显卡也有关,以及houdini并不关心面法线(face normals),无视了它。
现在,如果你创建一个box节点,你会看到一个“add vertex normals”的选项。很长时间以来(emmmmm...可能是H14版本之前),你必须连接一个facet节点或者normal节点来修正法线。但现在加了一个选项让你自行勾选了,高不高兴,开不开心?:)
Uvs
同理,UV也是类似的。如果你把你的uvs存储为点的属性,那他们在点之间将会进行插值混合,然后出现扭曲的丑陋线条,而不是带接缝(seams)的独立区域。
如果你把uvs存储为顶点属性(houdini默认就是这样的),那它们就不会连接到一起,你会得到正常的uv islands和borders。
如下图所示,我们用attribute promote节点把uvs信息从顶点属性转移为点属性,你会看到pig变得更丑了:

让我们来看看UV视图(uv view)(在场景视窗中按下快捷键5即可),你可以发现,在uvs处于点层级时(point level),他们就不能保持断开了,uv islands会被连接起来,uv就错乱了。而默认uvs在顶点属性里时,它们可以保持独立不连续的样子。

所以记住,如果你想要控制好你的uv接缝,就让它默认应用在顶点上就好。
译者注:嘛...反正放点上的属性就是会被插值混合吧...
Edges and prims(边和面)
我们可以操作点和面,有时候也捣鼓下顶点,那么边呢?就直接晾在一边了?说好的点线面三兄弟呢?怕不是表面兄弟哦。
但如我们所见,你只需要通过点和顶点就能定义一个面了,边缘线完全是个副产物。事实上,假如顶点verts是个二等公民,那边edges肯定就属于三等公民了。边是不能被轻易操控的,你也不能像你平时操作点/顶点/面那样轻松地给边存储属性。
“妈耶?!”你要哭了,“难道我们就不能搞边了吗?我们不能分裂它?给它设置选集?或者搞些其它事情?”
emmmmmm...你当然可以,但是认真看好了,下图,它再次揭露了残酷的事实。在这里我选了一个box的一条边,并且把它打组:

这条边并没有一个序号(id),而且你看到我给它设置选集的写法,它是由它的两个端点定义的(point 3和7)。
这其实并不算一个大问题,通常我们不会对边做太细太复杂的操作。操纵边在vex编程中是一个比较棘手的事情,因为你一般是间接地改变它们(vex中其实有一个专门用于操作半边(half-edges)的模块,我仍在试图搞清楚它)。
Edges and polylines and curves(边x折线x曲线)
这里有一个简单的初始立方体,旁边是一个同样的立方体,但下方连接了一个ends节点,并把Close U选项改为了Unroll:

如果你开启了“Display primitive numbers”,你会发现,有序号直接显示在了线框的边上。就好像那些用于吹泡泡的玩具一样,框内的泡泡被戳破了,只剩下玩具外框,prims也从面转为了边。(译者注:作者这里不知道啥奇葩比喻...不过不重要)。
这是houdini不同于maya的地方,在houdini中,边不必属于一个prim,它可以自己是一个独立的prim。或者你换种思考方式,边就是一个和多边形边缘位置重合的curve曲线。
在box和grid节点中,你可以改变连接方式connectivity,将其类型改为行rows,列columns或者其它形式。同样在节点底下连接个ends节点,你会看到各种不同形式的线框。
这也是houdini中最快得到一种可渲染线框的方法,使用ends节点就完事了,然后你就能用mantra渲染器渲染它们,你甚至可以通过改变点的@width属性来改变线条宽度。

“妈耶?!”你又要叫唤了,“你不是才说houdini很难对边进行操作吗?”是,我是这么说过。不过我要澄清一下,独立的边,也就是那种polywire/curve类型的线,是挺好操作的。然而你想操作一个由多个多边形组成的模型的polygon边缘上的边,那就比较难了。再强调一次,并不是完全没有方法搞它们,但是你很多时候必须从点/面的角度来思考问题。好了,现在你别再插嘴了,认真听为师讲课。
Splitting prims(分裂面)
有的时候你可能想把模型每个面分裂开,或者根据一些属性来分裂面。这里为师传你几招分裂大法。
最简单的方法就是在当前节点下连接一个fuse节点,并把模式切换到unique,面就自然被分开了。Fuse节点实际上是个三合一节点,包含consolidate,unique和snap三个模式。
就像我们之前讨论的内容一样,这个节点做的事情就是把共享点(point)拆开,让每个面上拥有一个单独的点(point),然后把顶点(vertices)重新连接(reconnects)到这些面上。虽然视觉上看起来拆分前和拆分后好像并没有多大区别,但是你可以在spreadsheet面板或者鼠标中键点击节点信息里看出区别,模型的点数量增加了。如果你对每个点进行一些移动操作,你会发现面已经分离开了:

另一种方法是使用vertex split节点。你可以告诉这个节点想通过哪个顶点属性进行分裂。就像我们之前说的,uvs信息经常是存储在顶点层级的。
这里我再介绍两个很方便的节点,exploded view和connectivity。connectivity节点会尝试去识别模型面的islands,并且给每块islands分配一个独特的数字,存储在@class属性中。
而exploded view节点也会尝试识别islands,但并不会去标记(tag)它们,该节点只会试着去移动这些islands,让它们相互远离,有点像是炸药包炸开了的感觉(注意这个节点对于打包好的初始体(packed primitives)以及泰森破碎生成的碎块(voronoi fractures)同样有效,很棒棒哦)。
如下图,我用vertex split节点根据pig模型的uv属性分裂它,然后通过connectivity节点给每块islands一个@class属性,再给它连上一个color节点,根据@class进行随机着色,最后用exploded view节点炸开它。

Create prims with add sop(用add节点来创建面)
只要有一些点,你就能用add节点把它们连成面。将add节点的子面板模式改为“By Group”,houdini就会按照点的序号ptnum把点连成线(默认为折线polyline)。在这里我以一个2x2的grid为例,先连接一个add节点,勾选“delete geometry but keep the points”把它面给删了只留下点,然后再连上第二个add节点生成折线,最后勾选“closed”来让它变为一个完整的面:

emmmmmm...情况好像有些不对。发生了啥?首先生成的折线是一种Z字型,然后生成的面也是呈现一种扭曲反转的样子。
就像我提到的那样,在默认情况下,add节点将会按@ptnum的顺序连接你的模型。如果你打开视窗的点序号显示,观察折线,它就是按顺序连接的。虽然已经说过了但是我还是要再再强调一次:当你根据点来生成面时,顺序是很重要的!所以我们面才会被扭曲了。
为了修复这个错误,我们可以手动在最后一个add节点的Group栏填入选集,也就是按想要连接的顺序填入点序号,用空格隔开,你可以自己多玩一玩:

Create prims in vex(用vex代码直接创建面)
在理解了上文的基础上,其实我们用vex直接来创建面是更合理的。我们这次使用detail wrangle节点,给它4个点,便能生成一个面:
int myprim = addprim(0,'poly'); /* addprim函数的第一个参数为想要写入数据的模型的句柄(geohandle),第二个参数为要生成的prim类型(type),我们这里是想生成多边形(poly) */
addvertex(0,myprim,0); /* int addvertex( 模型句柄; 要关联的prim序号; 要关联的点序号) */
addvertex(0,myprim,1);
addvertex(0,myprim,3);
addvertex(0,myprim,2);
译者注:这里场景中已经有至少4个点先存在了。所以代码才直接把顶点附上去。
首先我们创建一个空物体,然后定义一个变量’myprim’来存储primnum,并且告诉它是要创建实体面(‘poly’)还是折线(‘polyline’)。之后我们根据myprim给它添加顶点和ptnum。 到现在你应该明白了,一个面实际上由它的顶点直接定义的,而不是通过其它方式。
译者注:houdini16版本以后也可直接用addprim函数来生成面了,vex会自动为你完成顶点的中间人工作。具体可见我翻译的JoyOfVex教程第14章。
Transforming prims(操纵面)
查看spreadsheet面板你会发现,面并不像点一样有个位置@P属性。那么,怎么使用vex移动面呢?我们平时使用primitive节点时面又是怎样被移动的呢?
实际上,primitive节点只是玩了个小把戏而已。当你操作面时,它先临时计算了一个所谓的面位置,然后把这个位置和点联系到一起,让点移动到对应的位置。所以看起来你是直接移动面,实际上是同时移动了面上的所有点。我们在vops/vex中也用同样的原理来操作。
如果你只是想移动和缩放的话,你可以用两个attribute promote节点来得到面的位置。我们先用个fuse节点把模型面分裂开。然后用第一个promote节点把点的位置属性P转换到面上,并将其命名为Pavg,Promotion Method用默认的Average平均选项,这样面得到的就是它的中心位置。之后再用一个promote节点把Pavg属性从面转给点,现在每个点都有它所在面的位置属性了。然后下面加个wrangle节点用vex进行操作。
移动不说了,缩放的话,你可以计算出一个当前点指向面中心的向量,然后将点的位置加上这个向量,使它向中心移动,当然了,你可以给向量乘上一个数,这样就可以完成缩放了:
vector scaler = v@Pavg - @P;
@P += scaler*ch('scale');

Other primitive types(其它primitive类型)
虽然多边形面poly是目前为止我们用的最多的一种primitive,但houdini中的prims其实还有很多。
就像最前面有提到的,你能将点当作一种小圆球给渲染出来。Houdini和mantra渲染器就是创建了一种初始球体(a sphere primitive)来实现这种事的,从数学上来说,这是一种理想球体(a mathematically 'ideal' sphere),它通过点得到位置和半径信息(通过查找点的@pscale数值),也就是说它用圆心位置和半径这两个数据来定义了一个球体。
Houdini还提供了circle primitives, poly lines, bezier curves, nurbs curves, nurbs surfaces, bilinear shapes等初始体,以及更有趣的,volumes和vdb。尽管一个volume可能是由数百万voxels组成的,但它就是一个单独的primitive,并且它从lowly point得到它的位置.
Points万岁!






































