Я относительно новичок в 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 без проблем)
Заранее спасибо