Проблема генерации перлин-шума с помощью HLSL-шейдера - PullRequest
2 голосов
/ 01 сентября 2011

Я относительно новичок в HLSL и шейдерах в целом, я пытался заставить работать шейдер перлин-шума, и я думаю, что я почти на месте, однако визуализированный шум покрыт артефактами полос или швов, и я могу не понимаю почему. вот картина проблемы http://www.sharpoblunto.com/resources/news/perlin.jpg

Я использую c ++ и directx 9, я генерирую текстуру перестановки шума и градиентную текстуру в качестве входных данных для шейдера в ЦП, используя следующий код

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;
}

Фактический код шейдера выглядит следующим образом

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();
    }
}

Если бы кто-нибудь мог указать мне правильное направление, которое было бы фантастическим, я действительно хотел бы иметь возможность генерировать 3d-шум в hlsl, так как он намного быстрее, чем делать это на CPU (у меня есть работающая реализация CPU, но это рендеринг кубической карты perlin для объекта занимает около 10 секунд, шейдер, который у меня есть, рендерит со скоростью 60FPS без проблем)

Заранее спасибо

...