Skip to content

Sprite Demo

App: apps/sprite_demo/

Demonstrates billboarded sprites: one PNG loaded with Texture.load, drawn as four tinted, camera-facing quads at different depths. The sprites overlap, and because the renderer sorts them back-to-front by view-space depth each frame, the nearest (blue) draws over green over red. Runs unattended — there is no input; it takes a screenshot after 1.5 seconds and then just keeps drawing.

Terminal window
% ./plume3d sprite_demo
  • Loads a single texture with Texture.load("textures/circle.png") and logs _tex.valid plus _tex.width×_tex.height via Logger.info. The one texture is shared by all four sprites.
  • Builds the scene procedurally — no blend file. Scene.new(), then addCamera() and addNode("cam") at (0, 0.6, 6) with lookAt(0, 0, 0); FOV 0.8 rad, near 0.1, far 100.
  • Creates four Sprite.new(_tex) instances, each with its own size and color ([r, g, b, a] tint, all at alpha 0.95): red at z -3.0 (farthest, size 2.4), green at z -1.0, blue at z 1.0 (nearest), and a yellow one off to the side at (1.4, 0.9, 0.0).
  • Sets billboard = 0 (spherical) on every sprite — this app only exercises the default mode, not cylindrical (1) or flat (2).
  • Keeps the sprites in a plain list of [sprite, x, y, z] tuples and calls drawAt on each one every frame. Draw order does not decide occlusion — the renderer sorts the frame’s sprites by view-space depth, so the cascade reads correctly regardless.
  • In draw, enables the 3D path with Graphics.setViewProjectionEnabled(true) and feeds it _cam.getViewMatrix() / _cam.getProjectionMatrix(aspect), where aspect comes from Window.getWidth() / Window.getHeight() (guarded to 1 if it degenerates below 0.01).
  • In update, counts down 1.5 s and then fires Engine.screenshot("sprite_demo.png") once, latching a _shot flag so it never repeats.
  • No lights and no shadow mapping — sprites are unlit, alpha-blended textured quads.
// One texture, four sprites, each with its own size and tint.
_tex = Texture.load("textures/circle.png")
addSprite(-0.9, 0.0, -3.0, [1.0, 0.45, 0.45, 0.95], 2.4) // red, farthest
addSprite(-0.3, 0.0, -1.0, [0.5, 1.0, 0.5, 0.95], 2.2) // green
addSprite( 0.3, 0.0, 1.0, [0.5, 0.7, 1.0, 0.95], 2.0) // blue, nearest
addSprite(x, y, z, color, size) {
var s = Sprite.new(_tex)
s.size = size // world-space height; width follows texture aspect
s.color = color // [r, g, b, a] tint, multiplied with the texture
s.billboard = 0 // spherical (camera-facing on every axis)
_sprites.add([s, x, y, z])
}
// Re-submitted every frame; the renderer depth-sorts them for you.
for (e in _sprites) {
e[0].drawAt(e[1], e[2], e[3])
}
  • Spritenew, size, color, billboard, drawAt.
  • Textureload, valid, width, height.
  • Scenenew, addCamera, addNode.
  • CamerasetNode, setFovYRadians, setNearPlane, setFarPlane, getViewMatrix, getProjectionMatrix.
  • GraphicssetViewProjectionEnabled, setViewMatrix, setProjectionMatrix.
  • WindowgetWidth, getHeight.
  • Enginescreenshot.
  • Loggerinfo.