Issue ComputeShader Noise Map

Hello, it’s me again…

today i started with computeshaders and i wonder how they work… i wrote a little sample program that should hopefully output this:

So it is a simple float3 array | XY = Position | Z = 1/0 Terrain or Air
anyway this image below is not the compute shader, it should be the final output.

2594033--181513--mapFilled.PNG

Here is the output from my msBuffer, as u can see it gaves me very weird results…

And this is the workflow:

  1. Fill an float array with the noise results = noiseComputer
  2. Check if noise results r greater then 0
  3. Fill the float3 array with the results XYZ = msComputer
  4. Loop through this array and draw some gizmos

Here r my scripts:

This is the main script.
The “ImprovedPerlinNoise” comes from this little blog: https://scrawkblog.com/category/procedural-mesh/

using UnityEngine;
using System.Collections;
using ImprovedPerlinNoiseProject;

public class Generator : MonoBehaviour
{
    public ComputeShader noiseComputer, msComputer;
    public int S;
    public string seed;

    public Vector3[] positions;

    ComputeBuffer noiseBuffer, msBuffer;
    ImprovedPerlinNoise noise;

    int[,] map;

    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            if (S % 8 != 0)
                throw new System.ArgumentException("Size must be divisible be 8");

            map = new int[S, S];

            noiseBuffer = new ComputeBuffer(S * S, sizeof(float));
            msBuffer = new ComputeBuffer(S * S, sizeof(float));

            int newSeed = (seed == "") ? Random.Range(int.MinValue, int.MaxValue) : seed.GetHashCode();
            noise = new ImprovedPerlinNoise(newSeed);
            noise.LoadResourcesFor3DNoise();

            noiseComputer.SetInt("_Width", S);
            noiseComputer.SetInt("_Height", S);
            noiseComputer.SetFloat("_Frequency", 0.02f);
            noiseComputer.SetFloat("_Lacunarity", 2.0f);
            noiseComputer.SetFloat("_Gain", 0.5f);
            noiseComputer.SetTexture(0, "_PermTable2D", noise.GetPermutationTable2D());
            noiseComputer.SetTexture(0, "_Gradient3D", noise.GetGradient3D());
            noiseComputer.SetBuffer(0, "_Result", noiseBuffer);

            noiseComputer.Dispatch(0, S / 8, S / 8, 1);

            msComputer.SetInt("_Width", S);
            msComputer.SetInt("_Height", S);
            msComputer.SetBuffer(0, "_Map", noiseBuffer);
            msComputer.SetBuffer(0, "_Result", msBuffer);

            msComputer.Dispatch(0, S / 8, S / 8, 1);

            positions = new Vector3[S * S];
            msBuffer.GetData(positions);

            Debug.Log(positions.Length);
        }
    }

    void OnDrawGizmos()
    {
        if(positions != null)
        {
            Gizmos.color = Color.white;

            for (int i = 0; i < positions.Length; i++)
                if(positions[i].z == 1)
                    Gizmos.DrawWireCube(new Vector2(positions[i].x, positions[i].y), new Vector2(0.9f, 0.9f));
        }
    }
}

This is the noiseComputer.

#pragma kernel CSMain

SamplerState _PointRepeat;

Texture2D _PermTable1D, _Gradient2D;

float _Frequency, _Lacunarity, _Gain;

int _Width;

RWStructuredBuffer<float> _Result;

float2 fade(float2 t)
{
    return t * t * t * (t * (t * 6 - 15) + 10);
}

float perm(float x)
{
    return _PermTable1D.SampleLevel(_PointRepeat, float2(x,0), 0).a;
}

float grad(float x, float2 p)
{
    float2 g = _Gradient2D.SampleLevel(_PointRepeat, float2(x*8.0, 0), 0).rg * 2.0 - 1.0;
    return dot(g, p);
}

float inoise(float2 p)
{
    float2 P = fmod(floor(p), 256.0);    // FIND UNIT SQUARE THAT CONTAINS POINT
      p -= floor(p);                      // FIND RELATIVE X,Y OF POINT IN SQUARE.
    float2 f = fade(p);                 // COMPUTE FADE CURVES FOR EACH OF X,Y.

    P = P / 256.0;
    const float one = 1.0 / 256.0;
 
    // HASH COORDINATES OF THE 4 SQUARE CORNERS
      float A = perm(P.x) + P.y;
      float B = perm(P.x + one) + P.y;
    // AND ADD BLENDED RESULTS FROM 4 CORNERS OF SQUARE
      return lerp( lerp( grad(perm(A    ), p ),
                       grad(perm(B    ), p + float2(-1, 0) ), f.x),
                 lerp( grad(perm(A+one), p + float2(0, -1) ),
                       grad(perm(B+one), p + float2(-1, -1)), f.x), f.y);
                        
}

// fractal sum, range -1.0 - 1.0
float fBm(float2 p, int octaves)
{
    float freq = _Frequency, amp = 0.5;
    float sum = 0; 
    for(int i = 0; i < octaves; i++)
    {
        sum += inoise(p * freq) * amp;
        freq *= _Lacunarity;
        amp *= _Gain;
    }
    return sum;
}

// fractal abs sum, range 0.0 - 1.0
float turbulence(float2 p, int octaves)
{
    float sum = 0;
    float freq = _Frequency, amp = 1.0;
    for(int i = 0; i < octaves; i++)
    {
        sum += abs(inoise(p*freq))*amp;
        freq *= _Lacunarity;
        amp *= _Gain;
    }
    return sum;
}

// Ridged multifractal, range 0.0 - 1.0
// See "Texturing & Modeling, A Procedural Approach", Chapter 12
float ridge(float h, float offset)
{
    h = abs(h);
    h = offset - h;
    h = h * h;
    return h;
}

float ridgedmf(float2 p, int octaves, float offset)
{
    float sum = 0;
    float freq = _Frequency, amp = 0.5;
    float prev = 1.0;
    for(int i = 0; i < octaves; i++)
    {
        float n = ridge(inoise(p*freq), offset);
        sum += n*amp*prev;
        prev = n;
        freq *= _Lacunarity;
        amp *= _Gain;
    }
    return sum;
}

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    float2 uv = float2(id.xy);

    //uncomment this for fractal noise
    float n = fBm(uv, 4);

    //uncomment this for turbulent noise
    //float n = turbulence(uv, 4);

    //uncomment this for ridged multi fractal
    //float n = ridgedmf(uv, 4, 1.0);
 
    _Result[id.x + id.y * _Width] = n;

}

And finally the msComputer:

#pragma kernel CSMain

int _Width, _Height;

StructuredBuffer<float> _Map;
RWStructuredBuffer<float3> _Result;

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    if(id.x >= _Width - 1 - 1) return;
    if(id.y >= _Height - 1 - 1) return;
 
    int flagIndex = _Map[id.x + id.y * _Width];
    if(flagIndex == 0) return;

    _Result[id.x + id.y * _Width] = float3(id.x, id.y, 1);
}

I guess the problem could be the index of the linear float array coming from the noiseBuffer… but im not sure because i can simulate a non linear array by doing this:

int index = id.x + id.y * _Width;
float value = noiseArray[index];

Thanks to everyone who can help me with this tricky problem!
Cheers :slight_smile:

ok i solved it myself… anyway thanks for reading/watching my problems.

here r some performance stats…

noiseMap[2048, 2048] = 421ms

noiseMap[64, 64] = 2ms
2594266--181541--noiseSmall.PNG

Have a wonderful day :wink:
BR, Michael

“ImprovedPerlinNoise” comes from this little blog: https://scrawkblog.com/category/procedural-mesh/

The Site is down, Where can I find another one?