Search Results

Canvas3D Plugin

Overview

The Canvas3D plugin provides components for creating 3D visualizations in Clayground applications. It offers primitives for 3D boxes, lines, and voxel-based structures with support for custom edge rendering, toon shading, and efficient batch rendering.

Getting Started

To use Canvas3D components, import the module in your QML file:

import Clayground.Canvas3D

Minimal Example

Here’s a simple example showing a red box with dark edges:

import QtQuick
import QtQuick3D
import Clayground.Canvas3D

View3D {
    anchors.fill: parent

    PerspectiveCamera {
        position: Qt.vector3d(0, 200, 300)
        eulerRotation.x: -30
    }

    DirectionalLight {
        eulerRotation.x: -30
        castsShadow: true
        shadowFactor: 78
        shadowMapQuality: Light.ShadowMapQualityVeryHigh
    }

    Box3D {
        width: 100
        height: 100
        depth: 100
        color: "red"
        useToonShading: true
    }
}

Core Components

Box3D

The Box3D component creates a 3D box with customizable dimensions, edge rendering, and cartoon-style shading.

Creating Non-Uniform Shapes

Use scale properties to create pyramids, trapezoids, and other shapes:

// Pyramid
Box3D {
    width: 100; height: 100; depth: 100
    scaledFace: Box3DGeometry.TopFace
    faceScale: Qt.vector2d(0.1, 0.1)
}

Edge Mask Usage

Control which edges are visible:

Box3D {
    edgeMask: topEdges | bottomEdges  // Only horizontal edges
}

Lines

Canvas3D provides three components for drawing lines in 3D space:

  • Line3D: Simple wrapper for drawing a single line
  • MultiLine3D: Efficient component for drawing multiple lines in a single draw call
  • BoxLine3D: Creates a line using connected box segments for thicker, more visible lines

Voxel Maps

Voxel maps create 3D structures composed of cubic voxels with support for both dynamic updates and static optimization.

  • DynamicVoxelMap: Best for voxel maps that change frequently
  • StaticVoxelMap: Optimized for large, static voxel structures using greedy meshing

Toon Shading

Canvas3D implements cartoon-style rendering using a half-lambert lighting model, providing flat, stylized lighting with distinct shadow boundaries.

Optimal Lighting Setup

Toon shading requires specific shadow settings for the characteristic cartoon look:

DirectionalLight {
    eulerRotation.x: -35  // Optimal lighting angle
    castsShadow: true
    shadowFactor: 78                        // Strong shadows
    shadowMapQuality: Light.ShadowMapQualityVeryHigh  // Crisp edges
    pcfFactor: 2                           // Minimal softening
    shadowBias: 18                         // Artifact prevention
}

Usage

Enable toon shading on any Canvas3D component:

Box3D {
    useToonShading: true
    edgeColorFactor: 2.0  // Increase edge contrast for cartoon look
}

StaticVoxelMap {
    useToonShading: true  // Creates Minecraft-like blocky aesthetics
}

Coordinate System

Canvas3D uses Qt Quick 3D’s coordinate system:

  • X-axis: Points right
  • Y-axis: Points up
  • Z-axis: Points toward the viewer

Voxel Coordinates

The relationship between voxel coordinates and world positions:

worldPosition = voxelCoordinate * (voxelSize + spacing) + voxelOffset

Example dimensions calculation:

StaticVoxelMap {
    voxelCountX: 10
    voxelCountY: 5
    voxelCountZ: 10
    voxelSize: 2.0
    spacing: 0.5

    // width = 10 * (2.0 + 0.5) - 0.5 = 24.5
    // height = 5 * (2.0 + 0.5) - 0.5 = 12.0
    // depth = 10 * (2.0 + 0.5) - 0.5 = 24.5
}

Performance Considerations

Choosing Voxel Map Types

  • DynamicVoxelMap: Frequent updates, smaller maps (< 50^3 voxels)
  • StaticVoxelMap: Static content, large maps, performance-critical applications

Optimization Tips

  • Batch Operations: Call model.commit() once after multiple voxel changes
  • Edge Control: Disable showEdges for large voxel maps
  • Shadow Quality: Balance shadow settings with performance needs

Examples

Toon-Shaded Voxel Terrain

import QtQuick
import QtQuick3D
import Clayground.Canvas3D

View3D {
    environment: SceneEnvironment {
        clearColor: "#87CEEB"  // Sky blue
        backgroundMode: SceneEnvironment.Color
    }

    PerspectiveCamera {
        position: Qt.vector3d(200, 300, 400)
        eulerRotation.x: -30
    }

    DirectionalLight {
        eulerRotation.x: -35
        eulerRotation.y: -70
        castsShadow: true
        shadowFactor: 78
        shadowMapQuality: Light.ShadowMapQualityVeryHigh
        pcfFactor: 2
        shadowBias: 18
    }

    StaticVoxelMap {
        id: terrain
        voxelCountX: 80
        voxelCountY: 30
        voxelCountZ: 80
        voxelSize: 5
        useToonShading: true
        showEdges: false  // Avoid artifacts with terrain

        Component.onCompleted: {
            // Create layered terrain
            for (let x = 0; x < voxelCountX; x++) {
                for (let z = 0; z < voxelCountZ; z++) {
                    let h = Math.sin(x * 0.1) * Math.cos(z * 0.1) * 8 + 15

                    for (let y = 0; y < h; y++) {
                        let color = y < 5 ? "#8B4513" :   // Dirt
                                   y < 12 ? "#228B22" :   // Grass
                                           "#708090"       // Stone
                        set(x, y, z, color)
                    }
                }
            }
            model.commit()
        }
    }
}

Best Practices

Toon Shading

  • Use strong directional lighting with high shadow factor (70-80)
  • Enable crisp shadow maps (VeryHigh quality, low PCF factor)
  • Increase edgeColorFactor for enhanced cartoon aesthetics
  • Consider scene ambient lighting balance

Performance

  • Choose appropriate voxel map type based on update frequency
  • Batch voxel operations when possible
  • Use edge rendering selectively on large scenes
  • Profile shadow quality vs. performance trade-offs

Visual Design

  • Consistent lighting setup across toon-shaded objects
  • Use the demos (Box3DDemo.qml, VoxelDemo.qml) as implementation references
  • Test both rendering modes during development

Implementation References

For developers wanting to understand or extend the system:

  • Toon Shading: box3d.frag, voxel_map.frag - complete shader implementations
  • Edge Rendering: shouldShowEdge() function, grid line calculations
  • Greedy Meshing: VoxelMapGeometry::generateGreedyMesh()
  • Demo Implementation: Box3DDemo.qml, VoxelDemo.qml - complete working examples

API Reference

BenchLogger Samples a View3D's renderStats at a fixed interval and writes them to a CSV file

Properties

NameTypeDescription
extravarMap of extra column name to value or zero-argument function. Each entry adds one CSV column; functions are evaluated per sample. The key set is captured when logging starts
intervalMsintSampling interval in milliseconds
outputPathstringDestination CSV file path (plain path or file:// URL)
runningboolSet true to open the file and start sampling, false to flush, close and stop
view3DvarView3D whose renderStats are sampled. Required

Methods

MethodReturnsDescription
annotate(string key, var value)void

Signals

SignalDescription
sampleTaken()
Box3D A 3D box with customizable dimensions, edge rendering, and toon shading

Properties

NameTypeDescription
allEdges readonlyintConvenience constant for showing all edges
colorcolorBase color of the box
depthrealDepth of the box along the Z axis
edgeColorFactorrealDarkening factor for edges (0-1)
edgeMaskintBitmask controlling which edges are visible
edgeThicknessrealThickness of edge lines
faceScalevector2dScale factor for the selected face
heightrealHeight of the box along the Y axis
scaledFaceenumerationWhich face of the box should be scaled
showEdgesboolWhether to render dark edge lines
useToonShadingboolEnables cartoon-style rendering
widthrealWidth of the box along the X axis
Box3DGeometry Custom geometry for 3D boxes with edge rendering support

Properties

NameTypeDescription
edgeColorFactorrealDarkening factor for edge colors
edgeMaskintBitmask controlling which edges are visible
edgeThicknessrealThickness of edge lines in normalized units
faceScalevector2dScale factor applied to the selected face
scaledFaceenumerationWhich face of the box should be scaled
showEdgesboolWhether to render edge lines on the box
sizevector3dDimensions of the box as a 3D vector (width, height, depth)
BoxLine3D Renders a 3D line as connected box segments using GPU instancing

Properties

NameTypeDescription
colorcolorOf the line
materialMaterialUsed for rendering
positionsvector3dList of 3D positions defining the line path
widthrealOf the box-shaped line segments
Connector3D A dynamic connection line between two scene nodes, drawn in a batch

Properties

NameTypeDescription
colorcolorConnector color. Defaults to the layer's color
fromQtObjectNode the connector starts at (its scene position is tracked)
layerConnectorLayer3DThis connector draws into
styleIdintStyle-table row selecting dash/cap/opacity. Defaults to the layer's styleId. See LineBatch3D::styles
toQtObjectNode the connector ends at (its scene position is tracked)
widthrealConnector width. Defaults to the layer's width
ConnectorLayer3D Draws many dynamic Connector3D lines as a single instanced batch

Properties

NameTypeDescription
arcHeightrealArc lift as a fraction of link length (only when segmentsPerLink > 1)
colorcolorDefault line color for connectors that do not set their own
count readonlyintNumber of connectors currently drawn in the batch
depthBiasrealDepth bias forwarded to the batch, see LineBatch3D::depthBias
flowTimerealAnimation clock forwarded to the batch, see LineBatch3D::flowTime
segmentsPerLinkintNumber of straight segments each connector is drawn with
styleIdintDefault styleId for connectors that do not set their own
styleslistStyle table forwarded to the batch, see LineBatch3D::styles
viewportSizevector2dEnclosing View3D pixel size, forwarded to the batch. Required in Pixel width mode
widthrealDefault line width for connectors that do not set their own
widthUnitsenumerationHow connector width is interpreted, see LineBatch3D::widthUnits
DynamicInstances3D Fast, general-purpose dynamic instance table for animated fleets

Properties

NameTypeDescription
bytesLastUpload readonlyintSize in bytes of the instance data handed to the renderer on the last upload (count * 80)
capacityintPreallocated number of entries the table can hold
count readonlyintNumber of active entries currently rendered
packMsLast readonlyrealWall-clock milliseconds spent packing the last updatePoses call
uploadsPerSecond readonlyrealRolling rate of updatePoses calls over the last second

Methods

MethodReturnsDescription
setBulk(list scales, list colors, list customData)void
setEntryColor(int i, color c)void
setExtents(vector3d min, vector3d max)void
updatePoses(int first, ByteArray poses)void
DynamicVoxelMap Voxel map optimized for frequent updates using GPU instancing

Properties

NameTypeDescription
voxelCountXintNumber of voxels along the X axis
voxelCountYintNumber of voxels along the Y axis (height)
voxelCountZintNumber of voxels along the Z axis
Label3D A camera-facing callout label anchored to a 3D node or position

Properties

NameTypeDescription
anchorNodeQtObjectNode the label tracks; its scene position drives placement
anchorPositionvector3dFixed scene position to anchor to when anchorNode is null
cameraQtObjectThe label faces. Defaults to view.camera
distanceFadeboolWhen true, fade the label out with camera distance (Screen mode)
fadeFarrealCamera distance at and beyond which the label is fully transparent
fadeNearrealCamera distance at and below which the label is fully opaque
iconSourceurlOptional icon shown left of the text. Empty hides it
labelOffsetvector3dWorld-space offset of the pill from the anchor
labelStyleQtObjectGrouped pill styling: colors, radius, padding, halo and font
leaderStyleQtObjectGrouped leader-line styling: color and width (pixels)
maxScreenSizerealUpper clamp for the on-screen pill height in pixels (0 disables)
minScreenSizerealLower clamp for the on-screen pill height in pixels (0 disables)
priorityintOrdering hint for the future declutter manager; higher wins
scaleQuantumrealRelative scale change required before the pill is re-scaled (0 disables)
screenHeightrealTarget on-screen pill height in pixels (Screen size mode)
showLeaderboolWhen true, draw a thin line from the pill edge to the anchor
sizeModeintActive size mode, see SizeMode
textstringLabel text
viewQtObjectEnclosing View3D, used to resolve the camera, size the leader and register with the per-view label registry
worldHeightrealPill height in world units (World size mode)
LabelBatch3D Renders thousands of SDF text labels in a few instanced draw calls

Properties

NameTypeDescription
ascentPx readonlyrealFont ascent in atlas base pixels (for mapping a world text height onto setCurvedLabels sizes)
atlasHeight readonlyintCurrent glyph-atlas height in texels
atlasWidth readonlyintCurrent glyph-atlas width in texels
batchOpacityrealBatch-wide opacity multiplier (0..1). Default 1
capHeightPx readonlyrealFont cap height in atlas base pixels
count readonlyintNumber of labels currently in the batch
depthBiasrealShifts the glyph depth toward the camera (0..~0.001). Default 0
descentPx readonlyrealFont descent in atlas base pixels
fontQtObjectGrouped font config for the shared glyph atlas
glyphCount readonlyintNumber of glyph instances currently drawn
haloboolWhether glyphs get a halo outline for busy backgrounds. Default true
haloColorcolorHalo color (a dark halo is the robust default on bright and dark)
haloWidthrealHalo band width in SDF units past the glyph edge (0..0.5). Default 0.18
labelslistDeclarative list of labels
orientationintActive orientation, one of the Orientation values. Default Billboard. Only applies in World size mode
pillboolWhether a rounded background pill is drawn behind each label. Default false
pillColorcolorPill fill color (dark semi-transparent default)
pillPaddingrealPadding in base pixels between the text box and the pill edge
pillRadiusrealPill corner radius in base pixels
shapeMsLast readonlyrealWall-clock milliseconds spent shaping on the last setLabels
sizeModeintActive size mode, one of the SizeMode values. Default Screen
viewportSizevector2dPixel size of the enclosing View3D
writesDepthboolWhether inked glyph fragments write depth. Default false

Methods

MethodReturnsDescription
glyphAdvances(string text, real size)list
priorities()list
setCurvedLabels(list labels)void
setLabels(list labels)void
updatePositionsBulk(ByteArray positions, int first)void
LabelBatchInstancing Per-glyph instance table for the batched LabelBatch3D renderer

Properties

NameTypeDescription
labelslistDeclarative list of labels to render

Methods

MethodReturnsDescription
glyphAdvances(string text, real size)list
setCurvedLabels(list labels)void
updatePositionsBulk(ByteArray positions, int first)void
LabelGlyphAtlas Incremental single-channel SDF glyph atlas for LabelBatch3D

Properties

NameTypeDescription
baseSizeintRasterization size in pixels. Higher = crisper when magnified, larger atlas. Changing it clears the atlas
fontFamilystringFont family baked into the atlas. Changing it clears the atlas
fontWeightintFont weight (e.g. 400 normal, 700 bold). Changing it clears the atlas
LabelPillInstancing Per-label pill-background instance table for LabelBatch3D
Line3D A simple 3D line connecting multiple points

Properties

NameTypeDescription
colorcolorOf the line
coordsvector3dList of 3D points defining the line path
widthrealOf the line in world units
LineBatch3D Renders very large sets of styled polylines in a single instanced draw call

Properties

NameTypeDescription
count readonlyintNumber of lines currently in the batch
depthBiasrealPulls the lines toward the camera to win depth fights
flowAutoPlayboolConvenience clock that advances flowTime automatically
flowTimerealAnimation clock (seconds) driving every flowing/pulsing style
lineslistDeclarative list of styled polylines (convenience path)
opaqueboolRenders the batch as opaque geometry with early depth rejection
orientationintActive ribbon orientation, one of the Orientation values
styleslistPer-styleId table of pattern, cap shape, opacity and effects
viewportSizevector2dPixel size of the enclosing View3D
widthUnitsintActive width interpretation, one of the WidthUnits values

Methods

MethodReturnsDescription
pathLength(int lineId)real
positionAt(int lineId, real distance)vector3d
setBulk(ByteArray positions, ByteArray startIndices, ByteArray colors, ByteArray widths, ByteArray styleIds)void
updateEndpointsBulk(ByteArray positions)void
updateLinePoints(int lineIndex, list points)void
updatePolylinesBulk(ByteArray positions, int pointsPerLine)void
LineBatchGeometry Base quad geometry for the instanced LineBatch3D renderer

Properties

NameTypeDescription
boundsMaxvector3dMaximum corner of the axis-aligned bounding box covering all lines
boundsMinvector3dMinimum corner of the axis-aligned bounding box covering all lines
LineBatchInstancing Per-line instance table for the batched LineBatch3D renderer

Properties

NameTypeDescription
count readonlyintNumber of lines (polylines) currently in the batch
lineslistDeclarative list of styled polylines

Methods

MethodReturnsDescription
pathLength(int lineIndex)real
positionAt(int lineIndex, real distance)vector3d
setBulk(ByteArray positions, ByteArray startIndices, ByteArray colors, ByteArray widths, ByteArray styleIds)void
updateEndpointsBulk(ByteArray positions)void
updateLinePoints(int lineIndex, list points)void
updatePolylinesBulk(ByteArray positions, int pointsPerLine)void
LineInstancing GPU instancing for rendering lines as connected box segments

Properties

NameTypeDescription
colorcolorApplied to all line segment instances
positionslist<vector3d>List of 3D positions defining the line path
widthrealOf the line segments in world units
LineStyleTextureData Bakes a list of line styles into a small RGBA32F lookup texture

Properties

NameTypeDescription
styleCount readonlyintNumber of style columns in the texture (always at least 1)
styleslistDeclarative list of line styles baked into the texture
MultiLine3D Renders multiple 3D line paths in a single draw call

Properties

NameTypeDescription
colorcolorOf all lines. Defaults to red
coordslist<vector3d>Array of line paths, each path being an array of 3D points
orientationintLineBatch3D.Billboard (default) or LineBatch3D.Flat
widthrealOf all lines in world units. Defaults to 1
OrbitCamera3D An orbit camera on a leash: circles a pivot, never dives through the floor

Properties

NameTypeDescription
camera readonlyalias
camera \readonly readonlyPerspectiveCamera
distancereal
distance \brief Distance to the pivot.real
fieldOfViewreal
fieldOfView \brief Vertical FOV of the camera.real
maxDistancereal
maxDistance \brief Furthest allowed retreat.real
maxPitchreal
maxPitch \brief Steepest allowed angle (< 90).real
minDistancereal
minDistance \brief Closest allowed approach.real
minHeightrealLowest the camera may sit above the pivot plane
minPitchreal
minPitch \brief Flattest allowed angle.real
pitchreal
pitch \brief Angle above the pivot plane, degrees.real
pivotvector3d
pivot \brief The point the camera looks at.vector3d
yawreal
yaw \brief Angle around the pivot, degrees.real

Methods

MethodReturnsDescription
applyState(var s)void
clamp()void
frame(var points, real pad)void
orbitBy(real dYaw, real dPitch)void
state()var
zoomBy(real factor)void
PathLabel3D Street-name style text laid flat on the ground, following a line

Properties

NameTypeDescription
atrealPath distance (world units) the label centers on
glyphBatchActive readonlyboolWhether the lazy internal glyph batch currently exists (read-only)
glyphPlacementboolSelects per-glyph text-on-curve placement instead of per-word quads
groundOffsetrealHeight in world units the quads sit above y=0 to avoid z-fighting
labelStyleQtObjectGrouped ground-paint styling: color, halo, optional background, font
lineIdintIndex of the line inside lines to run the text along
linesQtObjectLineBatch3D whose geometry the label follows
oversamplerealTexture oversample factor for crispness (2 renders at 2x texels)
readingDirectionvector2dReference reading direction in the ground (X, Z) plane
repeatEveryrealSpacing in world units between repeated placements (0 = single)
skippedPlacements readonlyintNumber of placements skipped by the curvature guard (read-only)
textstringLabel text; split on whitespace into per-word quads
uniqueTextureCount readonlyintNumber of distinct word textures currently in use (read-only)
wordSpacingrealGap in world units between consecutive words. Negative auto-derives it from worldHeight
worldHeightrealText height in world units; the quad width follows the text aspect

Methods

MethodReturnsDescription
rebuild()void
PerfHud Compact always-on-top performance overlay for a View3D

Properties

NameTypeDescription
extendedboolWhen true, additionally shows Qt's DebugView with resource details next to the compact panel
view3DvarView3D whose renderStats are displayed. Required
PerfRegistry App-wide singleton for measuring named code sections and event rates

Methods

MethodReturnsDescription
begin(string name)void
end(string name)void
reset()void
snapshot()list
tick(string name)void
StaticVoxelMap Optimized voxel map for large, static structures

Properties

NameTypeDescription
chunkSizeintEdge length (in voxels) of a meshing chunk
voxelCountXintNumber of voxels along the X axis
voxelCountYintNumber of voxels along the Y axis (height)
voxelCountZintNumber of voxels along the Z axis
VoxelMap Base type for voxel-based 3D structures

Properties

NameTypeDescription
autoCommitboolWhether to automatically commit changes
depth readonlyrealTotal depth of the voxel map in world units
edgeColorFactorrealDarkening factor for edges
edgeThicknessrealThickness of grid edge lines
height readonlyrealTotal height of the voxel map in world units
modelvarUnderlying voxel data model
showEdgesboolWhether to render voxel grid lines
spacingrealGap between adjacent voxels in world units
useToonShadingboolEnables cartoon-style rendering
voxelCountXintNumber of voxels along the X axis
voxelCountYintNumber of voxels along the Y axis (height)
voxelCountZintNumber of voxels along the Z axis
voxelOffsetvector3dOffset applied to voxel edge calculations
voxelSizerealSize of each voxel cube in world units
width readonlyrealTotal width of the voxel map in world units

Methods

MethodReturnsDescription
fill(var shapes)void
get(int x, int y, int z)color
load(string path)void
save(string path)void
set(int x, int y, int z, color color)void
VoxelMapGeometry Optimized geometry for static voxel maps using chunked greedy meshing

Properties

NameTypeDescription
chunkSizeintEdge length (in voxels) of a meshing chunk
spacingrealGap between adjacent voxels in world units
vertexCount readonlyintCurrent number of vertices in the generated geometry
voxelCountXintNumber of voxels along the X axis
voxelCountYintNumber of voxels along the Y axis (height)
voxelCountZintNumber of voxels along the Z axis
voxelSizerealSize of each voxel cube in world units

Methods

MethodReturnsDescription
commit()void
fillBox(int cx, int cy, int cz, int width, int height, int depth, list colorDistribution, real noiseFactor)void
fillCylinder(int cx, int cy, int cz, int r, int height, list colorDistribution, real noiseFactor)void
fillSphere(int cx, int cy, int cz, int r, list colorDistribution, real noiseFactor)void
loadFromFile(string path)bool
saveToFile(string path)bool
setVoxel(int x, int y, int z, color color)void
voxel(int x, int y, int z)color
VoxelMapInstancing GPU instancing for dynamic voxel maps with per-voxel colors

Properties

NameTypeDescription
spacingrealGap between adjacent voxels in world units
voxelCountXintNumber of voxels along the X axis
voxelCountYintNumber of voxels along the Y axis (height)
voxelCountZintNumber of voxels along the Z axis
voxelSizerealSize of each voxel cube in world units

Methods

MethodReturnsDescription
commit()void
fillBox(int cx, int cy, int cz, int width, int height, int depth, list colorDistribution, real noiseFactor)void
fillCylinder(int cx, int cy, int cz, int r, int height, list colorDistribution, real noiseFactor)void
fillSphere(int cx, int cy, int cz, int r, list colorDistribution, real noiseFactor)void
loadFromFile(string path)bool
saveToFile(string path)bool
setVoxel(int x, int y, int z, color color)void
voxel(int x, int y, int z)color