Reputation: 3065
I'm currently trying to create 3D simplex noise implementation in CG shader for unity. I decided to use this implementation that is originally written in C++ and port it to CG, since they are simmilar.
I've decided to provide permutation and gradient vector as textures, so they can be easily used in code. Everything works fine, except the places that are at the edges of each simplex. This leads to inacceptable visual artifacts that I'd like to fix.
Notice the dotted lines on the texture. I thought it might be a problem with rounding/flooring but I can't figure out which operation causes this. I've tried to play around with the floorings, but nothing helps.
Here is my shader code:
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
}
}
}
And here are the images that immitate constant data in shader:
Remember to assign them to appropiate properties in shader.
Upvotes: 1
Views: 492