Qt Quick 3D Physics - Joints Example

Demonstrates using joints in a physics scene.

This example demonstrates using a few of the joints available in Quick 3D Physics.

The scene is a typical scene with a PhysicsWorld, a View3D with a PerspectiveCamera and a DirectionalLight:

 Window {
     width: 640
     height: 480
     visible: true
     title: qsTr("Qt Quick 3D Physics - Joints")

     PhysicsWorld {
         scene: viewport.scene
         running: true
     }

     View3D {
         id: viewport
         anchors.fill: parent

         environment: SceneEnvironment {
             clearColor: "#d6dbdf"
             backgroundMode: SceneEnvironment.Color
         }

         PerspectiveCamera {
             position: Qt.vector3d(0, 600, 700)
             eulerRotation: Qt.vector3d(-30, 0, 0)
             clipFar: 5000
             clipNear: 1
         }

         DirectionalLight {
             eulerRotation.x: -45
             eulerRotation.y: 45
             castsShadow: true
             brightness: 1
             shadowFactor: 50
             shadowMapQuality: Light.ShadowMapQualityHigh
         }

         Rope {
             eulerRotation: Qt.vector3d(0, 0, -90)
             position: Qt.vector3d(0, 500, 0)
         }

         Prismatic {
             id: prismatic
             position: Qt.vector3d(-250, 100, 0)
         }

         Revolute {
             id: revolute
             position: Qt.vector3d(200, 200, 100)
         }

         StaticRigidBody {
             position: Qt.vector3d(0, -100, 0)
             eulerRotation: Qt.vector3d(-90, 0, 0)
             collisionShapes: PlaneShape {}
             Model {
                 source: "#Rectangle"
                 scale: Qt.vector3d(20, 20, 1)
                 materials: PrincipledMaterial {
                     baseColor: "green"
                 }
                 castsShadows: false
                 receivesShadows: true
             }
         }

         FrameAnimation {
             id: animator
             running: true
             onTriggered: {
                 prismatic.jointRotation.z += 1
                 revolute.jointRotation.x += 0.95
             }
         }
     }
 }

There is a StaticRigidBody with a PlaneShape to act as the floor and three custom QML objects; Rope, Prismatic and Revolute.

 Rope {
     eulerRotation: Qt.vector3d(0, 0, -90)
     position: Qt.vector3d(0, 500, 0)
 }

 Prismatic {
     id: prismatic
     position: Qt.vector3d(-250, 100, 0)
 }

 Revolute {
     id: revolute
     position: Qt.vector3d(200, 200, 100)
 }

The Rope object is a series of capsules and a sphere that are connected with spherical joints for the capsules and a fixed joint for the sphere.

 Node {
     id: root

     SphericalJoint {
         bodyB: shape0
         positionA: root.position
         positionB: Qt.vector3d(-20, 0, 0)
     }

     SphericalJoint {
         bodyA: shape0
         bodyB: shape1
         positionA: Qt.vector3d(20, 0, 0)
         positionB: Qt.vector3d(-20, 0, 0)
     }

     SphericalJoint {
         bodyA: shape1
         bodyB: shape2
         positionA: Qt.vector3d(20, 0, 0)
         positionB: Qt.vector3d(-20, 0, 0)
     }

     SphericalJoint {
         bodyA: shape2
         bodyB: shape3
         positionA: Qt.vector3d(20, 0, 0)
         positionB: Qt.vector3d(-20, 0, 0)
     }

     SphericalJoint {
         bodyA: shape3
         bodyB: shape4
         positionA: Qt.vector3d(20, 0, 0)
         positionB: Qt.vector3d(-20, 0, 0)
     }

     SphericalJoint {
         bodyA: shape4
         bodyB: shape5
         positionA: Qt.vector3d(20, 0, 0)
         positionB: Qt.vector3d(-20, 0, 0)
     }

     FixedJoint {
         bodyA: shape5
         bodyB: sphere
         positionA: Qt.vector3d(20, 0, 0)
         positionB: Qt.vector3d(0, 0, 0)
     }

     DynamicRigidBody {
         id: shape0
         position: Qt.vector3d(0, 0, 0)
         collisionShapes: CapsuleShape {
             diameter: 10
             height: 40
         }
         Model {
             geometry: CapsuleGeometry {
                 diameter: 10
                 height: 40
             }
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }

     DynamicRigidBody {
         id: shape1
         position: Qt.vector3d(40, 0, 0)
         collisionShapes: CapsuleShape {
             diameter: 10
             height: 40
         }
         Model {
             geometry: CapsuleGeometry {
                 diameter: 10
                 height: 40
             }
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }

     DynamicRigidBody {
         id: shape2
         position: Qt.vector3d(80, 0, 0)
         collisionShapes: CapsuleShape {
             diameter: 10
             height: 40
         }
         Model {
             geometry: CapsuleGeometry {
                 diameter: 10
                 height: 40
             }
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }

     DynamicRigidBody {
         id: shape3
         position: Qt.vector3d(120, 0, 0)
         collisionShapes: CapsuleShape {
             diameter: 10
             height: 40
         }
         Model {
             geometry: CapsuleGeometry {
                 diameter: 10
                 height: 40
             }
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }

     DynamicRigidBody {
         id: shape4
         position: Qt.vector3d(160, 0, 0)
         collisionShapes: CapsuleShape {
             diameter: 10
             height: 40
         }
         Model {
             geometry: CapsuleGeometry {
                 diameter: 10
                 height: 40
             }
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }

     DynamicRigidBody {
         id: shape5
         position: Qt.vector3d(200, 0, 0)
         collisionShapes: CapsuleShape {
             diameter: 10
             height: 40
         }
         Model {
             geometry: CapsuleGeometry {
                 diameter: 10
                 height: 40
             }
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }

     DynamicRigidBody {
         id: sphere
         position: Qt.vector3d(240, 0, 0)
         scale: Qt.vector3d(0.5, 0.5, 0.5)
         collisionShapes: SphereShape {}
         Model {
             source: "#Sphere"
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }
 }

The Prismatic object consists of two bars locked in a prismatic joint along the x-axis of both of them. With this joint the smaller rod can move freely along this x-axis until it reaches its upper and lower constraint limit.

 Node {
     id: root
     property vector3d jointRotation : Qt.vector3d(0, 0, 0)

     PrismaticJoint {
         bodyA: prismaticBoxA
         bodyB: prismaticBoxB
         lowerLimit: -200
         upperLimit: 0
         positionA: Qt.vector3d(100, 0, 0)
         positionB: Qt.vector3d(-100, 0, 0)
     }

     DynamicRigidBody {
         id: prismaticBoxA
         kinematicPosition: Qt.vector3d(0, 200, 0)
         kinematicEulerRotation: root.jointRotation
         isKinematic: true
         scale: Qt.vector3d(2, 0.5, 0.5)
         collisionShapes: BoxShape {}
         Model {
             source: "#Cube"
             materials: PrincipledMaterial {
                 baseColor: "yellow"
             }
         }
     }

     DynamicRigidBody {
         id: prismaticBoxB
         position: Qt.vector3d(0, 0, 0)
         scale: Qt.vector3d(2, 0.4, 0.4)
         collisionShapes: BoxShape {}
         Model {
             source: "#Cube"
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }
 }

The Revolute object consists of two bars rotated by 90 degrees and locked in a revolute joint.

 Node {
     id: root
     property vector3d jointRotation : Qt.vector3d(0, 90, 0)

     RevoluteJoint {
         bodyA: revoluteBoxA
         bodyB: revoluteBoxB
         positionA: Qt.vector3d(100, 0, 0)
         positionB: Qt.vector3d(100, 0, 0)
         orientationB: Quaternion.fromEulerAngles(0, 0, 90)
         angularLimitLower: -Math.PI / 4
         angularLimitUpper: Math.PI / 4
         enableAngularLimit: true
     }

     DynamicRigidBody {
         id: revoluteBoxA
         kinematicPosition: Qt.vector3d(0, 0, 0)
         kinematicEulerRotation: root.jointRotation
         isKinematic: true
         scale: Qt.vector3d(2, 0.5, 0.5)
         collisionShapes: BoxShape {}
         Model {
             source: "#Cube"
             materials: PrincipledMaterial {
                 baseColor: "yellow"
             }
         }
     }

     DynamicRigidBody {
         id: revoluteBoxB
         position: Qt.vector3d(0, 100, -100)
         eulerRotation: Qt.vector3d(0, 90, -90)
         scale: Qt.vector3d(2, 0.5, 0.5)
         collisionShapes: BoxShape {}
         Model {
             source: "#Cube"
             materials: PrincipledMaterial {
                 baseColor: "blue"
             }
         }
     }
 }

Going back to the main scene there is a FrameAnimation object that rotates the kinematic prismatic and revolute joints.

 FrameAnimation {
     id: animator
     running: true
     onTriggered: {
         prismatic.jointRotation.z += 1
         revolute.jointRotation.x += 0.95
     }
 }

With all these moving parts we can see how the different joints interact in a physics scene.

Files: