Repository navigation
scenix v1.6.0 — Shader Nodes And Node Materials
Scenix v1.6.0 — Shader Nodes And Node Materials
Scenix 1.6.0 adds the optional scenix-nodes crate: typed shader graphs,
node materials, and a post-node effect language with WGSL and GLSL ES 3.00
backends. Node materials are a first-class renderer draw path, the post stack
executes generated effects, and the browser preflight compiles graphs to GLSL
before anything is uploaded. Every v1.6 surface is additive and behind the
nodes feature; the default facade build behaves exactly like v1.5.0.
Highlights
scenix-nodesis a standalone,no_std-capable CPU crate: build a
ShaderGraph, validate it, and mutate CPU state with zero GPU involvement.- Graphs carry three output ports:
fragment_color,fragment_alpha, and an
optional vertexvertex_offsetdisplacement port. Only the live subgraph is
validated and lowered; dead nodes are released by construction. - A typed
ShaderNodeKindvocabulary covers uniforms, vertex attributes,
world/view fragment sources, texture sampling, splat/component shaping,
arithmetic,Mix/Clamp/Smoothstep, the five-slotRemap,Fresnel,
sRGB/linear conversion, four lighting styles, tone mappers, and fog. Nodes
carry stage metadata, so fragment-only or post-only nodes in another stage
produce specificNodeDiagnostics instead of broken shaders. - The WGSL backend emits modules that match the renderer bind contract exactly:
group 0 frame, group 1 object, group 2 material (uniform + sampler +
texture_2d), group 3 set up for fragment-stage lights, and six varyings that
mirror the built-in vertex layout.Timecompiles to the frame elapsed slot. - Codegen deduplicates common subexpressions, prunes dead nodes, and treats
vec3 lighting/fog results correctly (alpha rides thevec4constructor
because WGSL forbids implicitvec3→vec4casts). NodeMaterialpairs a graph with CPU state (base color, emissive, metallic,
roughness, alpha mode/cutoff, double-sided, texture id). It reports the
FEATURE_NODE_GRAPHbit, aCustomshader-kind pipeline key, a stable graph
hash that ignores live CPU state, and optionalserdesupport.Renderer::register_node_material(behind the renderer'snodesfeature)
registers slots, packs node uniforms in the standard material block, builds
node pipelines lazily perNodeMaterialSlot, switches pipelines per draw,
buckets transparency from the slot's alpha mode, and rejects unregistered
node materials during culling with the same error pipeline as built-ins.PostNodeEffectpost graphs ship atomic presets (passthrough, vignette,
desaturate, posterize, pixelate, color grade, exposure) plus
scenix-post::NodeEffectProgram, which owns one generated module, builds
per-format pipelines lazily, and drives the[f32; 8]parameter contract
through the standard post pass.- The
scenix-wasmbrowser preflight compiles a serializedNodeMaterial
into GLSL with a diagnostic payload (compile_node_material_glsl) or
validates it without codegen (validate_node_material_json) — no GPU, no
renderer state, panic-free JsValue surfaces. - Color-like nodes (lighting, tone mapping, fog, conversions) accept rgba base
colors directly and drop alpha in codegen, so scripts authored against vec4
colors flow through unchanged.
Small Example
use scenix::{
generate_material_wgsl, LightingStyle, Material, NodeInput, NodeMaterial, ShaderGraph,
ShaderNodeKind, UniformInput, WgslOptions,
};
// Base color pulses over time, then feeds a Lambert lighting term.
let mut graph = ShaderGraph::new();
let base = graph.push(ShaderNodeKind::Uniform(UniformInput::BaseColor));
let time = graph.push(ShaderNodeKind::Uniform(UniformInput::Time));
let pulse = graph.add(
ShaderNodeKind::Multiply,
vec![NodeInput::Node(base), NodeInput::Node(time)],
);
let lit = graph.chain(ShaderNodeKind::Lighting(LightingStyle::Lambert), pulse);
graph.add_fragment_output(lit, None);
let material = NodeMaterial::new("pulse", graph);
assert!(material.validate().is_empty());
assert!(material.feature_bits() & scenix::FEATURE_NODE_GRAPH != 0);
let wgsl = generate_material_wgsl(&material, &WgslOptions::default()).unwrap();
// wgsl.source() is renderer-ready: bind groups 0..=3 follow the scenix
// contract, and Time resolved to frame.resolution.z.Feature Flags
nodes: enablesscenix-nodesthrough the facade with curated re-exports
(node vocabulary, materials, generators, diagnostics, parameter slots).nodes+renderer: node-material slots enter the draw path with lazy
pipelines and per-drawset_pipelineswitching.nodes+post:NodeEffectProgramexecutes generated post graphs.nodes+wasm: browser-side GLSL preflight for node editors.scenix-nodesstandalone:no_std-capable CPU crate (std/serde features).
Examples
cargo run -p scenix --example nodes_material --features nodes
cargo run -p scenix --example nodes_wgsl --features nodes
cargo run -p scenix --example node_post_effect --features nodesCompatibility
- All 18 workspace crates are version
1.6.0and require Rust1.98. - No existing enum gained variants; default features are unchanged.
- The renderer frame uniform now packs
[width, height, elapsed, 1 / height];
built-in shaders are unaffected, and directFrameUniformconsumers outside
scenix should account for the elapsed slot. - Node graphs that cannot resolve produce a typed
NodeDiagnostic
(StageUnsupported, port mismatches, cycles,UnknownNode) rather than a
panicking pipeline;NodeMaterial::validatecovers the fragment stage and
ShaderGraph::validate(Stage::Vertex)covers displacement ports explicitly. - GPU-gated tests (
SCENIX_RUN_GPU_TESTS=1) cover headless node rendering,
mixed node/builtin draws, culling rejection, and registration validation;
dedicated benchmarks cover graph build/lower hot paths.
See the full changelog and the
node API guide for API and verification
details.