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

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
CustomLineGeometry Custom geometry for rendering multiple 3D lines with shader-based width

Properties

NameTypeDescription
lineslist<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

Properties

NameTypeDescription
voxelCountXintNumber of voxels along the X axis
voxelCountYintNumber of voxels along the Y axis (height)
voxelCountZintNumber of voxels along the Z axis
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
Line3dGeometry Custom geometry for rendering 3D lines as box-shaped segments

Properties

NameTypeDescription
colorcolorOf the line
verticeslist<vector3d>List of 3D points defining the line path
widthrealOf the line in world units
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
MultiLine3D Efficiently renders multiple 3D line paths in a single draw call

Properties

NameTypeDescription
colorcolorOf all lines
coordslist<vector3d>Array of line paths, each path being an array of 3D points
materialCustomMaterialUsed for rendering the lines
widthrealOf all lines in screen pixels
StaticVoxelMap Optimized voxel map for large, static structures

Properties

NameTypeDescription
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 greedy meshing

Properties

NameTypeDescription
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