BillboardMeshRenderer requires CNA link
Easy3D / Data & Batching / BillboardMeshRenderer
Easy3D::BillboardMeshRenderer uploads a BillboardMesh's vertex/index arrays to GPU buffers and issues indexed TriangleList draw calls — it mirrors CubeMeshRenderer's role and shape exactly, field for field, method for method. The one real difference is lifecycle: see below.
#include <Easy3D/BillboardMeshRenderer.hpp>
namespace Easy3D { class BillboardMeshRenderer; }
<Easy3D/BillboardMeshRenderer.hpp> is not pulled in by the <Easy3D/Easy3D.hpp> umbrella header — include it directly, same as BillboardMesh.hpp.Constructor — uploads once
const std::vector<BillboardVertex>& vertices,
const std::vector<std::uint32_t>& indices)
vertices/indices to new GPU buffers immediately. indices.size() must be a multiple of 3; otherwise throws std::invalid_argument.Each BillboardVertex{Position, Uv} converts 1:1 to CNA's VertexPositionTexture{Position, TextureCoordinate}, and the index buffer is 32-bit — identical mechanics to CubeMeshRenderer.
Draw
effect's current technique. effect's World/View/Projection and, if texturing is wanted, TextureEnabled/Texture must already be set by the caller.[[nodiscard]] int PrimitiveCount() const noexcept
Lifecycle — rebuild whenever the camera moves
This is the one place BillboardMeshRenderer differs from CubeMeshRenderer: a billboard's vertex positions are baked in camera-facing at build time (see BillboardMesh). Since the camera typically moves every frame, that means a fresh BuildBillboardMesh call and a fresh BillboardMeshRenderer instance, every frame the camera changes — there is no camera-independent cache to reuse the way there is for cube terrain.
// Each frame:
const Vector3 cameraRight = /* derive from the current camera orientation */;
const Vector3 cameraUp = /* ... */;
std::vector<Easy3D::BillboardVertex> vertices;
std::vector<std::uint32_t> indices;
Easy3D::BuildBillboardMesh(sprites, cameraRight, cameraUp, vertices, indices);
Easy3D::BillboardMeshRenderer spriteRenderer(graphicsDevice, vertices, indices);
effect.World = Matrix::Identity; // positions are already in world space
effect.View = camera.GetViewMatrix();
effect.Projection = camera.GetProjectionMatrix();
effect.TextureEnabled = true;
effect.Texture = spriteSheetTexture;
spriteRenderer.Draw(graphicsDevice, effect);
Verification
Same constraint as CubeMeshRenderer: the constructor needs a live GraphicsDevice&, which a plain test main() cannot produce. Easy3D's test suite only compile-checks this class (see Testing); real runtime verification happens against a windowed CNA binary.