Repository navigation
scenix v1.8.0 — Terrain, Sky, And Water
Scenix v1.8.0 — Terrain, Sky, And Water
Scenix 1.8.0 adds three optional, no_std-capable CPU crates for real-world
environments — scenix-terrain (heightmaps, chunked LOD, splats, collision,
streaming), scenix-sky (procedural atmosphere, sun positions, baked
environment maps), and scenix-water (Gerstner waves, foam, fresnel,
underwater tinting, mirror/reflection helpers) — plus a GPU environment draw
path in scenix-renderer behind its environment feature, material
descriptors in scenix-material, and the schema ids in scenix-core.
Everything is additive and feature-gated; the default facade build behaves
exactly like v1.7.0.
Highlights
scenix-terrainis a standalone CPU crate (std/serde): deterministic
seededHeightmap::from_noise(raw noise stays in[-1, 1],
remap_rangerefits spans),TerrainGrid::generatechunking with
TerrainConfig(chunks per axis × chunk cells ×LodPolicybands),
per-LODchunk_geometrypluschunk_geometry_with_splatthat packs
normalized splat weights into vertex color channels,SplatMaplattice
math,TerrainColliderray probes (with_step,with_max_steps,
height_at, unit-lengthnormal_at), and a deterministic
ChunkStreamerpoll/unload loop over wrapping lattices.scenix-skyprofiles produce pure direction-tap colors:
SkyModel::clear_day/overcast_hazewith a turbidity/rayleigh/mie tuning
surface;SunPositiontranslates elevation/azimuth into unit-length sun
directions and drivesSunLight/DirectionalLight(warm low sun, neutral
zenith);bake_equirectangularproduces deterministic sky maps with the
v = 0 zenith baking convention,bake_light_probeprojects radiance into
sh_coefficients taps, andbake_ambientcollapses the map into sky/ground
hemisphere averages;GroundedSkyboxfades a dome into a flat ground
patch under the horizon line.scenix-watersimulates on the CPU as the source of truth:
WaveFieldpresets (ocean_shore,calm) hold up to MAX_WAVES (4)
stackedGerstnerWaves (wave_number = 2pi/wavelength, deep-water
phase_speed);WaterSurface::geometry(t)builds displaced meshes whose
vertices matchheight_atexactly, with unit-length normals;
FoamParams::shorelinegates crest energy behind a hard threshold;
FresnelParams::waterfollows Schlick reflectance (grazing angles mirror
fully);UnderwaterViewtints with red-first absorption and distance
murk drift;mirror_transform/reflected_camerabuild the reflection
math for planar water reflections.scenix-materialadds self-containedTerrainMaterial(four splat
layers with albedo/roughness/tiling plus optional splat and detail
textures),SkyMaterial(gradient triple, direction/color/glare sun
params, fade band, atmosphere flag), andWaterMaterial(deep/shallow
tints, Schlick base reflectance, optional foam threshold/sharpness,
optional reflection/refraction textures), plusShaderKind::Terrain,
ShaderKind::Sky,ShaderKind::Watervariants and the
FEATURE_SPLAT_MAP(1 << 22),FEATURE_ATMOSPHERE(1 << 23),
FEATURE_FRESNEL(1 << 24),FEATURE_FOAM(1 << 25), and
FEATURE_REFRACTION(1 << 26) bits.scenix-renderer(behindrenderer+environment) owns an environment
registry keyed by node material ids:register_environmentupserts a slot
fromEnvironmentMaterial::Terrain/Sky/Water(terrain gets pre-packed
chunk geometry; water gets theWaveFieldthe GPU paver replays), three
WGSL pipelines run per frame — splat weights from vertex channels or the
splat texture, a depth-no-write sky dome, and an alpha-blended water
surface that displaces with the same GPU Gems wave math as the CPU —
with sky-before-opaque and water-after-transparent draw ordering, an
environment uniform belt, and dynamic bind groups rebuilt only on
registration changes.scenix-coreadds theTerrainId,SkyId, andWaterIdnewtypes;
scenix-sceneaddsNodeKind::Terrain/Sky/Waternodes whose material
link drives slot lookup at draw time.scenix-textureaddsEquirectSampler(bilinear sampling over an
equirectangular map in the sky-bake row order) andheight_to_normal_map
(central-difference height-to-normal conversion) for environment
tooling.scenix-wasmdocuments the browser fallback plan:
environment_fallback_plan(WebGlCapabilityLevel)— WebGPU gets full WGSL
parity with reflection/refraction targets, WebGL 2 renders with static
per-slot uniforms (screen-space water survives via framebuffers), and
WebGL 1 falls back to CPU-baked vertex-color tinting without
screen-space water.- The facade gains
terrain,sky,water, andenvironmentfeatures
(terrain and sky re-export lists are curated because thelod/sky/sun
module names collide with the scene, material, and light glob re-exports).
Small Example
use scenix::{EnvironmentMaterial, MaterialId, Renderer, RendererConfig, SceneGraph, SceneNode};
use scenix::{SkyId, SkyMaterial, TerrainId, TerrainMaterial, WaterId, WaterMaterial};
use scenix::{Heightmap, LodBand, LodPolicy, TerrainConfig, TerrainGrid};
let mut renderer = Renderer::headless(RendererConfig::new(320, 240)).await?;
// 1. Terrain: a small two-chunk heightfield at LOD 0.
let map = Heightmap::from_fn(17, 17, 1.0, |ix, iz| ((ix + iz) as f32) * 0.5);
let policy = LodPolicy::new(&[LodBand::new(40.0, 0)])?;
let chunk = TerrainGrid::generate(&map, TerrainConfig::new(2, 8, policy))
.chunk_geometry(0, 0)?;
let terrain = TerrainMaterial::default_palette();
renderer.register_environment(
MaterialId::new(1),
EnvironmentMaterial::Terrain(&terrain, &chunk),
)?;
// 2. Sky: a procedural dominating dome.
let sky = SkyMaterial::clear_day();
renderer.register_environment(MaterialId::new(2), EnvironmentMaterial::Sky(&sky))?;
// 3. Scene nodes key the slots through the schema.
let mut scene = SceneGraph::new();
scene.add(SceneNode::terrain("hills", TerrainId::new(1), MaterialId::new(1)));
scene.add(SceneNode::sky("backdrop", SkyId::new(1), MaterialId::new(2)));
scene.update_world_transforms();
// stats.scene_environments / stats.visible_environments are reported per
// frame; FrameStats has no post-condition on culling counts.Feature gates: environment (terrain + sky + water), renderer + environment
for the GPU draw path, material for the descriptors (default-on in the
facade), and scene for the node schema (default-on).