Cetra v0.23.0
github.com/monological/cetraA real-time 3D graphics engine written in C11 on OpenGL 4.1 core. No system dependencies. glfw, glew, cglm, assimp, Jolt and Dear ImGui are vendored and built from source. An optional game framework sits over it: fixed timestep, physics, animation, audio, UI and saves. Runs on macOS, Linux and Windows.
Rendering
- Forward renderer, HDR + MSAA, multi-target G-buffer (color / normals / motion / albedo / SSS)
- Clustered forward light culling on a 16x8x24 frustum grid, up to 64 lights per draw
- Temporal AA, plus TAAU render-scale upscaling with runtime resolution switching
- Supersampling, moment-based order-independent transparency, screen-space refraction
- Instanced submission through a std140 instance block, with meshoptimizer LOD chains as index ranges in one buffer
- Cluster-DAG LOD: 128-triangle clusters grouped and simplified with their boundaries locked, every level indexing the original vertex buffer, so cracks are structurally impossible
- Front-to-back opaque ordering, optional depth prepass, frustum culling, including conservative bounds for wind and skinning, which displace vertices past the mesh's authored box
- Occlusion culling: authored occluders rasterised on the CPU into a masked depth buffer from this frame's camera, so there is no query, no readback and nothing to pop
- Per-material shader variants: every lit surface compiles to a program carrying only the features that material uses, with the uber-shader as the fallback rather than the exception
- Clustered decals projected through an oriented box, selected by a per-froxel mask
- Soft particles, shadow catcher, procedural skybox and HDR ground projection
Lighting
- Directional, point, spot and rectangular area lights on photometric (EV100) intensities
- IES photometric profiles: a real luminaire's measured 2D distribution, replacing a spot's analytic cone rather than multiplying it
- Emissive geometry derived as LTC area panels, by fitting a rectangle to the mesh
- Cascaded and punctual shadow maps, PCF with optional stochastic PCSS contact hardening
- Moment shadow maps, and translucent casters that attenuate instead of blocking
- Rectangular area-light shading via linearly transformed cosines
- Split-sum IBL, from an HDR probe or baked from the sky
- Hillaire physically-based atmosphere, with aerial perspective and a volumetric cloud layer
- Cloud shadows: a sun-transmittance map through the deck, reaching the ground, the fog and the water
- A day/night cycle on one clock, driving the sun and the stars together, with the environment re-bake sliced across frames and swapped atomically
- A procedural star field on two octahedral lattices, ramped through civil twilight
- A night-sky floor of airglow, zodiacal light and integrated starlight, inside the sky LUT, so it lifts the ground and the environment rather than only the backdrop
- The moon: phase derived from the sun rather than authored, Lommel-Seeliger shading over a baked crater surface, casting its own light
- DDGI irradiance probe volume; up to eight parallax-corrected reflection probes, blended per fragment off a per-froxel mask
- Screen-space contact shadows, marching the key light and every local light with no shadow map
Water
- Tessendorf spectral ocean over three cascades, or a cheaper Gerstner surface
- The FFT runs as fragment ping-pong. GL 4.1 has no compute stage, and a Stockham butterfly is a pure gather, so it costs draws rather than a redesign
- Two summed directional wave trains, wind sea and swell, each with its own wind speed and fetch on a JONSWAP/TMA spectrum
- A projected grid in NDC rather than a clipmap, so cell density is uniform in pixels and the surface reaches the horizon
- Shoaling against a bed field, with depth-limited breaking and a traced shoreline driving the swash
- Foam in three bands: crest from the Jacobian, shore from the shoal factor, whitecaps from the breaking face. Accumulated per cascade texel, so it persists beyond the wave that made it
- Volume absorption from per-channel extinction, plus caustics derived from the surface's own compression
- In-scatter as a fraction of the light actually falling on the sea, lit by the brightest directional, so the water tracks its own light and can be lit by the moon
- A submerged camera turns the body into a second froxel medium
- Cox-Munk sun glitter, wind-anisotropic, with far-field roughness derived from the spectrum's own slope variance
- A CPU query of the Gerstner surface, so gameplay and physics can stand on the water
Terrain
- A CDLOD quadtree: fine patches near the camera and coarse ones away, so the patch count tracks how many levels there are rather than how much ground they cover
- Patches are CPU-built off the height function shared by the collider and the scatter, rather than a shared grid displaced by a height texture, which would be a different surface
- Height from a runtime fBm or a stored field behind one sampler, with a filtered mip pyramid, and a 16-bit heightmap on either side of it
- Mei virtual-pipes hydraulic and thermal erosion, threaded and bit-identical at any worker count, producing flow, deposit and wear masks alongside the eroded heightfield
- Layered materials: N layers blended per texel from a splat, height-weighted so gravel interlocks with sand, on a world-aligned triplanar projection
- Roads as splat-weight overrides, applied before the height blend so a road is made of a layer instead of painted over one
- A composite cache over the blend, plus a paged virtual texture whose residency is driven by frustum prediction and a GPU feedback pass
- Streaming: an fp32 tiled pyramid on disk with one rectangular window resident per level, so extending a world adds no resident memory and only raising its resolution does
- A walkable island with props and collision resident per region around the player
Materials
- Metallic-roughness PBR with multi-scatter energy compensation
- glTF extensions: clearcoat, sheen (Charlie, with an environment prefilter), specular, transmission / IOR, volume / thickness
- Subsurface scattering: pre-integrated skin diffuse over a screen-space scatter pyramid
- Anisotropy, and hair with strand orientation and identity riding the same channel
- Parallax occlusion mapping, thin film, vertex colors, a second UV set
- 14 texture slots, plus a scene-wide array of unique per-texel images (masks, material layers and decals), so a whole feature costs a layer index rather than a sampler declaration
- Block-compressed storage chosen by the texture's declared role: BC5 for normals, BC4 for single-channel masks, colour opt-in because DXT quantises endpoints
- Alpha-tested cutouts that keep their coverage down the mip chain, and honour their authored cutoff at any sample count
- Pooled loads and async streaming
- Procedural generators for terrain, sand, rock, foliage and trees, with histogram-preserving stochastic sampling so a tiled texture stops reading as tiled
Post-processing
- GTAO on the visibility bitmask, with specular occlusion read from the same sector mask and a depth-aware bilateral upsample off half res; screen-space GI
- Screen-space reflections: hi-z trace, temporal accumulation, à-trous denoise
- Froxel volumetric fog (god rays, height haze) with local fog volumes, and aerial perspective
- Bokeh depth of field, McGuire motion blur, bloom pyramid, lens flare
- Histogram auto-exposure with uniform / centre-weighted / spot metering and percentile tails
- The Purkinje shift: rod vision in dim light, gated on both per-pixel radiance and the frame's own metered level, so a daylit shadow stays coloured and a moonlit sea drains
- ACES / AgX / neutral tonemaps, 3D LUT colour grading from a
.cubetable with tetrahedral interpolation, film finish (grain, vignette, chromatic aberration, sharpen, grade, output dither)
Animation
- Skeletal animation, GPU skinning up to 128 bones, prev-pose motion vectors
- Cross-rig retargeting by semantic bone matching, given the rig a clip was authored on, so a third-party character reconciles its channels instead of applying the rotations raw
- A phase-synced 1D blend space on one clock, so a foot planted 40% through the walk is planted 40% through the run; a crossfade whose settled pose is the incoming clip's own; one bone-masked override layer that releases itself; clip events dispatched after the pose is applied
- An animation state machine: a table of states over registered playback sources and a table of transitions over a closed condition vocabulary, resolved at bind against the rig actually loaded, so a state whose clip the rig lacks is unreachable and every transition into it is pruned
- Stride matching: the ground speed a clip's own feet imply, measured from the median toe velocity over its planted samples and blended across the space, so playback rate follows travel speed
- Root motion: a clip states how far its root travels and the character moves exactly that far, extracted per blend entry rather than from the blended pose
- Two-bone IK with foot planting on what a ray finds, the bend plane derived from how the rig binds its own knee, and sole clearance taken from the bind pose so a caller states a ground height rather than an ankle target
- Foot locking: a contact labelled from the ankle's lift and vertical speed, pinned at the toe in world space, and held until the label ends or the clip carries the foot past its unlock distance
- Ragdoll: twelve capsules derived from the bind pose with no authored asset, sized from the per-bone boxes the culler already measures, started from the live pose and written back at the pose seam, replacing the pose rather than correcting it
- Verlet spring bones for secondary motion
- Directional wind driving foliage, grass and cloth
Game framework
Optional, and layered over the engine rather than under it. A rendering-only app never meets any of it.
- Fixed-timestep loop with Jolt physics: rigid bodies, raycasts and sweeps, five constraint types with motors, and a
CharacterVirtualcontroller - ECS-lite entities with rigid-body, character, animator and audio-source components
- Audio: one device wrapping miniaudio, 2D one-shots and music, mixer buses, and 3D positional sound with the camera as listener. A headless run opens no device and renders offline instead
- A UI layer: a retained element tree over a two-pass layout, a geometric focus model, and a theme whose every zero means inherit, drawn after tone mapping so a menu is never graded or rescaled
- Save games: entities by name, components by name, spawned objects carrying the recipe that made them, per-section versions with a migration chain, and an atomic write
- Player settings persisted in the platform's own per-user location, including window mode: windowed, exclusive fullscreen or borderless, on a monitor stored by name
- Input as named actions over keys, mouse buttons, pad buttons and axes, so a stick and a key pair are one action; gamepads through GLFW's standard layout with hot-plug and a loadable mapping file
- Camera rigs of an anchor, an arm and an aim, with no mode enum: a follow is an anchor that moves, a viewer orbit one that does not, first person a distance of zero. Arm response, an occlusion probe seam, a pose blend, a decaying shake and a Catmull-Rom rail
Systems
- Scene graph with hierarchical transforms; lights, cameras and particle systems are first-class nodes
- Particle system: composable spawn/init/update modules, CPU and transform-feedback backends, curl noise, colliders
.cscnscene format with a Blender exporter that bakes material graphs glTF cannot carry- A JSON config snapshot: around 230 tuned settings dumped and restored, so a session can be handed to someone else instead of described
- A world origin shift, for worlds too large to measure from one point in fp32
- A derived-data cook: a content-addressed cache over the deterministic startup bakes (cluster DAGs, Jolt shapes, eroded fields, mip chains), keyed on the identity of its inputs, so a stale artefact is unfindable rather than detected
- Builds as a subdirectory of another CMake project, with no install step, bringing its include paths and vendored libraries with it
- FBX / glTF / GLB / OBJ import, SDF text rendering, Dear ImGui debug panels
- GPU profiler: per-pass GPU and CPU time with submission counts, in a HUD table and on stdout
- A golden-image corpus and a gate suite of fixtures whose answer is known in advance