Skip to content

Vertex

A single vertex: a required 2D or 3D position plus any per-vertex attributes your shader declares. Commonly that’s uv and color, but any key the shader’s vertex stage reads is fair game. Build vertices and feed them into a Mesh to draw.

For the channels you’ll reach for most often, use the typed constants instead of bare strings. The loader, the shader, and any later glTF import all agree on names without bikeshedding:

Position is set via Vertex::new(...) and is not part of the constants table; the rest live as &'static str literals on Vertex:

Constant Value Notes
Vertex::NORMAL "normal" Per-vertex normal.
Vertex::TANGENT "tangent" Per-vertex tangent (for normal-mapped shading).
Vertex::UV0 / UV1 "uv0" / "uv1" Texture coordinates. Use the numbered form when a mesh carries multiple UV sets (typical for glTF).
Vertex::COLOR0 / COLOR1 "color0" / "color1" Vertex colours.

The constants are plain &'static str literals: vertex.set(Vertex::UV0, [...]) and vertex.set("uv0", [...]) do the same thing. Mix the two styles freely; the constants exist to prevent typos and to give the glTF loader a stable vocabulary.

use fragmentcolor::mesh::Vertex;
let v = Vertex::new([0.0, 0.0, 0.0])
.set(Vertex::UV0, [0.5, 0.5])
.set(Vertex::NORMAL, [0.0, 1.0, 0.0]);

Construct a Vertex from a 2D or 3D position. Set additional attributes (uv, color, custom keys) with set to match the per-vertex inputs your shader declares.

use fragmentcolor::mesh::Vertex;
let v = Vertex::new([0.0, 0.0]);

Construct a Vertex that matches the PBR shader’s vertex input layout. Seeds every attribute Material::pbr reads (NORMAL, UV0, COLOR0, UV1, TANGENT) with a neutral identity default; chain .set(...) to override the slots a real mesh has data for.

A vertex built with Vertex::pbr(pos) alone renders the same way Scene::load renders a glTF primitive that carries only POSITION. Face-normal computation, UV defaults, vertex tint, and tangents all collapse to the values the loader falls back to. Useful for building PBR meshes by hand without spelling out every default attribute.

Defaults:

attribute default value what it means
NORMAL [0, 0, 1] forward-facing surface
UV0 [0, 0] corner of the texture
COLOR0 [1, 1, 1, 1] identity vertex tint
UV1 [0, 0] unused; only matters for maps that opt into UV1
TANGENT [1, 0, 0, 1] T = +X, bitangent sign +1
1 collapsed line
fn main() -> Result<(), Box<dyn std::error::Error>> {
use fragmentcolor::{Mesh, Vertex};
// Build a triangle; override only what the mesh actually carries — NORMAL
// / COLOR0 / UV1 / TANGENT use their identity defaults from Vertex::pbr.
let mesh = Mesh::new();
mesh.add_vertex(Vertex::pbr([ 0.0, 0.5, 0.0]).set(Vertex::UV0, [0.5, 1.0]));
mesh.add_vertex(Vertex::pbr([-0.5, -0.5, 0.0]).set(Vertex::UV0, [0.0, 0.0]));
mesh.add_vertex(Vertex::pbr([ 0.5, -0.5, 0.0]).set(Vertex::UV0, [1.0, 0.0]));
2 collapsed lines
Ok(())
}

Attach an arbitrary property to the vertex.

Locations and mapping:

  • When you call set(key, value) for the first time for a given key, the Vertex assigns the next available @location(N) to that property (starting after position). Subsequent calls reuse the same location.
  • At render time, shader vertex inputs (declared with @location(N)) are derived from the Shader and matched to Vertex/Instance properties by:
    1. explicit location (instance first, then vertex), then
    2. name (instance first, then vertex).
  • There is no special-case for location(0) in the mapping; position is just another vertex attribute exposed as position with a 2- or 3-component format depending on how you constructed the Vertex.

Planned explicit control:

  • You will be able to pin a property to a specific location using a fluent API: vertex.set(key, value).at(index).
  • Vertex construction may also support Vertex::from_shader(&Shader) to derive an initial layout directly from the shader AST.
use fragmentcolor::mesh::{Vertex, VertexValue};
let v = Vertex::new([0.0, 0.0, 0.0]).set("weight", 1.0).set("color",[1.0, 0.0, 0.0]);

Create an Instance that inherits this vertex’s attributes. Use this when you want a starting point for an instance whose per-instance values mostly match the source vertex, then call set on the result to change the fields that differ.

use fragmentcolor::mesh::Vertex;
let v = Vertex::new([0.0, 0.0]);
let inst = v.create_instance();
1 collapsed line
_ = inst;