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

    release16 мая 2026 г.

    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.

  • 0.4

    beta12 января 2026 г.

    Test version:

    • Addition of a visual style selection system (color palettes)
    • Addition of several color palette modes for a more personalized look
    • Addition of a system for creating your own color palette up to 8 bits (8 colors)
    • Menu improvements
    • Performance optimization
    • And more...
  • 0.3

    beta7 января 2026 г.

    Нет описания изменений

Совместимость

Сведения

Лицензия:
Опубликован:5 месяцев назад
Обновлён:4 недели назад
ID проекта:
Главная