Homework 0: Perlin Nosie

普通的Perlin Noise




import taichi as ti

#ti.init(ti.cpu, debug=True)




CellSize = 0.1

TEX_COUNT = int(2/CellSize)+1

RANDOM_TBL = ti.Vector(2, dt=ti.f32, shape=(TEX_COUNT,TEX_COUNT))

RANDOM3_TBL = ti.Vector(3, dt=ti.f32, shape=(



def rand1dT1d(t:ti.template)->ti.template:


    #ret = ti.sin(t*10+1.546)*143758.5453

    #return ti.abs(ret-int(ret))

    return RANDOM_TBL[t[0], t[1]]


def rand3dT3d(t:ti.template)->ti.template:


    ret = ti.sin(t+0.546)*143758.5453

    return ti.abs(ret-int(ret))


def easeIn(t:ti.template)->ti.template:

    return t*t


def easeOut(t:ti.template)->ti.template:

    return 1-easeIn(1-t)


def easeInOut(t:ti.template)->ti.template:

    easeInValue = easeIn(t)

    easeOutValue = easeOut(t)

    return lerp(easeInValue, easeOutValue, t)

    #return 6*(t**5)-15*(t**4)+10*(t**3)


def lerp(a:ti.template, b:ti.template, t:ti.f32)->ti.template:

    return a*(1-t) + b*t


def gradientNoise(t:ti.template)->ti.f32:

    fraction = t-int(t)

    interpolator = easeInOut(fraction)

    #return fraction.dot(fraction)

    #return fraction[0]

    ft = int(t)

    ct = ti.cast(ti.ceil(t), ti.i32)

    lowerleftd = rand1dT1d(ti.Vector([ft[0], ft[1]]))*2-1


    #return (lowerleftd.dot(ti.Vector([1,1])))/2

    #return lowerleftd[1]

    lowerrightd = rand1dT1d(ti.Vector([ct[0], ft[1]]))*2-1

    upleftd = rand1dT1d(ti.Vector([ft[0], ct[1]]))*2-1

    uprightd = rand1dT1d(ti.Vector([ct[0], ct[1]]))*2-1

    lowleftv = lowerleftd.dot(fraction-ti.Vector([0, 0]))

    lowrightv = lowerrightd.dot(fraction-ti.Vector([1, 0]))

    #-return ti.abs(lowleftv)

    upleftv = upleftd.dot(fraction-ti.Vector([0, 1]))

    uprightv= uprightd.dot(fraction-ti.Vector([1, 1]))

    low = lerp(lowleftv, lowrightv, interpolator[0])

    #return low

    up = lerp(upleftv, uprightv, interpolator[0])

    #return low

    noise = lerp(low, up, interpolator[1])

    return noise


def gradientNoise3D(t:ti.template)->ti.f32:

    fraction = t-int(t)

    interpolator = easeInOut(fraction)

    cellNoiseZ = ti.Vector([0.0,0.0,0.0])

    for z in ti.static(range(2)):

        cellNoiseY = ti.Vector([0.0,0.0,0.0])

        for y in ti.static(range(2)):

            cellNoiseX = ti.Vector([0.0,0.0,0.0])

            for x in ti.static(range(2)):

                cell = int(t) + ti.Vector([x, y, z])

                cellDirection = RANDOM3_TBL[cell[0], cell[1], cell[2]]*2-1

                # cellDirection = rand3dT3d(cell)*2-1

                compareVector = fraction - ti.Vector([x, y, z])

                cellNoiseX[x] = cellDirection.dot(compareVector)

                # return cellDirection.dot(compareVector)

                #return cellNoiseX[x]

            cellNoiseY[y] = lerp(cellNoiseX[0], cellNoiseX[1], interpolator[0])

        cellNoiseZ[z] = lerp(cellNoiseY[0], cellNoiseY[1], interpolator[1])


    noise = lerp(cellNoiseZ[0], cellNoiseZ[1], interpolator[2])

    return noise

    #return previousLinePoint*interpolator + nextLinePoint*(1-interpolator)


def complex_sqr(z):

    return ti.Vector([z[0]**2-z[1]**2,z[1]*z[0]*2])



def paint(t:ti.f32):

    for i,j in pixels:#Parallized over all pixels

        pos = ti.Vector([i,j])

        pixels[i,j]= gradientNoise(pos/n / CellSize) #1-iterations*0.02


def paint3d(t:ti.f32):

    for i,j in pixels:#Parallized over all pixels

        pos = ti.Vector([i,j,t])

        noise = gradientNoise3D(pos/n / CellSize) #1-iterations*0.02

        noise += 0.5

        noise *= 6

        noise = (noise-int(noise))

        if noise < 0.9:

            noise = 0

        pixels[i,j] = noise


def generate_random():

    for i in range(TEX_COUNT):

        for j in range(TEX_COUNT):

            RANDOM_TBL[i,j] = ti.Vector([ti.random(), ti.random()])


    for i in range(TEX_COUNT):

        for j in range(TEX_COUNT):

            for k in range(TEX_COUNT):

                RANDOM3_TBL[i,j, k] = ti.Vector([ti.random(), ti.random(), ti.random()])



for i in range(1000000):

    # paint(i*0.3)

    paint3d((i*0.3) % (n*2))







Wrong usage of ti.template, use ti.template() instead.
Also note that functions doesn’t need to be type-hinted so ti.template() can be removed.

The reason why we don’t support ti.Vector.random may be, it’s hard to know whether to generate on a cube range or unit sphere or unit ball.
@yuanming Will we have ti.Vector.random_cube, ti.Vector.random_unit_3d_surface, ti.Vector.random_unit_3d_solid later? Also found that having ti.mix or ti.clamp can be useful in some cases.

Sorry, I misread it!

It seems noting difference when i switch ti.template to ti.template(), what’s actually happend behind.

I think it’s not intuitive to use function call as param type declare.

Thanks for your reply.