iso

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: BSD-3-Clause Imports: 7 Imported by: 0

Documentation

Overview

Package iso is go-gfx's isometric projection and primitive-drawing layer: the pure-Go equivalent of obelisk.js. It turns positions and dimensions in a 3-D grid into 2-D screen polygons (a Projection), assembles them into shaded solids — Cube, Brick, Pyramid, Slope, Line and Side — and paints a depth-sorted Scene of them onto a raster surface with correct overlap.

It is deliberately just geometry and rasterization: it computes each solid's visible face polygons in screen space and fills them through github.com/go-gfx/gfx/vector, shading each face from one base colour with github.com/go-gfx/gfx/color.Shade (top brightest, sides progressively darker). It carries no widget, layout, event or windowing concern — a higher-level isometric-diagram widget and file exporters consume this layer.

The world axes are right-handed with +X to the screen right-and-down, +Y to the left-and-down and +Z straight up; see Vec3 and Projection.

Index

Constants

This section is empty.

Variables

View Source
var DefaultShading = Shading{Top: 1.0, Left: 0.75, Right: 0.55}

DefaultShading is the shading a solid uses when its own Shading is the zero value: the up face at full brightness and the two side faces darkened, with the +Y (left) face lighter than the +X (right) face.

Functions

This section is empty.

Types

type Brick

type Brick struct {
	Pos     Vec3
	Dim     Dimension
	Color   color.RGBA
	Shading Shading
}

Brick is an axis-aligned box occupying [Pos, Pos+Dim]. Viewed isometrically it shows three faces — the +X side (right), the +Y side (left) and the top — each filled from Color darkened by the matching Shading factor.

func (Brick) Depth

func (b Brick) Depth(p *Projection) float64

Depth returns the box's near-corner sort key.

func (Brick) Faces

func (b Brick) Faces(p *Projection) []Face

Faces returns the box's three visible faces: right (+X), left (+Y) then top. The three faces of a convex box seen from above never overlap, so the order is cosmetic.

type Cube

type Cube struct {
	Pos     Vec3
	Size    float64
	Color   color.RGBA
	Shading Shading
}

Cube is the special case of a Brick that is Size units on every axis.

func (Cube) Depth

func (c Cube) Depth(p *Projection) float64

Depth returns the cube's near-corner sort key.

func (Cube) Faces

func (c Cube) Faces(p *Projection) []Face

Faces returns the cube's three visible faces (see Brick.Faces).

type Dimension

type Dimension struct{ W, H, D float64 }

Dimension is a solid's extent in grid units along each world axis: W along +X, H along +Y and D (depth/height) along +Z.

type Face

type Face struct {
	Poly  []geometry.Point
	Color color.RGBA
}

Face is one filled, convex polygon in screen space: the projected outline of a single visible face of a solid, together with the colour to fill it. A Scene builds a path from Poly and fills it; the winding order of Poly does not matter under the non-zero fill rule.

type Line

type Line struct {
	From, To Vec3
	Color    color.RGBA
	Width    float64
}

Line is a straight segment between two world points, drawn as a stroked line Width pixels thick (1 when Width <= 0). It is the axis / edge primitive — no shading, just Color.

func (Line) Depth

func (l Line) Depth(p *Projection) float64

Depth returns the sort key of the segment's midpoint.

func (Line) Segment

func (l Line) Segment(p *Projection) (a, b geometry.Point)

Segment returns the line's projected screen endpoints.

type Projection

type Projection struct {
	Origin       geometry.Point // screen pixel of world (0,0,0)
	TileW, TileH float64        // screen width and height of one grid cell's diamond footprint
	ZScale       float64        // screen pixels one +Z unit rises
}

Projection maps world-space grid coordinates to 2-D screen pixels and back.

One world unit along +X projects to the screen vector (TileW/2, TileH/2) (right and down); one unit along +Y projects to (-TileW/2, TileH/2) (left and down); one unit along +Z projects to (0, -ZScale) (straight up). Origin is the screen pixel that world (0,0,0) lands on. The X and Y screen axes therefore each sit atan(TileH/TileW) below the horizontal, so the tile aspect ratio sets the viewing angle directly.

The zero Projection is degenerate (zero tile size); construct one with New, NewDefault or NewFromAngle.

func New

func New(origin geometry.Point, tileW, tileH, zScale float64) *Projection

New returns a Projection with an explicit tile footprint and vertical scale. TileW and TileH are the full screen width and height of one grid cell's diamond; ZScale is how many screen pixels one unit of height rises. All three should be positive for a well-formed view.

func NewDefault

func NewDefault(origin geometry.Point) *Projection

NewDefault returns the classic 2:1 "pixel-art" isometric projection anchored at origin: a 64x32 tile with a 32-pixel height unit.

The 2:1 width:height ratio places the ground axes at atan(1/2) ≈ 26.57° below the horizontal — the arrangement obelisk.js and most isometric tile art use, because a one-unit ground step is then exactly two pixels across for every one down, so anti-aliasing is unnecessary for crisp edges. ZScale is set to TileW/2 (equivalently TileH, since the tile is 2:1) so a unit cube's vertical side faces are as tall as the tile's top diamond is wide on the half-axis, which is the proportion that reads as a cube rather than a squat box.

func NewFromAngle

func NewFromAngle(origin geometry.Point, tileW, angleDeg, zScale float64) *Projection

NewFromAngle returns a Projection whose ground axes sit angleDeg below the horizontal, deriving TileH from TileW as TileW*tan(angleDeg). Passing 26.565° reproduces the 2:1 NewDefault tile; 30° gives the "true" isometric tile whose three cube faces are congruent. ZScale is taken as given.

func (*Projection) Depth

func (p *Projection) Depth(v Vec3) float64

Depth returns the painter's-algorithm sort key for a world point: world points with a smaller X+Y+Z sit farther from the viewer and must be drawn first, so a Scene fills its shapes in ascending Depth order for correct overlap. Height counts toward depth so a stacked solid correctly draws over the one beneath it.

func (*Projection) Project

func (p *Projection) Project(v Vec3) geometry.Point

Project maps a world-space point to its screen pixel.

func (*Projection) Unproject

func (p *Projection) Unproject(s geometry.Point, z float64) Vec3

Unproject is the inverse of [Project] for a known height z: it recovers the world X and Y whose projection at that z lands on screen point s. A screen pixel alone is ambiguous in 3-D (a whole ray of world points projects onto it), so the caller supplies the z-plane to intersect — for click-picking a tile on the ground that is z = 0. Project and Unproject round-trip: for any v, Unproject(Project(v), v.Z) == v up to floating-point rounding.

type Pyramid

type Pyramid struct {
	Pos     Vec3
	Dim     Dimension
	Color   color.RGBA
	Shading Shading
}

Pyramid is a solid with a Dim.W x Dim.H rectangular base at Pos and an apex centred Dim.D above it. Viewed isometrically it shows its two front triangular faces — the +X side (right) and the +Y side (left) — meeting at the apex.

func (Pyramid) Depth

func (py Pyramid) Depth(p *Projection) float64

Depth returns the pyramid's near-corner sort key.

func (Pyramid) Faces

func (py Pyramid) Faces(p *Projection) []Face

Faces returns the pyramid's two visible triangular faces: right (+X) then left (+Y).

type Scene

type Scene struct {
	Proj *Projection
	// contains filtered or unexported fields
}

Scene is an ordered collection of isometric [Shape]s sharing one Projection. Render draws them back-to-front so nearer solids correctly overlap farther ones. The zero Scene is not usable; make one with NewScene.

func NewScene

func NewScene(p *Projection) *Scene

NewScene returns an empty Scene that projects its shapes through p.

func (*Scene) Add

func (s *Scene) Add(shapes ...Shape) *Scene

Add appends shapes to the scene, preserving insertion order (which breaks ties between shapes at equal depth). It returns the scene so calls chain.

func (*Scene) Render

func (s *Scene) Render(dst *raster.Image)

Render draws every shape onto dst in ascending Projection.Depth order — the painter's algorithm — so a shape nearer the viewer is composited over the ones behind it. Ties keep insertion order (a stable sort). The sort orders a copy, leaving the scene's own insertion order untouched.

func (*Scene) Shapes

func (s *Scene) Shapes() []Shape

Shapes returns the scene's shapes in insertion order.

type Shading

type Shading struct{ Top, Left, Right float64 }

Shading holds the per-face brightness factors an isometric solid applies to its base colour: Top for the up-facing face, Left for the +Y side and Right for the +X side. Each is multiplied into the base colour by github.com/go-gfx/gfx/color.Shade. The convention is Top brightest (1), sides progressively darker, so the three faces of a cube read as one lit solid.

type Shape

type Shape interface {
	// Depth returns the shape's painter's-algorithm sort key; smaller draws
	// first (farther from the viewer).
	Depth(p *Projection) float64
	// contains filtered or unexported methods
}

Shape is a placeable isometric primitive a Scene can depth-order and draw. The concrete solids (Cube, Brick, Pyramid, Slope, Side) additionally expose a Faces method returning their projected face polygons, which an exporter can consume directly without rasterizing.

type Side

type Side struct {
	Pos     Vec3
	W, H    float64
	Plane   SidePlane
	Color   color.RGBA
	Shading Shading
}

Side is a single flat rectangular wall: W units wide along its plane's ground axis and H units tall along Z, anchored at Pos. It is the standalone face obelisk draws as SideX / SideY — a panel with no thickness.

func (Side) Depth

func (s Side) Depth(p *Projection) float64

Depth returns the wall's anchor sort key.

func (Side) Faces

func (s Side) Faces(p *Projection) []Face

Faces returns the wall's single face.

type SidePlane

type SidePlane int

SidePlane names the plane a Side wall lies in: SideXZ spans the X and Z axes (a wall facing along Y), SideYZ spans Y and Z (facing along X).

const (
	// SideXZ is a wall spanning X (width) and Z (height) at a fixed Y; it faces
	// +Y and is shaded as a left face.
	SideXZ SidePlane = iota
	// SideYZ is a wall spanning Y (width) and Z (height) at a fixed X; it faces
	// +X and is shaded as a right face.
	SideYZ
)

type Slope

type Slope struct {
	Pos     Vec3
	Dim     Dimension
	Dir     SlopeDir
	Color   color.RGBA
	Shading Shading
}

Slope is a wedge: a Dim.W x Dim.H base at Pos whose top is a flat ramp, raised to Dim.D along the SlopeDir edge and meeting the base at the opposite edge. It shows the ramp (top), the +X side (right) and the +Y side (left); whichever side collapses to the base edge has zero area and is skipped.

func (Slope) Depth

func (s Slope) Depth(p *Projection) float64

Depth returns the wedge's near-corner sort key.

func (Slope) Faces

func (s Slope) Faces(p *Projection) []Face

Faces returns the wedge's faces: right (+X), left (+Y) then the ramp (top).

type SlopeDir

type SlopeDir int

SlopeDir names which grid edge of a Slope is raised to full height; the opposite edge stays at the base, so the top ramps down toward it.

const (
	// SlopeE raises the +X (east) edge.
	SlopeE SlopeDir = iota
	// SlopeW raises the -X (west) edge.
	SlopeW
	// SlopeN raises the -Y (north) edge.
	SlopeN
	// SlopeS raises the +Y (south) edge.
	SlopeS
)

type Vec3

type Vec3 struct{ X, Y, Z float64 }

Vec3 is a point in the isometric grid's right-handed world space: X runs to the screen right-and-down, Y to the screen left-and-down, and Z straight up. Coordinates are continuous float64 grid units — a cube one unit on a side occupies [X, X+1] x [Y, Y+1] x [Z, Z+1].

func V

func V(x, y, z float64) Vec3

V is shorthand for Vec3{x, y, z}.

Jump to

Keyboard shortcuts

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