tecs.gfx.models
Resident glTF models and allocation-stable node animation.
tecs.gfx.models.load decodes a glTF or GLB file and returns a shared model. Each newInstance owns its joint palettes, morph weights, and primitive templates, so copies of one model can play different poses without duplicating geometry, materials, textures, morph deltas, or clips.
local model = assert(tecs.gfx.models.load("models/hero.gltf"))
local instance = model:newInstance()
local entities: {integer} = {}
for index, primitive in ipairs(instance.primitives) do
entities[index] = world:spawn(
primitive.transform,
primitive.mesh,
primitive.bounds,
primitive.material,
primitive.skin,
primitive.morph,
tecs.gfx.Tint(1, 1, 1, 1),
tecs.gfx.Renderable3D
)
end
world:commit()
for index, entity in ipairs(entities) do
instance:bind(world, index, entity)
end
instance:play("Walk")
world:addSystem({
name = "game.AnimateModel",
phase = tecs.ecs.phases.Update,
run = function(dt: number): nil
instance:update(dt)
end,
})Sampling resets the reusable pose to the file's base TRS, applies one clip, builds node world matrices in parent order, updates bound Transform3D components, and stages each instance-owned skin palette and morph vector. No table or cdata is allocated per sample. Bounds remain caller-owned and must enclose every pose.
Module contents
Constructors
| Constructor | Description |
|---|---|
newMaterial | Registers an independently authored material for any mesh. |
newMesh | Builds resident indexed geometry from the original twelve-float mesh layout. |
Types
| Type | Kind | Description |
|---|---|---|
Animation | record | Holds one authored clip and its reusable channel data. |
BoundsInput | record | Carries a native value across a mutation boundary without losing its definition. |
Instance | record | Plays one independently posed copy of a resident model. |
LoadOptions | type | Runs once per imported material before the resident GPU upload is queued. |
MaterialInfo | type | Allows import-time material tuning without duplicating geometry or images. |
MaterialInput | record | Carries a native value across a mutation boundary without losing its definition. |
MaterialOptions | type | Configures a shared mesh material. |
MeshInput | record | Carries a native value across a mutation boundary without losing its definition. |
MeshOptions | type | Describes one indexed triangle mesh in local coordinates. |
Model | record | Retains shared geometry, materials and authored clips. |
PlayOptions | type | Controls clip playback, with speed one, looping and immediate playback by default. |
Primitive | record | Holds the spawnable components for one independently posed primitive. |
Functions
| Function | Kind | Description |
|---|---|---|
load | function | Loads and registers a glTF or GLB scene for independent instances. |
loadEnvironment | function | Loads the six original environment faces and registers their shared GPU mip chain. |
nextUpload | function | Drains one model upload for the native host; zero means the queue is empty. |
Values
| Value | Kind | Description |
|---|---|---|
MATERIAL_LAMBERT | variable | Selects diffuse Lambert shading. |
MATERIAL_METALLIC_ROUGHNESS | variable | Selects Cook-Torrance metallic-roughness shading. |
MATERIAL_UNLIT | variable | Selects unlit base color and emission. |
Constructors#
newMaterialconstructor#
function newMaterial(options: MaterialOptions): MaterialInputRegisters an independently authored material for any mesh.
Arguments
| Name | Type | Description |
|---|---|---|
options | MaterialOptions | The caller supplies an identity, shading model, factors and optional maps. |
Returns
| Type | Description |
|---|---|
MaterialInput | Returns a shared MeshMaterial component ready to spawn. |
Raises
When a map cannot load or a material factor is invalid.
newMeshconstructor#
function newMesh(options: MeshOptions): MeshInput, BoundsInputBuilds resident indexed geometry from the original twelve-float mesh layout.
Arguments
| Name | Type | Description |
|---|---|---|
options | MeshOptions | The caller supplies a stable name, position/normal/tangent/UV vertices and zero-based triangle indices. |
Returns
| Type | Description |
|---|---|
MeshInput | The mesh component and its computed local bounding sphere. |
BoundsInput |
Raises
When streams are empty, malformed or contain nonfinite values or invalid indices.
Types#
Animationrecord#
Holds one authored clip and its reusable channel data.
Fields
channels#
channels: {Channel}Engine-owned. Retains decoded channels for sampling; game code uses Instance.
BoundsInputrecord#
record BoundsInput<T, C>
componentType: C
value: T
endCarries a native value across a mutation boundary without losing its definition.
Type parameters
| Name | Description |
|---|---|
T | |
C |
Fields
componentType#
componentType: CRead-only. Preserves the exact component or relationship definition.
Instancerecord#
record Instance
primitives: {Primitive}
transform: mesh.Transform3D?
animation: integer
time: number
speed: number
loop: boolean
playing: boolean
bind: function(exclusive self: Instance, world: World, primitive: integer, entity: integer): nil
unbind: function(exclusive self: Instance, primitive: integer): nil
play: function(exclusive self: Instance, animation: string | integer, options: PlayOptions?): nil
sample: function(exclusive self: Instance, animation: string | integer, time: number, loop: boolean?): nil
update: function(exclusive self: Instance, dt: number): nil
endPlays one independently posed copy of a resident model.
Methods
bind#
Binds one primitive to an existing entity's Transform3D.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | Instance | |
world | World | The caller supplies the entity's world. Every binding on one instance must use the same world. |
primitive | integer | The caller supplies a one-based primitive index. |
entity | integer | The caller supplies a live entity carrying |
Returns
| Type | Description |
|---|---|
nil | The operation returns no value. |
unbind#
unbind: function(exclusive self: Instance, primitive: integer): nilRemoves one primitive's entity binding.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | Instance | |
primitive | integer | The caller supplies a one-based primitive index. |
Returns
| Type | Description |
|---|---|
nil | The operation returns no value. |
play#
play: function(exclusive self: Instance, animation: string | integer, options: PlayOptions?): nilSelects and restarts a clip.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | Instance | |
animation | string | integer | The caller supplies a one-based index or clip name. |
options | PlayOptions? | Omitted fields default to speed one, looping, and immediate playback. |
Returns
| Type | Description |
|---|---|
nil | The operation returns no value. |
sample#
sample: function(exclusive self: Instance, animation: string | integer, time: number, loop: boolean?): nilSamples a clip at an explicit time without allocating.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | Instance | |
animation | string | integer | The caller supplies a one-based index or clip name. |
time | number | The caller supplies seconds. Negative values clamp to zero. |
loop | boolean? | Whether time wraps at the duration. Defaults to false. |
Returns
| Type | Description |
|---|---|
nil | The operation returns no value. |
update#
Advances and samples the selected clip.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | Instance | |
dt | number | The caller supplies non-negative elapsed seconds. |
Returns
| Type | Description |
|---|---|
nil | The operation returns no value. |
Fields
primitives#
primitives: {Primitive}Read-only. Contains this instance's spawnable primitive bundles.
transform#
transform: mesh.Transform3D?Caller-writable. Places the complete sampled model in world space, or nil to preserve the file's authored placement without placement work. Sampling composes this transform after the authored node hierarchy.
LoadOptionstype#
type LoadOptions = {
--- Caller-writable. Tunes each decoded material before its upload is queued.
--- @param value The callback receives the material's authored values in place.
--- @return The callback returns no value.
material: function(exclusive value: MaterialInfo): nil
}Runs once per imported material before the resident GPU upload is queued.
MaterialInfotype#
type MaterialInfo = {
--- Caller-writable. Names the authored material.
name: string,
--- Caller-writable. Selects metallic-roughness (0), unlit (1), or Lambert (2).
model: integer,
--- Caller-writable. Sets the metallic factor from zero to one.
metallic: number,
--- Caller-writable. Sets the perceptual roughness from zero to one.
roughness: number
}Allows import-time material tuning without duplicating geometry or images.
MaterialInputrecord#
record MaterialInput<T, C>
componentType: C
value: T
endCarries a native value across a mutation boundary without losing its definition.
Type parameters
| Name | Description |
|---|---|
T | |
C |
Fields
componentType#
componentType: CRead-only. Preserves the exact component or relationship definition.
MaterialOptionstype#
type MaterialOptions = {
--- Caller-writable. Names the shared material with a stable, non-empty identity.
name: string,
--- Caller-writable. Selects a MATERIAL_* model; metallic-roughness is the default.
model: integer?,
--- Caller-writable. Sets linear red reflectance and defaults to one.
baseR: number?,
--- Caller-writable. Sets linear green reflectance and defaults to one.
baseG: number?,
--- Caller-writable. Sets linear blue reflectance and defaults to one.
baseB: number?,
--- Caller-writable. Sets opacity from zero to one and defaults to one.
baseA: number?,
--- Caller-writable. Sets linear red emission and defaults to zero.
emissiveR: number?,
--- Caller-writable. Sets linear green emission and defaults to zero.
emissiveG: number?,
--- Caller-writable. Sets linear blue emission and defaults to zero.
emissiveB: number?,
--- Caller-writable. Sets the metallic factor from zero to one and defaults to zero.
metallic: number?,
--- Caller-writable. Sets perceptual roughness from zero to one and defaults to one.
roughness: number?,
--- Caller-writable. Scales the normal map XY channels and defaults to one.
normalScale: number?,
--- Caller-writable. Sets occlusion strength from zero to one and defaults to one.
occlusionStrength: number?,
--- Caller-writable. Selects opaque, mask, or blend and defaults to opaque.
alphaMode: string?,
--- Caller-writable. Sets the mask threshold from zero to one and defaults to 0.5.
alphaCutoff: number?,
--- Caller-writable. Disables back-face culling when true and defaults to false.
doubleSided: boolean?,
--- Caller-writable. Names the optional base-color texture, sampled as sRGB.
baseMap: string?,
--- Caller-writable. Names the optional tangent-space normal texture, sampled as
--- linear data.
normalMap: string?,
--- Caller-writable. Names the optional linear texture with roughness in green and
--- metallic in blue.
metallicRoughnessMap: string?,
--- Caller-writable. Names the optional linear texture with occlusion in red.
occlusionMap: string?,
--- Caller-writable. Names the optional emission texture, sampled as sRGB.
emissionMap: string?
}Configures a shared mesh material. Colors and emission are linear RGB texture paths load relative to the caller's content directory.
MeshInputrecord#
record MeshInput<T, C>
componentType: C
value: T
endCarries a native value across a mutation boundary without losing its definition.
Type parameters
| Name | Description |
|---|---|
T | |
C |
Fields
componentType#
componentType: CRead-only. Preserves the exact component or relationship definition.
MeshOptionstype#
type MeshOptions = {
--- Caller-writable. Names shared geometry with a stable, non-empty identity.
name: string,
--- Caller-writable. Supplies twelve floats per vertex: position XYZ, normal XYZ,
--- tangent XYZW and texture UV.
vertices: {number},
--- Caller-writable. Supplies zero-based triangle indices, three per triangle.
indices: {integer},
--- Caller-writable. Optionally supplies four linear RGBA values per vertex.
colors: {number}?,
--- Caller-writable. Optionally supplies four zero-based joint indices per vertex.
joints: {integer}?,
--- Caller-writable. Supplies four nonnegative weights with each joint quartet.
--- Each quartet must have positive total; the constructor normalizes it.
weights: {number}?
}Describes one indexed triangle mesh in local coordinates.
Modelrecord#
record Model
path: string
id: integer
animations: {Animation}
animationCount: integer
newInstance: function(self: Model): Instance
animationIndex: function(borrows self: Model, name: string): integer?
endRetains shared geometry, materials and authored clips.
Methods
newInstance#
Creates an independently animated instance.
Arguments
| Name | Type | Description |
|---|---|---|
self | Model |
Returns
| Type | Description |
|---|---|
Instance | Returns reusable primitive templates plus private joint palettes and morph-weight vectors. |
animationIndex#
Returns a clip's one-based index.
Arguments
| Name | Type | Description |
|---|---|---|
borrows self | Model | |
name | string | The caller supplies an authored or generated clip name. |
Returns
| Type | Description |
|---|---|
integer? | Returns its index, or nil when absent. Duplicate authored names raise because selecting either by that name would be ambiguous. |
Fields
PlayOptionstype#
type PlayOptions = {
--- Caller-writable. Multiplies elapsed time. Negative values raise on
--- `update`.
speed: number?,
--- Caller-writable. Controls whether playback wraps at the duration.
loop: boolean?,
--- Caller-writable. Controls whether `update` advances playback.
playing: boolean?
}Controls clip playback, with speed one, looping and immediate playback by default.
Primitiverecord#
record Primitive
transform: TransformInput
mesh: MeshInput
bounds: BoundsInput
material: MaterialInput
skin: SkinInput
morph: MorphInput
materialName: string = ""
endHolds the spawnable components for one independently posed primitive.
Fields
transform#
transform: TransformInputCaller-writable. Contains this primitive's sampled world transform.
bounds#
bounds: BoundsInputCaller-writable. Supplies the local bound, which must enclose every animated pose.
skin#
skin: SkinInputCaller-writable. Selects this instance's joint palette; its empty palette denotes rigid geometry.
morph#
morph: MorphInputCaller-writable. Selects this instance's morph weights; its empty palette denotes geometry without morph targets.
materialName#
materialName: stringRead-only. Reports the authored material name for fixture and game metadata.
Functions#
loadfunction#
function load(path: string, options: LoadOptions?): Model?, string?Loads and registers a glTF or GLB scene for independent instances.
Arguments
| Name | Type | Description |
|---|---|---|
path | string | The caller supplies a model path; external buffers and images resolve beside it. |
options | LoadOptions? | The caller may tune imported materials before upload. |
Returns
| Type | Description |
|---|---|
Model? | The shared model, or nil and the decoder's reason when loading fails. |
string? |
Raises
When the supplied path is empty.
loadEnvironmentfunction#
function loadEnvironment(name: string, faces: {string}): string?, string?Loads the six original environment faces and registers their shared GPU mip chain.
Arguments
| Name | Type | Description |
|---|---|---|
name | string | The stable, non-empty environment identity used by View lighting and snapshots. |
faces | {string} | File paths in positive X, negative X, positive Y, negative Y, positive Z, negative Z order. |
Returns
| Type | Description |
|---|---|
string? | The environment name, or nil and a decoding failure. All faces must be equally sized squares. |
string? |
nextUploadfunction#
function nextUpload(): integer, stringDrains one model upload for the native host; zero means the queue is empty.
Returns
| Type | Description |
|---|---|
integer | The model ID and packed geometry, or zero and an empty string. |
string |
Values#
MATERIAL_LAMBERTvariable#
const MATERIAL_LAMBERT: integerSelects diffuse Lambert shading.
MATERIAL_METALLIC_ROUGHNESSvariable#
const MATERIAL_METALLIC_ROUGHNESS: integerSelects Cook-Torrance metallic-roughness shading.
MATERIAL_UNLITvariable#
const MATERIAL_UNLIT: integerSelects unlit base color and emission.