码迷,mamicode.com
首页 > 其他好文 > 详细

Chapter 4 Perlin Noise

时间:2018-06-10 12:02:25      阅读:358      评论:0      收藏:0      [点我收藏+]

标签:near   for   修改   __init__   rate   ext   inter   lin   target   

为了获得炫酷的坚固纹理效果,大部分人使用某种形式的Perlin噪声, 这些都是以他们的发明家 Ken Perlin的名字命名的。 Perlin纹理不会像这样返回白色噪点:

技术分享图片

相反,它会返回类似于模糊白噪声的东西:

技术分享图片


  Perlin噪声的一个关键部分是它是可重复的:它将3D点作为输入并始终返回相同的随机数。附近的点返回相似的数字。Perlin噪声的另一个重要部分是它简单快速,所以它通常以黑客身份进行。根据Andrew Kensler的描述,我将逐步构建这种攻击。

  我们可以用一个随机数字的3D数组拼接所有的空间,并将它们用于块中。在重复明确的地方你会得到一些块状物:

  我们只是使用某种散列来搅乱这个,而不是拼贴。这有一些支持代码来完成这一切:

  

from math import floor
from random import random
class perlin:
    def __init__(self):
        self.ranfloat=perlin_generate()
        self.perm_x=perlin_generate_perm()
        self.perm_y=perlin_generate_perm()
        self.perm_z=perlin_generate_perm()
    def noise(self,p):
        u=p.x()-floor(p.x())
        v=p.y()-floor(p.y())
        w=p.z()-floor(p.z())
        i=int(4*p.x())&255
        j=int(4*p.y())&255
        k=int(4*p.z())&255
        return self.ranfloat[self.perm_x[i]^self.perm_y[j]^self.perm_z[k]]
def perlin_generate():
    p=[0.0 for j in range(256)]
    for i in range(0,256,1):
        p[i]=random()
    return p
def permute(p,n):
    for i in range(n-1,0,-1):
        target=int(random()*(i+1))
        tmp=p[i]
        p[i]=p[target]
        p[target]=tmp
    return ;
def perlin_generate_perm():
    p=p=[0 for j in range(256)]
    for i in  range(0,256,1):
        p[i]=i
    permute(p,256)
    return p

  现在,如果我们创建一个实际的纹理,它使这些浮点数在0和1之间并创建灰色颜色:

from texture import texture
from rayMath import vec3
from perlin import perlin
class noise_texture(texture):
    def __init__(self):
        self.noise=perlin()
    def value(self,u,v,p):
        return vec3(1,1,1)*self.noise.noise(p)

  加上散列之后,的确如我们所料的那样混乱:

技术分享图片

  为了使之更平滑,我们使用插值进行修改。

 

class perlin:
    def noise(self,p):
        u=p.x()-floor(p.x())
        v=p.y()-floor(p.y())
        w=p.z()-floor(p.z())
        i=floor(p.x())
        j=floor(p.y())
        k=floor(p.z())
        c=[[[0.0 for a in range(2)] for b in range(2)] for c in range(2)]
        for di in range(2):
            for dj in range(2):
                for dk in range(2):
                    temp=self.ranfloat[self.perm_x[i+di&255]^self.perm_y[j+dj&255]^self.perm_z[k+dk&255]]
                    c[di][dj][dk]=temp
        return trilinear_interp(c,u,v,w)

def trilinear_interp(c,u,v,w):
    accum=0
    for i in range(2):
        for j in range(2):
            for k in range(2):
                accum=accum+(
                    i*u+(1-i)*(1-u))*(
                    j*v+(1-j)*(1-v))*(
                    k*w+(1-k)*(1-w))*(c[i][j][k])
    return accum

  技术分享图片

  更好了,但有明显的网格效果。 其中一些是马赫带,一种颜色的线性内插的知名人造物。 一个标准的技巧是使用hermite立方来舍去插值:

  

    def noise(self,p):
        u=p.x()-floor(p.x())
        v=p.y()-floor(p.y())
        w=p.z()-floor(p.z())
        u=u*u*(3-2*u)
        v=v*v*(3-2*v)
        w=w*w*(3-2*w)
        i=floor(p.x())
        j=floor(p.y())
        k=floor(p.z())

  得到了看起来更平滑的效果:

  技术分享图片

  还是有点低频。 我们可以缩放输入点以使其变化更快:

class noise_texture(texture):
    def __init__(self,sc):
        self.noise=perlin()
        self.scale=sc
    def value(self,u,v,p):
        return vec3(1,1,1)*self.noise.noise(self.scale*p)

  技术分享图片

  

    def turb(self,p, depth=7):
        accum = 0
        temp_p = p
        weight = 1.0
        for i in range(depth):
            accum = accum + weight *self.noise(temp_p)
            weight=weight*0.5
            temp_p=temp_p*2
        return fabs(accum)

    def noise(self,p):
        u=p.x()-floor(p.x())
        v=p.y()-floor(p.y())
        w=p.z()-floor(p.z())
        u=u*u*(3-2*u)
        v=v*v*(3-2*v)
        w=w*w*(3-2*w)
        i=floor(p.x())
        j=floor(p.y())
        k=floor(p.z())
        c=[[[0.0 for a in range(2)] for b in range(2)] for c in range(2)]
        for di in range(2):
            for dj in range(2):
                for dk in range(2):
                    temp=self.ranvec[self.perm_x[i+di&255]^self.perm_y[j+dj&255]^self.perm_z[k+dk&255]]
                    c[di][dj][dk]=temp
        return perlin_interp(c,u,v,w)
    
    def perlin_interp(c,u,v,w):
        uu = u * u * (3 - 2 * u)
        vv = v * v * (3 - 2 * v)
        ww = w * w * (3 - 2 * w)
        accum=0
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    weight_v=vec3(u-i,v-j,w-k)
                    accum=accum+(
                        i*uu+(1-i)*(1-uu))*(
                        j*vv+(1-j)*(1-vv))*(
                        k*ww+(1-k)*(1-ww))*(c[i][j][k].dot(weight_v))
        return accum

  

class noise_texture(texture):
    def __init__(self,sc):
        self.noise=perlin()
        self.scale=sc
    def value(self,u,v,p):
        return vec3(1,1,1)*0.5*(1+sin(self.scale*p.z()+10*self.noise.turb(p)))

  

  技术分享图片

 

Chapter 4 Perlin Noise

标签:near   for   修改   __init__   rate   ext   inter   lin   target   

原文地址:https://www.cnblogs.com/TooYoungTsukasa/p/9161789.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!