BillboardMesh requires CNA link

Easy3D / Data & Batching / BillboardMesh

The BillboardMesh functions turn queued BillboardBatch items into plain CPU-side, camera-facing vertex/index arrays — mirroring CubeMesh's role for CubeBatch. No GPU work: no GraphicsDevice, no vertex/index buffers, no shaders — just std::vector data a caller can later upload.

#include <Easy3D/BillboardMesh.hpp>

namespace Easy3D
{
    struct BillboardVertex;

    void AppendBillboardMesh(const BillboardItem& item,
                             const Vector3& cameraRight,
                             const Vector3& cameraUp,
                             std::vector<BillboardVertex>& vertices,
                             std::vector<std::uint32_t>& indices);

    void BuildBillboardMesh(const BillboardBatch& batch,
                            const Vector3& cameraRight,
                            const Vector3& cameraUp,
                            std::vector<BillboardVertex>& vertices,
                            std::vector<std::uint32_t>& indices);
}
<Easy3D/BillboardMesh.hpp> is not pulled in by the <Easy3D/Easy3D.hpp> umbrella header — include it directly. (CubeMesh.hpp and CubeMeshRenderer.hpp are in the umbrella; BillboardMeshRenderer.hpp is not, either.)

Why billboards are different from cubes

A cube's geometry is fixed once you know its center and size. A billboard's geometry is not: a camera-facing quad's actual corner positions depend on which way the camera is currently pointing. So unlike CubeMesh (build once, cache forever, until the level changes), a BillboardMesh must be rebuilt whenever the camera moves — typically once per frame.

BillboardVertex

One mesh vertex — same shape as CubeVertex:

FieldTypeMeaning
PositionMicrosoft::Xna::Framework::Vector3World position (already offset onto the camera's right/up plane).
UvMicrosoft::Xna::Framework::Vector2Normalized texture coordinate.

AppendBillboardMesh

void AppendBillboardMesh(const BillboardItem& item,
                    const Vector3& cameraRight, const Vector3& cameraUp,
                    std::vector<BillboardVertex>& vertices,
                    std::vector<std::uint32_t>& indices)
Appends one billboard's quad — 4 vertices, 6 indices — to existing output arrays, facing the camera basis described by cameraRight/cameraUp (both expected normalized — e.g. an inverse view matrix's Right/Up rows). Indices are offset by the vertex count already present in vertices, so repeated calls concatenate correctly into one combined mesh.

How placement works:

Properties of the generated geometry:

BuildBillboardMesh

void BuildBillboardMesh(const BillboardBatch& batch,
                   const Vector3& cameraRight, const Vector3& cameraUp,
                   std::vector<BillboardVertex>& vertices,
                   std::vector<std::uint32_t>& indices)
Builds a combined triangle mesh for every item in batch, in BillboardBatch::Items() order, all facing the same camera basis. Equivalent to calling AppendBillboardMesh for each item in turn against the same vertices/indices.

Both functions append — they never clear the output vectors. Rebuild from scratch each frame by clearing your vectors first (or reusing their capacity with .clear() rather than reallocating).

Getting cameraRight / cameraUp

The camera basis vectors are whatever right/up axes the current Camera3D is looking along — derive them from its position/target/up the same way you would for any billboard technique (e.g. cross products of the view direction and the camera's up vector, or the appropriate rows of the inverted view matrix). Easy3D deliberately does not add a Camera3D::GetRight()/GetUp() convenience yet — no concrete consumer has asked for one; open a request if Galaxy Eggbert needs it.

Example — billboards facing the camera, rebuilt per frame

#include <Easy3D/BillboardBatch.hpp>
#include <Easy3D/BillboardMesh.hpp>

// Per frame: derive the camera's right/up axes from its current orientation
// (e.g. from the view direction cross world-up, then up = right cross forward).
const Vector3 cameraRight = /* ... */;
const Vector3 cameraUp    = /* ... */;

sprites.Begin();
// ... sprites.Add() one BillboardItem per visible sprite (see BillboardBatch) ...
sprites.End();

std::vector<Easy3D::BillboardVertex> vertices;
std::vector<std::uint32_t>           indices;
Easy3D::BuildBillboardMesh(sprites, cameraRight, cameraUp, vertices, indices);

// Upload with CNA and draw — see BillboardMeshRenderer, which does exactly this.

Scope and status

BillboardMesh is the second Phase 3 vertex builder (CubeMesh was first). A debug line/box vertex builder is the one remaining Phase 3 gap. See the Roadmap.

For actually issuing CNA draw calls from this data, see BillboardMeshRenderer — the Phase 4 adapter that uploads this output to GPU buffers and draws it.