VEX 算法基础
1.基础知识 attributes
1.四种属性类型 attributes
1.point
2.primitive
3.vertex
4.detail
2.数据类型

数组
f[]@aval = array(1.2,2.1,4.5);
wrangle
wrangle 中的vex 代码==同时==运行于每个point ,primitive ,vertex,但是==detail只运行一次==
multi threading 多线程 ,vex比python快的原因,vex可以一次将代码应用到所有点
保留属性

global attributes 全局属性
@Frame
@Time seconds
一般将global attribute 存储在detail,
2.组 groups
point ,primitive,vertex存储在对应的类型中,edge无法查看。
1.[==setpointattrib()== ] 设置point属性


1.相比直接设置 i@abc = 100 将所有点设置为同一属性值; setpointattrib(0,"abc",@ptnum,100)函数可以==选择性设置==一部分点的属性值。可控性更高。
2.[==setpointgroup()== ]设置point 组

3.primitive ,vertex 有同样的VEX function

2. 过滤 group 的相关函数 filtered group function
1.查找primitive==是否==在prim group 中
[==inprimgroup()== ]
如果primnum在groupname中,则返回1

2. 查找==有多少个==primitive在prim group 中
[ ==nprimitivesgroup()== ]

3.查找在group中的primitives 的编号, 返回数组
[==expendprimgroup== ]

4.近点函数 查找距离pt(位置)最近的点返回编号,这里可以设定范围为ptgroup,仅查找组内的点
[ ==nearpoint()== ]

geometry 指的是要搜索的几何体
3.参数 parameters
1.创建参数

2. 链接参数
copy parameter -> paste references
使用反引号引用链接即可读取内容

同样可以读取menu value

3.使用 VEX 访问参数
直接复制 使用的chs(),返回的是string类型,所以需要使用反引号,将字符串转换为float值

使用 ch(),函数

可以使用其他类型,这里可以使用chf(),
不同的ch()函数

4.避免修改参数的name导致链接断开,将参数链接到wrangle的新通道,再链接到VEX代码

可以直接创建不同的channel

5.斜坡参数 ==ramp parameter==

channel: 指的是channel name 名称
ramppos: 指的是输入的横坐标x轴的值,即需要评估的值,以返回对应的y轴值。
6. 全局变量 global variables 可以在任何地方任何节点访问

局部变量 local variable 只能再特定节点访问
比如transform ,在reference ->local variable 中查看

SIZEY

同样使用$符号引用

也可以在具体节点的文档查询可用的局部变量

脚本语言 H script 或者叫做 expressions function,可以在参数中直接使用

4.变量和运算符 variables and operations
1.变量 variable

2.运算符 operations
即数学运算
加减乘除以及类型转换
1.字符 运算 strings operation
字符串 相加(只能做加法运算,不能实现减,乘,除)

数字与字符串转换 casting
使用[ atof() ] 函数 将字符串转换为float
只有当变量为数字才生效,否则返回0

使用[ atoi() ] 函数 将字符串转换为integer
使用[ itoa() ] 函数 将integer转换为字符串

没有函数 ==ftoa()== 将==float==转换为字符串
使用[ sprintf() ] 函数 将==任何类型==数据 转换为字符串
第一个参数是要转换的变量的类型,第二个是转换变量


format

向量 运算 vector operation
加,减,乘,除
即==各项==相加,相减,相乘,相除
例如:使用==加法==,使点沿法线移动

==向量vector== 与 ==浮点数float== 运算
会将==float== 或者==integer== 转换为同样大小的==vector== 进行计算

==向量vector== 与 ==其他向量vector== 运算
将==较小的向量vector== 转化为与 ==较大的向量vector== 相同大小的向量==vector==,在多出来的轴增加0


访问向量中的分量
方法一:像访问数组一样
=vector[index];

方法二:使用点运算符
=vector.x;

5.数组 array
a container that can contain multiple items
包含各种数据类型的容器
1.创建数组
创建空数组变量 variable,方括号表示, 存储值放在==大括号中==
大括号只能使用值,不能使用变量variables。

使用[ array() ]函数 才能使用变量variables

创建具体的数组属性 array attributes , ==f[]@name === (方法一)


使用[ setdetailattrib() ] 函数 创建 attributes (方法二)

使用函数[ setdetailattrib() ] 的好处在于可以程序化修改变量名,以便参与循环等等

2.从数组中==获取==值, get item from array
1.使用索引 index ==访问== 数组的值 items
===values[index]==

3.向数组中==添加==值 add items
方法一 : 使用[ push() ] 函数
push(variables name, values );
参数为变量名,值;

方法二 : 使用[ append() ] 函数
以上两种方法需要将variables values 变量值 ==赋值给 一个属性==attributes
使用[ setdetailattrib() ] 函数 则可以直接向==属性attributes== 中==追加==值values
使用==“append”== 模式mode

4.从数组中==删除== 值 remove item
有三种方法 : 一是remove==最后一项==, 二是remove具体的==值values==,三是remove按==索引index==
1.方法一:使用[ pop() ]函数 remove 最后一项
pop(数组名);

2.方法二:使用[ removevalue() ]函数 remove values特定值
removevalues(数组名,特定值);
==注意==:这个函数并不会删除所有相同的值,==只删除第一个值==。


3.方法三:[ removeindex() ] 通过index 删除remove 值values
removeindex(数组名,索引);

5.其他关于数组的函数
1.从一个数组创建重复的数组
1.直接将一个数组 ==赋值== 给新的数组,以创建副本

2. 使用[ set() ] 函数 创建副本
set(数组名);

使用[ set() ] 函数的好处在于 当参数不是数组时,可以将向量vector或者矩阵matrix转化为 数组

获取一个数组中值的==总数==
使用[ len() ] 函数获取 数组长度
len(数组名);

6.字符串 strings
1.声明字符串 declare string
方法一:创建字符串变量并赋值 使用==双引号==
==string sname = "";==

方法二: 创建字符串变量并赋值 使用==单引号==
==string sname = '';==

从[ font ]节点, 访问字符串==属性== string attribute
能够访问detail的函数functions

[ details() ]函数 , 从detail attribute 返回 string
details(surface_node,attribute);
surface_node 指的是节点名, attribute 是属性名

为了将其作用为表达式expression,必须使用==反引号==
`detail(" "," ")`

2. 使用特殊字符 special characters
反斜杠作为转义符escape word \
1. ==\n== 反斜杠n ==换行符==
将双引号转换为字符串

单引号 和 双引号 ==交替使用==也可以实现

其他转义符

3.格式化字符串 formatting string
将值values 格式化为字符串
这里使用[ itoa() ]函数将==整数integer== 转化为字符串string
注意:没有 ==ftoa()==函数 将==浮点数float== 转化为字符串string

需要使用[ sprintf() ]函数 将==float==转化为字符串string


==sprintf("format", ...);==
format

修改VEX精度 precision

[ sprintf() ]函数 可以转化==多个不同类型==的变量

4.字符串操作 string operation
1.字符串==相加== addition ,将字符串连接起来


连接多个字符串

要连接多个不同类型的字符串需要使用[ sprintf() ]函数
5.访问字符串 string access
和访问数组类似
访问字符串中的==单个==字符
要访问字符串中的某个字符,要先计算该字符的索引index
=== variable_name[index];==

检索retrieve ==多个==字符
使用起始索引index_beg,冒号: ,结束索引index_end 的格式

===variable_name[index_beg:index_end];==
6.字符串和数组函数 string & array functions
1.[ join() ] 函数 连接数组中的所有字符串 形成一个字符串

==join(s[],spacer);==
spacer 作为字符串之间的间隔字符串

2.[ find() ]函数 在字符串中搜索字符
在字符串中搜索单个字符 返回index

==find(字符串,字符值);==
haystack 是要搜索的字符串(范围),needle 是要搜索的==字符串值==。
如果搜索多个字符,则只返回第一个字符的index

在数组中搜索单个字符 返回index,不仅可以用于字符

==find(array[],target);==

3.[ split() ]函数 将字符串转化为数组

==split(s,separators);== 返回数组
s 是要拆分的字符串, separators 是分隔符 即使用那些字符将字符串拆分为数组

4.[ len() ]函数 获取字符串长度

len()函数不仅用于数组array[],也用于string,

7.循环 looping
流程图

1. for循环基础 for loop basics

循环创建多个points
[ addpoint() ]函数 创建point,并返回point number

2.在for循环中访问属性 for loop for attributes
在for循环中访问已创建点的attributes
修改每个点的颜色 @CD

[ npoints() ]函数 返回输入geometry 的点数
[==setpointattrib()== ] 函数 设置点属性
3.for循环运用 for loop exercise
1.创建螺旋形状 helix
1.生成points


2.可以使用==三角函数==创建螺旋线
设置步进角θ, i:0-->num θ:0-->iθ
3.设置x,z坐标, x = cos(),z = sin();

4.设置y坐标

5.参数化变量
参数化 步进角 angratio, 步进高度 heightratio

4.while loop
while(){};
只有一个条件,且不能在括号直接创建
1.while loop

2.do while loop
至少运行一次,即使条件不符合
先运行一次,再检查条件,不符合则退出循环

5.while循环运用 while loop exercise
1.创建螺旋形状 helix
以总旋转角度 total rotated angle 为条件
创建变量

创建循环

6.foreach loop
需要与数组一起使用
1.foreach loop
先将values 依次存入数组中


创建foreach loop
val指的是values数组中的每一个值

以数组中的每一个值作为x坐标生成points


7.数组的for循环 for loop for array
使用for循环访问数组值
1.使用for循环依次以 数组中的值 作为点的x坐标生成点

8.foreach 循环运用 for each loop exercise
创建螺旋形状 helix,控制每个点的法线方向
以便于将geometry 复制到点上时 基于法线对齐
1.将基于三角函数生成的position信息依次==存储在数组中==
为了参考第一个点和第二个点之间 创建向量vector,没有数组很难定义当前点current和下一点next位置

2.使用另一个for循环访问(access) 数组中的值
条件中 i<len(positions)-1 ,总数减去1,保证当前点current point 始终有下一个点next point
否则当最后一个点作为当前点时 则没有下一个点了 即保证i+1任然在数组内
3.创建方向向量 ==next - current== = 由==current指向next==的向量

4.使用[ setpointattrib() ]函数 将方向向量存储在点的attributes中

5.结果 使每个box与曲线对齐 ,指向下一个点

6.额外设置up向量

9.嵌套循环 nested loop
在一个循环中创建另一个循环
1.创建nested loop
创建两层

创建三层

10.嵌套循环运用 nested loop exercise
1.创建多个螺旋形状 helix
1.创建变量
2.创建循环
单个helix
3.嵌套循环 用n控制正弦余弦的角度
用stepang = ==$PI*2 / num2==,即以num2 划分360度
在三角函数中 加上==stepang * n== ,即加上偏移值,生成每一个点对应的偏移点


4.利用n,为每条螺旋helix 设置attributes id


8.条件 conditional
1.if else条件 if else conditional
1.simple condition


1.[ font ]节点可视化

2.多于两个条件则增加 ==else if()==

2.单条语句的if条件 single line if conditional
1. 一行语句

2. 三元运算符 ternary operator
1. === 条件 ?"true 的action" : "false 的action" ;==

3.基本比较运算符 base comparison operators
1. 基本比较运算符


4.字符串匹配符 string match operator
1.字符串比较


2. ==~=== 匹配比较运算符 match operator
仅用于字符串匹配
模式一:使用 ==?== 匹配所有==字符==
只匹配单个字符

模式二: 使用 ==*== 匹配所有==字符串==
可以匹配任何长度的字符串


模式三: ==[]== 匹配==选定的字符==
只匹配单个字符

模式四: ==^== 匹配所有字符串时 排除另外一种情况
条件并列使用逗号连接排除的条件( ==,== )


5.运算符逻辑集 logical set
==与或非 and, or , not==
1. 与and , ==&&==
两个条件 ==同时满足== 才成立


2. 或or , ==||==
满足==其中一个条件==即成立


6. 用return==结束进程== ==end process== with return
在if语句中,如果满足条件,则return,以下的语句(s@next += "Not returned.";)不再执行.

7.用break==结束循环== ==end loop process== with break
满足条件则结束循环
只结束循环,以下的语句还是会执行

8.用continue ==结束迭代== ==end loop iteration== with continue
并不结束循环,只结束当前迭代并转到下一个迭代
1.使用continue跳过满足条件的循环迭代

9.条件练习 exercise - conditional with ==attributes==
条件与属性 ==attributes==
1.以时间@Time 为x坐标 创建point


2.基于时间@Time 改变point 大小 pscale

10.条件练习 exercise - conditional with ==group==
条件与组 ==group==
1.依据条件创建组

2.根据group 移动point
[ inpointgroup() ]函数 判断点是否在一个group内


11.条件练习 exercise - conditional with ==array==
条件与数组 ==array==
1.随机生成points,将pt(number)存储到数组pts中

2.根据阈值随机定义一部分points
这里改变颜色和大小属性
使用数组中存储的pt(每个点的number) 来为每个point设置属性


9.函数 function
1.函数类型 function type
不同的contexts 有不同的函数

这里主要在cvex contexts
自定义函数

2. 内置函数 built-in function overview

vex functions


3.无返函数 ==void== function
无返回值,只做某种操作
例如:[ append() ]函数
往数组或者字符串中追加值

这里的 ==&== 符号,带有的参数(作为输出参数)将在运行后==立即更新==
4.返回函数 ==return== function
有返回值
例如:[ len() ]函数
计算数组的长度

5.函数练习1 function exercise 1
[ nearpoint() ]函数
1.找到geometry 中距离pt(自己提供的位置)最近的point
2.VEX

[ point() ]函数 获取第二个输入点的位置
找到距离目标点最近的点 返回ptnum值 存放到npt中

改变所找出的点的属性,例如颜色

6.函数练习2 function exercise 2
更多参数的[ nearpoint() ]函数
1.需要一个搜索范围ptgroup
2.设置搜索距离
3.也可以直接将group的条件放到函数中
7.函数练习3 function exercise 3
具有多个输出参数output parameter 的函数
1.[ intersect() ]函数 计算与射线ray与geometry第一个交点
相交函数
有三个输出参数 p,u,v 还返回一个int值
参数
orig :射线ray的==原始位置==
dir :==射线的方向== 和 ==最大搜索距离==(vector的长度)
&p :交点的位置
&u,&v,&uvw :交点在相交的primitive的uv坐标
return :相交的==primitive number==
例子:将torus投射到地面,更新point位置到交点intersection位置
创建参数parameter

使用[ intersect() ]函数
更新位置
8.自定义函数 user-defined void function
void function
1.生成螺旋形spiral 点位置 的函数 ==void 无返回值==
1.参数:三个参数来确定螺旋点spiral point的位置 ==角度==,==半径==,==初始位置==
新的位置 :初始位置加上 根据三角函数得到的旋转后的位置 乘半径
生成point
调用函数
将参数设置为可控制的channel

9.自定义返回函数 user-defined return function
return function
1.生成螺旋形spiral 点位置 的函数 ==return 返回位置==
声明return function时最好使用 ==function 关键词== 避免出现未知错误
1.声明函数

2.调用函数
存储生成的点位置,利用生成的位置创建点

3.也可以使用条件设置多个返回值

10.声明输出参数 declare output parameter
为函数创建输出参数
1.生成螺旋形spiral 点位置 的函数 用output parameter输出位置
声明设置:增加输出参数 ==export type name==
更新输出参数值

调用函数

11.导入预安装函数 import preinstalled functions
导入houdini内置的外部函数,houdini引擎安装时提供的文件
1.houdini内置的函数位置
: houdini > vex > include >

2.导入houdini内置函数
1.包含头文件 #include"groom";
2.调用函数控制primitive的长度

12.导入自定义函数 import user-defined functions
导入自己创建的外部文件
1.创建一个include文件夹,将 自定义.h,文件放入
include文件夹要与当前工程文件在一个文件夹
2.导入函数
导入自定义函数时要加路径

3.调用函数

10.体素 volume basics
1. volume基础 basics
在体素voxel中存储属性attributes数据
1.volume类型 type
fog 和 sdf
sdf 提取表面 主要用于建模而不是流体模拟等
fog
2.volume的可视化和修改 visualize and modify ==scalar== volume
标量volume
直接用[volume]节点创建,或者转化
1.创建标量值density volume
2.可视化 [volume visualization]
3.用[volume wrangle]节点 修改density值
为每个voxel设置density值
使用[ noise() ]函数 为每个voxel设置density(根据==@P==)
也可以将volume转换为surfaces
使用[ convert ]节点转换为表面
volume offset
2.volume的可视化和修改 visualize and modify ==vector== volume
向量volume
1.创建向量值velocity volume
vector volume被拆分成 scalar分量 存储
2.可视化 visualization
3.修改volume 值
根据三个channel修改颜色

4.另一种可视化方法
将vector作为方向值,从volume中提取方向extract direction,
使用[ volume trail ]节点
3.surface转换为volume volume frome surface
从geometry shape 创建 volume
1.[ isooffset ]节点
以此创建的volume 任然是box形状,50*50*50的voxel分辨率.只是在geometry以外的体素值存储为0.

2.数学运算
1.检索density值,控制density

2.设置noise

4.volume 属性 volume attributes1
只能从volume wrangle 访问的保留属性 ==preserve attributes==
1. ==位置属性== ==@P==
在每个voxels 的中心位置
依据位置信息设置density
2.每个体素的索引 ==i@ix==, ==i@iy==, ==i@iz==
从原点开始沿x,y,z轴递增,即按照volume的分辨率依次递增
通过访问保留属性 ==i@ix==, ==i@iy==, ==i@iz==,分别获取volume在三个轴的index
3.访问每个轴的分辨率大小 ==i@resx==, ==i@resy==, ==i@resz==
5.volume 函数 volume funcition
使用==volume 函数==可以在其他wrangle类型中访问 基于volume的信息(density,velocity,resolution...)
检索volume,查看volume 函数
1.在volume的特定位置采样density值
1.在volume wrangle中检索
1.创建检索点的位置变量(这里[ add ]节点提供)
2.用[ distance() ]函数 计算(@P,pos)体素与检索点的距离
==注意:==只有==volume wrangle中可以修改==volume值,其他类型的wrangle可以访问但==不能==修改
3.[ volumesample() ]函数,从==scalar volume==中检索==scalar value==
6.==volume 函数2== volume function2
1.检索volume==向量==值
1.[ volumesamplev() ]函数 从==vector volume==中检索==vector value==
2.在point wrangle中从geometry中的每个点采样velocity值
获得特定位置(球体上的每个点)的向量值
3.依据采样的==vector value==移动点的位置
可以实现==按照volume中的向量变形几何体==
4.noise按时间变化
7.volume 函数3 volume function3
1.[ volumepostoindex() ]函数 将位置转换为volume 体素索引
[ volumeindextopos() ]函数 将volume 体素索引 转换为位置
2.根据volume实现几何体的==体素化效果==
1.用[ delete ]节点 删除球体的primitive face,==只保留点==
2. 使用[ volumepostoindex() ]函数 获得几何体每个点在volume中的索引值
检索==position== ,返回三个轴的==索引值==(vector), 检索的是在特定位置 ==最接近的==索引值
3.使用[ volumeindextopos() ]函数 ,将索引值转换为在volume中的位置
将volume 体素的==索引值== 转换为 位置==position==, 获得的是在特定的索引下 ==精确的==体素中心位置(voxels position)

4.以此实现==体素化效果==

5.由于移动后会有很多点在重复位置
使用[ fuse ]节点去除重复点
8.volume debugging
1.调试volume的技巧
在volume的每个体素位置添加point, 在每个点设置volume对应体素的属性
将volume存储在每个voxels的属性转换到对应位置的points上
==相当于将体素转换为对应的点==
这里先读取density到变量d,不能忽略, 直接在@P,位置生成点不起作用
这里类似一种巧合:可能涉及了houdini的VEX代码执行机制,由于volume wrangle主要是处理volume,其机制推断addpoint函数并不需要访问volume数据本身,所以可能并没有将@P设置为每个体素的中心位置。
当使用f@density,读取density的值,其机制判断需要读取体素值,所以计算好每个体素的@P,@density
这是一种编译上的优化处理。
同样适用于SDF
1.在每个体素的位置添加点
2. 使用[split] 节点 分开点和volume
11.字典 dictionary
1.基础 basics
字典中的每个item可以是==任何类型==的数据
1.声明字典 declare dictionary
使用 ==dict== 关键字 ==创建字典==
==dict name = {} ;== 创建dictionary
d@name = ; ==访问属性==
2.存储值
==key 必须是 字符串==
使用[ set() ] 函数 ==set("key" , value)== 可以一次创建多个键值对set("key" , value, "key", value)

使用==dict_name = set();==会覆盖其他值
2.设置字典中的项目 set item to dictionary
1.修改(添加)对应 key 的 value
使用方括号==dict_name["key"] = value;==
3. 删除字典中的项目 remove item from dictionary
==d@== 访问 dictionary attributes
==dict== 创建 dictionary
1.从给定的 index 删除项目
[ removeindex() ] 函数用于数组或者字典
==removeindex(dict_name,"key");== 返回1表示删除成功,返回0 表示没有这个key
4.在字典中查找键 check key in dictionary
1.检查key是否有效
[ isvalidindex() ]函数 检查给定的index是否有效
返回1表示存在于字典中,返回0表示无效,(适用于数组和字符串)
5.访问字典中的项目 access item in dictionary
1.直接访问对应的key,需要知道 ==值的key==,==值的类型==
访问不存在的key时,返回0,或者空字符
2.[ getcomp() ]函数
从vector,==array==,matrix中提取单个组件,也可用于字典
查找key并返回值,第三个参数 即查找失败的默认返回值
6.合并字典 combine dictionary
1.[ insert() ] 函数
向数组或字符串中插入值,可用于字典插入或合并
insert(dict1,dict2; 将dict2 合并到 dict1
7.将字典转换为JSON格式 dictionary to JSON
将 字典值 转换为 字符串
JSON是一种字符串的格式


1.[ json_dumps() ]函数 将==VEX dictionary== 转换为==JSON string==
string json = json_dumps(dict,flags);
flags: 标记 0,1,2,3 表示返回不同的json
转换为单行json字符串

可以通过font查看
转换为==多行json==字符串,改变==标志位flags为1==
将JSON 转换回字典
2.[ json_loads() ] 函数 将==JSON string== 转换为==VEX dictionary==
string json = json_dumps(string json,flags);
访问 json string attributes
创建dictionary
设置为字典attributes以查看
8.运用1 exercise 1
1.用字典控制球体每个点的位置颜色
1.设置scatter的点数与球体点数保持一致
用box的点云控制球体
2.为点云中的每个点创建dictionary
基于点云中点的位置创建颜色信息和比例信息
声明dictionary
存储到每个点的attributes中
3.在球体中引用dictionary信息
9.运用2 exercise 2
1.通过访问字典创建网格
为每个点创建字典
以数组的形式存储所有字典,并存储到detail属性中

检索字典并创建网格点
读取存储在detail属性中的字典数组
设置点属性
12.矢量 vector
具有方向和长度的信息
可以使用向量移动物体,也可以用于控制颜色(rgb)
1.向量加减法
1.向量加法 adding
首尾相加
2.向量减法 subtraction
即加上一个负的向量
3.向量运用1 vector exercise1
1.创建向量用来移动物体
创建一个用来移动的向量

在位置@P加上向量
加法减时,相当于将新向量的原点移动到原向量表示的坐标处,在原位置的基础上按照新向量的方向和长度移动
2.减法
创建随机向量
由于[ rand() ]函数创建的随机值在0到1之间,没有负数,所以只有正方向的向量。要获得所有方向上的随机向量,将得到向量每个轴减去0.5.
3.要得到一个 ==A指向B== 的向量,应该用 ==B - A==
两点位置相减,将原点移动到新点
使用[ addprim() ]函数 连接两点。
4. 向量运用2 vector exercise2
1.在for循环中更新向量,用来反复移动点.
1.获取当前位置,创建循环,在新位置add点
2.将最后一个点移动到新位置
分形fractal shape
3.创建方向向量,加到原位置作为新位置,在新位置生成点,再将新位置更新到原位置,以作为下一次移动的基础
4.增加角度值,使用三角函数更新x,z坐标,以获得螺旋线
5.向量乘法(标量) vector multiplication
1.向量==乘以标量== 只改变大,不改变方向
1.向量==除以标量== 只改变大,不改变方向 与乘法效果相同
6.向量除法(乘除法运用) vector division
当球体在世界坐标系的==原点处(0,0,0)==
1.控制geometry 的 scale
直接在点位置的基础上乘以标量
7.向量运用3 vector exercise3
当球体的中心不再世界坐标系的原点时,以中心点放缩
1.此时的乘法会放缩大小,但是也会往原点移动
直接用球体的位置@P乘以一个标量scale,放缩的时原点到球体位置的向量。所以产生移动。
2.方法:将球体移动到原点中心,scale,再移回原中心位置
8.规格化 和 模(大小) normalization and magnitude
1.规格化 normalize
即只考虑方向,大小始终为1
1.[ normalize() ]函数 归一化向量
2.[ length() ]函数 检索==retrieve==向量的大小
9.向量运用4 vector exercise4
1.生成随机大小的法向向量
2.以此向量移动点,并使向量在随机向量与归一化向量之间切换
==10.点积 dot product==
可以通过两个向量的点乘 来==检查向量之间的夹角==是否垂直,同向或者反向
1.点积定义(数量积或标量积)
代数定义
相乘再相加
几何定义
两向量的点积可以理解为==向量A在向量B上的投影再乘以B的长度==

点乘的结果是投影的大小
2.VEX
1.计算两向量的点积
[ dot() ]函数
2.设置角度channel,利用三角函数更新向量2的x,y值,以此旋转向量2 从0到360度
11.向量运用5 vector exercise5
1.==用点积判断一个点是否在几何体内部==
1.[ nearpoint() ]函数 检索距离最近的点 获取其属性
2.得到 ==当前点== 到 ==曲面上最近点== 的向量(==近点 - 当前点==)
3.计算 近点法向 与 当前点朝向向量 的点积, 以此判断当前点是否在几何内部
4.大于0 则在内侧, 小于0 则在外侧
以此作为条件改变点的属性
==12.叉积 cross product==
叉乘得到的结果是向量 是==两向量所在平面的法线向量,垂直于两向量==
其方向有右手定则确定
1.叉积定义(向量积,叉乘)
叉积仅在三维空间有定义
2.VEX
1.计算两向量的叉乘
[ cross() ] 函数
13.向量运用6 vector exercise 6
1.创建up向量
使用[ copytopoint ]时,==N== 和 ==up== 向量都可以控制几何体方向
1.计算两向量的 叉积
得到旋转矢量
2.将此向量引用到up向量
13.三角函数 trigonometry
1.角/角度 和 弧度 angle / degrees and radians
1.角度与弧度(又称弦度rad)
degrees:==角度== 0到360°
radians: ==弧度== Π表示180°(Π = 3.14159....)
Π = a / d(圆周长 / 直径), 单位弧度 定义为 ==圆弧长度等于半径时的圆心角==
2Πr=a ,所以一个圆完整的弧度为2Π,即360°。Π 表示180°
大多数计算机程序设计使用==弧度==作为计算
2.角度转换 angle conversion functions
1.角度转换为弧度 degrees to radians
[ radians() ]函数 将角度转换为弧度
2.弧度转换为角度 radians to degrees
[ degrees() ]函数 将弧度转换为角度
这里的channel为0到1 , 乘以一个PI,即可通过 0-1 控制 0-PI
3.正弦,余弦,正切 sine ,cosine,tangent
在单位圆上的点
cosθ 表示x轴位置 其值对应在x轴右半边 一四象限为正,左半边 二三象限为负
sinθ 表示y轴位置 其值对应在y轴上半边 一二象限为正,下半边 三四象限为负
1.基于圆 创建点 用三角函数表示
4. 三角函数可视化 visualize trigonometry
1.可视化
创建斜边
创建水平投射线
创建垂直投射线
合并
设置圆
通过设置角度channel控制transform中的旋转角度.
与内置函数[ sin() ],[ cos() ] [ tan() ]计算的结果相比,结果一致
设置半径channel 改变圆半径
改变半径并不改变三角函数值,三角函数表示的时三角形边的关系
5.运用三角函数画圆 exercise - draw circle
可以通过三角函数判断圆上点位置,即可以使用三角函数取圆
1.用三角函数画圆
1.创建for循环,控制循环次数
知道圆的半径,和夹角角度 即可通过三角函数计算圆上点的x,y坐标.
2.创建递进角度 三角函数计算x,y坐标(默认以半径为1) 所以再乘以半径(可变).
2Π / 循环总数 = 每次循环递进的角度 ,再乘以i,每次循环依次递加角度.
6.运用三角函数画圆动画 exercise - circular animation
1. 用三角函数创建绕圈动画
1.设置角度和半径channel控制点在圆上的位置.
7.运用三角函数画波形 exercise - draw wave
1.创建角度变量
只需要对应三角函数的y坐标,x坐标为固定的步进值
此时的角度可以无限扩展 并不需要固定在0-360°
1.wavenum控制波浪的数量,即有多少个360°.
2.x坐标为随循环递增的坐标值,y通过三角函数计算角度得到
设置三种切换
3.依据坐标生成点
8.运用三角函数画波形动画 exercise - wave animation
1.用三角函数波形移动点
1.用三角函数移动一点
2.设置角度,更新y坐标(sin),x坐标仅作为步进值
3.copy to point 移动几何体
9. sine和cosine的范围 range of sine and cosine
10.运用三角函数缩放动画 exercise - scaling animation
1.控制球体的缩放
1.随时间增长作为控制球体比例的的角度的值
2.由于控制的是大小比例,将-1 到 1 的范围重映射到 0.1 到 1
使用[ fit() ] 函数
再乘到P属性
11. 正割,余割,余切secant,cosecant,cotangent
作为(sine,cosine,tangent)逆inverse
VEX并没有对应的函数
1.==余割 cosecant== 与 正弦函数(==sine==) 互为倒数 = 1/sinθ

==余切 cotangent==:与正切函数(==tangent==) 互为倒数 = cosθ/sintθ

2.==正割 secant== :与余弦函数(==cosine==) 互为倒数 = 1/cosθ

==正切 tangent== :与余切函数(==cotangent==) 互为倒数 = sineθ/cosθ

3.VEX

12.反三角函数 inverse trigonometry (to get angle)
通过边==求角度==
1.反函数 可以使用[ degrees() ]函数转换为角度值
[ asin() ]函数 arcsin 即sine函数的反函数 (返回弧度值)
[ acos() ]函数 arccos 即cosine函数的反函数
[ atan() ]函数 arctan 即tangent函数的反函数
但是以上三个函数所得到角度是有限的
值域得不到完整360°
2.[ atan2() ]函数 可以获得完整的360°
0 - 180° - 0
13.运用 3D向量之间的角度 angle between two 3D vectors
1.判断两条线之间的角度
1.通过设置seed为两条线设置随机旋转
2.以其中一个向量作为基本轴,将另一个向量投影到此向量上(点乘)
v dot A :结果即v向量在A上的投影乘以A的长度,这里归一化A向量,则直接得到投影的长度(x)
在根据勾股定理计算对边的长度(y),以此使用[ atan2(y/x) ]函数 得到角度值
3.[ primpoints() ]函数 返回一个primitive 的点列表
获取每个primitive的两个点的位置,再计算方向向量并归一化
4.计算两个向量的点积x ,h
这里点积,定义任意一个向量作为x轴都可以,以dir1为参考轴(归一化),则点积结果为 dir2在dir1上的投影长度 ,相反也一样
14.向量之间画弧 exercise - draw arc between vectors
1.根据测量出的两条线之间的角度值画弧(3D空间)
以两个向量作为虚拟的x,y轴来确定对应的(x',y')坐标
2.向量v1,v2 以v1作为x轴 通过求v1,v2的叉积得到垂直于两个向量的z轴,再求z,v1的叉积得到y轴。
3.求出虚拟的xyz轴
4. 对应的角度值乘以虚拟xyz轴,得到虚拟的xy坐标,
这里以v1向量作为虚拟x轴,求出的虚拟y轴,最终坐标即两个向量相加
14.四元数 quaternion
主要用于3D空间中的==旋转变换== ,主要包含两个信息,==旋转轴rotational axis==,==旋转角度 rotational angle==
向量表示
1.声明四元数 declare quaternion
1.[ quaternion() ] 函数
角度和旋转轴
通过角度和旋转轴创建一个四元数变量
2.使用四元数旋转 rotation with quaternion
1.[ qrotate() ]函数 使用四元数旋转一个向量
返回旋转后的向量
1.VEX
3.运用四元数旋转物体 exercise - rotate object
1.使用四元数旋转几何体以给定的线作为旋转轴
1.检索线的终点获取位置,以此位置向量作为旋转轴
因为线的起点在0点,终点位置即可作为直线的方向向量
2.创建旋转角度,创建四元数
[ quaternion() ]函数 创建四元数
3.利用四元数旋转物体位置
[ qrotate() ]函数 利用四元数旋转向量
4.运用四元数螺旋旋转 exercise - spiral rotate
1.不同角度控制多个对象多个点
1.用ptnum乘以旋转角度,即每个点依次旋转更大的角度,形成螺旋线
5.欧拉转换到四元数 Euler to Quaternion
1.
[ eulertoquaternion() ] 将Euler角度 表示为一个四元数
order
将Euler旋转转变为四元数旋转
6.四元数转换到欧拉 quaternion to euler
1.将四元数转换到欧拉
1.[ quaterniontoeuler() ]函数 创建一个Euler角度来表示四元数
2.转换的角度
得到的角度并不一定等于初始的角度,但是旋转一样
7.四元数混合球面线性插值 quaternion blend with slerp
可以在两个四元数值之间创建平滑的插值
1.使用四元数控制点的法向量旋转
1.在法向量坐标处添加一个点,并连接两点形成线
[ addprim() ]函数将两点连接成polyline
2.将四元数保存到detail属性
3.创建另一个四元数
以用来在两个四元数(或两个角度)之间平滑的线性插值slerp
4.球面线性插值(slerp)
[ slerp() ]函数 基于偏差值bias==混合两个四元数==
5.用slerp混合后的四元数旋转原法线法向量N
再依据坐标创建两端点并来连接成线
并不是直线,而是创造处弧形,对于两个四元数,旋转轴并不相同
8.运用四元数设置旋转动画 exercise - rotational animation
1.基于不同的四元数依次旋转box并slerp
1.检索detail中的iteration属性作为随机种子 来设置旋转角度
2.检索旋转角度,将其转换为四元数
3.基于迭代次数创建属性
访问迭代次数,保存每一次迭代产生的四元数
4.创建变量
1.创建==range==,这里的range是在完整时间轴上每一次旋转的时间长度(所以用总帧数/循环次数)
2.确定当前帧在当前range的位置,用t 0-1 表示
3.确定当前帧所在的range是第几个range,当前帧数/range(0-num(5)之间)%num(取余num,将最后一个值变为0,即范围 0-4.999 取整则为0-4-0 )
一个0-5的数取余5,始终商0,得到原来的数,除了5,5除5商1,得0,这里==取余的作用在于将最后值变为0==
4.确定下一个range的数 即在当前数加1 由于会大于num 所以取余num将大于的变为0
5.通过当前number和下个number值来确定对应的四元数
基于变量t在两个四元数之间slerp,使用插值的四元数旋转物体
9.二面体定向矢量 orient vector with dihedral
使用四元数将一个向量定向到另一个向量
1.用dihedral计算一个四元数将第一个向量旋转到第二个向量
1.获取向量,计算四元数
[ dihedral() ]函数 计算将向量a旋转到向量b的四元数
2.使用求得的四元数旋转物体
10.运用二面体设置动画 exercise - animation with dihedral
1.设置沿着球体表面螺旋上升的点
1.创建一个在时间轴递增的角度
点在当前位置圆的半径r
2.创建螺旋上升线
旋转圈数,用另一个角度控制
3.设置坐标,更新位置 ,使点螺旋沿着球体上升
2.用动画的点移动几何体,并设置朝向
1.检索动画点位置
2.从几何体上得到平滑的法线方向
使用[ uvsample() ]函数 使用uv属性在特定uv坐标处,对属性值进行插值
依据@P属性在特定位置pos处,对属性N插值
3.用[ dihedral() ]函数创建旋转四元数
将几何体从向上旋转到N方向,再将动画的点坐标加到几何体
15.矩阵 matrix
1.基础 basics
矩阵是一个2D数字网格
1.矩阵类型
使用[ set() ] 函数设置矩阵值
2x2,3x3,4x4矩阵
2.声明 declare matrix
使用另外的方法声明矩阵
1.也可以使用大括号为矩阵赋值,但不能使用变量
等效于创建向量
2.单位矩阵 indentity matrix
1.单位矩阵
单位矩阵作为变换的基础
1.创建单位矩阵
[ ident() ]函数 创建单位矩阵
3. 行列式和逆矩阵 determinant and inverse matrix
1.行列式是再方块矩阵上计算的标量
可以用来==检测矩阵是否有逆矩阵==,为0则没有逆矩阵
==矩阵== 乘以他的 ==逆矩阵== 得到 ==单位矩阵==
2.行列式计算
对角线
1.[ determinant() ] 函数 计算矩阵的行列式
2x2,3x3,4x4的方块矩阵
结果为0,表示该矩阵不具有逆矩阵
2.[ invert() ]函数 创建逆矩阵 inverse matrix
返回逆矩阵或者原始矩阵(当行列式为0)
计算结果,可以通过与原矩阵相乘是否为单位矩阵判断是否是逆矩阵
4. 转置矩阵 transpose matrix
将行变成列
1.[ transpose() ]函数 创建一个矩阵的转置矩阵
5.矩阵与标量的乘法 multiplication with scalar
矩阵乘法有三种
matrix x matrix , matrix x scalar , matrix x vector
1. 矩阵 x 标量
1.矩阵的每个值与标量相乘
2.vex
6.矩阵与矩阵的乘法 multiplication with matrix
左乘不同的矩阵表示进行不同的变换操作,不同的顺序结果不同。
4x4矩阵可以声明所有3D旋转,缩放,移动操作
1.矩阵乘法
行乘以列相加得到对应位置的值
3x3矩阵乘法方式相同
不能交换顺序
矩阵相乘,得到矩阵大小为 第一个矩阵行x第二个矩阵列 3x2 2x3 = 3x3
2.vex
7.矩阵与单位矩阵相乘 multiplication with identity matrix
任何矩阵与单位矩阵相乘 结果不变,即使交换顺序,结果任然不变
1.vex
9.与转置矩阵相乘 multiplication with transpose matrix
1.vex
10.矩阵与向量相乘 multiplication with vector
向量在3D空间中通常用来声明方向或者位置,使用矩阵乘法,是将矩阵作为向量的变换
1.理论
1.将矩阵视为1x3 或者 3x1的矩阵 来进行矩阵乘法
在VEX中,使用行向量,但是使用时交换顺序并不影响结果
2.当使用4x4矩阵时==,向量变成 [x, y, z, 0/1]形式==
这里的 0/1 作为声明,为1时表示作为位置值,为0时表示作为方向值
但在VEX中,这个过程被隐藏,可以直接使用向量乘以矩阵
2.vex
11.矩阵平移 translation matrix
使用4x4矩阵进行==translate (平移)==变换
平移矩阵的形式
1.[ translate() ] 函数 通过向量 ==创建平移变换矩阵==
返回的这个矩阵表示一个平移变换
要点
1.通过向量生成一个平移矩阵,乘以位置即可实现变换
==(使用单位矩阵)==
与直接加上向量结果一样,只有进行更多的矩阵转换时,translate才有优势
12.矩阵缩放 scale matrix
使用4x4矩阵进行==scale (缩放)== 变换
缩放矩阵的形式
1.[ scale() ]函数 通过向量 ==创建一个缩放矩阵==
==(使用单位矩阵)==
1.任然与直接乘以scale向量结果一样.
13.旋转矩阵 rotation matrix
使用矩阵进行==rotate (旋转)== 变换
旋转变换时是对坐标系进行变换
2D空间
1.[ rotate() ]函数 ==创建一个旋转矩阵==
==(使用单位矩阵)==
沿着指定方向创建旋转矩阵,并应用到物体上
14.组合变换矩阵 combine transformation matrix
组合平移(translate),缩放(scale),旋转(rotate) 三种变换.
1.组合矩阵
1.创建变量和单位矩阵,控制变换的角度,旋转轴,平移向量,缩放向量
2.创建组合的变换矩阵 应用变换矩阵
应用的顺序不一样,变换结果也不一样
15.VEX函数 创建变换 maketransform VEX function
[ maketransform() ]函数 ==创建组合变换矩阵==
参数 trs:translate,rotate,scale的顺序
参数 xyz:rotate 的顺序
此函数使用的rotate 是角度
1.生成矩阵
此函数会生成矩阵,不需要使用单位矩阵
16.VEX函数 破解转换 cracktransform VEX function
[ cracktransform() ]函数 ==解构组合矩阵==
1.解构矩阵
以此得到平移,旋转,缩放的值
pivot:轴心点,旋转和缩放操作的中心点
注意:需要知道变换的顺序,旋转的顺序,以及轴心点。
17.运用1 基础变换 exercise - basic transformation
1.通过变换矩阵变换box
这里设置缩放的size时使用cos函数,以达到在一个360°以内按照cos波形变换4次
cos函数:1到0,0到-1,-1到0,0到1
依据时间创建动画
18. 运用2 扭曲和弯曲 exercise2 - twisting and bending
1.基于位置为每个点应用不同的变换
1.创建参数
box高度,扭曲角度,创建弯曲半径,弯曲角度,创建单位矩阵
创建根据位置计算的扭曲角度tang,重映射为0到扭曲角度最大扭曲角度
2.以y轴为扭曲轴 扭曲twisting
应用rotate到矩阵
3.按照高度映射为0到PI,以此sin的波形作为放缩值,取max 设置最小值0.01
应用放缩到矩阵,在xz轴缩放
4.创建弯曲角度,按照高度映射为0到最大弯曲角度
应用rotate到矩阵,以z轴作为弯曲轴
5.创建动画
动画弯曲角度bang
设置弯曲角度加上360°递增,前面映射的时每个点根据位置得到不同值,此时加上的值所有点都一样,所以整体旋转
动画扭曲角度tang
使扭曲动画不断旋转
19.运用3 反转变换 exercise 3 - inverse transformation
1.创建最终变换的逆变换并应用到position
==矩阵== 乘以 ==逆矩阵== 等于 ==单位矩阵==
1.[ invert() ]函数 求逆矩阵,应用到position,即可还原变换
20.二面体函数 dihedral VEX function
在四元数,[ dihedral() ]函数 计算使向量a旋转到向量b的四元数
1.利用[ dihedral() ]函数旋转物体
1.检索两条线的方向
2.创建一个3x3 的旋转矩阵,应用矩阵到position
21. lookat函数 lookat VEX function
[ lookat() ]函数 创建一个变换矩阵,该矩阵旋转一个物体使其局部Z轴指向目标位置
z轴负方向约定
1.
[ polyloft ]节点
创建参数
from,to: 从原点 看向 设置点位置
up:
这里第三个参数使用roll(角度值)
roll可以定向旋转,沿着lookat方向
22.实例化函数 instance VEX function
[ instance() ]函数 创建一个实例变换矩阵
类似[ copy to point ]节点
1.实现类似copy节点的功能
1.放缩设置(copy节点)
在z轴上(这里的实例指向-z,即“长度”)设置按照y方向位置的缩放
2.[ instance() ]函数
用矩阵的好处在于可以利用矩阵创建插值以实现动画效果
从原始位置到复制位置插值
23. 运用4 矩阵插值 exercise4 - matrix interpolation
从一个位置到另一个位置,从一个变换到另一个变换
1.由于矩阵没有直接可以使用的插值函数,==先解构变换矩阵==,==再利用每个变换向量插值==
2.对于==旋转==最好使用==四元数插值(slerp球面线性插值)==
3.最后结合所有变换到矩阵,使用新矩阵进行变换
1.VEX
1. 使用[ cracktransform() ]函数 解构最终变换矩阵
这里的变换顺序可以不一样
2.对于translate和scale可以直接使用[ lerp() ]函数 进行线性插值
3.使用四元数插值旋转
1.使用[ eulertoquaternion() ]函数 将当前旋转值==从Euler度数转换为四元数==
使用的弧度值
2.在(0,0,0)和最终角度的四元数之间==slerp==
3.为了创建最终旋转矩阵,再将==四元数转换回Euler角度==
使用[ quaterniontoeuler() ]函数
4.按照解构时的顺序==创建最终变换矩阵==
随着lerpval(插值的步进值)递增,实现由==原位置到新位置的插值变换==
16.几何体函数 geometry functions
1.基础 basic
使用VEX ,add ,delete geometry(point,primitive,vertices)
points, primitives ,vertices 的关系
functions :near point,minpos, intersect, neighbour
1.创建点 create single point
[ addpoint() ]函数 添加一个point
2.create spiral points 创建螺旋形点
创建角度,创建步长,创建循环
使用三角函数更新坐标
3.创建三角形多边形 create triangle polygon
1.用点画圆
2.用点创建三个间隔120°的三角形点
3. [ addprim() ]函数 创建primitive
创建三角形
4.创建圆锥多边形 create cone polygon
1.创建变量:圆锥半径,高度,点数
2.使用for循环 ,创建圆底面点
创建变量,ang: 每次循环递增的角度,使用三角函数 addpoint
要创建圆锥,依次创建从底面到顶点的三角形面
保存创建的ptnumber到数组,以便创建primitive时使用
3.创建生成 primitives 的for循环
获取当前点和下一个点,对下一个点编号取模 以便当i+1超过点数时变回0
使用[ addprim() ]函数 创建多边形,依据三个点number
5.创建直线 create line
创建两个点,添加polyline
polyilne 和polygon的区别在于,polyline是curve geometry,polygon是封闭的face
==polyline== 也可以说是==未封闭的== ==polygon==
6.创建螺旋线 create spiral polyline
将spiral 点连接成polyline
用已创建的点创建polygon
1.先创建一个空的primitive polyline
2.将点添加到空的primitive
使用[ addvertex() ]函数 为primitive添加顶点
也可以使用数组作为参数,用[ addprim() ]函数 生成polyline
将pt保存到数组中
2.删除点 delete points
1.按半径删除point
1.[ removepoint() ]函数 ==删除点==
3.删除primitives delete primitives
1.按半径删除primitives
[ removeprim() ]函数 ==删除primitives==
这里的 andpoints 参数:==为1== 表示删除与此primitive相关,与其他primitives不相关的点 (即==删除创建这些primitives的点==)
为0时,==保留创建这些primitives的点==
4.从primitive获取point信息 points from primitive
从primitive wrangle检索points信息
1.访问primitives,并从primitives中获得相关点
1.访问primitives中的点,创建窗口
2.[ primpoints() ]函数 返回primitive中点的列表(返回列表数组)
3.访问primitives中的点位置,减去primitive中心位置,得到由中心指向点的方向向量
乘以一个数控制其沿着向量的大小
创建新的点
4.保存新点到数组
注意:这里保存到数组中的点编号并不是最终点编号
[addpoint()] ,[ primpoints() ]函数所返回的点都==不一定是最终编号==
5.创建生成新primitives的for循环
从两个数组中,获取点编号,注意==取余数组长度值==,以免i+1超出数组范围
6.删除原始的primitives
这里的@primnum只是原来的
5.从point获取primitive信息 primitives from points
从point wrangle检索primitives 信息
1.获取一个点相关联的primitives的中心坐标,连接成polygon
[ pointprims() ]函数 返回一个点包含的primitives 列表
1.创建循环,==访问每一个primitives==的位置属性(即中心点位置),以此创建新的点
创建 数组 存储创建的新点编号,这里的数组:每一个点一个大小为3的数组,6个点
2.创建循环,==访问数组中的每一个点==,以此3个点创建四面体的侧边
每次以 ==其中两个点== 加上 ==顶点== 创建多边形
3.在访问primitives,创建新的点后 即可删除原来prim
可以放在这里删除,在wrangle中所有代码==同时运行==(使用当前同样的条件)在所有点上,循环中删除prim并不会影响其他点
6.顶点顺序 vertex order
顶点顺序为顺时针向外,逆时针向内
1.计算朝向
1.计算由原点指向面中心点的方向向量,使其==与法线点乘==,如果结果为正则法线方向向外,为负则反向
[ primvertices() ]函数 返回一个primitive的顶点列表
返回的是==linear vertices index== 是按顺序每个顶点的编号,与spreadsheet中的值不一样
2.创建循环 遍历每个primitives的顶点数组,访问顶点
1.使用[ vertexpoint() ]函数 从linear vertex访问点编号,得到对应的点
2.将得到的点编号存储进数组中
这里创建的数组存储着==每个prim==对应的顶点编号(vts[]),和点编号(pts[])
3.使用[ reverse() ]函数 将数组(或者字符串)反转顺序 并返回
反转每个prim的点顺序 即pts[]数组的顺序
使用[ setprimvertex() ]函数 将vertex重新布线到一个不同的点
这里的如果prim是-1,则vtxofprim是linear index,
等效函数[ setvertexpoint() ]
4.遍历pts数组中的所有点,访问对应的点编号和顶点编号,关联对应的顶点和点
使用linear index
使用 primnum
7.连接近点成线 line with nearpoint / nearpoints
1.[ nearpoint() ]函数 搜索近点 返回编号
[ nearpoints() ]函数 搜索所有的近点 返回编号数组
1.搜索最近的的点并连接两点
2.搜索所有的近点并连接
8. 近点网络 network with nearpoints
1.连接点云中最近的点 创建为网络
==消除重复line==,加一个判断条件 即==@ptnum < npt==, 在==每一个点==的近点数组中,小于当前点的编号的点,已经连接过了(本质上是同时运行,只连接大于当前点编号的点就不会重复)
9.最小距离创建凸面 convex with minpos
1.利用[ minpos() ]函数创建类似的凸形(将球体投影到几何上)
[ minpos() ]函数 返回几何体上最近的位置
与[ nearpoint() ]函数 区别在与近点函数搜索的是==最近的点==,minpos搜索的是最近的==表面位置==
2.vex
10.最小距离创建螺旋分支 spiral branch with minpos
minpos 搜索表面,也可以搜索曲线
1.处理几何体
2.在tube上 scatter 点,搜索最近的点并连线
11.简单的相交 simple intersect
1.[ intersect() ]函数 计算射线与几何体的第一个交点
如果射线与primitive相交,这里的变量会被==世界空间==下的交点位置覆盖
也就是说 &p:是交点位置,&uvw:参数化交点位置(可以与uvsample使用)
返回值为primitive number
2.vex
实例化交点,设置点属性,设置点组
12.用交点函数创建阴影 shadow with intersect
1. 基础设置 ,创建参数,创建光线方向
2.使用[ intersect() ]计算交点
13.邻居的多边形模式 polygonal pattern with neighbours
邻居点 :指的是相连接的临近点
1.[ neighbours() ]函数 返回一个点 相邻点编号 的数组
1.检索每个点的邻居点编号,遍历每一个邻居点检索其位置,计算其与当前点的中间位置并设置为新的点
2.创建多边形
1.先创建一个空的poly prim.
2.使用[ addvertex() ]函数 为中间点连接新顶点,将顶点添加到新的prim
3.删除原有顶点
14.随机行走网络 random walk network with neighbours
1.在网格上检索随机点的邻居
1.随机选取网络中的点
2.当所选点不在==遍历过的点数组(conns[])==中时,先创建一个不带任何点的polyline
3.进入创建ployline的循环
1.将当前点加入到conns数组
2.检索当前点的位置,并创建为新点,设置新点的属性以便识别
3.使用[ addvertex() ] 将该点添加到polyline
4.使用[ neighbours() ] 寻找当前点的neighbours(数组)
遍历邻居点,获取邻居点编号,判断邻居点是否在conns数组中,是则将此邻居点变为下一个选取的点,并使用break==退出 遍历邻居点的循环==
设置检查值,如果邻居点没有遍历过,设置为1
5.如果检查值为1,则退出创建polyline的循环
4.创建大循环,随机选取点,以进入创建polylines的循环
17.内在属性 intrinsic attribute
主要有两类,对primitive,和detail的
1.内在属性的类型 type of intrinsic attribute
不同的primitive类型有不同的内在属性
2.primitive的内在属性 primitive intrinsic attribute(==measuredarea==)
1.measurearea
使用[ primintrinsic() ]函数==访问prim的内在属性==
[ measure ]节点 可以获得同样的数据
对比在wrangle中使用内在属性,使用measure所花费的时间更长一些
3.primitive的内在属性 primitive intrinsic attribute(==measuredvolume== )
1.measurevolume
1.使用 [ attributepromote ]节点 计算求和
2.使用[ measure ]节点计算
4.primitive的内在属性 primitive intrinsic attribute(==bounds==)
1.bounds
表示primitive的边界
访问bounds 属性,创建边界框
计算中心点,和尺寸,设置scale属性,以使用copy节点创建边框
5.detail的内在属性 detail intrinsic attribute(==bounds==)
1.bounds
使用[ detailintrinsic() ] 函数 ==访问detail内在属性==
1.同样计算边界的中心点和尺寸
2.copy to point
6.设置primitive内在属性 set primitive intrinsic attribute(==closed== )
1.closed
指示该primitive是否闭合
[ primintrinsic() ]函数读取内在属性
[ setprimintrinsic() ]函数==写入内在属性==
7.primitive的内在属性 primitive intrinsic attribute (==typeid/typename==)
1.typeid,typename
类型id,类型名
houdini中的primitives有大量的几何类型,不同几何类型有不同的内在属性
[ pointprims() ] 返回每个点的prims列表数组
这里只需要数组第一个元素
使用[ primintrisic() ] 读取内在属性 typeid
利用typeid不同,为不同的类型设置不同运动方式
当一个节点中包含多种不同类型的几何体,就可以使用typeid属性,来==修改特定的几何体==
8.packed几何体的内在属性 intrinsic attribute for ==packed geometry==
packed geometry
1. 使用内在属性变换 packed geometry
对packed geometry,变换点就是变换整个几何体
1.创建一个平移矩阵
2.获取prim的点的位置
使用[ primpoint() ]函数 获取对应prim的点编号
检索对应点的位置。
3.变换点位置,由于是在prim下运行,需要[ setpointattrib() ]设置位置
4.访问内在属性中的pivot(轴心点),作为旋转和缩放的轴心点
5.这里使用创建的旋转矩阵旋转P,只针对点,并没有旋转几何体自身
2.访问内在的transform属性(4x4矩阵),将生成的变换矩阵应用到transform矩阵
[ setprimintrinsic ] 更新内在transform属性,即可实现几何体跟随旋转
设置放缩channel

9.packedtransform函数 packedtransform function
[ packedtransform() ] 函数
变换一个 packed primitive
使用一个4x4变换矩阵来变换
即可得到 与使用内在属性transform矩阵 进行变换 一样的结果
10.setpackedtrandform函数 setpackedtransform function
[ setpackedtransform() ] 函数
设置packed primitive 的变换
1.与 packedtransform的 区别在于 setpackedtransform 会先将轴心点放到原点
11.getpackedtransform函数 getpackedtransform function
[ getpackedtransform() ] 函数
获取 packed primitive 的变换
与生成的变换矩阵相比
12.运用 packed geometry变换 exercise - packed geometry transformation
1.打包一个 破碎
上色
2.获取每个primitive的pivot,并以此为旋转中心旋转
生成变换矩阵
使用[ packedtransform() ]函数 需要先平移到0点
再移动回原来位置,在两个平移变换之间旋转变换
旋转:创建随机的旋转轴
[ sample_sphere_uniform() ]函数 在球体表面随机生成点
3.向外平移
创建方向向量,并应用到变换矩阵
设置每个碎片不同的移动速度
即为方向向量添加一个随机乘数
18.随机 randomness
1.使用种子随机 randomness with seed
[ rand() ] 函数
生成的值位于0到1
获取随机值
1.[ rand() ]函数创建一个vector4, 再根据需要的值类型修剪
2. 可变种子值的随机 rand with various seeds
1.使用位置作为种子
使用ptnum属性,也可以为每个点随机不同的颜色
2.为每个面设置颜色
使用primnum作为seed
3.foreach 节点内的随机函数 rand function inside foreach node
1.foreach 循环中为每个pieces设置随机值
使用迭代次数 iteration,区分不同pieces
1.创建metadata,以获取detail属性 iteration
2.设置偏移seed
4.循环中的随机函数 rand function in loop
1.创建循环,生成点,设置随机scale属性
copy to point
5.运用1 exercise - function exercise1
控制百分比
1.按比例选取一部分点
随机值在0到1内平均分配,即可通过选取特定范围的的随机值来选取对应百分比的点云
1.vex
2.检查点数,创建一个detail计数属性
==设置detail属性,使用"add"模式==
6.运用2 exercise - rand function exercise2
基于随机的渐变
1.基于位置设置种子
越往下有更多的机会得到红色值
这里是使用当前高度与随机值相比,高度越高,高于当前位置的随机值就越多
7.运用3 exercise - rand function exercise3
使用ramp控制随机值的生成,来控制渐变
1.使用ramp映射随机值,即可通过控制曲线控制映射
8.运用4 exercise - rand function exercise4
对时间偏移量进行随机
1.使用正弦函数(随机时间偏移)控制scale球体大小
控制pscale属性
1.依据时间轴设置0-360°的递进
2.使用步进值的正弦值,重新映射到新的pscale值
3.为步进值设置随机偏移
4.为周期值设置随机值,以获得不同的动画速度
同样的时间长度,一个点的动画周期越多,动画速度越快
创建随机值时 使用[ ceil() ]函数向上取整,获得1到4的随机周期范围
5. 跟随pscale大小变化 改变颜色
9.非确定性随机 non - deterministic randomness
不需要使用seed值
[ nrandom() ]函数 获取0-1的随机值 不需要seed
可以设置不同的随机方法
1.直接使用
每一次运行会产生不同的随机值
2.nrandom函数运用 nrandom exercise
在for循环内部使用,每次循环会产生不同的随机值
1.使用for循环创建立方体点阵
2.为每个点设置随机颜色,和pscale属性
10.随机函数 random function
[ random() ]函数 基于在1-4D空间中的位置生成随机数
random函数 会将position==向下取整== noise(floor(position))以此获得随机值
同样获得0-1的值,但是整数变化随机
1.通过random改变点的高度
11. 随机分配 random distribution with rand
[ random_brj() ] 生成均匀的随机分布
[ random_sobol() ] 生成均匀的随机分布
1.在直线方向上 随机生成点
1.使用[ rand() ] 来分布点
并非均匀
2.使用[ random_brj() ] 分布点
==不同的种子生成不同的序列,offset提取序列中不同的条目==
所有点使用一个seed值,但offset值依据每个点变化,以此为所有点生成均匀的分布
3.使用[ random_sobol() ] 分布点 生成更加均匀的分布
参数与random_brj函数相同
seed生成不同的序列,offset提取序列中不同的条目
12.向量分布 vector distribution with random_sobol
使用[ random_sobol() ] 随机分布向量
使用[ sample_sphere_uniform() ]函数创建一个方向
1.使用[rand() ]生成随机向量
1.创建循环,生成点
1.使用[ rand() ] 生成随机向量
2.利用随机向量 使用[ sample_sphere_uniform() ]生成随机方向(大小并不一样)
3.以此向量作为坐标生成点
4.连接点到原点
[ addorim() ] 添加polyline
2.使用[ random_sobol() ] 随机分布生成随机向量
19.噪波 noise
noise是梯度噪波,距离越近,值也越接近
不同的噪波使用不同的方法生成数字
1.柏林噪波 perlin nosie
生成1-3D 的noise值 范围为0-1
[ noise() ]函数 基于==perlin噪波==
1.基于位置使用[ nosie() ]
通过改变传入的位置(设置一个==乘数==),即可对特定方向==拉伸==修改
位置信息乘以一个乘数则是对整个噪波的图案的放缩
2.柏林噪波的移动 shifting for perlin noise
在位置上==加上==偏移量
1.
对于2D网格,没有y方向,即可使用y方向上的偏移改变整个图形(作为动画效果)
3.单形噪波 simplex noise
基于perlin噪波的更新版本,非常接近柏林噪波
[ xnoise ]函数 基于==simplex噪波==
比柏林噪波更平滑
1.用法与[ noise() ] 一致
4.运用1 柏林噪波 perlin noise exercise1
1.生成噪波改变网格的y位置
2.将噪波值保存为属性,以设置渐变颜色
3.为每个点设置pscale,
1.这里的噪波值位于大概0.25-0.75之间,不同于[rand()] (0到1之间均匀分布),
2.使用噪波值 重映射pscale
4. copy to point
5.运用2 柏林噪波 perlin noise exercise2
1.创建螺旋线,使用噪波控制最终管道的厚度
在直线上
1.创建spiral
1.依据ptnum , 创建角度(随着ptnum依次增大)
2.创建半径
3.在xz平面旋转,使用三角函数更新xz轴,y轴坐标保持不变
2. 以ptnum 为参数 为每个点创建基于噪波的pscale属性
使用[ polywire ] 节点
使用表达式函数读取pscale ,这里的[ opinput() ]表达式函数 ,==$PT = ptnum==
为pscale创建随机值
3.设置动画在noise设置随时间移动的偏移值
4.使用noise改变颜色
6.运用3 perlin noise exercise3
使用矢量值作为输出
1.使用[ noise() ]改变表面颜色
1.使用[ noise() ]输出向量,为每个点改变颜色
颜色比较淡,在于[ noise() ]函数输出的值范围在0.25到0.75左右,于float输出一致
2.将噪波输出值clamp,并重映射到0-1
对其他几何体也适用
3.动画颜色的变化
1.由于球体的每个坐标轴都被用到,在轴上的设置偏移 只会产生噪波==平移效果==
2.如果想要所有==颜色逐渐变化==,而没有朝向,需要==附加轴来进行偏移==
可以使用==vector4==作为输入,即==为3D坐标添加一个轴==,来动画颜色变化
3.使用vector4作为[ noise() ]的输入,即可通过控制第四个参数的偏移控制颜色渐变(没有方向性)
7.运用4 perlin nosie exercise4
1.使用[ noise() ] 在表面上创造涟漪效果
1.使用位置信息生成vector4向量,再以此为参数生成一个float噪波
将此float噪波作为颜色噪波
2.将此float噪波作为三角函数参数,以此将点沿着法线方向移动
1.将此float值映射为角度
sin函数有负值
2.以此噪波值将点沿着法线移动
设置波浪数量
8.周期噪波 periodic noise
同样基于 perlin 噪波
由于周期性,可以生成无缝的图案模式,以此生成无限大的噪声比例
以一个模式不断重复平铺,边缘处采用梯度平滑值
1.[ pnpise() ]函数
perlin函数有两种形式:其一是在整个N维空间随机变化的非周期性噪波,另一种就是[ pnoise() ]使用的形式,在==给定空间范围==内==重复==的==周期性==形式
px,py,pz,pt指的是周期性平铺的尺寸,pt基于时间
2.使用[ pnoise() ]函数
9.运用 周期噪波 periodic noise exercise
1.创建三维的重复模式
1.使用volum
这里使用P 乘以 tile尺寸的原因在于,当tile尺寸变大时,需要更大的box装原本的tile个数,这里使用点的位置乘以tile尺寸大小,当tile尺寸增大时,整体尺寸变小相同的倍数.
即一个box范围内始终装ts乘ts乘ts个
==P乘以乘数对波形模式产生放缩作用==
注意:是在三维空间给定位置P采样,当坐标P乘以一个数变大时,采样点坐标彼此之间距离变大,即得到更大范围的噪波模式
这里假设有一个固定的噪波场,输入坐标变大,即采样更大范围的噪波场
2.使用[ convertvolume ]节点转换回多边形
3.使用大小为1的box剪切单个模式
4.以此模式在xyz轴重复
创建三层循环(对每一个轴)来生成点阵
copy to point
5.创建vector4,来控制模式变化
控制时间偏移 设置偏移值在时间轴内由0-1变化(FF/ENDF) 创建==可循环的动画==
即可 依据时间轴变化
10.流体噪波 flow noise
noise和periodic noise 混合的噪波 ==flow noise==
[ flownosie() ] 生成1D 或者3D流噪波
区别在于这时非周期noise ,flow参数是周期的(0-1),可以看作是特殊的pnoise
与[pnoise()]相比,相当于px,py,pz为0,pt为1
用于创建一个==非周期性的模式==pattern,但是基于时间回到最初的时间(创建==基于时间的循环==)
flow参数作为重复值(作为基于时间的值重复动画)
1.创建在时间轴上可连接的重复向量场
1.创建volume
创建位置信息,创建shift偏移值
2.使用[ flownoise() ]函数 基于pos,shift生成随机方向向量
设置shift,依据时间轴从0到1变化,最后一帧将与第一帧相连接
3.由于生成的值都在0-1之间
将生成的向量减去0.5,获得全方向的向量
11. 卷曲噪波 curl noise
[curlnoise()] 基于perlin噪波计算==无发散噪波==
只能创建向量值,通常用于创建矢量场相关的值
根据两个perlin noise的导数的叉积计算的无发散矢量场
divergence free vector field 无发散矢量场:
无发散:在矢量场中,散度(divergence)衡量场中某点作为源或者汇的强度,无发散指的是矢量场在任意点都没有源或者汇==.矢量线不会从某点产生或者消失==,而是形成==闭合回路==或者==无限延伸==.
因此:适用于生成自然漩涡结构,创建符合真实流体基本物理规律的流体模拟,烟雾模拟
1.创建向量场
1.以vector4作为输入,生成curl noise向量值
生成的向量场更干净(无发散矢量场)
12. 沃利噪波 worley noise
基于cellular(细胞)的噪波函数
基于空间划分的算法,在空间中随机分布一组特征点(称为种子点或特征点),然后对于空间中的任意位置,==计算其到最近几个特征点的距离==,并用这些距离值来生成纹理。
houdini中有三种内部算法
使用不同的方法计算两点之间的距离(Euclidean,Manhattan,chebyshev)
工作方式:
提供位置信息作为样本,在空间中创建随机的种子位置,对于空间中任意位置,所计算的到最近几个种子点的距离用f1-f4表示,
距离算法:
Euclidean:计算直接距离,所得到的距离渐变是圆形
Manhattan:计算x+y+z,得到距离比Euclidean长
chebyshev:各坐标数值差的最大值
这个算法也可以从特征点而非像素点的角度理解。在那种情况下,算法可以表述为:每个特征点向外扩张生长,直到它碰到其它扩张的区域。这反映了自然界的生长规则。生命的形态是由内部扩张、生长的力量和限制性的外部力量共同决定的。模拟这种行为的算法以 Georgy Voronoi 命名。
1.[ wnoise() ] 函数
1.使用[ wnoise() ]函数
2.依据seed值设置随机颜色
13.运用 worley噪波 worley noise exercise
1.创建海洋外观
1.创建变量
2.使用 [wnoise()]
3.使用组合距离更新点的y值
4.设置偏差值,依据时间从0-1,即可实现首位帧循环
5.更改颜色
14.Manhattan worley噪波 Manhattan worley noise
[ mwnoise() ] 函数
参数与wnoise一样
1.使用[ mwnoise() ] 函数
2.chebyshev worley噪波 chebyshev worley noise
使用[ cwnoise() ] 函数
15.短吻鳄噪波 alligator noise
alligator noise 短吻鳄噪波
[ anoise() ]函数
生成类似worley noise的细胞噪波,更适合创建海洋效果
1.使用[ anoise() ] 函数
创建变量
去掉scale
设置为负
上色
copy to point
16.voronoi 噪波 voronoi noise
1.[ vnoise() ]函数
可以产生抖动,只有F1,F2,可以获取种子点的位置,同样可以设置周期重复
2.VEX
创建参数
使用[ vnoise() ] 函数
使用输出值改变P.y
F1
设置jitter 范围为0-1
F2-F1
使用seed设置颜色
查看position 1 种子点1 (细胞中心点1)
相对比voronoi节点,产生一样的模式
17.运用 vornoni噪波 voronoi nosie exercise
1.使用voronoi 在volume上分区
1.创建两个volume ,seed和density用以分别在体素上存储seed值,和通过voronoi计算得到值density
2.合并
3.VEX
1.更新seed值,
可以通过内置属性查看volume值的最大最小值
2.利用seed在单元格之间创建分区,作为墙壁分区
检查像素点的种子值,边界点的seed不一样
3.先设置density = 0
4.通过体素的index检索值
5.检查x方向上的体素,下一个索引值即使邻居,如果和邻居的seed值不一样,则是设置为边界
6.使用循环检查x正负方向上的体素
7.创建三层循环,以检查y,z正负方向的体素
8.为每个轴并一个条件以不检查最后一个体素以去掉边框,即索引值小于分辨率减1
4.[volumeblur] 平滑volume
5.转换为表面
20.解算基础 solver
基于==帧反馈==的处理系统
1.基础平移 base translation
1.solver
每一帧都以上一帧的位置作为初始位置移动
2.移动和旋转
创建矩阵进行旋转
trail 生成拖尾 polyline
2.基础生长 basic growth
1.
1.先创建一个空的polyline
2.solver
在原来的位置添加点,相当于将原来的点冻结,形成trial尾迹,由于这里的group指定move,代码只影响组中的点,生成的这些点并不影响
3.在物体表面流动的向量 vector flow on object
1.使用[ curlnoise2d() ]函数 控制点在物体表面流动
1.使用[ curlnoise2d() ] 函数 生成 ==2D的curl noise==(2d的无发散噪波)
生成的向量并没有沿着物体表面( ==生成的向量都位于xy平面==)
2.使用[ dihedral() ] 二面体函数 生成将噪波向量旋转到表面的矩阵
z方向相当于这个噪波所在==xy平面的法向==,沿着表面流动的向量应该垂直于==物体的法线方向==,将z方向(xy平面法向)对齐物体法向,则xy平面的向量对齐流动的向量
假设表面切向为T,物体法向为N,N与T垂直.噪波方向为C. Z轴方向与其垂直,则当Z与N平行时,C与T也平行
T ⊥ ==N==, C ⊥ ==Z== ---> 当Z与N平行时, C与T也平行. 即将垂直于噪波的方向对齐到物体法向,噪波也将对齐物体切向 (使用同样的变换)
这里生成对应的旋转矩阵,应用到噪波向量,即可使噪波向量沿着物体表面
3.使用scatter的点在矢量场上采样
1.为每个点设置随机life
2.使用[ ray ]节点,即可从表面上的点位置对向量场采样
3.即使向量场的数量很少,通过采样矢量场的中间位置,可以创建一个平滑的矢量场
4.点移动 解算 solver
1.连接solver
2.更新点的位置(加上法线向量,即噪波)
3.减去生命值,设置条件,生命值小于0时,删除对应点
4.将点投射到表面,采样法线方向
5. 在随机位置生成点,以便总数不变
使用[ uvsample() ] 函数 根据uv属性在物体表面 采样随机位置
依据位置所生成的随机向量(==其值在0-1范围==),将此向量作为uv坐标,在物体的==uv属性==中==查找对应的uv坐标==(ruv),对于点或者顶点属性,从周围点==插值==后返回插值的属性(这里是P,三维位置)
这里的pighead自带二维的uv属性(通常uv坐标只有两个分量,这里第三个分量为0,表示其为二维uv坐标,在houdini中一般存储为vector,即三维向量,对于二维uv并不使用第三个分量),其值==范围为0-1==,这里使用三维向量ruv作为uv坐标查找时,会自动忽略第三个分量
6.为新生成的点设置生命值
当有点死亡时,在表面随机位置生成新的点,保持总数
5.可视化 设置颜色
1.检索的所有点指定距离的所有近点,计数近点数量
2.使用[ attribpromote ]节点 找到最大值,以设置颜色值的范围
3.使用近点数量来设置颜色(衡量点的密度)
==将以上步骤的着色代码放到solver中,加快计算速度==
4.生成拖尾
在当前点位置的法线N反方向添加点,在连接成polyline,设置为同样的颜色
4. 在volume内流动的向量 vector flow inside volume
1.使用[ curlnoise() ]函数 控制点在volume中流动
1.创建volume velocity
2.生成curl noise
1.创建vector4,使用时间控制第四个分量,以此创建动画
2. 用4维向量 生成3D curlnoise,以此更新velocity值
使用[ volumetrail ]节点可视化
3.解算 solver, 基于volume中的velocity向量移动点
1.根据每个点当前的位置从volume中采样一个方向,并以此方向更新点的位置
[ volumesamplev() ]函数 对volume的矢量值采样
超出volume的点将会停止移动
2.将停止移动(或速度很小)的点删除,并在volume内随机随机生成新的点(或者==将其移动到volume中的其他位置==)
rand()生成一个随机向量(值的范围为0-1),所以需要为每个分量减去0.5.==更新当前点的位置到随机位置==
3.创建拖尾
1.以每个点的方向反向创建polyline
4.设置颜色
同样使用近点数量来设置颜色(衡量点的密度)
5. 几何修改 geometrical modification
使用sub solver在给定几何体上雕刻轨迹
实际上仍然是修改点,再用点生成primitives
[ sample_sphere_uniform() ] 函数 给定向量u,在单位球体生成对应的点
将传入参数u的xyz分量分别作为对应==球坐标系==的方位角,极角,半径
如果给定的随机向量u均匀随机(其值为0-1),则生成的向量相对于单位球体内均匀随机
1.球坐标系
2.示例
1.在[ sample_sphere_uniform() ]函数中 u.x对应方位角φ, u.y对应极角θ, u.z对应半径r
2.x轴分量控制方位角(0-360°), y轴分量控制极角(倾角0-180°), z轴分量控制半径

1.使用solver修改球体
在球体上创建路径,再通过路径生成雕刻线条
1. 创建参数
1.基于时间创建x分量,范围为0-1循环,控制方位角,对应范围是0-360°
由于范围是0-360°,可以使用取余使大于1的值变为0,0°与360°是连接的
2.基于时间使用正弦波,映射到0-1,作为y分量
由于y分量控制极角,对应范围为0-180°,无法使用取余获得循环,这里使用重映射的正弦波
2.使用[ sample_sphere_uniform() ]函数 获得对应球面上的点向量dir(设置半径为1)
3.计算 向量dir 到 球体当前点@P 的距离
设置搜索半径rad,限制距离值
将距离值 从0-rad 重映射 到1-0, 球体上到向量点越近的点影响越大
4.使用距离值 在点上以法线方向@N更新位置
6.基础分形 basic fractal
1.类似l-system的分形
设置方向vel ,分组last
2.solver
1.更新点位置,沿着方向val移动,创建新点
2.将两点连接成线
3.将新生成的点加入last分组以作为下一次移动点时的基础,将原本组中的点移除
设置为0移除,设置为1加入
4.设置新点的速度vel
无限向上生长
3.设置分支
1.依据当前帧取余,每一定帧范围生成一次分支,这里每20帧生成一次分支
2.设置循环以生成正负方向的旋转矩阵
3.用旋转矩阵更新速度vel的值(设置绕z轴旋转)
4.以此速度值vel作为位置设置新的点,和线
5.将新点加入到last组中,移除原来的点
6.为新点设置新的vel属性
4.基于三角函数改变旋转轴
7. 链式解算 chained solver
类似弹跳框中的弹跳框
1.创建第一个求解器
1.为primitives添加法线
2.设置弹跳点的属性
1.用rand()生成随机向量,减去0.5
2.将生成的向量归一化,乘以一个速度值,保存到N属性
3.在solver中设置反弹函数
1.设置沿N方向更新点的位置,即向随机生成的向量方向移动
4.确定点是否在盒子内部,使用点乘计算
1.计算点乘: 盒子的法向量N,与点指向其在盒子上投影点的向量dir,大于0则在内测
1.找到最近距离的点
1.使用[ xyzdist() ]函数 查找从点到曲面几何==最近位置==的==距离==.,函数返回的是float距离值
其输出参数prim,uv,则存储着最近位置的primnum,和对应的uv坐标
2.使用[ primuv() ]函数 使用prim,uv坐标 读取属性N 和P
对于点和顶点属性,给定uv坐标处的值将从周围点插值
2.计算点乘判断是否在内部
5.==当检测到点在盒子外侧时== 设置反射方向
先反向,在以盒子法线N为轴旋转180°.得到反射方向
1.通过创建旋转矩阵,以法线norm为轴旋转180°,更新新的N方向.
2.更新新位置(加上新的方向向量)
这里的语句仅在点==刚飞出盒子==的第一帧运行,即检测到点在外测,==将原来的运动方向更新为其反射方向==,设置这一帧的新位置为最近点位置加上新的运动方向.
6.以点为中心 copy球体
2.以反弹的球体作为另一个盒子
在更小的volume球体内部scatter点,以防止超出球体边界
1.设置属性
1.为每个点生成随机方向
2.设置pscale用于点与点之间的碰撞
3.创建新的求解器
4.为每个点设置反射
1.使用[ nearpoints() ]为每个点搜索两个最近点(其中一个是自身)
由于当在==一个点云==中以其中的每个点的位置来搜索,会将这个点本身也算在内
2.当数组长度为2(搜索到除自己意外的最近点)
获取最近点的位置,最大搜索距离设置为2倍pscale(一个pscale是半径,2倍则为直径)
3.设置反射矢量,更新运动方向
使用当前点指向近点作为作为方向矢量dir,先反向 再以此为轴旋转180°, 得到反射向量
更新新的运动方向属性, 更新此时位置:基于近点位置npos,沿dir方向的两倍半径距离,加上新的方向向量
4.在开始移动位置
5.以上一个球体作为边界反弹
1.检测小球是否接触到大球的边界
判断小球在最近点方向上一个半径长度的位置 如果在边框之外即发生碰撞
这里的 normalize(pos-@P)*fpscale,即指向最近点的大小为半径的向量
加上@P (当前小球中心的位置),==ppos即为小球边界点位置向量==.
dir向量则为小球边界点指向大球边界点的向量,在内部时,指向外,外部时,指向内
当判断ppos点处于外侧时,更新位置:基于近点位置,沿dir方向移动一倍半径,加上新的运动向量
6.设置颜色,Alpha
21.half-edge 翼边/半边
将将面视为==每个面都有自己的边==。
1.半边都是定向的,一个起点顶点,一个终点顶点
2.一个顶点只能属于一个prim,所以一个顶点最多只有一个以其作为源的半边
翼边的顺序决定法线方向
可以通过对应两点检索两点之间的翼边,可以通过prim检索翼边,也可以通过当前翼边编号检索下一个翼边,检索共享边
在检索网络中,设置细分等非常有用
1.从点获取翼边1 halt-edge from point1
[ pointhedge() ]函数 从给定点 或者 给定点和终点 来获取翼边
只给定一个点时,==将此点作为源点==,检索其对应的半边
1.使用[ pointhedge() ]函数 ==以单个点(源点)获取半边==
这里的半边的编号是唯一的
2.从半边获取其源点和终点
1.从半边获取其源点
[ hedge_srcpoint() ]函数 ==获取源点==
2.从半边获取其终点
[ hedge_dstpoint() ]函数 ==获取终点==
2.从点获取翼边2 half - edge from point2
1.使用[ pointhedge() ]函数 ==以源点和终点获取半边==
可以只使用一个源点编号
1.[ pointedge ]函数 给定两个端点(无需给定顺序)获取半边
当这两个端点只有一个半边时,不考虑参数顺序。当端点有两个半边时,则考虑参数的顺序
3.检查半边的有效性 check half-edge validity
1.检查半边num是否有效(存在)
[ hedge_isvalid() ] 函数检查半边number是否是有效的半边
4.下一个或前一个半边 next/previous half-edge
[ hedge_next() ]函数 返回下一个半边的编号
[ hedge_prev() ]函数 返回上一个半边的编号
1.获取以每个为源点的半边,找到其下一个半边,再检索下一个半边的起点和终点
2.找到其上一个半边,再检索上一个半边的起点和终点
5.下一个等效的半边 next equivalent half-edge
从一个prim的共享边的半边检索另一个半边
1.检索一个半边的等效半边
[ hedge_nextequiv() ]函数 检索与 给定半边 等效的半边
6.运用 对偶网格 exercise - dual mesh
对偶网格是将原始网格进行拓扑转换得到的新网格
将原始网格的面中心点转换为新网格的顶点,原始网格的顶点对应新网格的面
这里三角面网格的对偶网格是六边形网格
1.vex计算对偶网格
[divide]节点有计算对偶网格功能
1.先找以每个点为起点的半边,计算每个点的邻居数(等于每个点对应的prim数)
2.以此创建循环
1.检测半边的prim,获取其位置信息(prim的位置P,即中心点)
[ hedge_prim() ]函数 返回半边的prim
2.在中心位置添加新点
3.检索当前半边的上一个半边
4.检索前一个半边的共享的另一个半边(这个半边将以当前点为起点),并作为下一次循环的半边
3.连接这些点
1.在循环外先创建一个空的poly
2.循环中将点连接到顶点
3.删除当前点
删除prim: 找到所有点对应的prim,foreach循环遍历数组中的项
7.运用 网格细分 exercise - mesh subdivision
获取一个prim和其相邻prim的中点位置,并与源点连接为三角形
[ primhedge() ]函数 获得prim的其中一个半边
[ pointhedgenext ]函数 返回与给定半边有相同源点的半边(连续调用可以返回此源点对应的所有半边)
1.先获取当前prim上的一个半边
2.不断调用[ hedge_next() ]函数获取当前prim上一个半边的下一个半边
产生顺序
3.设置点
1.先在prim中心添加新的点
2.根据 当前半边 检索等效的半边(共享边的另一侧,即邻居prim的半边)
3.在根据这个==等效半边==使用 [ hedge_prim() ]函数 检索出邻居prims的编号
4.检索邻居prims的位置信息,并添加新的点
5.检索 ==当前半边的源点== (或者等效边的目标点),以此三个点连接为新的prims
使用[ addprim() ]函数 根据三个点创建多边形(直接创建)
4.删除原来的prims
8.运用 网格斜角 exercise - mesh bevel
1.倒角
1.先检索(以当前点为源点)的一个半边
2.计数当前点的邻居数
3.创建循环
1.使用[ hedge_dstpoint() ]函数 检索半边的目标点
2.检索目标点的位置信息
3.创建介于两点之间的位置,使用当前点位置加上指向目标点的向量乘以比例
4.添加新的点
5,检索当前半边的上一个半边,在检索上一个半边的等效半边 以等效半边作为下一次循环的半边
4.添加新的多边形,使用先在循环外添加空的prim,再在循环中添加顶点的方式
因为循环中不能同时得到三个新点的坐标,但循环是按照顺序来的,依次添加顶点
5.删除原来的点和prims
由于代码运行在point上,并不能直接依据primnum删除,需要遍历每个点的prims,再删除
2.创建倒角面
1.检索prim的一个半边
2.创建一个while循环
不断调用[ hedge_next() ]函数获取当前prim上一个半边的下一个半边
3.获取当前半边的源点位置和目标点位置
4.依据倒角时的比例,在两点之间创建两个新的点
5.使用添加顶点的方法添加新的多边形面
3.merge
4.斜角操作可以递归,使用foreach
5.依据面积设置颜色
22.重映射 remapping
使用重映射放缩 remapping with scale
1.使用fit函数重映射 remapping with fit
[ fit() ]函数 将值从 一个区间 映射到 另一个区间
2.使用fit01函数重映射 remapping with fit01
[ fit01() ]函数 将值从 ==0到1== 区间 映射到其他区间
fit01函数 默认值得范围在0-1之间
3.使用fit10函数重映射 remapping wit fit10
[ fit10() ]函数 将值从 ==1到0== 区间 映射到其他区间
4.使用fit11函数重映射 remapping with fit11
[ fit11() ]函数 将值从 ==-1到1== 区间 映射到其他区间
适用于与三角函数一起使用, 其值域范围就在-1到1区间
5.使用efit函数重映射 热mapping with efit
[ efit() ]函数 同样将 一个区间的值 映射到 另一个区间
但与fit()函数的不同在于,fit函数将值钳制在区间内,当给定的数超出范围,得到的值始终是区间的最大/最小值
但是efit()函数是利用两个区间的==映射关系==对超出的部分采用同样的映射 ,当给定的数超出范围时,得到的值按照映射关系无限的线性放大或者缩小
6.运用 重映射噪波 exercise - remapping for nosie
1.使用vector4生成依据时间变化变化的噪波.
2.将噪波值属性promote的到detail 使用maximum/minimum方法,以此获取噪波的范围
3.获取范围
4.重映射噪波值,将点沿法线移动
5.设置颜色值
7.运用 重映射表面距离 exercise - remapping surface dist
使用efit()函数
1.在表面生成以中心点为中心的波浪状曲面
1.找到表面上离参考点最近的点
2.计算 这点 到 表面上其他所有点 的距离(并不是直线距离,而==是在曲面上的距离==)
[ surfacedist() ]函数, 检索 点 到 ==沿着几何曲面==的一组点 的距离
3.映射颜色
4.将距离值作为三角函数的角度
efit()函数并不钳制source value, 就是说当dist的值超出所给定的范围时,将按照线性关系映射值,比如将 0-0.5 映射到 0 - 2PI, 当dist超出0.5 为1时, 将得到4PI.也就是说这里的rangedist控制着正弦波的数量,其范围越大,得到正弦波越少.
5.将正弦值重映射并作为沿法线的高度值
6.将正弦值映射到0-1作为颜色值的乘数
7.为角度加上一个时间偏移,得到动态的正弦波
8.使用ramp重映射 remapping with ramp
1.在网格中检索所有点到中心点的距离
使用attributepromote计算区间
2.使用斜坡映射 ramp remap
1.获取属性基于距离值映射一个高度值作为每个点的高度
2.使用ramp函数,先将高度值映射0-1范围
再使用chramp
3.将重映射的值再次映射到最终值
9.使用lerp插值重映射 remapping with lerp
[ lerp() ]函数 在值之间执行线性插值
这里的amount值在0-1范围内,所以先使用fit()函数将一些值映射到0-1范围,再使用lerp()函数将一个值无缝切换为另一个值
1.在球体的两个位置状态之间无缝切换
1.检索第二个球体的位置信息(由于是同样的球体,有相同的点数).
在两个位置之间插值,使用val控制
更新当前位置到新位置
2.将基于时间正弦波映射到0-1,并作为val控制lerp插值
实现在两个位置之间不断切换的动画
10.运用 使用lerp插值重映射 exercise-remapping with lerp
创建几何体多个状态之间的循环切换动画
1.设置不同状态的球体
1.在空间中散布一些点,设置scale和id属性
将scale重映射,设置范围
2.copy to point获得不同状态的球体
2.移动球体
1.根据球体个数将时间轴划分区域
f:计算当前帧在整个时间轴的位置(这里¥FEND加了1,所以最后一帧并不能到1,接近0.999)
i:计算当前帧所对应的索引值,f乘以点数,再向下取整,得到0到count-1的索引值(这里的f不取1的原因,否则索引值超出)
ff:计算当前帧在划分区域的位置,由于f在0-1,所以将1/count,表示将f的范围按照个数划分成几份,在由f==取余==,则得到值在这个范围内(0-1/count)循环,再乘以count,将值映射回0-1。这个ff则随着时间移动在每一个范围内从0到1变化
使用==当前帧== 取余 ==划分的长度== ,再比上划分长度 即得到当前帧在划分区域的位置比例
2.找到当前帧对应球体的位置
[ findattribval() ] 函数 找到具有特定属性值的点/prim/顶点
1.在第二个输入中找到所有id相同的点。(id为i,即当前帧随对应的索引值)
2.找到每个点对应另一个球体的点的编号,获取其位置
实际上这里通过@ptnum,是找的数组中第多少个元素,由于几何体点数一致,每一个对应的@ptnum都有一个对应的数组元素。
3.更新位置
3.使用slep插值
1.获取下一个球体的位置
使用(i+1)%count,即i为最后一个值,下一个变为0,回到起点形成循环
2.使用ff插值
4.使用斜坡函数重映射ff值,获得变化的动画
5.[ smooth() ]函数 创建缓和的插值
11.uv重映射 UV remapping
1.使用[uv flatten ]节点展uv
打开输出seams属性(可以不用)
[2.uvquickshade]节点查看
3.vex,找到每个点对应的uv坐标
1.获取每个点对应的编号
[ pointvertex() ]函数 提供线性顶点编号
2.使用顶点编号即可获得顶点属性,这里检索uv属性
3.将点移动到uv
由于接缝处连接
4.使用[ edgecusp ]
其工作原理是:检测uv边界,复制共享点,为每一个uv块创建独立的点,并断开拓扑结构
即通过接缝剪开uv
5.在两个位置之间插值
12.运用 uv重映射 exercise-uvremapping
1.获取每个点对应的uv坐标
2.对uv取余x/y,表示将uv划分为几个区域,每个区域的uv值从0-x/y
3.在将其重映射回到0-1范围,即每个区域重复从0到1
4.以uv作为正弦函数的角度(0-PI)获得正弦波值,再以此作为高度值沿法线改变位置
即将整个uv坐标系划分成多个重复的小块,依据当前点新的uv的值来移动点的高度。
23.有向距离场 SDF
SDF用于可视化表面
越靠近表面的值越接近0
1.check SDF values with points
1.使用volume wrangle在当前体素位置创建新的点
1.直接读取体素值
2.删除volume
中心没有点
3.将读取的体素值设置为点的属性
数值大于0则在表面外,小于0则在表面内
4.删除值大于0 的点
5.使用体素值设置颜色可视化
2.使用点检查SDF的梯度 check SDF gradient with points
1.
[ volumegradient() ]函数 计算volume primitive的梯度
计算梯度值并写进点属性中
==梯度==:是从中心点指向外
3.使用fog volume 可视化SDF值 visualize SDF value with Fog volume
1.将SDF转换为fog
使用vdb在球体外没有体素,这里使用isooffset,可以填充边界外
2.复制sdf的值到标准volume
使用[ volumesample() ]函数 采样当前位置的surface值
1.将得到的值更新到density以便查看
2.使用可视化节点
4.使用vex修改SDF basic SDF modification with VEX
修改体素值
SDF表面的体素值为0,所有体素加上一个值,则0值向内移动,表面收缩.反之向外扩张
5.动画化修改SDF animated SDF modification
以y轴作为角度使用三角函数产生波形
角度值乘以PI乘以整数作为波的数量,三角函数值乘以一个数作为移动的距离
2.在角度中添加时间则波形移动
6.使用梯度修改SDF SDF modification with gradient
1.使用[ volumegradient() ] 采样梯度值
计算梯度向量与xz轴的夹角,
1.先将梯度向量值y轴设置为0,再归一化
2.使用[ atan2() ]函数 arctan 获得连续的角度(0-180-0)
这里应该将将z设置为绝对值(-z变为正,即沿着x轴镜像),才能得到0-180°.==将x设置为绝对值,是沿着z轴镜像==(将-x的部分变为正)得到的角度将是正负90°
3.将利用角度产生正弦波,映射到0-1,再使用斜坡重映射,再重映射控制距离,作为移动表面的值
转换为多边形
重映射颜色,基于曲面位置映射颜色
7.SDF碰撞检测 basic collision with SDF
将SDF作为外部信息修改其他几何体
1.获取信息
[ volumesample() ] 采样体素值
[ volumegradient() ] 采样梯度值
2.检查点的位置,并通过梯度方向移动
8.动画化碰撞检测 animated collisionwith SDF
在求解器中检测碰撞
1.设置动画
2.解算器中设置碰撞检测
9.使用SDF梯度的向量动画 vector animation SDF gridient
在volume内生成点,每一帧将点沿着梯度方向移动,知道接触表面删除或者移动到其他地方
将体积作为第三个输入以用来生成随机位置
1.沿着梯度方向移动点
1.采样SDF的体素值和梯度向量
2.当体素值大于等于0时(判断带点在表面以外),将点移动到scatter随机生成的位置
使用梯度方向按一定速度更新位置,保存梯度值为法向N,保存体素值
2.着色
1.使用attributepromote 计算体素值的最小值,以此映射颜色
2.使用法向(梯度方向)创建拖尾
为新点设置颜色
10. 从SDF扩展向量场 extended vector field from SDF
1.生成矢量场
1.生成curl noise
将噪波与梯度方向相加作为新的速度矢量
调整
2.重新采样矢量场velocity
24.力 force
1.重力 gravity force
1.为点添加一个velocity属性
2.创建重力向量gravity存储为属性
3.更新速度
4.更新位置
5.判断是否到达地面
2.弹跳 bouncing
1.设置速度反向,将位置y轴重置到0
2.减小返回的速度值(真实物理世界,有阻力有损耗,返回的速度小于到达的速度)
3. 初始化速度 initial velocity
1.设置初始速度
(更真实的情况这个速度也要有损耗)
2.碰撞反向时,只对速度的y轴反向
如果地面不平整则需要考虑地面的法线方向,以法向作为反向
4. 对多个物体的力 force for multiple objects
1.为多个物体设置初始速度
5. 质量的力 force with mass
mass 质量是物体的==属性==
==weight = force== 重量是地球对物体的引力
F = ma ,
1.为每个球体设置质量属性
2.设置加速度
这里的gravity设置为一个向下的速度,并不是重力加速度,而是作为力,所以增加了质量属性,加速度 acc使用 F/m = a公式
v=at(1a, 2a, 3a....)每一帧的当前速度 ==实际上就是将加速度值累加到速度中==
位置为累加的速度(因为在解算器中,==每一帧走过路程就是一个速度向量==)
6.空气摩擦 air friction
1.设置摩擦
理论上更大的尺寸摩擦力更大
1.摩擦力与速度方向相反乘以一个比例,将摩擦力更新到速度
7.水摩擦力 water friction
1.使用SDF作为水体
2.检测球体是否在水体中
这里是是以速度的反方向为方向乘以一个值作为大小,每一帧都施加同样大小的摩擦力
消除抖动,以当前的速度反方向乘以一个固定比率(即速度是按照比例损耗的),每一帧施加一个上一帧速度固定比例的反方向速度
3.设置以pscale为检测触地条件
8.风力 wind force
1.设置风力
1.将风力添加到速度
9.湍流力 turbulance force
使用volume引入矢量场
1.使用体素位置为基础
1.y轴分量先设置为0
2.沿y轴设置抖动,基于位置的较小随机值,放大噪波,再重新归一化
3.将向量沿y轴旋转90度,使其沿着中心旋转方向(原本的向量取自位置,即由中心向外发散)
2.使用矢量场更新速度
1.在当前点位置采样volume中的速度值
乘以一个放大倍数,加入到速度矢量中
25.力进阶 force extended
1.吸引力算法 attractor force algorithm
1.简单的吸引力 simple attractor force
1.计算公式
==这里加上单位向量v,作为方向==
==两个质点之间的万有引力与距离的平方成反比==
2.设置吸引点和移动点,设置mass属性
使用mass设置pscale
为吸引点设置gravitation 引力属性
为移动点设置val速度属性
3.创建求解器
4.计算需要的信息
1.检索两个物体的质量,计算彼此之间的距离
2.获取吸引点的引力
3.计算速度方向值(==始终由移动点指向吸引点==)
5.计算吸引力
由于当距离很小时过于放大引力,这里设置最大引力限制。
更新force引力
6.使用引力 更新速度和位置
1.访问速度val属性,将引力向量添加到速度向量
2.将速度向量添加到位置
7.调整
1.钳制引力的大小,以免引力太强,或者太弱
2.更新速度之后,钳制速度的最大值
2.多个物体的引力 multiple attracted objects
1.替换单个移动点为多个
1.需要为每个点设置随机的质量mass
2.调整
3.多个吸引点 multiple attractors
1.替换多个引力点
1.为每个引力点设置随机质量mass
2.计算总的引力
1.使用循环访问所有引力点
2.计算总引力:即所有引力的向量累加
3.替换速度
2.调整
4. 朝向吸引物体 attracted object with heading
设置朝向
解算器内更新位置之后,更新移动点的法向为速度方向即可
设置吸引点随机移动
1.使用SDF的梯度值使其不会超出范围
2.随机移动
使用curlnoise 创建一个力
2.创建一个边界力
超出边界时,按照梯度(梯度由内指向外)回到球内
3.计算合力
4.更新速度,位置
5,限制速度大小
5. 角向力算法 angular force algorithm
绕物体旋转的力
通过增加角度θ,增加旋转的速度
计算公式
1.创建旋转点,和中心点
为旋转点设置随机的质量属性mass并作为pscale,设置角度属性 ang
为中心点设置引力属性gravitation,质量属性mass
可视化:copy to point,上色
2.求解旋转力rotational force 和 角力angular force
1.检索所有需要的信息
1.获取中心点位置posC
2.获取中心点质量massC
3.获取中心点引力g
4.计算中心点到当前点距离dist
5.获取当前物体的质量massM
2.计算力
1.限制力f的大小
使用==设定上限== 与 ==当前值== ==取最小值==的方法
2.使用力f 增加角度值
3.限制角度的大小
使用 ==设定最大值== 与 ==当前值== ==取最小值== 的方法
3.设置旋转
1.创建旋转矩阵
2.先将位置移动到以原点为参考,旋转位置之后再移动回原位置(假如中心发生移动)
6.角向运动算法 angular motion algorithm
利用物体自身的中心旋转
使用==角向运动==算法是==旋转物体的法线方向==进行角向运动,角向力则是旋转位置本身
计算公式
只与自身质量mass有关
1.创建起始条件
初始化再设置一个角度2,设置法向N,设置引力系数gravitation
==由于这里将法向量N设置在点上,后续旋转法向量N,再copy物体到点上,则物体将自动对齐法向量N,以此产生绕自己旋转的效果==
2.求解角向运动angular motion
1.获取信息
mass质量,引力系数g
2.计算力和角度,限制大小
使用取最小值的方法
3.旋转法线
1.创建旋转矩阵
2.旋转法线
旋转时,以原点(0,0,0)为中心,旋转操作本身并不考虑向量的位置(默认在起点)。
这里旋转的是向量N(1,0,0),与当前点的位置无关。
向量本身只有方向和大小,并没有位置概念。只是在用法上可以将其作为位置
7.钟摆算法 pendulum algorithm
计算公式
1.单摆 single pendulum
1.创建直线line,分组一个单摆的球体
2.measure节点测量primitive的长度
3.设置初始化角度
1.设置角度
2.旋转
4.设置质量属性mass,pscale属性(与质量相关),设置速度值属性val
2.解算
1.获得信息
1.获取摆的长度l
2.设置引力系数g
3.获取质量mass
4.过滤ball组,只移动球
2.计算力
==这里需要加一个负号==,
3.更新速度,再更新角度
4.更新位置
这里先将向量(0,-1,0)按计算的角度旋转作为方向,再乘以长度,即得到球应该在的位置
5.设置阻尼
按照比例每一帧减小速度
8.多个钟摆 multiple pendulums
1.使用foreach创建多个钟摆
1.获取当前迭代和迭代总数
2.重映射长度,判断当前点是否是ball点,修改位置
3.为每一个钟摆创建初始角度
4.调整解算算法
1.通过获取每一个点的prims,来获取其长度
2.枢纽点,即每个prims的0号点
3.检索枢纽点位置
4.更新位置:使用当前钟摆的枢纽点位置加上旋转的位置
5.调整
重映射摆的长度
9.弹力算法 spring force algorithm
计算公式
1.简单弹力 simple spring
固定一点移动另一点
1.设置分组,属性
创建mass属性,设置目标长度
根据mass设置pscale
设置速度矢量
2.解算器
1.筛选分组,只运行在ball,即固定一个点的弹力
2.计算信息
1.获取 点0 的位置(固定点)pivotpos
2.计算指向固定点的向量v
3.计算长度l
4.获取目标长度tl
5.计算长度差diffl
6.设置刚度n
3.计算force
1.使用force更新速度vel
F = ma,v = at; ==在每一帧上,速度是加速度的累加,也是力的累加,位移是速度矢量的累加==
2.使用速度vel更新位置(由于矢量即表示大小又表示方向,所以==每一帧的位移就是速度矢量==,位置则是速度矢量的累加)
4.设置阻尼
5.调整
1.设置力与距离的平方成正比,(使用平方丢失符号)使用差值除以其绝对值获得原本的符号,乘以0.5,表示值运动一端。
2.添加一个重力f2
3.限制force f1的大小
10.链式弹力 chained spring (rope)
1.创建chains
1.congvertline节点
否则line只有一个prims
2.计算每条line(primes)的长度
3.初始化条件
1.固定端点(设置为pin组)
2.设置每个点有相同的质量mass,设置速度属性
3.使用primitivewrangle为每个prims设置目标长度(使用测量的长度作为原始长度)
4.设置移动handle以此控制一个端点
2.解算
使用prim wrangle
1.访问prims中的点,创建循环遍历每一个点,计算force
1.这里在第一个循环pt1=0,pt2=1;第二个循环pt1=1,pt2=0;
for循环数组中的 i+1取余数组长度,都是避免索引超出数组长度,当取最后一个值时,跳转回0(第一个值)
==这里数组只有两个元素,第二次循环则交换编号==
2.获取两个点的位置和mass属性(这里错误,mass2应该是mass1)
3.计算两个点之间的方向向量
4.计算两点之间的长度
5.获取prim的目标长度属性
6.计算长度差
7.计算力,钳制大小
这里的两次循环:==第一次将由pt1指向pt2的力累加到pt1==,==第二次将由pt2指向pt1的力累加到pt2==
==中间的每一个点有两个方向的力,所以需要累加==
2.使用point wrangle 添加重力, 更新速度
3.更新位置
判断点不不是pin固定点
4.调整
1.计算弹力的公式中不考虑质量,后续加入了质量,重复了
2.
5.加入控制端点
将端点位置更新到控制点位置
26.递归 recursion
不断调用自身
可以用来创建分形
1.houdini中的递归 recursion houdini
1.三个方法
1.使用foreach循环实现递归 recursion with foreach loop
1.添加新点,创建方向属性
创建分组,设置为最后一个点(将其不断移动)
2.foreach number 循环
1.调整为feedback each iteration
2.调整为fetch feedback
3.每一次迭代将last点沿x轴移动一个位置
这里每次迭代,将last点移动一个位置再与原来的点合并
4.加上旋转,向上平移
2.使用foreach和VEX实现递归 recursion with foreach loop + VEX
1.设置旋转距离,旋转角度,旋转高度作为参数
2.添加新的点
将新的点设置为last组,将当前点移除last组
为新点设置dir属性(add的新点没有任何属性)
3.设置旋转
创建旋转矩阵,加上y值
3.使用解算器实现递归 recursion with solver
1.使用同样的VEX代码
4.使用VEX实现递归 recursion with only VEX
1.使用for循环包含所有代码
1.更新位置(在循环中使用pos = @P,只会重复使用第一个点的位置)
不需要分组,每一次循环已经将最后一个点的位置储存在pos中
5.使用foreach生成谢尔宾斯基三角形 sierpinski triangle with foreach loop
1.初始图形(使用circle设置一个三角形)
以每个顶点为枢纽点pivot,将三角形缩小0.5,即可得到周边的三角形
2.使用foreach循环
1.使用foreach prims 访问每一个三角形
2.再其中使用foreach point 访问三角形的每一个点
3.使用transform 设置pivot,来缩放三角形
1.设置pivot
4.理解
主要的for each num设置为feedback,每次迭代作用于上一次的所有三角形(也将是将上一次的所有三角形按照其三个顶点为轴心分别缩放得到三个小三角形),在这个大的反馈循环中,使用foreach prim遍历每一个三角形,再再这个prims循环中使用foreach point遍历每一个三角形的每一个点,以此作为pivot,将每一个三角形以三个点为轴心分别缩放一次。

6.使用forach循环加VEX生成谢尔宾斯基三角形 sierpinski triangle with foreach loop + VEX
使用wrangle可以并行运行,获得更快的计算速度
1.VEX
1.获取每个三角形的三个点
这里的每个三角形都是一个prim,运行在primitive wrangle上
2.循环三个点,使用point()函数获取三个点位置
3.再循环以三个点将当前三角形(三个点位置)缩放一半,得到三个小三角形的位置
vex代码运行再每一个prims上,即处理的是单个三角形
第一层循环,是循环三个点,分别作为pivot,这里的pos位置。第二层循环分别以三个点为pivot,移动三角形三个点的位置(减去pos枢纽点,==得到的是由枢纽点指向顶点的向量==),
注意理解:这里减去之后得到的是由==pos点====位置==指向==npos点位置==的==向量==,缩小一半,其终点在两点的中点,==起点在pos向量终点==,所以需要加上pos向量,将其起点变为pos起点。才能作为位置(由于pos,npos都是作为位置,所以以此为向量,起点在原点)
理解2:位置由起点在原点的向量表示,默认缩放位置时,是缩小这个以原点为起点的向量,当要使用别的位置作为枢纽点缩放时,减去枢纽点向量相当于将枢纽点放回原点,缩放操作后,需要再加上枢纽点位置。
4.创建多边形
添加顶点
删除原prims
7.使用解算器生成谢尔宾斯基三角形 sierpinski triangle with solver
1.直接使用foreach中的VEX代码
solver和foreach 反馈迭代一样,只是==solver以每一帧为一次反馈迭代==
2.设置switch划分时间轴为迭代次数
8.只是用VEX生成谢尔宾斯基三角形 sierpinski triangle with only VEX
使用VEX代码实现递归函数难度大
1.VEX没有嵌套的数组,中有一维数组
2.在一个wrangle中生成的点或者prims,并不能使用primpoints函数再次查询,需要离开当前wrangle节点
3.并不能在函数中创建函数,在函数中调用函数
本质在于递归需要顺序执行,而VEX是并行执行,所有点/prims是同时处理。线程之间无法通信
1.使用VEX递归
1.只需要删除一次原三角形
2.primpoints只能访问单个三角形
3.不能使用点/prims编号进行反馈操作,需要将其转换为位置
创建一个向量数组,存储三角形的三个点位置
4.不能在反馈循环中生成prims,其编号不能用于下次迭代
这里有迭代循环和访问每个点的循环,缺少第二层循环,即访问每个三角形的循环
5.第二层循环需要遍历所有三角形
使用位置数组长度除以3得到三角形的数量
6.创建三角形点位置的索引
7.替换为位置
8.创建新的数组存储所有新三角形的位置
9.在反馈循环最后更新位置数组,作为下一次迭代的位置
10.使用位置信息创建几何体
2.递归执行测试 recursion performance test
| 方法 | 时间 | iteration |
|---|---|---|
| 只使用foreach | 18s | 11 |
| ==foreach 加上 VEX== | 0.165s | 11 |
| ==solver== | 0.19s | 11 |
| 纯VEX | 10.75s | 11 |
9.2D L系统树 2D L-system tree
1.设置end组,作为每一次迭代的点
2.设置属性
设置分支的长度,角度
3.使用foreach feedback loop
point wrangle控制end点
1.设置参数
分支角度
2.循环三次创建三个分支点
创建旋转矩阵,将沿着x方向沿y轴旋转角度a
创建新位置
添加新点
连接点为polyline
重新依据i(0,1,2)为每个分支获取角度,(将0,1,2向负方向移动,得到-1,-,1)
3.选择end点作为下一个分支的点
1.在循环后将生成的点设置为end组
2.将原来的点移除end组
3.更改新的分支的长度属性,角度属性
4.当角度为120,生成了谢尔宾斯基三角形

10.使用foreach循环实现3DL系统树 3D L-system tree with foreach loop
1.创建一条线,分组prims,作为操作的分支
2.设置水平轴
3.创建feedback反馈循环
1.使用primitive wrangle,
2.设置参数
1.创建分支角度
2.设置缩放比例
3.设置角度比例
5.设置最小长度作为结束循环的条件
6.设置分支数
7.创建种子值
3.获取起点终点点号,获取其位置
4.设置起点指向终点 的向量为轴
5.获取水平轴,计算当前的长度
6.以水平方向为轴旋转,移动,添加新的点
以(1,0,0)旋转,即沿着x轴在xy平面旋转
这里是旋转之后再加上原来的分支向量,即将新的分支沿着原分支方向移动到顶点
这里的npos 先加回pos1,得到原位置,再加上pos2-pos1(原来分支的矢量),将顶点沿原分支移动,得到新分支顶点位置。
7.连接新点
4.创建循环来生成分支
1.计算分支的角度
将360°划分为几个分支
2.以垂直方向为轴,旋转分支生成多个分支的位置
添加新的点和线
3.将新的线添加进last组,将原本的线移除last组
5.添加旋转轴属性
注意属性传递问题:新加的线没有任何属性
添加新的水平轴
初始的水平轴为(1,0,0)指向x方向,生成新的分支时,竖直轴为上次分支的指向,以此旋转生成分支,新的水平轴也应该旋转同样的角度,以此对齐新的分支,下一次的分支将沿着新的水平轴旋转角度,形成对称的图形
6.创造停止迭代条件
检查最小分支长度,return将跳过所有代码
7.应用angle ratio每次缩小分支的角度
需要将分支角度设置为可以迭代的属性
2.读取分支角度属性
3.设置更新分支角度属性
这里的属性是以角度存储的,使用时先转换为弧度,保存时再转换为角度
8.引入随机的分支角度
创建垂直方向的上旋转的随机角度(即分支之间的角度),映射到固定可调范围
9.引入随机的水平旋转角度
10.设置pscale,创建厚度
1.创建厚度属性
2.获取分支顶点的厚度属性
3.设置比例减小厚度
4.访问厚度属性
11.着色,依据厚度
11.解算器创建3D l系统树 3D L-system tree with solver
使用solver可以创建更流畅的生长动画
1.将foreach替换为solver
在每一帧,分支立即生成
2.使用carve节点
对primitive切片
12. 递归细分 rectangle subdivision
1.创建prims属性
设置切换属性,每一次迭代切换一个状态
2.创建反馈循环
1.改变点标号顺序
2.使用primitive wrangle分割矩形
2.获取iteration,prim中 的点号
3.设置切换值,每次迭代切换一次
为0,表示选择的位置为横向切割,为1表示竖向切割
4.设置切割的位置
1.设置随机种子,依据迭代次数,和prims
2.创建随机值
3.设置最小比例
4.映射随机值的范围
5.创建两次循环创建两个prims
6.在嵌套一个循环遍历每一个点
1.获取每一个点位置,获取对角点位置用来作为缩放的枢纽点
2.计算从第一个对角点指向其他点的向量odir
3.如果sw=0(沿x方向切),取方向向量的x分量
4.添加顶点,删除原prims
注意理解:这里举例沿x轴横向切时(sw=0),将 由对角点指向其他点的矢量odir 的x分量缩放,(==只缩放x分量,其位置就只在x轴缩放==)。新点的位置为对角点位置加上这个方向向量。
sw=1时,即沿着z轴切,缩放z轴的分量
两次循环中嵌套四次循环(点数,对每个点执行),依次添加顶点,生成多边形
3.使用noise动画化,
1.创建noise(依据每一帧),映射到范围,加入到缩放值
这里的缩放值为0.2,即切割位置在边的比例为0.2到0.8范围,这里加入每一帧noise变化的+-0.2,(由于使用的noise,变化具有连续性)
4.上色
基于面积上色

版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
彬的特效学习指南!
喜欢就支持一下吧