跳转至

Grain-scale rendering

The simulation surface remains the existing 512-square heightfield mesh. The realism pass deliberately keeps the deployed rendering architecture and its interaction/performance profile: there is still one bounded 3×3 procedural-grain neighborhood search per visible surface fragment, no explicit bed-grain mesh, no per-pixel raymarch, and no additional render pass.

The former grain field used a regular 0.43 mm jittered Voronoi lattice. At a glance it was convincing, but close inspection exposed the repeated statistical structure: grain footprints were too similar, dark minerals were distributed too uniformly, and the micro-relief read more like a material function than irregular packed beach sand.

The revised field keeps the same neighborhood count but makes each candidate grain anisotropic. The existing per-cell random values now determine an orientation and aspect ratio, and distances are evaluated in that grain-local metric. A small smooth world-locked coordinate warp bends the otherwise regular lattice without introducing another stochastic texture lookup. The winning grain therefore has a distinct elongated/rounded footprint while the shader still evaluates the same nine neighboring cells as before.

The selected grain also receives a second deterministic seed after the neighborhood search. That seed drives crown height, faceting, mineral family, roughness, and restrained translucency. Because the extra seed is evaluated only for the winning grain rather than for every candidate, the realism work stays bounded.

Material response now uses overlapping quartz-like, feldspar-like, pale mineral, iron-rich, and dark heavy-mineral families. A very coarse world-space composition seed only biases which families appear in a region; it does not directly multiply the surface color, so composition can drift over centimeters without introducing visible patch boundaries. The overall sand palette, direct-light level, environment model, and existing post-processing path are intentionally preserved from the checkpoint.

Grain-scale depth remains a small fragment-depth displacement derived from the selected analytic crown. Micro-normal direction now follows the anisotropic grain footprint rather than a circular radial bump. Crevices retain stronger local occlusion, while translucent mineral families receive only a restrained body-light term. This is intentionally a small optical correction rather than a full subsurface or path-traced transport model.

The key performance constraint is that this pass does not double the grain candidate population. The abandoned heavy approach evaluated eighteen analytic candidates per fragment with multiple per-candidate trigonometric/power operations and replaced the display pipeline at the same time; at multi-million-pixel drawing buffers that could saturate the GPU badly enough that simulation/input appeared non-responsive. The shipped retry instead keeps nine candidates, computes the two smooth warp waves once per fragment, and leaves the established HDR-to-display path untouched.

Mobile alias control

The mobile artifact was isolated to the procedural grain material itself, not the simulation grid, lighting cache, or mobile layout. grainAppearance() places one randomly jittered grain inside every regular 0.43 mm world-space cell. In a portrait phone view, perspective drives that cell spacing through roughly one rendered pixel across the middle of the bed. Sampling the regular cell lattice at the regular framebuffer lattice creates the visible fan/ring moiré pattern. A standalone reproduction of only the grain function and camera projection produces the same pattern, while the heightfield normal signal does not produce that fan structure.

Desktop keeps the original shader unchanged. Mobile keeps the same world-space grain function as well, but once the projected grain spacing enters the alias-prone range, each framebuffer pixel takes a stable stochastic sample at a different location inside its actual world-space pixel footprint. This breaks the coherent phase relationship between the two lattices and turns the unresolved sub-pixel detail into the grain's own stochastic statistics instead of a large-scale false pattern. The stochastic sample is already the anti-moire filter, so mobile does not additionally fade visible grain albedo, micro-normal, roughness, or crevice contrast as the footprint grows; doing both created a strong top-to-bottom sharpness gradient in portrait views. Fragment-depth grain relief is still independently faded once it is too small to resolve, which avoids noisy sub-pixel depth without softening the visible material. Desktop remains unchanged.

Sun glints and bloom

Reflective mineral chips stay physically tiny and sparse. Candidate chips are world-locked in the existing 4.8 mm cells, with physical radii of roughly 0.06-0.14 mm. Their visible sparkle is not produced by enlarging the mineral itself.

For each candidate, the shader computes the microfacet slope required to reflect the real sun direction into the fixed camera. The glint now uses the resolved grain micro-normal and a material-family affinity, so dark/rough grains are less likely to produce the same flash response as pale reflective minerals. Rather than testing a handful of explicit facet normals, it evaluates a broad crystal-slope distribution at that required slope and makes one deterministic Bernoulli draw per chip. This is a bounded stochastic-microfacet approximation: the chip represents many unresolved crystal faces, and only a small stable subset produce a solar flash. Changing the surface normal or light geometry changes that probability naturally.

The physical chip remains sub-pixel, but its solar reflection receives a minimum approximately one-pixel optical footprint so its energy cannot disappear between framebuffer samples. The final visible sparkle shape is intentionally completed in post as a soft optical event with a compact core, short streaks, and a smeared glow rather than as a simple white disk. Coconut/direct-light visibility attenuates the glint before it is written to the second MRT attachment (r16float). The post composite additionally scales the visible sparkle footprint and gain down in portrait mobile viewports so the flash stays visually proportional to the finer apparent grain scale there. The base sand radiance is unchanged.