Repository navigation
Etna 0.9.0: World and Auto Resolution, own anti-aliasing, entities lit like the world, no code from other packs - #5
Draft
Atomsk-debug wants to merge 34 commits into
Draft
Atomsk-debug wants to merge 34 commits into
Atomsk-debug wants to merge 34 commits into
Conversation
Reflections: fixed steps (24 + 6 halvings, no per-pixel noise, one fixed pixel per 2x2 block), a hit only where the ray runs into a surface rather than going behind something in front of it, misses written with their distance so the upsampler averages them (0.8.0 skipped them, so one lone hit grew into a speck), a 16-texel steady upsample, and the ray following a quarter of the swell's slope. The sky's reflection that is taken out keeps the full swell, as the water shader drew it. Foam: no foam over shallow floors and none on water flowing down a slope (new etnaWaterLevel flag from the unsnapped face normal); thinner, fainter line (0.2 blocks, 0.7) broken by fine bubbles, pale non-glowing colour. Version 0.8.1, changelog. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
Contact hardening (the PCSS idea): 8 gathers look for casters round the point; the blur radius is the softness plus 0.025 x (softness - 0.25) of their average distance along the light, capped at 1.2 blocks / 32 texels. The near part keeps the exact area-weighted box, the wide part a 12-point bilinear-PCF Vogel disk, blended between. No casters found: lit at once. At the lowest softness all of it is skipped. Low sun: shadows fade up to 35% lighter below ~20 degrees. From a review of the shadow code: receivers beyond the shadow casters' chunk box (16 * ceil((distance + 14) / 16) blocks along world x/z) fade to lit instead of ending at a hard line; points beyond the map's far depth plane count as lit (terrain filter, unfiltered test, leaves, shafts) instead of shadowed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
The shadows that soften with distance read the map up to 1.2 blocks round a point and compare it with the surface's plane over that disc, but the shadow pass still dropped casters by the old filter's reach (softness + 1 texels). Near the camera that is a few hundredths of a block, so a caster just outside the view, or a little below everything on screen, could be left out of the map while a pixel's blur still read where it would be: part of a soft edge missing at the side of the screen, coming back as the camera turns. The view test's margins (sideways and behind) and the receiver floor now take the wider reach into account; nothing changes at the lowest softness, where the wider blur is off. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
Contact hardening no longer turns its reads every frame or gives up where a few reads find nothing: the box filter now also reports blockers, six fixed bilinear search reads cover the ring beyond it, the disc (16 reads, at most 16 texels) is skipped where everything read is blocked or open, and only discs wider than about eight texels turn, by more the wider they are. In the offline bench the flicker after TAA is 35-65 % below the tested build's and below 0.8.0's with a low sun. The shadow map warp and the water's fresnelDielectric are rewritten from first principles and the Cook-Torrance form, without Photon's code: the warp's distance n = sqrt(1 - (1-x^2)(1-y^2)) fills the whole map and keeps far texels two to five times finer towards the corners. EtnaShadows' margins follow its bounds. CREDITS and README list them as Etna's own. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
- World Resolution (50 to 100%): the level is drawn into a smaller target of Etna's (GameRenderer.mainRenderTarget() hands it out during the level), the scaled world chain runs on it, and Etna's new anti-aliasing rebuilds the full-size picture into Minecraft's own. Hand, screen effects, bloom and the HUD stay at full size. Texture detail follows the screen's pixels. - Etna's own temporal anti-aliasing replaces the Photon port: this frame rebuilt from the 3x3 level pixels with jitter-aware Gaussian weights, the history's weight kept in alpha, nearest-depth reprojection, Catmull-Rom history, YCoCg variance clipping along the line to this frame's colour, and a 1 / (1 + luma) weighted blend. - Jitter: 8 Halton steps at full size, 8 / scale^2 rounded up to a power of two below it. The terrain reads the current jitter from its block. - Light shafts: the 2x2 order comes from Bayer's ordered-dither matrix. - Fixed-size post targets are written as an explicit offset size, so a size equal to the chain's own is never mistaken for "no size". - Benchmark step "world resolution 75%"; docs and translations. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
With the anti-aliasing and the shafts' order rewritten here and 0.8.1's own shadow warp and water Fresnel, nothing ported from Photon Shaders is left: LICENSE-PHOTON.txt and its jar entry go, the CREDITS rows and the Modrinth note go (the techniques are credited instead), LICENSE is plain MIT, and the README, fabric.mod.json and the changelog say so. Version 0.9.0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
Atomsk-debug
force-pushed
the
claude/project-thread-5pxz6a
branch
from
October 11, 2026 02:06
f766f94 to
26034ac
Compare
The water's top took the sharp shadow of its own point as the body's light, while the bottom seen through it had its own shadow, shifted by the depth; the two copies crossed each other out. The body's sun share is now the shadow at four points down the refracted view, placed at equal shares of the light scattered back above the bottom (green extinction down along the sun and back up along the view), each a bilinear 2x2 lookup (new shadowSoftAt). Clear shallow water shows the bottom's shadow; murky or deep water a soft shadow in the water. Water whose bottom the shadow map can't show (wide shade, a roof) went back to the plain, far more opaque look in the shadow's shape. A fourth ring at 8 blocks looks for the bottom further round, and where none is found the depth model keeps going with 4 blocks of water. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
A ray that only just meets or misses an edge went either way from frame to frame (the jittered picture's edges move by up to half a pixel, the waves move on), and a whole half-resolution texel, spread over its neighbours by the world pass, changed at once: too smooth for the TAA's neighbourhood clip to tell from a real change, so the reflection flickered. The reflections pass now traces from the pixel's unjittered centre and reads depth and colour at the jittered spot that holds each point, and with anti-aliasing on it blends each texel with its own history (SSR_BLEND 0.3, more of this frame while the camera moves), reprojected by the water point's position with PrevViewProj and kept only where last frame held water at that distance. The history is two persistent half- size targets, water_ssr0/1, swapped with the TAA history (PostChainMixin); the plain chain binds the shafts as a placeholder and never reads it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
…ct-thread-5pxz6a # Conflicts: # src/main/resources/assets/etna/post_effect/etna_world.json # tools/gen_post_effects.py
The sun and sky colours, the direct sun's strength, the sky light on a face, the soft terminator and the torch colour move unchanged from terrain.fsh into an include, so entities and items can be lit by the same functions. The terrain includes it where they were and draws exactly as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
Etna's own entity and item shaders, made from vanilla's: everything is vanilla's but the light, which is the terrain's (sun, sky, shadow map, clouds, torch colour, cave light, haze), shared through etna_light.glsl. The first-person hand is lit as if it stood at the camera. The validator builds them with the defines of the pipelines Etna will copy. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
Vanilla's prepared render types draw every entity, block entity and item through one private method. A new optional mixin swaps its pipeline for Etna's copy (entity or item shader, Etna's bind group) while Etna lights the draw, and binds the terrain block, shadow maps and cloud texture with the default uniforms; the terrain's binding moves to EtnaShadows.bindLight for both. Only the level's draws and the first-person hand's are swapped, never the menus', and only classic pipelines (no Improved Transparency stages). New Entity Lighting switch on the Lighting page (default on), saved in etna.properties, and an "entity lighting off" benchmark step. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
The benchmark holds the sun, so no sun-step fade happens during a run and its table never shows what the fades cost in play (every sunlit pixel filtering both maps for part of the time). benchmarkFade, set and put back by EtnaBenchmark, keeps a fade running along the held direction, held at its middle once the second map is drawn: both maps drawn in turn and read half and half, as in a real fade. Off by default; nothing else changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
The benchmark holds the sun, so the fade between shadow maps as the sun moves never ran in it. "shadow map fade" turns on EtnaShadows.benchmarkFade for its step, so the table shows what sunrise and sunset add. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
Far water seen at a grazing angle changes its distance from the camera by several blocks a pixel, more than the history check's 0.3 + 3 % allowed, so the reflections pass threw its history away exactly where the shore's reflection flickers most (from about 60 blocks out, sooner from a boat). The check now also allows four pixels' change in distance on the water (the history texels lie up to two pixels away, plus last frame's jitter), capped at a quarter of the distance. The water body's four shadow points go down along the bent view, so where the bottom rises ahead of it (a beach stepping up out of a lake) the deeper ones ended up inside the sand and read the bottom above them as a shadow: a darker band in front of the steps. Each point is now looked up where its way to the sun crosses the water's surface (the same texels of the map), so only what stands above the water shades it. The header no longer claims a still scene traces the same rays every frame: each ray starts from the point the jittered pixel shows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
…into claude/project-thread-5pxz6a
…tem keeps vanilla light From an independent review of the entity lighting: - The copies are built and compiled two a frame as the level starts, not at their first draw, which stalled the game when a new mob, an enchanted item or the hand first came into view. - The draw path is a plain map lookup: no lambda per draw, the compile is checked once per copy (again after a resource reload), and the shadow block's slice is made once per buffer. - The hand phase ends right after the hand, so the totem screen effect keeps vanilla's light (its normals aren't world-oriented). - The special glint copies get names of their own. - A hand copy that fails no longer disables the level's copy, and back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
A new General-page setting (off, 60, 90, 120, 144, 165 fps). EtnaAutoScale picks the World Resolution from a few fixed steps (100% down to 50%) by the GPU's own time per frame, from the GPU timer on one frame in eight, so VSync and frame limiters don't hide the room there is: - two timed frames over the budget step down, one far over it two steps; - a step up only when every timed frame of the last two seconds would still fit with headroom at the bigger size, counting the whole frame as growing with the pixels, so it doesn't bounce straight back; - frames drawn before a step aren't counted after it. It never goes below World Resolution (70% when that is at 100%), is off during the benchmark, and keeps the setting without GPU timestamps. The performance log shows the resolution it picked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
…ict steps up by the scaled passes From an independent review: - The lowest step is the first one at or below World Resolution and draws at that floor exactly: at 95% Auto drew at 100% and could never go down. - It steers by the GPU time up to the end of Etna's final pass, without the HUD and the copy to the window, where a VSync wait can land on some drivers and would have held it at its lowest. - A step up predicts only the level and world passes growing with the pixels; the shadow pass, the hand, bloom and grade keep their cost. - No sentinel time for 'room since', frames timed while it didn't steer aren't counted, the GPU timer's doc names Auto Resolution. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
The warp is centred on the map's middle, so each time the middle moved, every texel of the map landed somewhere else on the world by a fraction of a texel and the map took every edge and every leaf's holes at new points. It moved a texel (0.1 blocks) at a time: while walking, most frames. The dappled shade under trees and the shadow edges further out shimmered for as long as the camera moved. Now the middle holds still in the world and steps after the camera once it is three quarters of a 2-block step away on an axis of the map (a hold, so it can't flick back and forth). Offline (a canopy of leaf blocks with holes, swaying, under the area-weighted filter, walking at 4.3 blocks a second) the mean change from one frame to the next drops from 0.05-0.09 to 0.004-0.008 of full shade, 16 to 150 blocks away; the frame the map steps is no worse than any frame was before. Near the camera texels get at most 7% wider (16% along the line to the middle). The shadows fade out towards the map's edge counted from the camera (etnaMapOut, EtnaShadowInfo.w: the share of the radius the map always covers round the camera), so where they end no longer jumps when the middle steps. The caster tests count from the middle (the square, the caster floor) or widen by the camera's lead (the columns, the view margins). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
etnaMapOut now returns at least 1 for a point outside the map itself, so every reader (filter, leaf light, single and bilinear tests, water) treats it as past the edge, as post/shafts.fsh already did. It only happens while the maps fade, when the older map is read a frame late behind a camera flying faster than the slack a frame; those points were nearly faded out but read the map's clamped edge texels. The middle-step comment now gives the texel growth for both the 160 and the 96-block distance, and says how much shorter the shadows end. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
…into claude/project-thread-5pxz6a
…mera From 20 to 44 blocks out the shadow pass fades the sway out. Further away a texel of the map is wider than the sway, which then only flips leaf texels between lit and shaded every frame: far tree shade twinkled even with the camera still. On screen the sway is under a pixel there anyway, and the leaves themselves keep swaying, by less than their shadow lookup's offset and bias (1.5 texels along the light plus the thin bias). Offline (leaflab, swaying leaf blocks with holes, area-weighted filter, the 2-block map steps): with the camera still the change per frame at 32-150 blocks goes from 0.003-0.004 to none; walking it drops by about 40%, the rest coming from the map's steps. Average shade unchanged. The far vertices also skip the wind maths. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
…into claude/project-thread-5pxz6a
Two fine noise octaves (9x and 15x the base) give the star clouds and the dust lanes' edges detail down to about three pixels at 1080p; before, the smallest detail was about 14 pixels and the band looked low resolution. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx
waterBodyShadow follows the straight line of sight into the water instead of the refracted ray. The bottom shows through the water unbent (the blend lays the water over it), so the shade in the water now lands on the shadow seen on the bottom. Before, the two sat side by side: shaded water over a lit bottom looked colourless and see-through, lit water over a shaded bottom like a patch of colour. Far water seen nearly edge on: the waves a pixel no longer resolves still tilt the facets it sees towards the eye (HIDDEN_TILT, 0.08), so they mirror sky from a little above the horizon and less of it than a flat mirror (waterSeenCos, waterSeenMirror in water_waves.glsl, used by the terrain and by the reflections pass alike). From a block or two above the water, far water mirrored almost only the whitish horizon. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xzo7zbTpyU7a3y3XQNbw1n
…into claude/project-thread-5pxz6a
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before: Etna always shaded every screen pixel. Its temporal anti-aliasing and the light shafts' 2x2 order were ported from Photon Shaders, and the jar carried the Photon Shaders License, which blocks Modrinth and CurseForge. Mobs, chests and the hand kept vanilla's flat lighting, so they didn't match the shaded world around them.
After: a new World Resolution setting (50 to 100%) draws the world at fewer pixels, and Etna's own anti-aliasing builds the full-size picture back up. Auto Resolution (off by default) picks that size by itself to hold a chosen frame rate. The anti-aliasing is new, and it is steadier and sharper than the old one even at full size. Mobs, animals, chests, signs, item frames and the first-person hand now take Etna's sun, sky and block light and sit in its shadows; this is the new Entity Lighting toggle on the Lighting page. No code from other shader packs is left, so
LICENSE-PHOTON.txtis gone and the licence is plain MIT.This branch includes PR #3 (0.8.1, merged in up to 10f1337) because the licence cleanup sits on top of that branch's own shadow warp and Fresnel. Merge #3 first; this PR's diff then shrinks to its own changes. Not tested in game yet, so don't merge until Cosimo has tested it: a merge publishes a release.
How
Render scale. While the level is drawn,
GameRenderer.mainRenderTarget()hands out a smaller target of Etna's (EtnaScale), so the whole level is drawn into it.etna_world_scaled) runs on that target.EtnaScale.LevelDepth.Auto Resolution (
EtnaAutoScale). It picks the scale from fixed steps (100% down to 50%) by the GPU's own time per frame, up to the end of Etna's final pass, timed on one frame in eight. Using GPU time means VSync and frame limiters don't hide spare room.Anti-aliasing (
taa.fsh), clean-room from the cited papers.Jitter. 8 Halton steps at full size; at smaller sizes, 8 / scale² rounded up to a power of two. The terrain now reads the current jitter from its block instead of keeping its own copy of the table.
Entity Lighting.
etna:lit/...while the level is drawn,etna:hand/...for the first-person hand. It also binds Etna's light block and shadow maps next to the default uniforms.terrain.fshintoinclude/etna_light.glsl, shared by terrain, entities and items, so a mob in shade darkens like the grass next to it.Benchmark. Two new steps: "shadow map fade" holds a fade at its middle using PR Etna 0.8.1: solid water reflections, thin shoreline foam, shadows that soften with distance #3's hook, and "entity lighting off". That makes 23 steps, about 150 seconds.
Post target sizes. Fixed sizes are now written as
REFERENCE_SIZED + size. Before, a size that happened to equal the chain's own size was taken for "no size", which made the half-size passes four times too big at 1280x720 and 75%.Robustness from review.
renderHEAD andrenderLevelRETURN.validate_shaders.pyrejects option-like arguments.Licence cleanup. Removed:
LICENSE-PHOTON.txtand its jar entry;fabric.mod.json.The techniques are credited in CREDITS.md. Version 0.9.0.
Offline TAA test bench (64 frames against a 16x supersampled reference), old vs new at full size:
At 75% it is still steadier than the old one at full size; in motion it is slightly softer.
🤖 Generated with Claude Code
https://claude.ai/code/session_01F7MajtknSApr1T68EGCPtx