Aurora 0.4
What's new
Aurora X v2.0
121 files added, 19 modified, nothing deleted.
Settings are split across six screens in the in-game shader menu: Volumetric Clouds · Water & Reflections · Sky · Nether & End · Volumetric Light · Post Processing 72 options in total (49 sliders, 23 toggles). Everything can be switched off.
Depth of field ships off. Turn it on in Post Processing. It's tiring during normal play, but it's nice for screenshots.
If the frame rate hurts, in this order: Cloud Quality → Low, AO Samples → 6, Reflection Steps → 8, Bloom Radius → 50. Every effect also has its own off switch.
Bugs found and fixed
These are the pack's own bugs — not things v2.0 introduced, things it uncovered.
screen2view was never defined. gbuffers_skybasic.fsh called it, but it
wasn't in transformations.glsl, so the sky program simply didn't compile on Iris
1.17+. Wrote the function.
Nothing ever included gbuffers_basic. The file was sitting there without an
entry point. It's the root of the fallback chain, so everything under it went down
with it: chests, signs, beds, banners, item frames, particles, the block selection
outline, beacon beams, the sun and the moon — all of it was being drawn by Iris's
built-in shader. No pack fog, no ambient, no directional shading. That's why a
chest lit differently from the block next to it. Added three programs
(gbuffers_basic, gbuffers_textured, gbuffers_textured_lit); all eight
categories now go through the pack.
The old gbuffers_basic.fsh also did texture × lightmap × colour, which made
the selection outline invisible in the dark. Dropped the lightmap.
There was no block.properties. The code checked IDs 10008, 10014, 10031,
10059, 10068, 10072, 10175, 10176 and 20008, but the mapping file wasn't in the
pack — so mc_Entity.x was always 0 and every one of those checks silently
did nothing: glowing ores, glass alpha, the waxed copper highlight, flat lighting
on thin plants. Wrote the file; the numbering was reverse-engineered from the
values in the code (10000 + legacy block ID).
isEyeInWater was declared vec3 in gbuffers_clouds.vsh (it's an int).
That would have broken compilation pre-1.17. Now an int.
Something was writing to colortex6 that nothing read. gbuffers_clouds wrote
it, no pass consumed it, and two full-screen buffers were being allocated for
nothing. Removed.
The lighting was completely flat, and the reason was measurable. All six face directions in shadow came out at exactly 0.750 — there was no directional term at all. In a forest almost everything is in shadow, so the whole canopy collapsed into one flat green mass. On top of that the sun term used a fixed gain of 2.5, which clamps every face more than ~24° off the sun to the same value: in sunlight, six faces produced two distinct brightnesses.
| before | after | |
|---|---|---|
| Distinct brightnesses in shadow (of 6) | 1 | 6 |
| Spread in shadow | 0.000 | 0.254 |
| Distinct brightnesses in sun | 2 | 6 |
| Spread in sun | 0.486 | 0.747 |
New: sky
Volumetric clouds
Ray-marched cumulus layer. 3D value noise built from noisetex, FBM shape plus high-frequency detail erosion, a flat-bottomed height profile, a light march towards the sun, Beer + powder, a dual-lobe Henyey-Greenstein phase and a three-octave multiple-scattering approximation. A weather map makes the sky patchy, it closes over in rain, and distant clouds fade into the fog. Soft cloud shadows land on the world.
Vanilla's cubic clouds are discarded.
Aurora
Folding curtains in the night sky. Domain warp plus fine vertical striations. Fades out at dawn and in rain, and costs nothing during the day.
End sky
Procedural nebula and star field, sampled straight from the view direction with 3D noise — no seam anywhere on the sphere, which a lat/long parameterisation would have given you.
Volumetric light
Dithered ray march through the shadow map with Henyey-Greenstein forward scattering. Strongest with a low sun and in rain. Range is capped by shadowDistance, so the cost doesn't grow with render distance. Fades out on its own underground.
New: water
Waves — animated displacement, wave normals, a specular glint on the crests.
Reflections (SSR) — screen-space ray march with binary refinement. How much reflects is driven by Fresnel, so looking down at water you still read the Minecraft water texture and only grazing angles go mirror-like. There's a ceiling on top of that (65% by default), so the texture never disappears entirely at any angle. Rays that leave the screen fall back to the sky.
Refraction — the bottom seen through the surface is displaced by the wave slope. The displacement is a world-space amount divided by distance on screen; otherwise far water shimmers harder than the water at your feet, which is backwards. If the offset lands on something in front of the water the sample is rejected, or you'd smear the bank across the surface. Underwater, the same value wobbles the whole view.
Absorption — not a mix() toward one colour. Water eats red first, then green,
and barely touches blue. The colour comes out of the thickness of the water column
(depthtex0 vs depthtex1), not out of a fixed tint:
| depth | colour over a sand bottom | blue/red |
|---|---|---|
| 0 blocks | (0.80, 0.72, 0.52) | 0.65 — the bottom itself |
| 1 block | (0.51, 0.69, 0.55) | 1.08 |
| 4 blocks | (0.14, 0.62, 0.60) | 4.19 |
| 16 blocks | (0.03, 0.38, 0.58) | 18.1 |
The scattering term follows the sky, so deep water doesn't go to black but doesn't glow on its own at midnight either.
Wet ground in rain — surfaces that can see the sky darken and go glossy, with patchy puddles driven by noise, and they pick up reflections from the same SSR pass.
New: the Nether and the End
The pack shipped with only world0, which meant both dimensions fell all the
way back to vanilla. There are now world-1 and world1 program sets (15 programs
each). Anything that needs a sun, clouds or weather is #undef'd outside the
overworld — the shadow pass doesn't even run in the Nether.
Nether portal — parallax occlusion. The texture's own brightness is used as a
height field: the ray walks in from the surface, the field rises to meet it, and
where they cross is the surface for that pixel. Near parts of the swirl hide the far
ones, and the whole thing slides as you walk past. Samples are wrapped inside their
own atlas tile with fract() (otherwise you get the neighbouring block inside your
portal), and the recess closes at grazing angles the way a real recess does —
without that it reads as a tunnel going on forever.
Nether lava bounce — vanilla's lightmap gives the top of a block and its underside the same value; added a warm term weighted towards downward-facing surfaces. Lava now emits its own light.
The End — purple ambient (the pack had #ifdef THE_END code that never ran;
it's live now) plus the procedural void sky.
New: lighting and post
Directional ambient — sky light from above weighted against bounce light from below by the face normal. Where the sun doesn't reach, this is the only thing shaping anything.
Softer sun falloff — gain 250% → 150%. 250% is the original look.
Specular — Fresnel-weighted sun glint. About 15 instructions and zero texture fetches. It's the only lighting term that changes when the camera moves rather than when the world does.
SSAO — contact shadows in corners, window recesses and along kerbs. The normal is rebuilt from the depth buffer, so no extra g-buffer.
Bloom — bright pass plus a separable gaussian, two passes × 7 bilinear taps.
Sharpening — 4-tap unsharp mask, applied before the bloom (after it, you'd just get a dark ring around every glow).
Colour grading — deliberately not a filmic tonemap. Reinhard/ACES-style curves lift the black point and pull colour towards grey, and they buy you nothing here because the pack is already LDR. Instead: an S-curve anchored at black and white, plus saturation. Measured on your own screenshot: black 0.144 → 0.110 (it went down), white 0.845 → 0.929, contrast +21%, saturation +47%.
Depth of field — centre-focused, 12 taps on two rings. Near-field blur is deliberately weaker than the far field. Off by default.
Performance
The cloud ray march was optimised in three stages:
- A provable early out in the shape FBM — after each octave you know the most the remaining octaves can still add, so a sample that can't clear the threshold even in the best case is dropped at octave 2. Not an approximation; exact, and costs nothing in image quality.
- The density function was split into a cheap half and an expensive half. The detail FBM and the light march only run once the cheap half says there's actually a cloud there.
- The light march reuses the previous result once the ray has already gone opaque.
Texture fetches per pixel: 305–565 → 145–272 (~2.1×). Difference from the reference is 39.7 dB PSNR — you can't see it. Looking at the horizon, ~51% of pixels are culled before a single sample.
SSAO moved to a checkerboard (occlusion is low frequency and the blur averages it anyway). The blur weights by a validity flag, so skipped pixels contribute nothing rather than contributing a wrong value:
| pass | before | after |
|---|---|---|
| deferred: SSAO | 16.0 | 8.0 |
| deferred1: AO blur | 18.0 | 13.5 |
| specular | — | 0.0 |
| sharpening | — | 4.0 |
| total | 34.0 | 25.5 |
So a near pixel is 25% cheaper even with specular and sharpening added on top. The checkerboard differs from full rate by 0.0022 on average, 0.0301 at p99.
Per-frame clears are off for the intermediate buffers, since they're fully overwritten anyway.
Verification
- Compilation: 3 dimensions × 294 programs × 33 setting combinations (Iris/OptiFine, 1.16.5/1.21, every effect off individually and all together, 4 cloud qualities) — clean.
- SSAO: the first version used
dFdx/dFdy, which reads across silhouettes and mixes two different surfaces, putting a dark outline on every block edge. Fixed by picking, per axis, whichever neighbour is closer in depth. The regression test measures AO in the 2px ring next to sky: 0.96 (the bug would push it well below 0.9). - SSR: in a synthetic mirror scene, 99.6% of reflective pixels find the analytically correct point, mean error 0.23 blocks.
- Portal: neighbouring atlas tiles were painted red and tested at 8 angles — not one pixel of bleed. The slide peaks at 0.40 tiles at 45° and falls to 0.009 at 85°. The contrast curve is a bijection on [0,1], monotone, with the pivot exactly fixed.
- Water absorption: at zero depth the bottom is preserved exactly, red is absorbed faster than blue, the blue/red ratio rises monotonically through the transmissive range, deep water is blue > green > red, and no channel overflows.
- Grading: verified on a real screenshot that the black point doesn't lift, contrast goes up and saturation doesn't drop.
- Pipeline: buffer read/write order checked in every dimension — no pass reads a buffer before something writes it. Every menu option has a matching define in shader.h and a label in the lang file.
Known limits
- The colours were tuned without seeing them in game. The maths behind each effect is tested, but the brightness and density choices were made against offline renders. If anything is too much or too little, that's what the sliders are for.
- No End portal. It's a block entity, which needs
gbuffers_block, and I couldn't test whether block entity IDs come through reliably. - A very high-contrast portal texture can terrace. Raise Portal Steps; portal pixels are a tiny fraction of the screen so the cost is irrelevant.
- No anti-aliasing. Thin railings and poles are still jagged. FXAA would be one pass; TAA would be better and would pay for itself by letting the cloud and SSAO sample counts drop, but it's a serious piece of work.
All Relations
- All Relations
- Embedded Library
- Optional Dependency
- Required Dependency
- Tool
- Incompatible
- Include
This mod has no related projects

