The goal is to:
- allow aggressive mesh sharing
- avoid implicit state
- support procedural and imported geometry
- keep rendering explicit and predictable
1. Mesh: Pure Geometry Data
A Mesh represents geometry only.
It contains:
- vertex data
- index data
- bounds (AABB)
- GPU render data
A mesh does not represent a scene object.
_cubeMesh = assets.Add<Mesh>("CubeMesh", Cube.GetMesh(defaultMaterial));
Meshes are:
- reusable
- shareable
- asset-managed
- independent of transforms
2. Default Material on Meshes
A mesh may define a default material.
_cubeMesh.Material = defaultMaterial;
This allows:
- simple use cases without per-object materials
- safe fallback behavior
- minimal setup for primitives
- its an reference only. The material should be an own asset
3. Primitives: Scene-Level Geometry Instances
A Primitive is a GameElement that references a mesh.
var ground = new Primitive("Ground", _cubeMesh);
A primitive:
- owns a transform
- participates in scene hierarchy
- does NOT own geometry
- does NOT own GPU memory
Multiple primitives may reference the same mesh.
4. Material Overrides per Primitive
Primitives may override the mesh’s default material.
var rightCube = new Primitive("RightCube", _cubeMesh, debugMaterial);
Material resolution order:
- Primitive material override
- Mesh default material
This allows:
- one mesh, many visual styles
- debug rendering
- editor highlighting
- instanced variations
5. Rendering Contract
Rendering is handled by the renderer using explicit parameters.
renderer.DrawMesh(transform, mesh, materialOverride);
The renderer:
- never mutates mesh state
- never assumes materials
- resolves material explicitly
This avoids hidden state and side effects.
6. Procedural Mesh Generation
Meshes can be generated procedurally using static factories.
Mesh sphere = Sphere.GetMesh();
Mesh cube = Cube.GetMesh(defaultMaterial);
Procedural meshes:
- produce CPU-side data
- can be registered as assets
- follow the same lifetime rules as imported meshes
This makes primitives and imported models behave identically.
7. Mesh Sharing & Instancing
Meshes are designed to be shared aggressively.
Example:
var leftCube = new Primitive("LeftCube", _cubeMesh);
var rightCube = new Primitive("RightCube", _cubeMesh);
Benefits:
- minimal GPU memory usage
- cache-friendly rendering
- consistent bounds and collision
For high-volume objects, MeshInstancer is used.
var instancer = new MeshInstancer(_projectileMesh, debugMaterial);
8. Materials as Assets
Materials are assets and are managed by the AssetManager.
_defaultMaterial = assets.Add(new SGMaterial("DefaultMaterial", color));
Materials:
- manage textures and uniforms
- can be shared across meshes and primitives
- are not scene-owned
9. Transparency & Render Ordering
Transparency is determined by the effective material.
public override bool HasTransparency =>
Material?.IsTransparent ?? Mesh.Material?.IsTransparent ?? false;
This ensures:
- correct render sorting
- consistent behavior for overrides
- predictable blending
10. Ownership Rules (Very Important)
Primitives never dispose meshes or materials.
Summary
The mesh system in GFX-Next is built around:
- strict separation of geometry and instances
- explicit material resolution
- aggressive mesh sharing
- predictable rendering contracts
- asset-managed lifetime
This keeps rendering scalable, debuggable, and editor-safe.