Jump to content

  • Log In with Google      Sign In   
  • Create Account

We need your feedback on a survey! Each completed response supports our community and gives you a chance to win a $25 Amazon gift card!


Bizarre Terrain Glitch


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
2 replies to this topic

#1 jsuffolk   Members   -  Reputation: 319

Like
0Likes
Like

Posted 23 May 2013 - 07:55 PM

I have a planet terrain shader that perturbs vertex positions by using a 3D fractal noise lookup on a sphere as the heightmap. It works perfectly 99.9% of the time except for these bizarre glitch vertices that occasionally appear. It looks like a spike in the middle of the otherwise normal mesh.

 

I've narrowed it down to the trilinear texture lookups into the noise. The glitch always only affects a single vertex, smaller than a texel in size. It occurs consistently for the same position lookup in the texture

 

Annoyingly, my fractal lookup is pretty basic and after looking over this code and trying dozens of things I remain stumped to the cause. I suspect the problem must be some sort of glitch in the vertex shader trilinear filtering; I see few other possibilities at this point. Anyway, here's some pics of the glitch and the relevant code for the vertex shader (I omit the pixel shader for brevity).

 

#define textureSize 80.0
#define halfTexelSize 0.00625
#define texelSize 0.0125

texture NoiseRealVertex;
sampler3D NoiseRealVertexSampler = sampler_state {
    Texture = <NoiseRealVertex>;
	AddressU = WRAP;
	AddressV = WRAP;
	AddressW = WRAP;
	MinFilter = Point;
	MagFilter = Point;
	MipFilter = Point;
};

// Vertex Noise Functions
float4 tex3D_trilinear(float3 t) 
{ 
	t -= halfTexelSize.xxx;
	float3 f = frac(t * textureSize);
	float4 x = float4(t, 0);

	float4 t000 = tex3Dlod(NoiseRealVertexSampler, x);
	float4 t100 = tex3Dlod(NoiseRealVertexSampler, x + float4(texelSize, 0, 0, 0)); 
	float4 t010 = tex3Dlod(NoiseRealVertexSampler, x + float4(0, texelSize, 0, 0)); 
	float4 t110 = tex3Dlod(NoiseRealVertexSampler, x + float4(texelSize, texelSize, 0, 0)); 
	float4 t001 = tex3Dlod(NoiseRealVertexSampler, x + float4(0, 0, texelSize, 0)); 
	float4 t101 = tex3Dlod(NoiseRealVertexSampler, x + float4(texelSize, 0, texelSize, 0)); 
	float4 t011 = tex3Dlod(NoiseRealVertexSampler, x + float4(0, texelSize, texelSize, 0)); 
	float4 t111 = tex3Dlod(NoiseRealVertexSampler, x + float4(texelSize, texelSize, texelSize, 0)); 

	return lerp(
		lerp(
			lerp(t000, t100, f.x), 
			lerp(t010, t110, f.x),
		f.y),
		lerp(
			lerp(t001, t101, f.x), 
			lerp(t011, t111, f.x),
		f.y)
	, f.z);
}

Attached Thumbnails

  • With Patch Lines.png
  • Spike.png
  • SpikeShaded.png

Edited by jsuffolk, 23 May 2013 - 09:19 PM.


Sponsor:

#2 C0lumbo   Crossbones+   -  Reputation: 2503

Like
3Likes
Like

Posted 24 May 2013 - 01:07 AM

Your code is basically requesting 8 corners of a cube, and is calculating trilinear interpolation values between them. Where I think it might be going wrong is that you're calculating the interpolation values in the HLSL, but you're leaving the point sampling to the texture fetch instruction. I suspect there might be some subtle floating point rounding differences that mean that occasionally you're using interpolation values for one cube, but texture samples from another.

 

I think the solution would be to provide the texture fetch instruction with unambiguous coordinates to eliminate the possibility of a rounding error. Some pseudocode which could replace the first 3 lines of your tex3D_trilinear function:

 

// t = frac(t); // This line might help if magnitude of t is very large.
float3 topCorner = (t - halfTexelSize.xxx) * textureSize;
float3 topCornerFloor = floor(topCorner);
float3 f = topCorner - topCornerFloor;
float3 topCornerUV = topCornerFloor / textureSize;
float3 topCornerUV += halfTexelSize.xxx;  // This half texel offset means you're attempting to sample the centre of the texel instead of the top-left corner. I think it helps, but if it doesn't, then try without it, or try a 1/4 or 1/3 offset.
float4 x = float4(topCornerUV, 0);
 


#3 jsuffolk   Members   -  Reputation: 319

Like
1Likes
Like

Posted 24 May 2013 - 06:19 AM

Worked like a charm!!! Thanks, that was a lifesaver after pulling my hair out for a few days! Next up: mipmapping the surface noise on the GPU and switching the surface from normal mapping to relief mapping!

 

Just in case you're curious the algorithm basically uses this GPU gems piece on a planetary scale in a manner similar to CDLOD. It works extremely well for planetary LOD with just 2 passes (1 CPU, 1 GPU), able to push > 3 million tris on a couple year old GPU with no framerate dips and can be adjusted for older hardware by changing the value of a single constant. Morphing's a little tricky, though.

 

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch05.html


Edited by jsuffolk, 24 May 2013 - 06:21 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS