太极图形学——程序动画

图形学的基础是编程,在此基础上又有了三种需要学习的分支,分别是程序动画,渲染和仿真,这也就是为什么图形学难以入门的原因

程序动画的特点是使用较少的外部资源,基于一些自己制定的规则

在画布上最小的单元认为是像素,每一个像素填充上不同的颜色就可以认为是程序动画的简单实现

要完成一个程序动画总共可以分为六个步骤

第一步:准备画布

在做每一个程序动画的开始,codebase,也是分为四个步骤,初始化,设置数据(像素),渲染画布,gui实现可视化,在太极中的实现步骤如下

import taichi as ti
ti.init(arch = ti.cuda)

res_x = 512
res_y = 512
pixels = ti.Vector.field(3,ti.f32,shape = (res_x,res_y))

@ti.kernel
def render():
    #在初始画布上进行渲染
    for i,j in pixels:
        color =  ti.Vector([0.0,0.0,0.0])# init your canvas to black
        pixels[i,j] = color

gui = ti.GUI("Canvas", res = (res_x,res_y))

for i in range(100000):
    render()
    gui.set_image(pixels)
    gui.show

第二步:在画布上绘制颜色

基于此代码,我们就可以获得一个黑布,若是添加上下列的代码

@ti.kernel
def render(t:ti.f32):
    # draw something on your canvas
    for i,j in pixels:
        r = 0.5 * ti.sin(t + float(i) / res_x) + 0.5
        g = 0.5 * ti.sin(t + float(j) / res_y + 2) + 0.5
        b = 0.5 * ti.sin(t + float(i) / res_x + 4) + 0.5
        color = ti.Vector([r, g, b])
        pixels[i, j] = color

gui = ti.GUI("Canvas", res=(res_x, res_y))

for i in range(100000):
    t = i * 0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

这个画圆的方式就是一个简单的分型 

@ti.kernel
def render(t:ti.f32):
    #在初始画布上进行渲染
    for i,j in pixels:
        color =  ti.Vector([0.0,0.0,0.0])# init your canvas to black
        pos  = ti.Vector([i,j])
        center = ti.Vector([res_x/2.0,res_y/2.0])
        radius = 100.0
        r = (pos-center).norm()
        if r < radius :
            color = ti.Vector([1.0,1.0,0.0])    
        pixels[i,j] = color

gui = ti.GUI("Canvas", res = (res_x,res_y))

for i in range(100000):
    t = i*0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

 例如rgb绘制和图元绘制还可以生成这些图像

第三步: 绘制出基本单元,几何体

可以看出画出的圆比较粗糙,我们可以进行插值,最后会生成这样一个边缘具有模糊的圆

@ti.func
def circle(pos,center,radius,blur):
    r = (pos-center).norm()
    t = 0.0
    if blur >0.0:
        t = smoothstep(1.0,1.0-blur,r/radius)
    return t

@ti.kernel
def render(t:ti.f32):
    #在初始画布上进行渲染
    for i,j in pixels:
        color =  ti.Vector([0.0,0.0,0.0])# init your canvas to black
        pos  = ti.Vector([i,j])
        center = ti.Vector([res_x/2.0,res_y/2.0])
        radius = 100.0
       
        c = circle(pos,center,radius,0.1)
        color = c*ti.Vector([0.0,0.0,1.0])

        pixels[i,j] = color

gui = ti.GUI("Canvas", res = (res_x,res_y))

for i in range(100000):
    t = i*0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

第四步:重复基本单元的放置,有效的一个方法是结块tiles

思想是在绘制出基本的图元之后,按照规则重复这些图元

@ti.kernel
def render(t:ti.f32):
    #在初始画布上进行渲染
    for i_,j_ in pixels:
        color =  ti.Vector([0.0,0.0,0.0])# init your canvas to black

        tile_size = 64

        i = mod(j_,tile_size)
        j = mod(i_,tile_size)

        pos  = ti.Vector([i,j])
        center = ti.Vector([tile_size/2.0,tile_size/2.0])
    
        radius = tile_size/4.0
       
        c = circle(pos,center,radius,0.1)

        color = c*ti.Vector([0.0,0.0,1.0])

        pixels[i_,j_] = color
        
gui = ti.GUI("Canvas", res = (res_x,res_y))

for i in range(100000):
    t = i*0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

除了结块这种操作,还可以做分型,用一大堆子集去重复母集的操作,就像是不断的去套娃

只是单纯的加入了一个for循环,就可以实现这些效果

@ti.kernel
def render(t:ti.f32):
    #在初始画布上进行渲染
    for i_,j_ in pixels:
        color =  ti.Vector([0.0,0.0,0.0])# init your canvas to black

        tile_size = 16

        for k in range(3):
            i = mod(j_,tile_size)
            j = mod(i_,tile_size)

            pos  = ti.Vector([i,j])
            center = ti.Vector([tile_size/2.0,tile_size/2.0])
    
            radius = tile_size/2.0
            c = circle(pos,center,radius,0.1)
            color += c*ti.Vector([1.0,1.0,1.0])

            color /= 2.0
            tile_size *= 2

        pixels[i_,j_] = color
        
gui = ti.GUI("Canvas", res = (res_x,res_y))

for i in range(100000):
    t = i*0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

第五步:做动画化,额外添加时间轴

@ti.kernel
def render(t:ti.f32):
    #draw something on your canvas
    for i,j in pixels:
        r = 0.5*ti.sin( t + float(i) / res_x) + 0.5
        g = 0.5 * ti.sin(t + float(j) / res_y + 2) + 0.5
        b = 0.5 * ti.sin(t + float(i) / res_x  + 4) + 0.5
        color = ti.Vector([r,g,b])
        pixels[i,j] = color    
gui = ti.GUI("Canvas", res = (res_x,res_y))

for i in range(100000):
    t = i*0.03
    render(t)
    gui.set_image(pixels)
    gui.show()           

第六步: 加入些许的随机性元素

@ti.kernel
def render(t:ti.f32):
    # draw something on your canvas
    for i,j in pixels:
        color = ti.Vector([0.0, 0.0, 0.0]) # init your canvas to black

        tile_size = 16
        for k in range(3):
            
            center = ti.Vector([tile_size//2, tile_size//2])
            radius = tile_size//2

            pos = ti.Vector([mod(i, tile_size),mod(j, tile_size)]) # scale i, j to [0, tile_size-1]
            
            blur =fract(ti.sin(float(0.1*t+i//tile_size*5+j//tile_size*3)))
            c = circle(pos, center, radius, blur)
            
            r = 0.5*ti.sin(float(0.001*t+i//tile_size)) + 0.5
            g = 0.5*ti.sin(float(0.001*t+j//tile_size) + 2) + 0.5
            b = 0.5*ti.sin(float(0.001*t+i//tile_size) + 4) + 0.5

            color += ti.Vector([r, g, b])*c
            
            color /= 2
            tile_size *= 2

        pixels[i,j] = color

gui = ti.GUI("Canvas", res=(res_x, res_y))

for i in range(100000):
    t = i * 0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

引入柏林噪声,创造了一个既保有随机性,同时又具有局部连续性的东西,和白噪声不同,整体随机但是局部连续,生成这种噪声并不复杂

import taichi as ti

ti.init(arch = ti.cuda)

res_x = 1200
res_y = 675
pixels = ti.Vector.field(3, ti.f32, shape=(res_x, res_y))

@ti.kernel
def render(time:ti.f32):
    # draw something on your canvas
    for i,j in pixels:
        color = ti.Vector([0.0, 0.0, 0.0]) # init your canvas to black

        uv = ti.Vector([float(i) / res_x, float(j) / res_y]) - 0.5 # putting everything between -0.5 and 0.5
        t = time * 0.1 + ((0.25 + 0.05 * ti.sin(time * 0.1))/(uv.norm() + 0.07)) * 2.2;
        si = ti.sin(t)
        co = ti.cos(t)
        ma = ti.Matrix([[co, si], [-si, co]])

        v1 = v2 = v3 = 0.0
        s = 0.0

        for k in range(90):
            p = s * uv
            ps = s

            p = ma @ p # rotate
            p += ti.Vector([0.22, 0.3])
            ps += s - 1.5 - ti.sin(time * 0.13) * 0.1

            # draw spiral curves
            for l in range(8):
                len2 = p.dot(p) + ps * ps
                p = ti.abs(p) / len2 - 0.659
                ps = ti.abs(ps) / len2 - 0.659
            
            len2 = p.dot(p) + ps * ps
            v1 += len2 * 0.0015 * (1.8 + ti.sin(uv.norm() * 13.0) + 0.5 - time * 0.2)
            v2 += len2 * 0.0013 * (1.5 + ti.sin(uv.norm() * 14.5) + 1.2 - time * 0.3)
            v3 += p.norm() * 0.003
            s += 0.035 

        len = uv.norm()
        v1 *= smoothstep(0.7, 0.0, len)
        v2 *= smoothstep(0.5, 0.0, len)
        v3 *= smoothstep(0.9, 0.0, len)
	
        color[0] = v3 * (1.5 + ti.sin(time * 0.2) * 0.4)
        color[1] = (v1 + v3) * 0.3
        color[2] = v2
        color += smoothstep(0.2, 0.0, len) * 0.85 + smoothstep(0.0, 0.6, v3) * .3

        color = clamp(color, 0.0, 1.0)

        pixels[i, j] = color

gui = ti.GUI("Canvas", res=(res_x, res_y))

for i in range(100000):
    t = i * 0.03
    render(t)
    gui.set_image(pixels)
    gui.show()

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值