Character3D Plugin
The Character3D plugin provides a framework for creating animated 3D characters
in Clayground applications. It features a modular body part system, procedural
animation capabilities, and integrates with the Canvas3D toon shading system
for stylized cartoon characters.
Getting Started
To use Character3D components, import the module in your QML file:
import Clayground.Character3D
Core Components
Character - Base component managing body parts and animations with extensive dimension properties
ParametricCharacter - High-level parameters (bodyHeight, realism, maturity, femininity, mass) that auto-calculate dimensions
RatioBasedCharacter - Dimension ratios for fine-tuned proportion control
CharacterEditor - Visual editor overlay for character customization with persistence
Speech - Voice output (text-to-speech or wav/mp3) with approximate lip-sync
ThoughtBubble - Simple text bubble for speech/thought display
Usage Examples
Basic Character
import QtQuick
import QtQuick3D
import Clayground.Canvas3D
import Clayground.Character3D
View3D {
anchors.fill: parent
PerspectiveCamera {
position: Qt.vector3d(0, 200, 400)
eulerRotation.x: -20
}
DirectionalLight {
eulerRotation.x: -35
castsShadow: true
shadowFactor: 78
shadowMapQuality: Light.ShadowMapQualityVeryHigh
}
Character {
y: 0
activity: Character.Activity.Idle
}
}
Parametric Character Creation
ParametricCharacter {
name: "hero"
bodyHeight: 10.0
// Body shape
realism: 0.3 // Cartoon-like
maturity: 0.7 // Adult
femininity: 0.3 // Masculine
mass: 0.5 // Average
muscle: 0.7 // Athletic
// Face
faceShape: 0.5
eyes: 1.2
hair: 0.8
// Colors
skin: "#d38d5f"
hairTone: "#734120"
topClothing: "#4169e1"
bottomClothing: "#708090"
}
Character with Movement
ParametricCharacter {
id: player
name: "player"
// Activity controls animation
activity: isMoving ? Character.Activity.Running : Character.Activity.Idle
// Movement derived from animation geometry
property bool isMoving: controller.axisX !== 0 || controller.axisY !== 0
// Move based on currentSpeed (auto-calculated from animation)
x: x + controller.axisX currentSpeed dt
z: z - controller.axisY currentSpeed dt
}
Character Editor Integration
import Clayground.Character3D
import Clayground.GameController
Item {
View3D {
id: view3d
anchors.fill: parent
ParametricCharacter {
id: character1
name: "char1"
}
ParametricCharacter {
id: character2
name: "char2"
x: 20
}
}
GameController {
id: gameController
Component.onCompleted: selectKeyboard(
Qt.Key_W, Qt.Key_S, Qt.Key_A, Qt.Key_D,
Qt.Key_Shift, Qt.Key_Space
)
}
CharacterEditor {
anchors.fill: parent
characters: [character1, character2]
view3d: view3d
gameController: gameController
enabled: true
}
}
Facial Expressions
Character {
id: character
// Set facial expression
faceActivity: Head.Activity.ShowJoy
// Animate expressions
SequentialAnimation on faceActivity {
loops: Animation.Infinite
PropertyAnimation { to: Head.Activity.ShowJoy; duration: 2000 }
PropertyAnimation { to: Head.Activity.Idle; duration: 1000 }
PropertyAnimation { to: Head.Activity.Talk; duration: 2000 }
PropertyAnimation { to: Head.Activity.Idle; duration: 1000 }
}
}
Speech with Lip-Sync
Characters can speak text (via text-to-speech when available) or play
recorded audio (wav/mp3) - the mouth movement approximates the speech
in both cases:
Character {
id: npc
Component.onCompleted: {
// Text: spoken aloud when a TTS engine is available,
// otherwise the mouth animates silently at an estimated pace
npc.say("Hello! Welcome to Clayground.")
}
}
// Recorded dialog line - mouth follows the audio's loudness envelope
npc.say("dialog/intro.wav")
// Emotional conversation: colors face, voice (TTS pitch/rate) and -
// while the character is idle - body language gestures
npc.say("I lost my favorite shovel...", "sad")
npc.say("We found the treasure!", "happy")
npc.say("Give it back right now!", "angry")
// Inline annotations switch the emotion mid-speech
npc.say("angry Get off my ground immediately! " +
"happy Just a joke - come in and have a cup of tea with me.")
// Body language is optional: disable it (or just keep the character
// walking/fighting) and only face and voice carry the emotion
npc.speechBodyLanguage = false
// Advanced configuration
npc.speech.rate = 0.2 // a bit faster
npc.speech.volume = 0.8
npc.speech.finished.connect(() => console.log("done talking"))
The mouth is driven by continuous shape parameters on Head
(mouthOpen, mouthWide, mouthRound - readonly outputs - plus the
writable mouthCornerLift). Emotions keep control of the mouth corners
while speaking, so characters can smile and talk at the same time.
For fully manual mouth control, assign any object with speaking,
mouthOpen, mouthWide and mouthRound properties to
head.speechSource.
Best Practices
1. Use ParametricCharacter for quick character creation with intuitive parameters.
2. Activity-Based Animation: Set the activity property to control animations - speeds are auto-derived from geometry.
3. Toon Shading: Use the Canvas3D DirectionalLight setup for consistent cartoon rendering.
4. Character Editor: Add CharacterEditor during development for visual tuning, remove for production.
5. Proportions: Adjust realism (0-1) to shift between cartoon and realistic body ratios.
Technical Implementation
The Character3D plugin implements:
Modular Body Parts: Head, torso, arms, legs with independent dimensions
Procedural Animation: Walk, run, idle animations derived from body geometry
Animation-Speed Coupling: Movement speeds calculated from leg swing geometry
Facial Expressions: Multiple expression states (idle, joy, anger, sadness, talk)
Editor Integration: 3D picking, parameter sliders, and per-character persistence
Coordinate System: Origin at ground level (Y=0 at feet), character faces -Z when rotation is (0,0,0)
The animation system uses frame-based updates with biomechanically-inspired joint rotations and parent-child transform hierarchies.