← Back to Docs
  • index.html
  • Clayground
  • Clayground.Canvas3D
  • DynamicInstances3D
  • Clayground 2026.2
  • DynamicInstances3D QML Type

    Fast, general-purpose dynamic instance table for animated fleets. More...

    Import Statement: import Clayground.Canvas3D

    Properties

    Methods

    Detailed Description

    DynamicInstances3D renders many copies of one base mesh through a single GPU instance table whose per-entry transforms are updated every frame from a packed binary buffer - no per-instance QObject and no CPU table rebuild on the hot path. It is the C++-backed alternative to a declarative InstanceList of InstanceListEntry objects: where an InstanceList pays a property write per entry per changed field (and a full table rebuild), this type takes one updatePoses call per frame carrying every entry's pose.

    Each 80-byte entry stores an affine transform (three vec4 rows, row.w = translation), a color and a customData vec4, exactly like the built-in instancing. Per-entry statics (scale, color, customData) are set once via setBulk; movement is pushed each frame via updatePoses from a packed float32 buffer of [x, y, z, yawRad] per entry. The transform is translate(x,y,z) * rotateY(yaw) * scale, so the base mesh's local +Z axis points along yaw.

    Set it as a Model's instancing and drive it from a reused Float32Array:

    import QtQuick
    import QtQuick3D
    import Clayground.Canvas3D
    
    Model {
        source: "#Cube"
        instancing: DynamicInstances3D {
            id: fleet
            Component.onCompleted: {
                var scales = [], colors = []
                for (var i = 0; i < 500; ++i) {
                    scales.push(Qt.vector3d(0.02, 0.01, 0.03))
                    colors.push("#00d9ff")
                }
                setBulk(scales, colors)
                setExtents(Qt.vector3d(-200, 0, -200), Qt.vector3d(200, 10, 200))
            }
        }
        materials: PrincipledMaterial { lighting: PrincipledMaterial.NoLighting }
    }

    See also LineBatch3D and PerfRegistry.

    Property Documentation

    bytesLastUpload : int [read-only]

    Size in bytes of the instance data handed to the renderer on the last upload (count * 80).


    capacity : int

    Preallocated number of entries the table can hold.

    Growing capacity reallocates the backing buffer; the table never shrinks implicitly. setBulk auto-grows capacity to fit the entries it is given.


    count : int [read-only]

    Number of active entries currently rendered.


    packMsLast : real [read-only]

    Wall-clock milliseconds spent packing the last updatePoses call.


    uploadsPerSecond : real [read-only]

    Rolling rate of updatePoses calls over the last second.


    Method Documentation

    void setBulk(list scales, list colors, list customData)

    Sets the per-entry statics (rare / setup path).

    scales holds one vector3d per entry, colors one color per entry and customData an optional vec4 per entry. count becomes the number of entries and capacity auto-grows to fit. Existing poses are preserved for entries that stay in range; new entries start at the origin until the next updatePoses.


    void setEntryColor(int i, color c)

    Sets the color of a single entry (occasional path).


    void setExtents(vector3d min, vector3d max)

    Declares the roaming volume so bounds are not recomputed per upload.

    Sets the instancing's shadow bounds to min / max. When the host knows the volume its instances stay inside (e.g. a streamed tile), this skips the O(n) per-upload bounds scan Qt otherwise runs over the whole table.


    void updatePoses(int first, ByteArray poses)

    Hot path: rewrites entry poses from a packed float32 buffer.

    poses is packed [x, y, z, yawRad] (four float32) per entry, applied to entries starting at index first. Each entry's transform is rebuilt from its stored scale and the given yaw and written straight into the table before a single upload is triggered. Entries beyond count (or the current capacity) are ignored.