Shader floating point precision issue on large planets
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.
Replies have been locked on this page!