Gltf.Node (Gltf v0.1.0)

Copy Markdown View Source

Node transforms and scene-graph traversal.

A node positions itself either with a 16-float matrix or with separate translation, rotation and scale — never both, and the specification is explicit that the two forms compose as T * R * S, in that order. Getting the order wrong produces a model that looks right until something is both rotated and non-uniformly scaled, at which point it shears.

Matrices are column-major flat lists of 16 numbers, the same order glTF stores them in, so a matrix read from a file needs no rearranging.

Cycles

The node graph is a forest by specification, but nothing in a file enforces it, and a node that lists an ancestor as its child makes naive traversal loop until the machine dies. world_transforms/2 tracks the path it is on and reports the cycle instead.

Summary

Types

A 4×4 transform as 16 numbers in column-major order.

Functions

The identity transform.

A node's local transform.

Multiplies two column-major 4×4 matrices, a * b.

Transforms a point by a column-major matrix, with the implicit w = 1.

World transforms for every node reachable from a scene, keyed by node index.

Types

matrix()

@type matrix() :: [number()]

A 4×4 transform as 16 numbers in column-major order.

Functions

identity()

@spec identity() :: matrix()

The identity transform.

iex> Gltf.Node.identity() |> Enum.take(4)
[1.0, 0.0, 0.0, 0.0]

local_transform(node)

@spec local_transform(map()) :: matrix()

A node's local transform.

Returns the node's matrix when it has one, otherwise composes T * R * S from whichever of the three are present, defaulting each to its identity.

iex> Gltf.Node.local_transform(%{"translation" => [1, 2, 3]}) |> Enum.drop(12)
[1, 2, 3, 1.0]

multiply(a, b)

@spec multiply(matrix(), matrix()) :: matrix()

Multiplies two column-major 4×4 matrices, a * b.

Applied to a column vector this means b acts first — which is why a parent transform is the left operand.

transform_point(matrix, arg)

@spec transform_point(matrix(), {number(), number(), number()}) ::
  {number(), number(), number()}

Transforms a point by a column-major matrix, with the implicit w = 1.

world_transforms(document, opts \\ [])

@spec world_transforms(
  map(),
  keyword()
) ::
  {:ok, %{required(non_neg_integer()) => matrix()}} | {:error, Gltf.Error.t()}

World transforms for every node reachable from a scene, keyed by node index.

Nodes not reachable from the scene are absent rather than given an identity transform — an unreferenced node is not at the origin, it is nowhere.

Options

  • :scene — which scene to walk. Defaults to the document's own scene, then to scene 0.