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.
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
}
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
- 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
Box3D
A 3D box with customizable dimensions, edge rendering, and toon shading
View full documentation
Properties
| Name | Type | Description |
allEdges readonly | int | Convenience constant for showing all edges |
color | color | Base color of the box |
depth | real | Depth of the box along the Z axis |
edgeColorFactor | real | Darkening factor for edges (0-1) |
edgeMask | int | Bitmask controlling which edges are visible |
edgeThickness | real | Thickness of edge lines |
faceScale | vector2d | Scale factor for the selected face |
height | real | Height of the box along the Y axis |
scaledFace | enumeration | Which face of the box should be scaled |
showEdges | bool | Whether to render dark edge lines |
useToonShading | bool | Enables cartoon-style rendering |
width | real | Width of the box along the X axis |
Box3DGeometry
Custom geometry for 3D boxes with edge rendering support
View full documentation
Properties
| Name | Type | Description |
edgeColorFactor | real | Darkening factor for edge colors |
edgeMask | int | Bitmask controlling which edges are visible |
edgeThickness | real | Thickness of edge lines in normalized units |
faceScale | vector2d | Scale factor applied to the selected face |
scaledFace | enumeration | Which face of the box should be scaled |
showEdges | bool | Whether to render edge lines on the box |
size | vector3d | Dimensions of the box as a 3D vector (width, height, depth) |
BoxLine3D
Renders a 3D line as connected box segments using GPU instancing
View full documentation
Properties
| Name | Type | Description |
color | color | Of the line |
material | Material | Used for rendering |
positions | vector3d | List of 3D positions defining the line path |
width | real | Of the box-shaped line segments |
CustomLineGeometry
Custom geometry for rendering multiple 3D lines with shader-based width
View full documentation
Properties
| Name | Type | Description |
lines | list<list<vector3d>> | Array of line paths, where each path is an array of 3D points |
DynamicVoxelMap
Voxel map optimized for frequent updates using GPU instancing
View full documentation
Properties
| Name | Type | Description |
voxelCountX | int | Number of voxels along the X axis |
voxelCountY | int | Number of voxels along the Y axis (height) |
voxelCountZ | int | Number of voxels along the Z axis |
Line3D
A simple 3D line connecting multiple points
View full documentation
Properties
| Name | Type | Description |
color | color | Of the line |
coords | vector3d | List of 3D points defining the line path |
width | real | Of the line in world units |
Line3dGeometry
Custom geometry for rendering 3D lines as box-shaped segments
View full documentation
Properties
| Name | Type | Description |
color | color | Of the line |
vertices | list<vector3d> | List of 3D points defining the line path |
width | real | Of the line in world units |
LineInstancing
GPU instancing for rendering lines as connected box segments
View full documentation
Properties
| Name | Type | Description |
color | color | Applied to all line segment instances |
positions | list<vector3d> | List of 3D positions defining the line path |
width | real | Of the line segments in world units |
MultiLine3D
Efficiently renders multiple 3D line paths in a single draw call
View full documentation
Properties
| Name | Type | Description |
color | color | Of all lines |
coords | list<vector3d> | Array of line paths, each path being an array of 3D points |
material | CustomMaterial | Used for rendering the lines |
width | real | Of all lines in screen pixels |
StaticVoxelMap
Optimized voxel map for large, static structures
View full documentation
Properties
| Name | Type | Description |
voxelCountX | int | Number of voxels along the X axis |
voxelCountY | int | Number of voxels along the Y axis (height) |
voxelCountZ | int | Number of voxels along the Z axis |
VoxelMap
Base type for voxel-based 3D structures
View full documentation
Properties
| Name | Type | Description |
autoCommit | bool | Whether to automatically commit changes |
depth readonly | real | Total depth of the voxel map in world units |
edgeColorFactor | real | Darkening factor for edges |
edgeThickness | real | Thickness of grid edge lines |
height readonly | real | Total height of the voxel map in world units |
model | var | Underlying voxel data model |
showEdges | bool | Whether to render voxel grid lines |
spacing | real | Gap between adjacent voxels in world units |
useToonShading | bool | Enables cartoon-style rendering |
voxelCountX | int | Number of voxels along the X axis |
voxelCountY | int | Number of voxels along the Y axis (height) |
voxelCountZ | int | Number of voxels along the Z axis |
voxelOffset | vector3d | Offset applied to voxel edge calculations |
voxelSize | real | Size of each voxel cube in world units |
width readonly | real | Total width of the voxel map in world units |
Methods
| Method | Returns | Description |
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 greedy meshing
View full documentation
Properties
| Name | Type | Description |
spacing | real | Gap between adjacent voxels in world units |
vertexCount readonly | int | Current number of vertices in the generated geometry |
voxelCountX | int | Number of voxels along the X axis |
voxelCountY | int | Number of voxels along the Y axis (height) |
voxelCountZ | int | Number of voxels along the Z axis |
voxelSize | real | Size of each voxel cube in world units |
Methods
| Method | Returns | Description |
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
View full documentation
Properties
| Name | Type | Description |
spacing | real | Gap between adjacent voxels in world units |
voxelCountX | int | Number of voxels along the X axis |
voxelCountY | int | Number of voxels along the Y axis (height) |
voxelCountZ | int | Number of voxels along the Z axis |
voxelSize | real | Size of each voxel cube in world units |
Methods
| Method | Returns | Description |
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 | |