Skip to content

Instantly share code, notes, and snippets.

@Erkaman
Last active November 17, 2020 07:35
Show Gist options
  • Save Erkaman/dec44bfd0a9de1635ea2729684bdc9da to your computer and use it in GitHub Desktop.
Save Erkaman/dec44bfd0a9de1635ea2729684bdc9da to your computer and use it in GitHub Desktop.
Texture minification using Custom Trilinear Interpolation. From my tweet: https://twitter.com/erkaman2/status/1090645031227191296
Shader "Custom/CustomTriLerp"
{
Properties
{
[NoScaleOffset] _MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma enable_d3d11_debug_symbols
#include "UnityCG.cginc" // for UnityObjectToWorldNormal
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
Texture2D _MainTex; SamplerState sampler_MainTex;
float AreaLod(float sx, float sy, float tx, float ty, float texWidth, float texHeight) {
float sxp = sx * texWidth;
float syp = sy * texWidth;
float txp = tx * texHeight;
float typ = ty * texHeight;
float j = sqrt(abs(sxp * typ - syp * txp));
return j;
}
float maxAbsLod(float sx, float sy, float tx, float ty, float texWidth, float texHeight) {
float j = max(max(abs(sx),abs(sy))*texWidth, max(abs(tx),abs(ty))*texHeight);
return j;
}
// implement trilinear texture interpolation.
float4 triLerp(float2 uv, float j, Texture2D tex, SamplerState samp) {
float l = floor(log2(j));
float f = (j - pow(2, l)) / (pow(2, l));
// SampleLevel, if used at integer LODs, means we can sample bilinearily from the texture, without any trilinear interpolation.
return lerp(
tex.SampleLevel(samp, uv, l).r,
tex.SampleLevel(samp, uv, l + 1).r,
f);
}
float longestSideLod(float sx, float sy, float tx, float ty, float texWidth, float texHeight) {
float sxp = sx * texWidth;
float syp = sy * texWidth;
float txp = tx * texHeight;
float typ = ty * texHeight;
float j = max(sqrt(sxp*sxp + txp * txp), sqrt(syp*syp + typ * typ));
return j;
}
fixed4 frag(v2f i) : SV_Target
{
float sx = ddx(i.uv.x); float sy = ddy(i.uv.x);
float tx = ddx(i.uv.y); float ty = ddy(i.uv.y);
// NB: texture sizes is hardcoded to 1024.
float texWidth = 1024; float texHeight = 1024;
float j;
// this implements trilinear interpolation with the GPU hardware.
fixed4 hardwareCol = _MainTex.Sample(sampler_MainTex, i.uv).r;
// implement trilinear interpolation with our custom implementation.(this one is best)
j = longestSideLod(sx, sy, tx, ty, texWidth, texHeight);
float4 longestSideCol = triLerp(i.uv, j, _MainTex, sampler_MainTex);
// another custom implementation.
j = maxAbsLod(sx, sy, tx, ty, texWidth, texHeight);
float4 maxAbsCol = triLerp(i.uv, j, _MainTex, sampler_MainTex);
// another custom implementation.
j = AreaLod(sx, sy, tx, ty, texWidth, texHeight);
float4 areaCol = triLerp(i.uv, j, _MainTex, sampler_MainTex);
fixed4 col;
col = longestSideCol;
return col;
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment