scene

package
v0.0.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 7, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package scene shows 3D inside your screen. Go describes the scene: a camera, lights, and objects with a shape, a color or a picture, and a place. Models come from glTF files, the format Blender and most 3D tools export. The phone draws it with its own GPU API, Metal on iOS and Vulkan on Android, with shadows if you ask, and runs animations such as Spin and the orbit camera itself, every frame, so they stay smooth whatever Go is doing.

nimbus native plugin add scene

cup, err := scene.LoadGLTF(glb, nil)
scene.View{
	Camera:  scene.Camera{Position: scene.V(0, 1.5, 4)},
	Orbit:   true,
	Shadows: true,
	Nodes: []scene.Node{
		scene.Fit(cup, 1.5),
		{ID: "floor", Mesh: scene.Plane(6, 6), Color: ui.Hex("#e8e2d8"), Position: scene.V(0, -0.75, 0)},
	},
	OnTap: func(id string) { picked(id) },
	Style: ui.Style{Height: ui.Pt(300)},
}

Changing anything re-describes the scene, so change it in answer to something (a tap, new data), not every frame; for motion, use Spin. Meshes and pictures go to the phone once each, when it first needs them.

Index

Constants

View Source
const MaxTexture = 4096

MaxTexture is the largest side a Texture may have, in pixels: every GPU on a supported phone takes this.

Variables

This section is empty.

Functions

This section is empty.

Types

type Camera

type Camera struct {
	Position Vec3    // where it stands; zero means (0, 0, 5)
	Target   Vec3    // what it looks at, and what Orbit turns around
	FOV      float32 // vertical field of view in degrees; 0 means 60
	Near     float32 // nothing closer is drawn; 0 means 0.1
	Far      float32 // nothing farther is drawn; 0 means 100
}

Camera is where the scene is seen from.

type Light

type Light struct {
	Direction Vec3     // the way the light travels
	Color     ui.Color // white when 0
	Intensity float32  // 0 means 1
}

Light is sunlight from one direction. Ambient light fills in the rest. With Shadows, the first light casts them.

type Mat4

type Mat4 [16]float32

Mat4 is a 4×4 transform, column by column, as glTF and the GPUs keep it.

type Mesh

type Mesh struct {
	// contains filtered or unexported fields
}

Mesh is a shape made of triangles. Box, Sphere and Plane make the usual ones; NewMesh takes your own, and LoadGLTF reads them from a file.

func Box

func Box(w, h, d float32) *Mesh

Box is a box w wide, h high and d deep, centered on its node. A Texture covers each face whole.

func NewMesh

func NewMesh(positions, normals []Vec3, indices []uint32) *Mesh

NewMesh makes a shape from triangles: positions and their normals, one each per vertex, and three indices into them per triangle, counter- clockwise seen from the front. A nil normals works them out, flat.

func NewTexturedMesh

func NewTexturedMesh(positions, normals []Vec3, uvs []UV, indices []uint32) *Mesh

NewTexturedMesh is NewMesh with where each vertex falls on a Texture.

func Plane

func Plane(w, d float32) *Mesh

Plane is a flat rectangle w by d, facing up: a floor or a table top. A Texture covers it whole, its top at the far edge.

func Sphere

func Sphere(r float32) *Mesh

Sphere is a ball of radius r, smooth enough at any size on a phone. A Texture wraps around it like a map of the world.

type Node

type Node struct {
	ID          string   // your name for it, sent to OnTap
	Mesh        *Mesh    // its shape: Box, Sphere, Plane, NewMesh, or from LoadGLTF; nil for a group
	Texture     *Texture // a picture wrapped on it, tinted by Color; nil for none
	Color       ui.Color // the theme's Primary when 0, or white with a Texture
	Unlit       bool     // ignore the lights and shadows, and show Color as it is
	Shine       float32  // how glossy, 0 (matte) to 1
	DoubleSided bool     // draw its back faces too, for leaves and open shapes
	NoShadow    bool     // cast no shadow
	Position    Vec3     // where its center is
	Rotation    Vec3     // degrees around X, then Y, then Z
	Scale       Vec3     // zero means (1, 1, 1)
	// Matrix, when set, places it instead of Position, Rotation and Scale.
	Matrix   *Mat4
	Spin     Spin   // a turn the phone animates
	Children []Node // placed relative to this node, turning with its Spin
}

Node is one object, or a group of them.

func Fit

func Fit(n Node, size float32) Node

Fit wraps a node so it's size across at its widest, centered on its new parent's place: a model from any tool, at the size your scene wants.

func LoadGLTF

func LoadGLTF(data []byte, files func(uri string) ([]byte, error)) (Node, error)

LoadGLTF reads a glTF 2.0 model: a .glb, or a .gltf with its buffers and pictures embedded or beside it. It gives a Node holding the file's scene: each glTF node becomes a Node with the same name as its ID, with its meshes, colors and textures, placed as the file says.

files reads what a .gltf points to (a .bin, a .png) by its relative path; nil is fine for a .glb or a .gltf with everything embedded. Draco and meshopt compression aren't supported, and nor are skins, morph targets or animations: export without them.

type Spin

type Spin struct {
	Axis  Vec3    // what it turns around; zero means up (0, 1, 0)
	Speed float32 // degrees a second; negative turns the other way
}

Spin turns a node around its own center, forever, drawn by the phone. Its children turn with it.

type Texture

type Texture struct {
	Width, Height int // in pixels
	// contains filtered or unexported fields
}

Texture is a picture to wrap on a mesh: a PNG or a JPEG.

func NewTexture

func NewTexture(data []byte) (*Texture, error)

NewTexture reads a PNG or a JPEG. The phone decodes it, and makes the smaller copies that keep it crisp from far away.

type UV

type UV struct {
	U float32 // across, 0 at the left
	V float32 // down, 0 at the top
}

UV is a place on a Texture: (0, 0) its top left, (1, 1) its bottom right.

type Vec3

type Vec3 struct {
	X float32 // across, to the right
	Y float32 // up
	Z float32 // toward the viewer
}

Vec3 is a point or a direction. Y is up; the camera looks down -Z unless told otherwise.

func Bounds

func Bounds(n Node) (lo, hi Vec3)

Bounds is the box around a node and its children, as placed, ignoring Spin.

func V

func V(x, y, z float32) Vec3

V makes a Vec3.

type View

type View struct {
	Camera     Camera   // where it's seen from
	Orbit      bool     // drag to turn the camera around Target, pinch to zoom
	Lights     []Light  // none means one from above and in front
	Ambient    float32  // light that comes from everywhere, 0 to 1; 0 means 0.25
	Shadows    bool     // the first light casts shadows
	Background ui.Color // the theme's Background when 0; set alpha to 0 to see through, on iOS
	Nodes      []Node   // the objects
	// OnTap gets the ID of the node tapped, or "" for none.
	OnTap func(id string)
	Style ui.Style // its size and place on the screen
}

View is a 3D scene inside your screen.

func (View) Hit

func (v View) Hit(x, y, aspect float32) string

Hit says which node is under a point of the view: x and y from 0 to 1, from the top left, and the view's width over its height. OnTap uses it. A spinning node, and anything turning with it, is tested by the sphere it sweeps, since only the phone knows how far it has turned.

func (View) Render

func (v View) Render(c *ui.Ctx) ui.Component

Render describes the scene to the phone.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL