• Chapter 4 Perlin Noise


    为了获得炫酷的坚固纹理效果,大部分人使用某种形式的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)))
    

      

      

  • 相关阅读:
    IOS 网络编程 + 后台保持连接
    iOS 通过代码关闭应用程序
    iOS 委托和协议区别和联系
    对于WIFI版ipad(无GPS芯片)定位功能的释疑
    iOS单例
    svn不能添加.a文件的解决方法
    mac下SVN上传.a静态库文件
    iOS7 兼容及部分细节
    app被Rejected 的各种原因翻译
    iOS 沙盒购买,弹出“需要验证”,“继续登录”的问题?
  • 原文地址:https://www.cnblogs.com/TooYoungTsukasa/p/9161789.html
Copyright © 2020-2023  润新知