Files
Reimagined/shaderpacks/Reimagined - Low/shaders/lib/misc/pixelation.glsl
T
2026-05-07 21:38:27 +03:00

98 lines
3.3 KiB
GLSL

#if !defined PIXELATION_FILE
#define PIXELATION_FILE
#if PIXEL_SCALE == -2
#define PIXEL_TEXEL_SCALE 4.0
#elif PIXEL_SCALE == -1
#define PIXEL_TEXEL_SCALE 2.0
#elif PIXEL_SCALE == 2
#define PIXEL_TEXEL_SCALE 0.5
#elif PIXEL_SCALE == 3
#define PIXEL_TEXEL_SCALE 0.25
#elif PIXEL_SCALE == 4
#define PIXEL_TEXEL_SCALE 0.125
#elif PIXEL_SCALE == 5
#define PIXEL_TEXEL_SCALE 0.0625
#else // 1 or out of range
#define PIXEL_TEXEL_SCALE 1.0
#endif
#ifdef FRAGMENT_SHADER
// Thanks to Nestorboy
// Computes axis-aligned screen space offset to texel center.
// https://forum.unity.com/threads/the-quest-for-efficient-per-texel-lighting.529948/#post-7536023
vec2 ComputeTexelOffset(vec2 uv, vec4 texelSize) {
// 1. Calculate how much the texture UV coords need to shift to be at the center of the nearest texel.
vec2 uvCenter = (floor(uv * texelSize.zw) + 0.5) * texelSize.xy;
vec2 dUV = uvCenter - uv;
// 2. 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.
vec2 dUVdS = dFdx(uv);
vec2 dUVdT = dFdy(uv);
if (abs(dUVdS) + abs(dUVdT) == vec2(0.0)) return vec2(0.0);
// 3. Invert the texture delta from fragment delta matrix. Where the magic happens.
mat2x2 dSTdUV = mat2x2(dUVdT[1], -dUVdT[0], -dUVdS[1], dUVdS[0]) * (1.0 / (dUVdS[0] * dUVdT[1] - dUVdT[0] * dUVdS[1]));
// 4. Convert the texture delta to fragment delta.
vec2 dST = dUV * dSTdUV;
return dST;
}
vec2 ComputeTexelOffset(sampler2D tex, vec2 uv) {
vec2 texSize = textureSize(tex, 0) * PIXEL_TEXEL_SCALE;
vec4 texelSize = vec4(1.0 / texSize.xy, texSize.xy);
return ComputeTexelOffset(uv, texelSize);
}
vec4 TexelSnap(vec4 value, vec2 texelOffset) {
if(all(equal(texelOffset, vec2(0.0)))) return value;
vec4 dx = dFdx(value);
vec4 dy = dFdy(value);
vec4 valueOffset = dx * texelOffset.x + dy * texelOffset.y;
valueOffset = clamp(valueOffset, -1.0, 1.0);
return value + valueOffset;
}
vec3 TexelSnap(vec3 value, vec2 texelOffset) {
if(all(equal(texelOffset, vec2(0.0)))) return value;
vec3 dx = dFdx(value);
vec3 dy = dFdy(value);
vec3 valueOffset = dx * texelOffset.x + dy * texelOffset.y;
valueOffset = clamp(valueOffset, -1.0, 1.0);
return value + valueOffset;
}
vec2 TexelSnap(vec2 value, vec2 texelOffset) {
if(all(equal(texelOffset, vec2(0.0)))) return value;
vec2 dx = dFdx(value);
vec2 dy = dFdy(value);
vec2 valueOffset = dx * texelOffset.x + dy * texelOffset.y;
valueOffset = clamp(valueOffset, -1.0, 1.0);
return value + valueOffset;
}
float TexelSnap(float value, vec2 texelOffset) {
if(all(equal(texelOffset, vec2(0.0)))) return value;
float dx = dFdx(value);
float dy = dFdy(value);
float valueOffset = dx * texelOffset.x + dy * texelOffset.y;
valueOffset = clamp(valueOffset, -1.0, 1.0);
return value + valueOffset;
}
#endif
#endif // !defined PIXELATION_FILE