Skip to content

Instantly share code, notes, and snippets.

@pema99
Created May 9, 2025 19:28
Show Gist options
  • Save pema99/b0d046a30afb0ca1b2fdc3e14b6c2920 to your computer and use it in GitHub Desktop.
Save pema99/b0d046a30afb0ca1b2fdc3e14b6c2920 to your computer and use it in GitHub Desktop.
Compares SW and HW mipmap selection
Shader "Unlit/CompareMipSelection"
{
Properties
{
_MainTex ("Main color texture", 2D) = "white" {}
_MipTexture ("Texture with different color mips", 2D) = "white" {}
_AnisoLevel ("Aniso Level (must set manually to match texture)", Range(0, 16)) = 0
[ToggleUI] _VisualizeMipLevels ("Visualize Mip Levels", Integer) = 0
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
Texture2D _MainTex;
SamplerState sampler_MainTex;
float4 _MainTex_ST;
float4 _MainTex_TexelSize;
Texture2D _MipTexture;
SamplerState sampler_MipTexture;
float _AnisoLevel;
bool _VisualizeMipLevels;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
void EllipsoidTransformDerivatives(inout float2 dx, inout float2 dy)
{
bool anyZero = length(dx) == 0 || length(dy) == 0;
bool parallel = (dx.x * dy.y - dx.y * dy.x) == 0;
bool perpendicular = dot(dx, dy) == 0;
bool nonFinite = isinf(dx) || isinf(dy) || isnan(dx) || isnan(dy);
if (!anyZero && !parallel && !perpendicular && !nonFinite)
{
float A = dx.y*dx.y + dy.y*dy.y;
float B = -2.0 * (dx.x * dx.y + dy.x * dy.y);
float C = dx.x*dx.x + dy.x*dy.x;
float F = (dx.x * dy.y - dy.x * dx.y) * (dx.x * dy.y - dy.x * dx.y);
float p = A - C;
float q = A + C;
float t = sqrt(p*p + B*B);
float2 newDx, newDy;
newDx.x = sqrt(F * (t+p) / ( t * (q+t)));
newDx.y = sqrt(F * (t-p) / ( t * (q+t)))*sign(B);
newDy.x = sqrt(F * (t-p) / ( t * (q-t)))*-sign(B);
newDy.y = sqrt(F * (t+p) / ( t * (q-t)));
bool failed = any(isnan(newDx) || isinf(newDx) || isnan(newDy) || isinf(newDy));
if (!failed)
{
dx = newDx;
dy = newDy;
}
}
}
float CalculateLodLevel(float2 texSize, float2 dx, float2 dy, float anisoLevel)
{
dx *= texSize;
dy *= texSize;
// Ellipsoid transform
EllipsoidTransformDerivatives(dx, dy);
// Regular mip selection
if (anisoLevel == 0)
{
float lengthX = sqrt(dx.x*dx.x + dx.y*dx.y);
float lengthY = sqrt(dy.x*dy.x + dy.y*dy.y);
return log2(max(lengthX,lengthY));
}
// Anisotropic filtering
else
{
float squaredLengthX = dx.x*dx.x + dx.y*dx.y;
float squaredLengthY = dy.x*dy.x + dy.y*dy.y;
float determinant = abs(dx.x*dy.y - dx.y*dy.x);
bool isMajorX = squaredLengthX > squaredLengthY;
float squaredLengthMajor = isMajorX ? squaredLengthX : squaredLengthY;
float lengthMajor = sqrt(squaredLengthMajor);
float ratioOfAnisotropy = squaredLengthMajor/determinant;
float lengthMinor;
if (ratioOfAnisotropy > anisoLevel)
{
ratioOfAnisotropy = anisoLevel;
lengthMinor = lengthMajor/ratioOfAnisotropy;
}
else
{
lengthMinor = determinant/lengthMajor;
}
return log2(lengthMinor);
}
}
float4 frag (v2f i) : SV_Target
{
bool hardware = i.vertex.x > _ScreenParams.x / 2;
float4 col = 0;
if (_VisualizeMipLevels)
{
if (hardware)
{
col = _MipTexture.Sample(
sampler_MipTexture,
i.uv);
}
else
{
col = _MipTexture.SampleLevel(
sampler_MipTexture,
i.uv,
CalculateLodLevel(_MainTex_TexelSize.zw, ddx(i.uv), ddy(i.uv), _AnisoLevel));
}
}
else
{
if (hardware)
{
col = _MainTex.Sample(
sampler_MainTex,
i.uv);
}
else
{
col = _MainTex.SampleLevel(
sampler_MainTex,
i.uv,
CalculateLodLevel(_MainTex_TexelSize.zw, ddx(i.uv), ddy(i.uv), _AnisoLevel));
}
}
return col;
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment