Unofficial site, not affiliated with modrinth.com.What is this?
Шейдеры/Dithering3D
Dithering3D

Dithering3D

Pixelated, retro, Dark Fantasy, gradient, B&W, RGB and more

6.6K
20
Все версииDithering3D 0.5

Dithering3D 0.5

Release4 нед. назад

Список изменений

Dither3D Shader — Audit & Fix Report

Date: 2026-05-15

Scope: Full codebase integrity review against original Dither3DInclude.cginc


1. BUG FIXES

1.1 — CRITICAL: Sky double exposure/offset

File: shaders/gbuffers_skybasic.fsh:37 Severity: High — visual blowout at any non-default exposure/offset

applyDither3DColor() already applies DITHER_EXPOSURE * color + DITHER_OFFSET internally (line 53 of dither3d_color.glsl). The sky shader was pre-applying the same transform:

// BEFORE (bug):
vec3 skyColor = clamp(glcolor.rgb * DITHER_EXPOSURE + DITHER_OFFSET, 0.0, 1.0);
vec3 result = applyDither3DColor(skyUV, screenPos, dx, dy, skyColor);
// Result: exposure and offset squared (over-exposed sky)

// AFTER (fix):
vec3 result = applyDither3DColor(skyUV, screenPos, dx, dy, glcolor.rgb);

All other gbuffer fragment shaders pass raw colors — only gbuffers_skybasic.fsh had this issue.

1.2 — MEDIUM: Invalid SVD frequency test

File: tests/test_math.py:15-30 Severity: Medium — test was validating a different algorithm than the shader uses

The Python compute_uv_frequency() computed sqrt(sqrt(lambda1 * lambda2)) — a geometric mean of eigenvalue square roots — instead of the SVD singular values the shader actually computes. The shader's algorithm:

float Q = dot(dx,dx) + dot(dy,dy);          // Frobenius norm squared
float R = dx.x*dy.y - dx.y*dy.x;            // determinant
float disc = sqrt(Q*Q - 4.0*R*R);
vec2 freq = sqrt(vec2(Q + disc, Q - disc) * 0.5);  // singular values (sigma_1, sigma_2)

The test now matches this exactly with three validated cases:

  • Isotropic (uniform UV scale): both singular values equal scale ✓
  • Anisotropic (stretched UV): singular values equal individual axis scales ✓
  • Rotated (45°): singular values invariant under rotation ✓

Also fixed: Unicode characters (checkmarks, arrows) replaced with ASCII for Windows console compatibility.


2. CODE QUALITY IMPROVEMENTS

2.1 — Clarified dotRadius formula

File: shaders/lib/dither3d_core.glsl:98

// BEFORE (confusing):
float dotRadius = 0.25 / sqrt(activeDots * 0.25);

// AFTER (clear):
float dotRadius = 0.5 / sqrt(activeDots);

Both expressions are mathematically identical. The new form directly shows the relationship: radius scales as 0.5 / sqrt(N), giving 0.125 for 16 dots and 0.25 for 4 dots.

2.2 — PALETTE_COLOR_MATCH default changed to Color-Aware

Files: shaders/lib/dither3d_options.glsl:41, shaders/lib/dither3d_config.glsl:63

#define PALETTE_COLOR_MATCH 1  // was 0

Color-aware palette matching preserves hues by finding the two closest palette colors and dithering between them. This gives better results for colored palettes (CGA, Pico-8, Nord, Eldritch). The GAMEBOY profile explicitly overrides to 0 (luminance-based) for authentic retro look.


3. ARCHITECTURE VERIFICATION

3.1 — Include chain (correct)

Fragment shader
  -> dither3d_options.glsl     (defines all macros first)
  -> dither3d_color.glsl
       -> dither3d_core.glsl
            -> dither3d_config.glsl   (fallback defaults via #ifndef)
       -> dither3d_utils.glsl
       -> dither3d_palettes.glsl
            -> dither3d_utils.glsl    (guard prevents double include)

All 6 modules have unique, consistent include guards:

ModuleGuard
dither3d_options.glslDITHER3D_OPTIONS_GLSL
dither3d_config.glslDITHER3D_CONFIG_GLSL
dither3d_core.glslDITHER3D_CORE_GLSL
dither3d_utils.glslDITHER3D_UTILS_GLSL
dither3d_palettes.glslDITHER3D_PALETTES_GLSL
dither3d_color.glslDITHER3D_COLOR_GLSL

3.2 — Vertex shaders (all 14 pairs verified)

All vertex shaders correctly compute and pass screenPos = gl_Position for radial compensation. World position and normal calculations are consistent across all geometry types:

  • Terrain, Entities, Block, Hand, Water: triplanar UV with world normal
  • Basic, Clouds, Weather, Armor Glint, Spider Eyes: simple world UV (no normal available)
  • Sky Basic: cylindrical UV with view direction and alternate UV seam handling
  • Sky Textured: texture atlas UV (scaled x4 for dithering)
  • Beacon Beam: XZ plane with vertical offset

3.3 — Fragment shaders (all 14 pairs verified)

All fragment shaders follow the same pattern:

  1. Include dither3d_options.glsl (first, defines macros)
  2. Include dither3d_color.glsl (pulls in everything)
  3. Sample textures, compute color
  4. Call applyDither3DColorSimple() or applyDither3DColor()
  5. Output to gl_FragData[0] with proper alpha preservation

3.4 — Shader properties (validated)

  • shaders.properties: 14 RENDER_STYLE values, 8 profiles, proper slider ranges, nested submenu structure
  • lang/en_US.lang: all options, values, profiles, and screen names have labels
  • Custom palette sliders (colors 1-8, 24 RGB sliders) all wired through shaders.propertiesdither3d_options.glsldither3d_config.glsl

3.5 — Palette system (validated)

  • 9 built-in palettes: 1-Bit(2), GameBoy(4), CGA(4), VirtualBoy(4), Sepia(4), Nord(8), Solarized(8), Pico-8(16), Eldritch(16)
  • 3 custom modes: 2-color, 4-color, 8-color via user-adjustable RGB sliders
  • Dual matching: luminance-based (fast, crisp) and color-aware (preserves hues)
  • All palettes sorted by luminance for correct dithering gradient
  • getPaletteColor() centralizes all access with clamp() bounds safety

3.6 — CMYK halftone (validated)

  • 4 plates with correct traditional screen angles (15°, 75°, 0°, 45°)
  • Slight scale variation per plate breaks up moire patterns
  • Round-trip conversion matches original HLSL (validated by test)

4. ORIGINAL PORT FIDELITY

Original (HLSL)Port (GLSL)Status
SVD frequency analysisIdentical math (Q, R, discriminant)Match
Fractal level selectionlog2(spacing) + floor()Match
Sublayer calculationlerp(0.25*dotsTotal, dotsTotal, 1-f)Match
Dither pattern generationProcedural circular dots (replaces 3D texture)Adapted
Contrast applicationSame formula with adjusted multiplier (0.15 vs 0.1)Calibrated
Brightness rampSimplified (no ramp texture lookup)Adapted
Radial compensationgbufferProjection instead of UNITY_MATRIX_PAdapted
GetDither3DAltUVIdentical derivative comparison logicMatch
CMYK conversionIdentical mathMatch
UV rotationIdenticalMatch

Known differences (intentional adaptions for Minecraft):

  • No 3D texture: replaced with procedural Bayer-pattern circular dots
  • No brightness ramp texture: direct clamping used instead
  • Contrast multiplier: 0.15 vs 0.1 (compensates for procedural pattern difference)
  • contrastFade formula: 1/(1+c*0.5) vs 1.05/(1+c) (recalibrated for procedural dots)
  • RENDER_STYLE 0 (RGB) uses small UV offsets instead of original's per-channel dithering

5. TEST RESULTS

python tests/test_math.py
======================================================================
Dither3D Mathematical Function Tests
======================================================================

--- SVD Frequency Computation (matches dither3d_core.glsl) ---
PASS Isotropic test:  maxFreq=2.000, minFreq=2.000, stretch=1.000
PASS Anisotropic test: maxFreq=4.000, minFreq=1.000, stretch=0.250
PASS Rotated test:     maxFreq=2.000, minFreq=2.000, stretch=1.000

--- CMYK Color Conversion ---
PASS Red, Green, Blue, Yellow, Magenta, Cyan, White, Black (8/8)

--- Bayer Matrix Generation ---
PASS Bayer 1x1, 2x2, 4x4, 8x8 (4/4)

======================================================================
All tests passed!
======================================================================

6. SUMMARY

CategoryCount
Critical bugs fixed1 (sky double exposure)
Invalid tests fixed1 (SVD algorithm mismatch)
Code clarity improvements1 (dotRadius formula)
Default value changes1 (PALETTE_COLOR_MATCH 0→1)
Files audited37 (lib + gbuffers + composite + final + config)
Architecture issues found0

Verdict: Codebase is stable, well-structured, and faithful to the original algorithm.

Метаданные

Канал релиза

Release

Номер версии

0.5

Загрузчики

Iris
OptiFine

Версии игры

1.0–26.1.2, 26w14a

Загрузок

2.1K

Дата публикации

4 нед. назад

Загрузил

ID версии

Главная