前言

  最近因为要开始做三维动画的实训课,所以开始疯狂看教程了,(其实网页项目还没做完,不过研究出Houdini VDB 流程解决方案,还是简化了不少工作量)
  本来我们和动画合作要搞太空科幻题材的动画,这就需要破碎、爆炸、星尘之类的特效的。
  不过看到自己移动硬盘中以前囤积的教程,还是忍不住先看一下吧。

VEX入门

  • 对着相关的函数按F1可以跳转到Houdini的相关函数的网页界面,而且经过我的测试,这是Houdini 16.5为你搭建的本地服务器所访问的内容,无需担心网络的问题
  • 按d键进入界面设置可以在vissualize标签中将相关变量显示出来(visualize节点也可以)
  • 属性和变量的区别,从编程的角度说就是全局和局部变量的区别,从Houdini来讲就是能否传递数值
  • printf(format, …)命令可以在Houdini console中打印数据。
  • vector变量的通道可以通过abc 、rgb 、 xyz 三种不同的方式获取
  • Matrix属于多维数组可以通过aa ab 获取其中的单通道
  • wrangle节点可以通过 alt + E 打开Houdini的代码编辑器,比起wrangle的小界面好用太多了,不过我还是觉得VScode好用
  • Houdini的Function定义类似于C语言 先声明返回值的变量类型 后接函数名和参数 需要注意的是Houdini的参数声明使用 ; 间隔而不是逗号(调用函数时参数间隔还是用逗号的)
  • Array添加数组使用 append(array, value) 函数,效果和JavaScript的push是一样的。
  • len(array) 函数可以获取数组的的长度,与JavaScript array.length 效果一样。
  • 函数传参修改回改变参数自身的,建议使用函数局部变量进行数据交换。
  • 向量声明可以使用set 或者 用{} 声明

教程中VEX详解

第十集 - 点线面命令相关的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//获取属性
point(geometry, attribute_name, pointnumber);
prim(geometry, attribute_name, prim);
vertex(geometry, attribute_name, prim, vertex);
detail(geometry, attribute_name, ignored);

//修改属性
setpointattrib(geohandle, name, pt, value, mode="set")
setprimattrib(geohandle, name, prim, value, mode="set");
setvertexattrib(geohandle, name, elemnum, vtxofprim, value, mode="set");
setdetailattrib(geohandle, name, value, mode="set");

//创建
addpoint(geohandle, pos);
addprim(primnum, geohandle, type, points, vertices);
addvertex(geohandle, prim, point);

//有多少个
npoints(filename);
nprimitives(filename);
nvertices(filename);

//放进数组中
setpointgroup(geohandle, name, pt, value, mode="set");
setprimgroup(geohandle, name, prim, value, mode="set");
setvertexgroup(geohandle, name, elemnum, vtxofprim, value, mode="set");

/*获取属性 代码解析*/
vector myPos = point(0, "P", @ptnum);
/*
* 第一个参数: ` geometry ` - wrangle节点的输入通道(0表示wrangle节点的第一个通道)
* 第二个参数: ` attribute_name ` - 获取属性名称 如 N(法线Normal) Cd(颜色ColorDiffuse) P(位置Position)
* 第三个参数: ` pointnumber ` - 根据点序号进行获取操作
* 上述操作就可以将特定模型点的位置存入到vector变量 myPos 中
*/

/*修改属性 代码解析*/
setpointattrib(0, "P", @ptnum, @P+1, "set");
/*
* 第一个参数: ` geohandle ` - wrangle节点的输入通道
* 第二个参数: ` name ` - 获取属性名称
* 第三个参数: ` pt ` - 进行操作的点序号
* 第四个参数: ` value ` - 进行操作的数值
* 第五个参数: ` mode ` - 官方文档有更多模式
* 上述操作就可以将特定模型点的位置偏移
*/

第十一集 - Array数组操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
vector pos;

vector pos_all[];

for(int i = 0; i<npoints(0);i++)
{
pos = point(0, "P", i);
//将获取到点位置信息存放到数组中
append(pos_all,pos);
}

//遍历数组 获取数组中的信息
for(int y = 0; y<len(pos_all);y++)
{
printf("%d\n",pos_all[y]);
}

// foreach (int index; element_type value; array)
foreach (int index; vector posi; pos_all){
//posi是当前index遍历中pos_all数组的一个元素
if(posi.y > 0 )
{
posi.y = 0;
setpointattrib(0, "P", index, posi, "set");//进行位移操作
}
}

/***************************************/
/************第二种实现方案**************/
/***************************************/

vector pos;

//根据面返回点 这里就是快速获取所有的点
int pts[] = primpoints(0, @primnum);

foreach(int pt; pts)
{
// 计算所有点的位置
pos = point(0, "P", pt);
if(pos.y > 0)
{
pos.y = 0;
setpointattrib(0, "P", pt, pos, "set");
}
}

/***************************************/
/************第三种实现方案**************/
/***************************************/

if(@P.y>0)@P.y=0;

/***************************************/
/*************foreach解析***************/
/**************************************/

// 三个参数情况
// 官方解释
// For each iteration, this form assigns the current position in the array to index,
// copies the current member to value, and executes statement. For example:

string days[] = { "Mon", "Tue", "Wed", "Thu", "Fri" }
// i为当前遍历的序号
// name为days中的元素(根据当前遍历序号获取)
foreach (int i; string name; days) {
printf("Day number %d is %s", i, name);
}

// 两个参数情况
// 官方解释
// This loops over the members of array. For each iteration,
// it copies the current member to value and then executes statement. For example:

int an_array[] = {1, 2}
foreach (int num; an_array) {
//num既是index也是数组的元素
printf("%d", num);
}

球体压平]

第十三集 - 创建几何体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建一个面片
vector pos1 = set(1,0,1);
vector pos2 = set(-1,0,-1);
vector pos3 = set(-1,0,1);
vector pos4 = set(1,0,-1);

int p1 = addpoint(0, pos1);
int p2 = addpoint(0, pos2);
int p3 = addpoint(0, pos3);
int p4 = addpoint(0, pos4);

int prim1 = addprim(0, "poly");

// 注意添加顺序
addvertex(0, prim1, p1);
addvertex(0, prim1, p3);
addvertex(0, prim1, p2);
addvertex(0, prim1, p4);

平面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 创建一个金字塔
vector pos1 = set(1,0,1);
vector pos2 = set(-1,0,-1);
vector pos3 = set(-1,0,1);
vector pos4 = set(1,0,-1);

int p1 = addpoint(0, pos1);
int p2 = addpoint(0, pos2);
int p3 = addpoint(0, pos3);
int p4 = addpoint(0, pos4);

int prim1 = addprim(0, "poly");

addvertex(0, prim1, p1);
addvertex(0, prim1, p3);
addvertex(0, prim1, p2);
addvertex(0, prim1, p4);

vector pos = {0,2,0};
int p = addpoint(0, pos);

int prim2 = addprim(0, "poly");
addvertex(0, prim2, p);
addvertex(0, prim2, p1);
addvertex(0, prim2, p3);

int prim3 = addprim(0, "poly");
addvertex(0, prim3, p);
addvertex(0, prim3, p4);
addvertex(0, prim3, p1);

int prim4 = addprim(0, "poly");
addvertex(0, prim4, p);
addvertex(0, prim4, p2);
addvertex(0, prim4, p4);

int prim5 = addprim(0, "poly");
addvertex(0, prim5, p);
addvertex(0, prim5, p3);
addvertex(0, prim5, p2);

金字塔

第十六集 - polyline

1
2
3
4
5
6
7
8
9
10
11
//找到附近的点
int closePTS[] = nearpoints(0, @P, 5);

foreach(int pt; closePTS)
{
int connect = addprim(0, "polyline");

addvertex(0, connect, @ptnum);
addvertex(0, connect, pt);
}

连线效果

第十七集 - nearpoints

1
2
3
4
5
6
7
8
9
10
11
12
// 获取第二输入几何体序号为零的点位置
vector pos = point(1,"P",0);

float distance = ch("dist");

//寻找小于distance的点
int targets[] = nearpoints(0, pos, distance);

foreach(int pt;targets)
{
setpointattrib(0, "Cd", pt, 1, "set");
}

靠近变红色

第十八集 - neighbour

1
2
3
4
5
6
7
8
int origin = chi("source");

int neigh = chi("neigh");

//neigh 可以获取单独的neighbour元素
int targets = neighbour(0, origin, neigh);

setpointattrib(0, "Cd", targets, 1, "set");

neighbour元素

1
2
3
4
5
6
7
8
9
int origin = chi("source");

// 获取所有neighbour相关元素
int targets[] = neighbours(0, origin);

foreach(int pt; targets)
{
setpointattrib(0, "Cd", targets, 1, "set");
}

neighbours 多个元素

第十九集 - 点云基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float distance=ch("dist");
int amount=chi("amount");
int target;
vector pos =point(1,"P", 0);
int pcloud=pcopen(0,"P", pos, distance, amount);

if(pcnumfound(pcloud)>0){
while(pciterate(pcloud)){
pcimport(pcloud,"point.number", target);
setpointattrib(0, "Cd", target, 1, "set");
}
}

// 获取最远的点
f@far = pcfarthest(pcloud);

点云实现点的获取

第二十集 - 点云操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//获取点云信息
int pcCloud = pcopen(1, "P", @P, 2, 1);

//获取球的的位置信息
vector pos = point(1, "P", 0);

//计算球到面的距离算出方向
vector dir = normalize(@P - pos);

//获取点云识别到的点
if(pcnumfound(pcCloud)>0)
{
//计算两者之间的距离 因为上面的搜索半径为2 所以dist 是从0到2变化的
float dist = distance(@P, pos);

//将距离信息重新映射作为区域的衰变范围
float falloff = fit(dist, 0, 2, 1, 0);

//falloff 的作用是当距离越靠近的时候减弱点的位移,距离越远受到的位移就越大
@P += dir * falloff;
}

点云实现点凹陷