Skip to content

Instantly share code, notes, and snippets.

@antonkudin
Created April 6, 2024 13:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonkudin/32176606ce86f899b07c82785f39d6d8 to your computer and use it in GitHub Desktop.
Save antonkudin/32176606ce86f899b07c82785f39d6d8 to your computer and use it in GitHub Desktop.
void TexelSnap_float(float3 WorldPos, float4 UV0, float4 TexelSize, out float3 SnappedWorldPos)
{
// 1.) Calculate how much the texture UV coords need to
// shift to be at the center of the nearest texel.
float2 originalUV = UV0.xy;
float2 centerUV = floor(originalUV * (TexelSize.zw))/TexelSize.zw + (TexelSize.xy/2.0);
float2 dUV = (centerUV - originalUV);
// 2b.) Calculate how much the texture coords vary over fragment space.
// This essentially defines a 2x2 matrix that gets
// texture space (UV) deltas from fragment space (ST) deltas
// Note: I call fragment space "ST" to disambiguate from world space "XY".
float2 dUVdS = ddx( originalUV );
float2 dUVdT = ddy( originalUV );
// 2c.) Invert the texture delta from fragment delta matrix
float2x2 dSTdUV = float2x2(dUVdT[1], -dUVdT[0], -dUVdS[1], dUVdS[0])*(1.0f/(dUVdS[0]*dUVdT[1]-dUVdT[0]*dUVdS[1]));
// 2d.) Convert the texture delta to fragment delta
float2 dST = mul(dSTdUV , dUV);
// 2e.) Calculate how much the world coords vary over fragment space.
float3 dXYZdS = ddx(WorldPos);
float3 dXYZdT = ddy(WorldPos);
// 2f.) Finally, convert our fragment space delta to a world space delta
// And be sure to clamp it in case the derivative calc went insane
float3 dXYZ = dXYZdS * dST[0] + dXYZdT * dST[1];
dXYZ = clamp (dXYZ, -1, 1);
// 3a.) Transform the snapped UV back to world space
SnappedWorldPos = (WorldPos + dXYZ);
}
@antonkudin
Copy link
Author

Works on any value, not just worldPos!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment