1

我目前正在尝试在 CG 着色器中创建 3D 单纯形噪声实现以实现统一。我决定使用这个最初用 C++ 编写的实现并将其移植到 CG,因为它们很相似。

我决定提供排列和梯度向量作为纹理,因此它们可以很容易地在代码中使用。一切正常,除了每个单纯形边缘的地方。这会导致我想修复的不可接受的视觉伪影。

神器

注意纹理上的虚线。我认为这可能是舍入/地板的问题,但我无法弄清楚是哪个操作导致了这种情况。我试过玩地板,但没有任何帮助。

这是我的着色器代码:

Shader "Custom/PerlinNoise" {

Properties {
        _Permutation ("RandomVector (RGB)", 2D) = "white" { }
        _Gradient3 ("GradientVector (RGB)", 2D) = "white" { }
    }

    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            uniform sampler2D _Permutation;
            uniform sampler2D _Gradient3;

            //Get the i-th int3 gradient. x,y,z in range [-1, 1]
            int3 grad3(int i)
            {
                float2 pos;
                pos.x = i / 16.0;
                pos.y = 0;
                fixed3 tx = tex2D(_Gradient3, pos);
                tx = tx * 2.0 - 1;
                return tx;
            }

            //Get the i-th permutation. Result in range [0-255]
            int p(int i)
            {
                float2 pos;
                pos.x = i / 256.0;
                pos.y = 0.5;
                return tex2D(_Permutation, pos).r * 256;
            }

            float dt(const int3 g, float x, float y, float z) 
            { 
                return g.x*x + g.y*y + g.z*z; 
            }

            int fastfloor(const float x) 
            { 
                return x > 0 ? (int) x : (int) x - 1; 
            }

            //Almost a copy-paste from the original C++ code
            float simplex(const float x, const float y, const float z) 
            {
                float n0, n1, n2, n3; // Noise contributions from the four corners

                // Skew the input space to determine which simplex cell we're in
                float F3 = 1.0/3.0;
                float s = (x+y+z)*F3; // Very nice and simple skew factor for 3D

                int i = fastfloor(x+s);
                int j = fastfloor(y+s);
                int k = fastfloor(z+s);

                float G3 = 1.0/6.0; // Very nice and simple unskew factor, too
                float t = (i+j+k)*G3;
                float X0 = i-t; // Unskew the cell origin back to (x,y,z) space
                float Y0 = j-t;
                float Z0 = k-t;
                float x0 = x-X0; // The x,y,z distances from the cell origin
                float y0 = y-Y0;
                float z0 = z-Z0;

                // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
                // Determine which simplex we are in.
                int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
                int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords

                if(x0>=y0) {
                    if(y0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
                    else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
                    else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order
                }
                else { // x0<y0
                    if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
                    else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
                    else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
                }

                // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
                // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
                // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
                // c = 1/6.
                float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
                float y1 = y0 - j1 + G3;
                float z1 = z0 - k1 + G3;
                float x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords
                float y2 = y0 - j2 + 2.0*G3;
                float z2 = z0 - k2 + 2.0*G3;
                float x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords
                float y3 = y0 - 1.0 + 3.0*G3;
                float z3 = z0 - 1.0 + 3.0*G3;

                // Work out the hashed gradient indices of the four simplex corners
                int ii = i & 255;
                int jj = j & 255;
                int kk = k & 255;
                int gi0 = p(ii+p(jj+p(kk))) % 12;
                int gi1 = p(ii+i1+p(jj+j1+p(kk+k1))) % 12;
                int gi2 = p(ii+i2+p(jj+j2+p(kk+k2))) % 12;
                int gi3 = p(ii+1+p(jj+1+p(kk+1))) % 12;

                // Calculate the contribution from the four corners
                float t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
                if(t0<0) n0 = 0.0;
                else {
                    t0 *= t0;
                    n0 = t0 * t0 * dt(grad3(gi0), x0, y0, z0);
                }

                float t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
                if(t1<0) n1 = 0.0;
                else {
                    t1 *= t1;
                    n1 = t1 * t1 * dt(grad3(gi1), x1, y1, z1);
                }

                float t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
                if(t2<0) n2 = 0.0;
                else {
                    t2 *= t2;
                    n2 = t2 * t2 * dt(grad3(gi2), x2, y2, z2);
                }

                float t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
                if(t3<0) n3 = 0.0;
                else {
                    t3 *= t3;
                    n3 = t3 * t3 * dt(grad3(gi3), x3, y3, z3);
                }

                // Add contributions from each corner to get the final noise value.
                // The result is scaled to stay just inside [0,1)
                return 16.0*(n0 + n1 + n2 + n3) + 0.5;
            }

            float4 frag(v2f_img i) : SV_Target 
            {
                float v = simplex(i.uv.x * 4, i.uv.y * 4, _Time);
                return fixed4(v, v, v, 1.0);
            }
            ENDCG
        }
    }
}

以下是在着色器中模仿常量数据的图像:

梯度 研究生3

排列 向量

请记住将它们分配给着色器中的适当属性。

4

0 回答 0