Mesh
Description
Section titled “Description”High-level geometry container. A Mesh owns a list of vertices and optional instances. Internally it deduplicates vertices and always draws indexed and instanced (instance_count defaults to 1 when none are provided).
Vertex layouts are managed by the Shader. At render time, inputs declared in your shader’s vertex function (annotated with @location(N)) are derived from the source and matched by name and type to Mesh properties across both streams (instance first, then vertex).
Mapping is driven by shader reflection; there are no special-case names or reserved locations. The renderer matches attributes by explicit location if provided (instance first, then vertex), and otherwise by name.
If a required input cannot be found or its type does not match, rendering returns an error indicating the missing attribute or mismatch.
Example
Section titled “Example”use fragmentcolor::mesh::{Mesh, Vertex, VertexValue};
let mut mesh = Mesh::new();mesh.add_vertex([0.0, 0.5, 0.0]);mesh.add_vertex([-0.5, -0.5, 0.0]);mesh.add_vertex([0.5, -0.5, 0.0]);import { Mesh, Vertex } from "fragmentcolor";
const mesh = new Mesh();mesh.addVertex([0.0, 0.5, 0.0]);mesh.addVertex([-0.5, -0.5, 0.0]);mesh.addVertex([0.5, -0.5, 0.0]);from fragmentcolor import Mesh, Vertex
mesh = Mesh()mesh.add_vertex([0.0, 0.5, 0.0])mesh.add_vertex([-0.5, -0.5, 0.0])mesh.add_vertex([0.5, -0.5, 0.0])import FragmentColor
let mesh = Mesh()try mesh.addVertex([0.0, 0.5, 0.0])try mesh.addVertex([-0.5, -0.5, 0.0])try mesh.addVertex([0.5, -0.5, 0.0])import org.fragmentcolor.*
val mesh = Mesh()mesh.addVertex(Vertex(listOf(0.0f, 0.5f, 0.0f)))mesh.addVertex(Vertex(listOf(-0.5f, -0.5f, 0.0f)))mesh.addVertex(Vertex(listOf(0.5f, -0.5f, 0.0f)))Methods
Section titled “Methods”Mesh::new
Section titled “Mesh::new”Create an empty mesh. Add vertices with add_vertex (or add_vertices)
and instances with add_instance, then attach the mesh to a shader to
draw it.
Example
Section titled “Example”use fragmentcolor::mesh::Mesh;let m = Mesh::new();1 collapsed line
_ = m;import { Mesh } from "fragmentcolor";const m = new Mesh();from fragmentcolor import Meshm = Mesh()import FragmentColorlet m = Mesh()import org.fragmentcolor.*val m = Mesh()Mesh::from_vertices
Section titled “Mesh::from_vertices”Create a mesh from an iterator of Vertex values.
Example
Section titled “Example”use fragmentcolor::Mesh;
let mesh = Mesh::from_vertices([ [0.0, 0.0], [1.0, 0.0], [0.0, 1.0],]);import { Mesh } from "fragmentcolor";
const mesh = Mesh.fromVertices([ [0.0, 0.0], [1.0, 0.0], [0.0, 1.0], ]);from fragmentcolor import Mesh
mesh = Mesh.from_vertices([ [0.0, 0.0], [1.0, 0.0], [0.0, 1.0],])import FragmentColor
let mesh = try Mesh.fromVertices([ [0.0, 0.0], [1.0, 0.0], [0.0, 1.0],])import org.fragmentcolor.*
val mesh = Mesh.fromVertices(listOf(Vertex(listOf(0.0f, 0.0f)), Vertex(listOf(1.0f, 0.0f)), Vertex(listOf(0.0f, 1.0f))))Mesh::add_vertex
Section titled “Mesh::add_vertex”Append a single vertex to the mesh. Pass an array literal for the
position ([x, y] or [x, y, z]); for vertices that carry uv, color,
or other per-vertex attributes, build a Vertex
first and pass it in.
Example
Section titled “Example”use fragmentcolor::mesh::{Mesh};let mut m = Mesh::new();m.add_vertex([0.0, 0.0]);import { Mesh } from "fragmentcolor";const m = new Mesh();m.addVertex([0.0, 0.0]);from fragmentcolor import Meshm = Mesh()m.add_vertex([0.0, 0.0])import FragmentColorlet m = Mesh()try m.addVertex([0.0, 0.0])import org.fragmentcolor.*val m = Mesh()m.addVertex(Vertex(listOf(0.0f, 0.0f)))Mesh::add_vertices
Section titled “Mesh::add_vertices”Add many vertices to the mesh.
Example
Section titled “Example”use fragmentcolor::mesh::Mesh;let mut m = Mesh::new();m.add_vertices([[0.0, 0.0],[1.0, 0.0],]);import { Mesh } from "fragmentcolor";const m = new Mesh();m.addVertices([ [0.0, 0.0], [1.0, 0.0], ]);from fragmentcolor import Meshm = Mesh()m.add_vertices([[0.0, 0.0],[1.0, 0.0],])import FragmentColorlet m = Mesh()try m.addVertices([[0.0, 0.0],[1.0, 0.0],])import org.fragmentcolor.*val m = Mesh()m.addVertices(listOf(Vertex(listOf(0.0f, 0.0f)), Vertex(listOf(1.0f, 0.0f))))Mesh::add_instance
Section titled “Mesh::add_instance”Add a single per-instance attribute set to the mesh.
An Instance is a bag of named attributes (transform, color, id, …) sent to
the shader’s per-instance inputs. It carries no position; the mesh’s vertices
are reused for every instance.
Adding an instance also clears any previously set instance count override
(see Mesh::set_instance_count).
Example
Section titled “Example”use fragmentcolor::mesh::{Mesh, Instance};
let m = Mesh::new();let offset: [f32; 2] = [0.25, 0.10];let tint: [f32; 4] = [1.0, 0.0, 0.0, 1.0];m.add_instance(Instance::new().set("offset", offset).set("tint", tint));import { Mesh, Instance } from "fragmentcolor";
const m = new Mesh();const offset = [0.25, 0.10];const tint = [1.0, 0.0, 0.0, 1.0];m.addInstance(new Instance().set("offset", offset).set("tint", tint));from fragmentcolor import Mesh, Instance
m = Mesh()offset = [0.25, 0.10]tint = [1.0, 0.0, 0.0, 1.0]m.add_instance(Instance().set("offset", offset).set("tint", tint))import FragmentColor
let m = Mesh()let offset = [0.25, 0.10]let tint = [1.0, 0.0, 0.0, 1.0]try m.addInstance(Instance().set("offset", offset).set("tint", tint))import org.fragmentcolor.*
val m = Mesh()val offset = listOf(0.25f, 0.10f)val tint = listOf(1.0f, 0.0f, 0.0f, 1.0f)m.addInstance(Instance().set("offset", offset).set("tint", tint))Mesh::add_instances
Section titled “Mesh::add_instances”Add many per-instance attribute sets to the mesh in one call.
Each Instance is a bag of named attributes (transform, color, id, …) sent to
the shader’s per-instance inputs. Instances carry no position; the mesh’s
vertices are reused for every instance.
Adding instances also clears any previously set instance count override
(see Mesh::set_instance_count).
Example
Section titled “Example”use fragmentcolor::mesh::{Mesh, Instance};
let m = Mesh::new();let red: [f32; 4] = [1.0, 0.0, 0.0, 1.0];let green: [f32; 4] = [0.0, 1.0, 0.0, 1.0];let blue: [f32; 4] = [0.0, 0.0, 1.0, 1.0];m.add_instances([ Instance::new().set("tint", red), Instance::new().set("tint", green), Instance::new().set("tint", blue),]);import { Mesh, Instance } from "fragmentcolor";
const m = new Mesh();const red = [1.0, 0.0, 0.0, 1.0];const green = [0.0, 1.0, 0.0, 1.0];const blue = [0.0, 0.0, 1.0, 1.0];m.addInstances([ new Instance().set("tint", red), new Instance().set("tint", green), new Instance().set("tint", blue), ]);from fragmentcolor import Mesh, Instance
m = Mesh()red = [1.0, 0.0, 0.0, 1.0]green = [0.0, 1.0, 0.0, 1.0]blue = [0.0, 0.0, 1.0, 1.0]m.add_instances([ Instance().set("tint", red), Instance().set("tint", green), Instance().set("tint", blue),])import FragmentColor
let m = Mesh()let red = [1.0, 0.0, 0.0, 1.0]let green = [0.0, 1.0, 0.0, 1.0]let blue = [0.0, 0.0, 1.0, 1.0]m.addInstances([ try Instance().set("tint", red), try Instance().set("tint", green), try Instance().set("tint", blue),])import org.fragmentcolor.*
val m = Mesh()val red = listOf(1.0f, 0.0f, 0.0f, 1.0f)val green = listOf(0.0f, 1.0f, 0.0f, 1.0f)val blue = listOf(0.0f, 0.0f, 1.0f, 1.0f)m.addInstances(listOf(Instance().set("tint", red), Instance().set("tint", green), Instance().set("tint", blue),))Mesh::clear_instances
Section titled “Mesh::clear_instances”Reset the mesh’s instance state to the default (1 draw, no per-instance data).
Specifically, this:
- Drops any per-instance attributes added via
add_instance/add_instances. - Clears any count override previously set with
set_instance_count.
After calling, the mesh renders as a single instance unless you populate it
again or call set_instance_count.
Example
Section titled “Example”use fragmentcolor::mesh::{Mesh, Instance};
let m = Mesh::new();let red: [f32; 4] = [1.0, 0.0, 0.0, 1.0];m.add_instance(Instance::new().set("tint", red));m.clear_instances(); // back to a single uninstanced drawimport { Mesh, Instance } from "fragmentcolor";
const m = new Mesh();const red = [1.0, 0.0, 0.0, 1.0];m.addInstance(new Instance().set("tint", red));m.clearInstances(); // back to a single uninstanced draw;from fragmentcolor import Mesh, Instance
m = Mesh()red = [1.0, 0.0, 0.0, 1.0]m.add_instance(Instance().set("tint", red))m.clear_instances(); # back to a single uninstanced drawimport FragmentColor
let m = Mesh()let red = [1.0, 0.0, 0.0, 1.0]try m.addInstance(Instance().set("tint", red))m.clearInstances(); // back to a single uninstanced drawimport org.fragmentcolor.*
val m = Mesh()val red = listOf(1.0f, 0.0f, 0.0f, 1.0f)m.addInstance(Instance().set("tint", red))m.clearInstances(); // back to a single uninstanced drawMesh::set_instance_count
Section titled “Mesh::set_instance_count”Override how many instances to draw without providing per-instance attributes.
Use this when driving instance data from a storage buffer and indexing via
@builtin(instance_index) in the vertex shader. Common for compute-driven
simulations and large particle systems.
The override is automatically cleared if you later call add_instance /
add_instances (those carry their own count) or clear_instances.
Example
Section titled “Example”use fragmentcolor::mesh::Mesh;let mut m = Mesh::new();m.add_vertices([ [-0.01, -0.01], [ 0.01, -0.01], [ 0.00, 0.01],]);// Draw one million instances, fetching per-particle data from a storage buffer.m.set_instance_count(1_000_000);import { Mesh } from "fragmentcolor";const m = new Mesh();m.addVertices([ [-0.01, -0.01], [ 0.01, -0.01], [ 0.00, 0.01], ]);// Draw one million instances, fetching per-particle data from a storage buffer.m.setInstanceCount(1_000_000);from fragmentcolor import Meshm = Mesh()m.add_vertices([ [-0.01, -0.01], [ 0.01, -0.01], [ 0.00, 0.01],])# Draw one million instances, fetching per-particle data from a storage buffer.m.set_instance_count(1_000_000)import FragmentColorlet m = Mesh()try m.addVertices([ [-0.01, -0.01], [ 0.01, -0.01], [ 0.00, 0.01],])// Draw one million instances, fetching per-particle data from a storage buffer.m.setInstanceCount(1_000_000)import org.fragmentcolor.*val m = Mesh()m.addVertices(listOf(Vertex(listOf(-0.01f, -0.01f)), Vertex(listOf(0.01f, -0.01f)), Vertex(listOf(0.00f, 0.01f))))// Draw one million instances, fetching per-particle data from a storage buffer.m.setInstanceCount(1_000_000u)Mesh::set_indices
Section titled “Mesh::set_indices”Provide the index buffer directly, bypassing the mesh’s automatic vertex dedup pass. Use this when an asset already carries its own indexing: glTF loaders, OBJ importers, or hand-authored meshes whose corners share positions but need to keep distinct UVs, normals, or tangents (the typical case for sharp creases and texture seams).
By default the mesh dedupes vertices by full attribute equality before
producing an index array. That’s fine for hand-built meshes, wrong for assets
where two corners with identical positions must stay separate because
their other attributes differ. After set_indices, every vertex you added
with add_vertex is packed in insertion order and the indices you supply
are used verbatim. Call clear_indices to return to the auto-derived
path.
Example
Section titled “Example”use fragmentcolor::{Mesh, Vertex};
// A quad split into two triangles via explicit indexing. The four corners// happen to carry distinct UVs (only positions repeat), so we keep them// all and reference each by index.let mesh = Mesh::new();let uv00: [f32; 2] = [0.0, 0.0];let uv10: [f32; 2] = [1.0, 0.0];let uv11: [f32; 2] = [1.0, 1.0];let uv01: [f32; 2] = [0.0, 1.0];mesh.add_vertices([ Vertex::new([-0.5, -0.5]).set("uv", uv00), Vertex::new([ 0.5, -0.5]).set("uv", uv10), Vertex::new([ 0.5, 0.5]).set("uv", uv11), Vertex::new([-0.5, 0.5]).set("uv", uv01),]);mesh.set_indices([0, 1, 2, 0, 2, 3]);import { Mesh, Vertex } from "fragmentcolor";
// A quad split into two triangles via explicit indexing. The four corners// happen to carry distinct UVs (only positions repeat), so we keep them// all and reference each by index.const mesh = new Mesh();const uv00 = [0.0, 0.0];const uv10 = [1.0, 0.0];const uv11 = [1.0, 1.0];const uv01 = [0.0, 1.0];mesh.addVertices([ new Vertex([-0.5, -0.5]).set("uv", uv00), new Vertex([ 0.5, -0.5]).set("uv", uv10), new Vertex([ 0.5, 0.5]).set("uv", uv11), new Vertex([-0.5, 0.5]).set("uv", uv01), ]);mesh.setIndices([0, 1, 2, 0, 2, 3]);from fragmentcolor import Mesh, Vertex
# A quad split into two triangles via explicit indexing. The four corners# happen to carry distinct UVs (only positions repeat), so we keep them# all and reference each by index.mesh = Mesh()uv00 = [0.0, 0.0]uv10 = [1.0, 0.0]uv11 = [1.0, 1.0]uv01 = [0.0, 1.0]mesh.add_vertices([ Vertex([-0.5, -0.5]).set("uv", uv00), Vertex([ 0.5, -0.5]).set("uv", uv10), Vertex([ 0.5, 0.5]).set("uv", uv11), Vertex([-0.5, 0.5]).set("uv", uv01),])mesh.set_indices([0, 1, 2, 0, 2, 3])import FragmentColor
// A quad split into two triangles via explicit indexing. The four corners// happen to carry distinct UVs (only positions repeat), so we keep them// all and reference each by index.let mesh = Mesh()let uv00 = [0.0, 0.0]let uv10 = [1.0, 0.0]let uv11 = [1.0, 1.0]let uv01 = [0.0, 1.0]try mesh.addVertices([ try Vertex([-0.5, -0.5]).set("uv", uv00), try Vertex([ 0.5, -0.5]).set("uv", uv10), try Vertex([ 0.5, 0.5]).set("uv", uv11), try Vertex([-0.5, 0.5]).set("uv", uv01),])try mesh.setIndices([0, 1, 2, 0, 2, 3])import org.fragmentcolor.*
// A quad split into two triangles via explicit indexing. The four corners// happen to carry distinct UVs (only positions repeat), so we keep them// all and reference each by index.val mesh = Mesh()val uv00 = listOf(0.0f, 0.0f)val uv10 = listOf(1.0f, 0.0f)val uv11 = listOf(1.0f, 1.0f)val uv01 = listOf(0.0f, 1.0f)mesh.addVertices(listOf(Vertex(listOf(-0.5f, -0.5f)).set("uv", uv00), Vertex(listOf(0.5f, -0.5f)).set("uv", uv10), Vertex(listOf(0.5f, 0.5f)).set("uv", uv11), Vertex(listOf(-0.5f, 0.5f)).set("uv", uv01)))mesh.setIndices(listOf(0u, 1u, 2u, 0u, 2u, 3u))Mesh::clear_indices
Section titled “Mesh::clear_indices”Drop the user-supplied index buffer and return to auto-derived indexing.
After set_indices the mesh draws vertices in insertion order using the
indices you provided. clear_indices reverses that: the next render
re-runs the vertex dedup pass and rebuilds the index buffer from the
deduplicated unique set, the same way a freshly built mesh behaves.
Example
Section titled “Example”use fragmentcolor::{Mesh, Vertex};
let mesh = Mesh::new();mesh.add_vertices([ Vertex::new([-0.5, -0.5]), Vertex::new([ 0.5, -0.5]), Vertex::new([ 0.0, 0.5]),]);mesh.set_indices([0, 1, 2]);mesh.clear_indices(); // back to auto-derived dedupimport { Mesh, Vertex } from "fragmentcolor";
const mesh = new Mesh();mesh.addVertices([ new Vertex([-0.5, -0.5]), new Vertex([ 0.5, -0.5]), new Vertex([ 0.0, 0.5]), ]);mesh.setIndices([0, 1, 2]);mesh.clearIndices(); // back to auto-derived dedup;from fragmentcolor import Mesh, Vertex
mesh = Mesh()mesh.add_vertices([ Vertex([-0.5, -0.5]), Vertex([ 0.5, -0.5]), Vertex([ 0.0, 0.5]),])mesh.set_indices([0, 1, 2])mesh.clear_indices(); # back to auto-derived dedupimport FragmentColor
let mesh = Mesh()try mesh.addVertices([ try Vertex([-0.5, -0.5]), try Vertex([ 0.5, -0.5]), try Vertex([ 0.0, 0.5]),])try mesh.setIndices([0, 1, 2])mesh.clearIndices(); // back to auto-derived dedupimport org.fragmentcolor.*
val mesh = Mesh()mesh.addVertices(listOf(Vertex(listOf(-0.5f, -0.5f)), Vertex(listOf(0.5f, -0.5f)), Vertex(listOf(0.0f, 0.5f))))mesh.setIndices(listOf(0u, 1u, 2u))mesh.clearIndices(); // back to auto-derived dedup