学会这 6 个技巧,分分钟搭建炫酷场景 | Taichi 进阶秘籍
时间:2022-11-06 21:17:19 阅读:75
距离 Taichi 体素创意大赛截止提交仅剩 2 天,我们已经收到近 90 份精美的体素作品。目前小伙伴们都进入到作品修改阶段,编辑部特意请来两位社区中的体素高手,分享他们的创作心得,希望在最后冲刺阶段,助力大家打磨出最满意的作品!
关于坐标系的说明
API 中有一个可能产生困惑的地方是:整个空间的坐标范围是 [-1,+1]³,但是在调用 set_voxel 函数时你传入的并不是它们的绝对坐标 (x,y,z),而是三个整数 (i,j,k) ,它们是 voxel 的下标。下标为 (-64, -64, -64) 的 voxel 的实际占据的位置是左下角为 (-1,-1,-1),右上角为 (-1+1/64, -1+1/64, -1+1/64) 的立方体空间,下标为 (63, 63, 63) 的 voxel 实际占据的位置是左下角为 (1-1/64, 1-1/64, 1-1/64),右上角为 (1,1,1) 的立方体空间。其它同理。
快速搭建复杂场景的 Tips
在搭建比较复杂的场景时,一个一个手动摆放体素实在是太低效了,那么有哪些方法可以帮助我们高效地实现一些好玩的效果呢?这些小贴士请收好!
使用隐函数绘制几何体
如果一个几何体可以用隐函数 来表示,其中 为几何体的内部, 为几何体的外部,那么你可以将一个 voxel (i,j,k) 首先变换到 对应的坐标系下,然后代入 的表达式,通过符号来判断它是否属于这个几何体 。我们用球面作为例子来说明。
思路:我们在 sphere 这个函数内遍历在 x, y, z 三个方向 (-64, 64) 允许区间范围内的所有点,计算其到 pos 参数(在这里 pos 是一个三维向量,代表球心位置)的距离,当距离小于某个定值 r 时就放置一个体素。这样在 initialize_voxels 里执行 sphere 的结果就会出现一个以 pos 为球心,r 为半径的球体。用类似的思路也可以实现不同的几何体,随后在 kernel 中就可以反复调用,达到节省代码减少重复的目的。(关于 @ti.kernel 和 @ti.func 的概念和详细释义请参考 Taichi 语言官方文档 ¹)
示例代码见下:
import taichi as ti
from taichi.math import *
@ti.func
def sphere(pos, r, mat, color):
for i,j,k in ti.ndrange((-64,64),(-64,64),(-64,64)):
v = vec3(i, j, k)
if dot(v - pos, v - pos) < r*r:
scene.set_voxel(vec3(i,j,k), mat, color)
@ti.kernel
def initialize_voxels():
pos = vec3(0, 0, 0)
color = vec3(213.255, 255./255, 13./255)
sphere(pos, 15, 1, color)
这部分代码运行后,将得到这样的一个以原点为球心的球体:
构造波浪曲面
我们可以巧妙借助三角函数的力量,利用正弦函数在三维坐标系内构建波浪的形状,基本思路是两个 函数相乘,所用的公式是:
代码还是类似前述放置球体的思路:我们先让程序遍历空间中的点,计算每个点所对应的波浪曲面高度 h,当其位置处于这个高度之下时就放置一个体素,结果就会出现一个类似波动水面的实体。我们也可以调整三角函数的振幅和相角等参数,就可以构建不同的曲面形状了。
示例代码见下:
@ti.func
def wave():
for i,j,k in ti.ndrange((-64,64),(-64,64),(-64,64)):
h = 7 * ti.sin(ti.cast(i, ti.f32) 50 * 3.14)* ti.sin(ti.cast(j, ti.f32) 45 * 3.14) - 35
if k < h:
scene.set_voxel(vec3(j,k,j), 1,(0.42,.62,1.))
@ti.kernel
def initialize_voxels():
wave()
这部分代码运行后,将得到这样的一个波浪形曲面:
巧用扫掠参数曲线,做出不规则几何体
扫掠是三维设计软件中经常出现的一个构建几何体的方法。所谓扫掠参数曲线是指把几何体沿着空间曲线推移,将几何体沿路所覆盖的空间体积全部填满,这样一种构造三维实体的方法。利用这个思路,我们可以去创作一些不规则的线条/几何体等,这里以一个螺线形的弹簧为例。螺线的公式可以选择如下:
我们只要枚举一系列 t 的值,并沿着相应的 (x(t), y(t), z(t) 去放置体素或者几何体,就可以模拟出扫掠的效果了。
示例代码见下:
@ti.kernel
def initialize_voxels():
for t in range(-64,64):
tt = ti.cast(t, ti,f32) 32 * 3.14
x = ti.cast(16 * ti.sin(tt), ti.i32)
y = t
z = ti.cast(16 * ti.cos(tt), ti.i32)
sphere(vec3(x,y,z), 4, 1, vec3(0., 224./255, 150./255))
这部分代码运行后,将得到这样的一个截面为以 4 为半径的圆形的螺线:
使用 uv 映射绘制纹理图案
如果你想在某个物体的表面喷绘某种二维图案,比如 Mandelbrot 集,那么你可以将物体表面的 voxel 映射到二维平面上的坐标 ,然后就可以根据 是否属于 Mandelbrot 集(甚至进一步,迭代的次数)来给这个 voxel 染色啦!
比如下图的 Mandelbrot 集合其实将显示屏映射到一个平面区域上然后计算的。
灵活使用噪声
通过使用噪声函数,我们可以绘制地形、城市、数目,这次比赛中有许多作品通过噪声得到了非常棒的效果:
使用空间折叠的技巧
在社区的投稿中,有一个精彩的作品使用了空间折叠的技巧:
这是一个盆景作品,它的结构乍看起来挺复杂的,但注意到它具有对称性,taichi作者是通过一系列镜像对称和旋转将整个结构转换到一个扇形区域里面,然后又使用了分形中的迭代技巧制造镂空的细节 ²。在不刻意压缩代码的情况下很漂亮地实现了一个视觉上非常复杂的结构。taichi https://taichi-lang.cn/
关于坐标系的说明
API 中有一个可能产生困惑的地方是:整个空间的坐标范围是 [-1,+1]³,但是在调用 set_voxel 函数时你传入的并不是它们的绝对坐标 (x,y,z),而是三个整数 (i,j,k) ,它们是 voxel 的下标。下标为 (-64, -64, -64) 的 voxel 的实际占据的位置是左下角为 (-1,-1,-1),右上角为 (-1+1/64, -1+1/64, -1+1/64) 的立方体空间,下标为 (63, 63, 63) 的 voxel 实际占据的位置是左下角为 (1-1/64, 1-1/64, 1-1/64),右上角为 (1,1,1) 的立方体空间。其它同理。
快速搭建复杂场景的 Tips
在搭建比较复杂的场景时,一个一个手动摆放体素实在是太低效了,那么有哪些方法可以帮助我们高效地实现一些好玩的效果呢?这些小贴士请收好!
使用隐函数绘制几何体
如果一个几何体可以用隐函数 来表示,其中 为几何体的内部, 为几何体的外部,那么你可以将一个 voxel (i,j,k) 首先变换到 对应的坐标系下,然后代入 的表达式,通过符号来判断它是否属于这个几何体 。我们用球面作为例子来说明。
思路:我们在 sphere 这个函数内遍历在 x, y, z 三个方向 (-64, 64) 允许区间范围内的所有点,计算其到 pos 参数(在这里 pos 是一个三维向量,代表球心位置)的距离,当距离小于某个定值 r 时就放置一个体素。这样在 initialize_voxels 里执行 sphere 的结果就会出现一个以 pos 为球心,r 为半径的球体。用类似的思路也可以实现不同的几何体,随后在 kernel 中就可以反复调用,达到节省代码减少重复的目的。(关于 @ti.kernel 和 @ti.func 的概念和详细释义请参考 Taichi 语言官方文档 ¹)
示例代码见下:
import taichi as ti
from taichi.math import *
@ti.func
def sphere(pos, r, mat, color):
for i,j,k in ti.ndrange((-64,64),(-64,64),(-64,64)):
v = vec3(i, j, k)
if dot(v - pos, v - pos) < r*r:
scene.set_voxel(vec3(i,j,k), mat, color)
@ti.kernel
def initialize_voxels():
pos = vec3(0, 0, 0)
color = vec3(213.255, 255./255, 13./255)
sphere(pos, 15, 1, color)
这部分代码运行后,将得到这样的一个以原点为球心的球体:
构造波浪曲面
我们可以巧妙借助三角函数的力量,利用正弦函数在三维坐标系内构建波浪的形状,基本思路是两个 函数相乘,所用的公式是:
代码还是类似前述放置球体的思路:我们先让程序遍历空间中的点,计算每个点所对应的波浪曲面高度 h,当其位置处于这个高度之下时就放置一个体素,结果就会出现一个类似波动水面的实体。我们也可以调整三角函数的振幅和相角等参数,就可以构建不同的曲面形状了。
示例代码见下:
@ti.func
def wave():
for i,j,k in ti.ndrange((-64,64),(-64,64),(-64,64)):
h = 7 * ti.sin(ti.cast(i, ti.f32) 50 * 3.14)* ti.sin(ti.cast(j, ti.f32) 45 * 3.14) - 35
if k < h:
scene.set_voxel(vec3(j,k,j), 1,(0.42,.62,1.))
@ti.kernel
def initialize_voxels():
wave()
这部分代码运行后,将得到这样的一个波浪形曲面:
巧用扫掠参数曲线,做出不规则几何体
扫掠是三维设计软件中经常出现的一个构建几何体的方法。所谓扫掠参数曲线是指把几何体沿着空间曲线推移,将几何体沿路所覆盖的空间体积全部填满,这样一种构造三维实体的方法。利用这个思路,我们可以去创作一些不规则的线条/几何体等,这里以一个螺线形的弹簧为例。螺线的公式可以选择如下:
我们只要枚举一系列 t 的值,并沿着相应的 (x(t), y(t), z(t) 去放置体素或者几何体,就可以模拟出扫掠的效果了。
示例代码见下:
@ti.kernel
def initialize_voxels():
for t in range(-64,64):
tt = ti.cast(t, ti,f32) 32 * 3.14
x = ti.cast(16 * ti.sin(tt), ti.i32)
y = t
z = ti.cast(16 * ti.cos(tt), ti.i32)
sphere(vec3(x,y,z), 4, 1, vec3(0., 224./255, 150./255))
这部分代码运行后,将得到这样的一个截面为以 4 为半径的圆形的螺线:
使用 uv 映射绘制纹理图案
如果你想在某个物体的表面喷绘某种二维图案,比如 Mandelbrot 集,那么你可以将物体表面的 voxel 映射到二维平面上的坐标 ,然后就可以根据 是否属于 Mandelbrot 集(甚至进一步,迭代的次数)来给这个 voxel 染色啦!
比如下图的 Mandelbrot 集合其实将显示屏映射到一个平面区域上然后计算的。
灵活使用噪声
通过使用噪声函数,我们可以绘制地形、城市、数目,这次比赛中有许多作品通过噪声得到了非常棒的效果:
使用空间折叠的技巧
在社区的投稿中,有一个精彩的作品使用了空间折叠的技巧:
这是一个盆景作品,它的结构乍看起来挺复杂的,但注意到它具有对称性,taichi作者是通过一系列镜像对称和旋转将整个结构转换到一个扇形区域里面,然后又使用了分形中的迭代技巧制造镂空的细节 ²。在不刻意压缩代码的情况下很漂亮地实现了一个视觉上非常复杂的结构。taichi https://taichi-lang.cn/
郑重声明:文章内容来自互联网,纯属作者个人观点,仅供参考,并不代表本站立场 ,版权归原作者所有!
上一篇:X系列的颜值里程碑,荣耀X40民间测评,千元曲面巅峰之作
下一篇:初探Taichi图形编程语言
相关推荐