I'm trying to program a Compute-Shader Perlin Noise code based on a working C# code.
The problem is that i only got smooth dots.
Left C# Working, Right Compute-Shader
with this values for both
If i lower the frequency the dots get bigger:
This is the code i'm using
#pragma kernel CSMain
RWTexture2D<float> Result;
RWStructuredBuffer<float> resfloat;
float res;
float frequency;
float octaves;
float lacunarity;
float persistence;
StructuredBuffer<float3> gradients3D;
StructuredBuffer<int> hash;
float lerp(float v0, float v1, float t);
float Dot(float3 g, float x, float y, float z);
float Smooth(float t);
float Perlin3D(float3 v, float frequency);
float noise(float3 v, float frequency, int octaves, float lacunarity, float persistence);
int hashMask = 255;
int gradientsMask3D = 15;
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
float3 v = float3(id.x, id.y, id.z) / res;
float h = 0.0;
h = noise(v, frequency, octaves, lacunarity, persistence);
Result[id.xy] = float4(h, 0, 0, 0);
resfloat[id.x + id.y * res] = h;
}
float lerp(float v0, float v1, float t) {
return v0 + t * (v1 - v0);
}
float Smooth(float t) {
return t * t * t * (t * (t * (float) 6 - (float) 15) + (float) 10);
}
float Perlin3D(float3 v, float frequency) {
v *= frequency;
int ix0 = (int) floor(v.x);
int iy0 = (int) floor(v.y);
int iz0 = (int) floor(v.z);
float tx0 = v.x - ix0;
float ty0 = v.y - iy0;
float tz0 = v.z - iz0;
float tx1 = tx0 - (float) 1;
float ty1 = ty0 - (float) 1;
float tz1 = tz0 - (float) 1;
ix0 &= hashMask;
iy0 &= hashMask;
iz0 &= hashMask;
int ix1 = ix0 + (float) 1;
int iy1 = iy0 + (float) 1;
int iz1 = iz0 + (float) 1;
int h0 = hash[ix0];
int h1 = hash[ix1];
int h00 = hash[h0 + iy0];
int h10 = hash[h1 + iy0];
int h01 = hash[h0 + iy1];
int h11 = hash[h1 + iy1];
float3 g000 = gradients3D[hash[h00 + iz0] & gradientsMask3D];
float3 g100 = gradients3D[hash[h10 + iz0] & gradientsMask3D];
float3 g010 = gradients3D[hash[h01 + iz0] & gradientsMask3D];
float3 g110 = gradients3D[hash[h11 + iz0] & gradientsMask3D];
float3 g001 = gradients3D[hash[h00 + iz1] & gradientsMask3D];
float3 g101 = gradients3D[hash[h10 + iz1] & gradientsMask3D];
float3 g011 = gradients3D[hash[h01 + iz1] & gradientsMask3D];
float3 g111 = gradients3D[hash[h11 + iz1] & gradientsMask3D];
float v000 = dot(g000, float3(tx0, ty0, tz0));
float v100 = dot(g100, float3(tx1, ty0, tz0));
float v010 = dot(g010, float3(tx0, ty1, tz0));
float v110 = dot(g110, float3(tx1, ty1, tz0));
float v001 = dot(g001, float3(tx0, ty0, tz1));
float v101 = dot(g101, float3(tx1, ty0, tz1));
float v011 = dot(g011, float3(tx0, ty1, tz1));
float v111 = dot(g111, float3(tx1, ty1, tz1));
float tx = Smooth(tx0);
float ty = Smooth(ty0);
float tz = Smooth(tz0);
return lerp(
lerp(lerp(v000, v100, tx), lerp(v010, v110, tx), ty),
lerp(lerp(v001, v101, tx), lerp(v011, v111, tx), ty),
tz);
}
float noise(float3 v, float frequency, int octaves, float lacunarity, float persistence)
{
float sum = Perlin3D(v, frequency);
float amplitude = 1;
float range = 1;
for (int o = 1; o < octaves; o++) {
frequency *= lacunarity;
amplitude *= persistence;
range += amplitude;
sum += Perlin3D(v, frequency) * amplitude;
}
return sum / range;
}
And this is the C# code that calls the shader
I already checked that the StructuredBuffer
(gradients3D and hash), and the float
params are correctly loaded .
Any ideas?
The problem was that for some reason, when the function Perlin3D
, used hashMask
and gradientsMask3D
, they had a 0
.
So i moved the definition to the function:
float Perlin3D(float3 v, float frequency)
{
int hashMask = 255;
int gradientsMask3D = 15;
v *= frequency;
int ix0 = (int) floor(v.x);