Jump to content
  • Advertisement
Sign in to follow this  
gigaworm

Simplex Noise Texture Lookups?

This topic is 1851 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I've been really struggling to find information on how to generate a terrain using noise on the HLSL. Currently I have a terrain generated on the gpu using a couple of octaves of simplex noise but it runs a little slow. To speed it up I am trying to use a texture for the permutation table, but I cant find much information on it. First of all, I'm not sure how to fill the texture with values from 0-255, so I'm currently doing this on the cpu side and passing it in as a shader resource:

 

int index = 0;
int data[256];
for( int i = 0; i < 256; i++ )
{
    data = ( p[index] );
    index++;
}
 

Would this work the same way as an array filled from 0-255? Or am I doing it completely wrong?

 

Then in the simplex noise function in the effect file, I dont understand how to use it as the permutation table. Normally I just use:

uint ii = i & 255;
uint jj = j & 255;
uint gi0 = perm[ii+perm[jj]] % 12; 
uint gi1 = perm[ii+i1+perm[jj+j1]] % 12; 
uint gi2 = perm[ii+1+perm[jj+1]] % 12;  
 

 

Where perm was the array, to get the hashed gradients, but with the texture I nee to use:

 

PermTex.SampleLevel( SampleType, ??, 0 )

Any help would be amazing.

Edited by gigaworm

Share this post


Link to post
Share on other sites
Advertisement
Simplex noise on the GPU. Nice.

Texture sampling uses normalized co-ordinates [0..1], in your case something like ii / 256.0 (make sure to use a float division!). You probably also want to set your sampler to point sampling and wrap, similar to the example at the bottom of the SampleLevel documentation. The texture format can be any of single channel UInt, e.g. R8_UInt - just make sure they match the type you're feeding from the application side (you're currently using int, so rather R32_SInt/UInt).

Share this post


Link to post
Share on other sites

I do this by generating a simplex based texture as part of my compilation cycyle and use the texture in the game engine just like any other texture. In the shader I sample the noise texture using Wrap and just use the camera world position XZ, suitably scaled up or down depending on the density of the nosie required, as the texture UV parameter. Because Vertex Texture Fetch only supports Point sampling, you need to roll your own Wrap method. (at least this is true for XNA4 and Vector4 textures - other implementations might not have that restriction).

Edited by PhillipHamlyn

Share this post


Link to post
Share on other sites

So I need to wrap the texture when I create it to a 512 texture? Also, I used the texture I created as the texture for the terrain to make sure it was being passed in correctly and for some reason the only value that will output some form of texture is DXGI_FORMAT_R8_TYPELESS, otherwise I just get a black screen. 

 

So for what to use as the texture parameter, something like this?

 

 

 

float ii = (i & 255)/256;
float jj = (j & 255)/256;


float gi0 = PermTex.SampleLevel( SampleType, ii+ (PermTex.SampleLevel( SampleType, jj, 0 )), 0 ) ;
 

 

Edited by gigaworm

Share this post


Link to post
Share on other sites

Ok, I need to qualify my earlier reply; In XNA4 Vector4 textures can only use Point Sampling in Vertex Shaders. I have no information on whether this is different for SlimDX or other frameworks, so you might be able to rely on the sampler to do the Wrap for you.

 

So I vary the height of the vertex like this;

// Now sample the noise texture to add some variation into the nearby tiles.
float4 noiseCoordinates = (float4)0;
noiseCoordinates.x = heightMapUV.x * (Param_HeightMapWorldSize ) * 10;
noiseCoordinates.y = heightMapUV.y * (Param_HeightMapWorldSize ) * 10; 
noiseCoordinates.z = 0.0f;
noiseCoordinates.w = 0.0f; // First mip map
		
float4 noiseHeight = tex2Dlod(VertexNoiseTextureSampler, noiseCoordinates);
worldPosition.y += (noiseHeight - 0.5f) * 2;

Share this post


Link to post
Share on other sites
Please apologize for giving bad advice earlier. You mentioning a TYPELESS format made me curious. I was wrong: One cannot sample from S/UInt formats, as it seems:

[6056] D3D11: ERROR: ID3D11DeviceContext::Draw: The Shader Resource View in slot 0 of the Pixel Shader unit is using the Format (R8_UINT). This format does not support 'Sample', 'SampleLevel', 'SampleBias' or 'SampleGrad', at least one of which may being used on the Resource by the shader. This mismatch is invalid if the shader actually uses the view (e.g. it is not skipped due to shader code branching). [ EXECUTION ERROR #371: DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_UNSUPPORTED ]

So, instead:
  • use a format you can sample from, e.g. a _FLOAT type. Oh, and by float division I meant ii / 256.0. You will get bad results with ii / 256 wink.png
  • Use Load instead of Sample and wrap manually.
Always make sure your normalization/indexing is sane: texture sampling uses normalized co-ordinates, Load uses texel, i.e. integer, co-ordinates.

Concerning wrapping. Either you wrap manually (your & 255), or you let the sampler do it. No need to do both. For Load, of course, you need to wrap manually. Alternatively - something I have seen in some Perlin implementation - is to use a bigger array (and duplicate the data) so you can save you the wrapping (Is this what you meant with the 512 wide texture ?). Edited by unbird

Share this post


Link to post
Share on other sites

Hey, thanks for all your help, I'm still struggling to get this working. I'm now using DXGI_FORMAT_R16_FLOAT and that shows up when using it as a texture for the terrain so I know it has been created correctly, but when I try SampleLevel or Load, no matter what a pass in as co-ordinates it still outputs the terrain as if gi0,2 and 3 where equal to zero. I've made the texture 512 wide, and put divided ii by 256.0 and still nothing. I also tried converting the texture to a 1D texture instead and still nothing. Any ideas?

Share this post


Link to post
Share on other sites

Ok, heres my the code to set up the texture:

 

static int p[] = {151,160,137...131};
int index = 0;
float data[512];
float data2[256];

for( int i = 0; i < 256; i++ )
{
   data2 = ( p[index] );
   index++;
}
for(int i=0;i<256;i++)
{
data = data2;
}
for(int i=0;i<256;i++)
{
data[i+256] = data2;
}


ID3D11Texture1D* PermTexture = NULL; 
ID3D11ShaderResourceView* PermTextureSRV = NULL;
D3D11_TEXTURE1D_DESC desc;
desc.Width = 512;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format =  DXGI_FORMAT_R16_FLOAT; 
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA dataDesc;
dataDesc.pSysMem = data;
dataDesc.SysMemPitch = 512;
device->CreateTexture1D( &desc, &dataDesc, &PermTexture );

D3D11_SHADER_RESOURCE_VIEW_DESC descSRV;
ZeroMemory( &descSRV, sizeof( descSRV ) );
descSRV.Format = DXGI_FORMAT_R16_FLOAT;
descSRV.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
descSRV.Texture1D.MipLevels = 1;
descSRV.Texture1D.MostDetailedMip = 0;
device->CreateShaderResourceView( PermTexture, &descSRV, &PermTextureSRV );

deviceContext->PSSetShaderResources(0, 1, &PermTextureSRV); 

And then in the shader I have

 

 

 

Texture1D<float>   tex : register(t0); 


SamplerState SampleType
{
    Filter = MIN_MAG_MIP_POINT;
    AddressU = Wrap;
    AddressV = Wrap;
};


float test = tried lots of values here;


float gi0 = tex.SampleLevel( SampleType, test, 0 ) ;
 

 

 

Share this post


Link to post
Share on other sites

R16_FLOAT is a half-float, but you're initualizing the texture with floats, which would be R32_FLOAT.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!