API Reference · Geometry

Primitives

Namespace: Ava3D

public static class Primitives

Ready-made geometry, so a scene can be built without a model file.

Every mesh here is generated with normals and texture coordinates already in place, and each is a plain Mesh — share one across as many nodes as you like and it uploads once.

All of it is wound counter-clockwise when seen from outside, which is the glTF and OpenGL convention and the one Mesh.WithGeneratedNormals assumes when it takes cross(b−a, c−a) as the outward face normal. That only became observable when CullMode arrived — with nothing ever culled, a mesh wound the other way looked identical — so it is worth stating rather than leaving for someone to discover the first time they cull a sphere and lose the wrong half of it.

The round shapes all take a sweepDegrees and a startDegrees, measured about the vertical axis in the same direction and from the same place, so a partial cylinder inside a partial ring under a partial dome line up without anyone having to work out whose zero is where. A partial shape is left open along the cut: it is a shell rather than a solid, because closing it means inventing two flat faces the caller may well not want. Mesh.Merge is where those go if they are.

Everything here is smooth-shaded, which on a shape with few segments is not what you want — see Mesh.WithFlatNormals, which is the difference between an eight-sided tube that looks badly lit and an octagonal drum that looks deliberate.

Methods

MemberDescription
static Mesh Box(float width = 1.0f, float height = 1.0f, float depth = 1.0f)

An axis-aligned box centred on the origin, with sharp edges.

static Mesh Box(float width, float height, float depth, float chamfer)

An axis-aligned box centred on the origin.

width

Along x.

height

Along y.

depth

Along z.

chamfer

How much is taken off each edge, in metres. Clamped to a third of the shortest side, so asking for a heavy chamfer on a thin panel gives a heavily chamfered thin panel rather than an inside-out one. Zero returns the plain box, exactly.

static Mesh Cylinder(float radiusTop = 0.5f, float radiusBottom = 0.5f, float height = 1.0f, int segments = 32, bool capped = true, float sweepDegrees = 360.0f, float startDegrees = 0.0f)

A cylinder, cone or truncated cone about the Y axis, centred on the origin.

Giving the two ends different radii is what makes it general: equal radii are a tube, a zero radiusTop is a cone, and anything between is the tapered hull section that most hand-built spacecraft and architecture are made of. The side normals are tilted by the taper rather than left radial, so a cone shades as a cone instead of as a cylinder that happens to be pointy.

radiusTop

Radius at +Y. Zero gives a cone.

radiusBottom

Radius at −Y.

height

Total length along Y.

segments

Faces around the axis. Six gives the faceted look of a hex tube; thirty-two is smooth.

capped

Whether the two ends are filled. Open is right for a tunnel or a shell.

sweepDegrees

How far round the axis to build. 360 is the whole tube; less is a trough, a curved corridor section or a pipe cut open to show what is inside it. The cut is left open — see Primitives.

startDegrees

Where the sweep begins, measured from +X toward +Z.

static Mesh Disc(float radius = 0.5f, int segments = 32, float sweepDegrees = 360.0f, float startDegrees = 0.0f)

A flat circle in the XZ plane, facing up, whole or a wedge of one.

The round counterpart to Primitives.Plane, and the piece Primitives.Cylinder cannot be asked for on its own: a zero-height cylinder is two coincident discs facing opposite ways, which z-fights with itself. This is a dial face, a landing pad, a pie slice, or the lid welded onto an open tube.

Texture coordinates are radial — the centre of the image lands at the centre of the disc — so a square texture maps onto it the way a clock face expects rather than being stretched across a bounding box.

radius

Distance from the centre to the rim.

segments

Divisions around the rim.

sweepDegrees

How much of the circle to build. 360 is all of it.

startDegrees

Where the sweep begins, measured from +X toward +Z.

static Mesh Plane(float width = 1.0f, float depth = 1.0f, int widthSegments = 1, int depthSegments = 1)

A flat rectangle in the XZ plane, facing up, optionally divided into a grid.

The divisions are what make it more than a backdrop. Four vertices can only ever be flat, so a plane is where a heightfield, a flag, a water surface or anything else driven by Mesh.InvalidateGeometry starts — and it needs vertices to move. It is also what a per-vertex renderer needs to light a large surface at all: the CPU fallback shades once per vertex, so a four-vertex floor under a point light gets four samples of it.

Turn it on its edge with Mesh.Transformed to get a wall: Primitives.Plane(4f, 4f).Transformed(Matrix4x4.CreateRotationX(MathF.PI / 2f)).

width

Extent along X.

depth

Extent along Z.

widthSegments

Divisions along X. One is the single quad this used to be.

depthSegments

Divisions along Z.

static Mesh Sphere(float radius = 0.5f, int segments = 32, int rings = 16, float latitudeDegrees = 180.0f, float latitudeStartDegrees = 0.0f, float sweepDegrees = 360.0f, float startDegrees = 0.0f)

A UV sphere, whole or a patch of one.

The four angles cut it down without changing anything about how the rest is built, so the defaults are the sphere this has always returned. latitudeDegrees is the one to reach for: Sphere(latitudeDegrees: 90f) is a dome, which is the shape a radome, a lamp shade and the top half of a capsule all are, and there is no other way to get one — a full sphere with its bottom clipped is twice the triangles and shows its inside.

Texture coordinates span the patch rather than the whole sphere: u runs 0..1 along whatever arc was asked for and v likewise. On a full sphere that is the ordinary latitude-longitude mapping, which is also what EnvironmentLight.Texture expects — so one image can be a sky sphere and the light coming off it at the same time.

radius

Distance from the centre to the surface.

segments

Divisions around the vertical axis.

rings

Divisions from top to bottom.

latitudeDegrees

How much of the pole-to-pole sweep to build. 180 is the whole of it.

latitudeStartDegrees

Where that sweep begins. 0 is the top pole, 90 the equator.

sweepDegrees

How far round the vertical axis to build. 360 is the whole way.

startDegrees

Where that sweep begins, measured from +X toward +Z.

static Mesh Torus(float radius = 0.5f, float tube = 0.15f, int segments = 32, int tubeSegments = 16, float sweepDegrees = 360.0f, float startDegrees = 0.0f)

A torus lying in the XZ plane, so its axis is Y and it reads as a ring around something upright.

Three.js builds its torus in XY and everyone rotates it a quarter turn; building it flat here means a ring of lit windows around a hub, or a docking collar, needs no rotation at all.

Porting from three.js: the two segment counts are named the other way round. TorusGeometry(radius, tube, radialSegments, tubularSegments) calls the divisions around the tube's cross-section radial and the ones around the ring tubular; here segments goes around the ring and tubeSegments around the tube. Passing three.js's arguments straight through gives a valid torus with its two tessellations swapped, which is a picture that looks nearly right and is a silent parity bug — so it is worth checking rather than assuming.

radius

Distance from the origin to the centre of the tube.

tube

Radius of the tube itself.

segments

Divisions around the ring.

tubeSegments

Divisions around the tube. Six is a faceted pipe; sixteen is smooth.

sweepDegrees

How far round the ring to build. 360 closes it; less is an arc, which is a collar with a gap in it or a pipe bend. The cut is left open — see Primitives.

startDegrees

Where the sweep begins, measured from +X toward +Z.

See also