Bad LOD at edge of quadrant

I have set up a system where I generate a bunch of quads (2 triangles) to make up a map grid. These quads are not connected in a single mesh, because my long term plan is to have some of them use different geometries than a simple quad.

Additionally, I have a specialized texture sampling function (that is a WIP) to reduce visible tiling of textures. That’s why in the examples below my samples are rotated and shifted.

However, I am having a problem with the texturing at the edges of my quads. On the edges of some quads, I get a line of almost a solid color that continues the full length of the screen. They move depending on where the camera is and usually seem to occupy approximately the same area of the screen (not the 3D scene).

This wouldn’t be so bad if they didn’t move around, but they do - so the pattern starts to look like extremely bad aliasing as the camera moves around.

My initial thought was that this was the fault of my sampling algorithm, so I modified my shader to show the calculated uv coordinates. They appear as intended – there is no visible discontinuity at the edges.

I believe this has something to do with the LOD/implicit derivatives going bad at these edges. I tested that theory by using textureLod with an LOD of 0, and the lines disappeared completely.

I need to keep my tiles as separate geometry, but I also need these discontinuities between them to go away. I’m also not sure why they’re here to begin with, as I’ve not run into this sort of problem before with disconnected triangles. Though to be fair, I am not sure I would have noticed if they weren’t in a grid like this.

Any suggestions?

#version 430 core

layout(binding=0) uniform usampler2D cell_types;
layout(binding=1) uniform sampler2DArray cell_type_textures;

float random( in float seed )
{
	return fract( sin( mod( seed, 3.14 ) * 10000.0 ) );
}

void improvedContinuousSample(
	in sampler2DArray textureArray,
	in vec2 worldLocation,
	in float index,
	out vec4 color)
{
	vec2 tileLocation = fract( worldLocation );
	vec2 tileIndex = floor( worldLocation );
	vec2 shift = vec2( random( tileIndex.x ), random( tileIndex.y ) );
	
	float angle = 6.283185 * random( shift.x * shift.y + shift.y );
	vec2 rotatedTileLocation = vec2(
		tileLocation.x * cos( angle ) - tileLocation.y * sin( angle ),
		tileLocation.x * sin( angle ) + tileLocation.y * cos( angle ) );
	
	// Offset the rotation as well.
	vec2 finalLocation = rotatedTileLocation + shift;
	
	color = texture( textureArray, vec3( finalLocation, index ) );

	// debug version in the 0 LOD image
//	color = textureLod( textureArray, vec3( finalLocation, index ), 0 );
	
	// debug display of texture coordinates
//	color = vec4( fract( finalLocation ), 0.0, 1.0 );
}

void mapTexture(
	in vec2 worldLocation,
	out vec4 diffuse)
{
	uint cellType = texelFetch( cell_types, ivec2( int( worldLocation.x ), int( worldLocation.y ) ), 0 ).x;
	improvedContinuousSample( cell_type_textures, worldLocation, float( cellType ), diffuse );
}

layout(location=0) out vec4 color;

in vec3 vo_world_position;

void main( )
{
	vec4 diffuse;
	mapTexture( vo_world_position.xy, diffuse );
	
	color = vec4( diffuse.rgb, 1.0 );
}

Indeed.

Consider the derivatives of fract and floor; they’re constant within the interior of each tile with high ridges at the edges. Any function based upon these will have similar derivatives. I suggest replacing the texture call with

	color = textureGrad( textureArray, vec3( finalLocation, index ),
			     dFdx( worldLocation), dFdy( worldLocation) );

Or if the scale factor will be constant (like in your pictures), just use textureLod with the LoD computed externally and passed in via a uniform.

Supplying the coordinate-based derivatives did it! I guess I need to be more careful with this sort of thing - this is the first time I’ve gotten quite this deep into messing with texture sampling coordinates.

Really appreciate the response!

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.