Shader floating point precision issue on large planets

Equinox shared this bug 28 days ago
Submitted

STR: Create a 1250km planet, fly down close to the surface.

The triplanar shaders uses voxel-local coordinates for texture UVs, but passes these voxel-local coordinates around using single precision. This results in significant pixelization on large planets due to those single precision -- a radius of 1250km has +/- .125m precision when used at single precision, corresponding to the pixel size below.


The loss of precision is due to an implicit assignment from Vector3D to Vector3 in


MyVoxelCellComponent.CreateRenderableProxyForPart:

myRenderableProxy.VoxelCommonObjectData.VoxelOffset = this.m_offset;


This ultimately gets used in shader code as a texture coordinate in TriplanarSampling.hlsli:

float3 texcoords = (triplanarInput.texcoords + offset) * scale;
Since texture coordinates wrap, this is equivalent to:


float3 texcoords = frac(triplanarInput.texcoords * scale) + frac(offset * scale);
To resolve the pixelization is is necessary to hoist the high precision frac call out of the shader and into C# code. This is possible because the unique values for scale are limited, and it should be possible to pre-compute every possible frac(offset * scale) value that could be used, storing that information on the object constants structure.

There might be some clever molduar math that can be performed here to find a f(offset, scales) such that [ frac(f(offset, scales) * scale) == frac(offset * scale) for all scale in scales ], which could avoid some constant buffer size.


1a3c3d0bfbb79c878d127e91fdf9a7a6

Leave a Comment
 
Attach a file
Access denied