Last active
November 17, 2020 07:35
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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