3

I'm relatively new to HLSL and shaders in general, I've been trying to get a perlin noise shader working and I think I'm almost there, however the rendered noise is covered in banding or seam artifacts and I can't figure out why. heres a picture of the problem http://www.sharpoblunto.com/resources/news/perlin.jpg

I'm using c++ and directx 9, I'm generating a noise permutation texture and a gradient texture as inputs to the shader on the CPU using the following code

IDirect3DTexture9 *ImprovedPerlinNoise::GeneratePermTexture(IDirect3DDevice9 *device)
{
    IDirect3DTexture9 *tex;
    device->CreateTexture(256,256,1,NULL,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&tex,NULL);

    D3DSURFACE_DESC surfaceDesc;
    tex->GetLevelDesc(0,&surfaceDesc);

    D3DLOCKED_RECT lockedRect;
    tex->LockRect(0,&lockedRect,NULL,NULL);

    DWORD *imageData = (DWORD*)lockedRect.pBits;
    for (int y=0;y<surfaceDesc.Height;++y)
    {
        for (int x=0;x<surfaceDesc.Width;++x)
        {
            int A = Perm2d(x) + y;
            int AA = Perm2d(A);
            int AB = Perm2d(A + 1);
            int B = Perm2d(x + 1) + y;
            int BA = Perm2d(B);
            int BB = Perm2d(B + 1);
            int index =y*lockedRect.Pitch / 4 + x;
            imageData[index] = D3DCOLOR_ARGB(BB,BA,AB,AA);
        }
    }

    tex->UnlockRect(0);
    return tex;
}

IDirect3DTexture9 *ImprovedPerlinNoise::GenerateGradientTexture(IDirect3DDevice9 *device)
{
    IDirect3DTexture9 *tex;
    device->CreateTexture(256,1,1,NULL,D3DFMT_Q8W8V8U8,D3DPOOL_MANAGED,&tex,NULL);

    D3DSURFACE_DESC surfaceDesc;
    tex->GetLevelDesc(0,&surfaceDesc);

    D3DLOCKED_RECT lockedRect;
    tex->LockRect(0,&lockedRect,NULL,NULL);

    DWORD *imageData = (DWORD*)lockedRect.pBits;
    for (int y=0;y<surfaceDesc.Height;++y)
    {
        for (int x=0;x<surfaceDesc.Width;++x)
        {
            int index =y*lockedRect.Pitch / 4 + x;
            int q = _gradients[_permutation[x] % 16][0] * 127;
            int w = _gradients[_permutation[x] % 16][1] * 127;
            int v = _gradients[_permutation[x] % 16][2] * 127;
            int u = 1 * 127;

            imageData[index] = D3DCOLOR_ARGB(q,w,v,u);

        }
    }

    tex->UnlockRect(0);
    return tex;
}

The actual shader code is as follows

float4x4 World;
float4x4 View;
float4x4 Projection;

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float2 texCoord : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 texCoord : TEXCOORD0;
    float4 wPosition: TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
    output.wPosition = mul(input.Position, World);
    output.texCoord = input.texCoord;

    return output;
}

texture permTexture2d;
texture permGradTexture;

sampler permSampler2d = sampler_state 
{
    texture = <permTexture2d>;
    AddressU  = Wrap;       
    AddressV  = Wrap;
    MAGFILTER = POINT;
    MINFILTER = POINT;
    MIPFILTER = NONE;   
};

sampler permGradSampler = sampler_state 
{
    texture = <permGradTexture>;
    AddressU  = Wrap;       
    AddressV  = Clamp;
    MAGFILTER = POINT;
    MINFILTER = POINT;
    MIPFILTER = NONE;
};

float3 fade(float3 t)
{
    return t * t * t * (t * (t * 6 - 15) + 10); // new curve
}
float4 perm2d(float2 p)
{
    return tex2D(permSampler2d, p);
}
float gradperm(float x, float3 p)
{
    float3 sample = tex1D(permGradSampler, x);
    return dot(sample, p);
}

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

    P = P / 256.0;
    const float one = 1.0 / 256.0;

    // HASH COORDINATES OF THE 8 CUBE CORNERS
    float4 AA = perm2d(P.xy) + P.z;

    // AND ADD BLENDED RESULTS FROM 8 CORNERS OF CUBE
    return lerp( lerp( lerp( gradperm(AA.x, p ),  
                            gradperm(AA.z, p + float3(-1, 0, 0) ), f.x),
                    lerp( gradperm(AA.y, p + float3(0, -1, 0) ),
                            gradperm(AA.w, p + float3(-1, -1, 0) ), f.x), f.y),

                    lerp( lerp( gradperm(AA.x+one, p + float3(0, 0, -1) ),
                            gradperm(AA.z+one, p + float3(-1, 0, -1) ), f.x),
                    lerp( gradperm(AA.y+one, p + float3(0, -1, -1) ),
                            gradperm(AA.w+one, p + float3(-1, -1, -1) ), f.x), f.y), f.z);
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    float3 p = input.wPosition;
    float inz = inoise(p)*0.5+0.5;
    return float4(inz,inz,inz,1);
}

technique PerlinNoise
{
    pass Pass1
    {
    VertexShader = compile vs_3_0 VertexShaderFunction();
    PixelShader = compile ps_3_0 PixelShaderFunction();
    }
}

If anyone could point me in the right direction that would be fantastic, I really would like to be able to generate 3d noise in hlsl as its so much faster than doing it on the CPU (I have a working CPU implementation but it takes around 10 seconds to render a perlin cubemap for an object, the shader as I have it renders at 60FPS no problems at all)

Thanks in advance

Glenn
  • 111
  • 3
  • 3
    Found the problem, turned out to be the c++ code I was using to generate the permutation and gradient textures, I was packing the color values into the texture data in the wrong order. For the permutation texture I was doing this `imageData[index] = D3DCOLOR_ARGB(BB,BA,AB,AA);` when it should have been `imageData[index] = D3DCOLOR_ARGB(BB,AA,AB,BA);` Likewise for the gradient texture I was doing this `imageData[index] = D3DCOLOR_ARGB(q,w,v,u);` when it should have been `imageData[index] = D3DCOLOR_ARGB(u,v,w,q);` – Glenn Sep 02 '11 at 04:46
  • 3
    Glenn, you can answer your own question (i.e., enter the above as an answer.) Not only is it fine in terms of etiquette to do so, it helps the site, since other people with a similar problem can easily see that there is a correct solution. – David Sep 11 '12 at 12:54

0 Answers0