Revision control

Copy as Markdown

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick3D
import QtQuick3D.Physics
import QtQuick3D.Helpers
import QtQuick.Controls
import QtQuick.Controls.Universal
import QtQuick.Layouts
ApplicationWindow {
width: 1280
height: 720
visible: true
title: qsTr("PhysX Physics Demo")
Universal.theme: Universal.Dark
Universal.accent: Universal.Orange
PhysicsWorld {
id: physicsWorld
gravity: Qt.vector3d(0, -9.81, 0)
running: false
forceDebugDraw: true
typicalLength: 0.2
typicalSpeed: 10
scene: scene
viewport: viewport1.scene
}
Node {
id: scene
PerspectiveCamera {
id: camera1
position: Qt.vector3d(1, 3, 7)
eulerRotation.x: -30
eulerRotation.y: 10
clipFar: 100
clipNear: 0.01
}
DirectionalLight {
eulerRotation.x: -45
eulerRotation.y: 45
castsShadow: true
brightness: 1
shadowMapQuality: Light.ShadowMapQualityMedium
shadowBias: 0.05
pcfFactor: 0.005
}
StaticRigidBody {
id: floor
position: Qt.vector3d(0, -1, 0)
eulerRotation: Qt.vector3d(-90, 0, 0)
collisionShapes: PlaneShape {
enableDebugDraw: viewport.debugView
}
Model {
source: "#Rectangle"
scale: Qt.vector3d(0.3, 0.3, 1)
materials: PrincipledMaterial {
baseColor: "green"
}
castsShadows: false
receivesShadows: true
}
}
StaticRigidBody {
id: wall
position: Qt.vector3d(-4, 0, 0)
eulerRotation: Qt.vector3d(0, 90, 0)
collisionShapes: PlaneShape {
id: wallShape
enableDebugDraw: viewport.debugView
}
Model {
source: "#Rectangle"
scale: Qt.vector3d(0.3, 0.3, 1)
materials: PrincipledMaterial {
baseColor: "gray"
cullMode: Material.NoCulling
}
opacity: 0.3
}
}
DynamicRigidBody {
id: dynamicTorus
position: Qt.vector3d(0.5, 3.5, 1.0)
property bool inArea: false
mass: 10 // kg
scale: Qt.vector3d(0.01, 0.01, 0.01).times(scaleSlider.value)
Model {
source: "meshes/newTorus.mesh"
materials: PrincipledMaterial {
baseColor: "orange"
}
}
collisionShapes: ConvexMeshShape {
id: torusShape
source: "meshes/newConvexTorus.mesh"
enableDebugDraw: viewport.debugView
}
}
DynamicRigidBody {
id: kinematicTorus
kinematicPosition: Qt.vector3d(-0.5, 2, 0.5)
position: Qt.vector3d(-0.5, 2, 0.5)
property bool inArea: false
scale: Qt.vector3d(0.015, 0.015, 0.015).times(scaleSlider.value)
mass: 10 // kg
Model {
source: "meshes/newTorus.mesh"
materials: PrincipledMaterial {
baseColor: "lightGray"
metalness: 1.0
roughness: 0.5
}
}
collisionShapes: TriangleMeshShape {
id: torusShape2
source: "meshes/newTorus.mesh"
enableDebugDraw: viewport.debugView
}
isKinematic: true
}
DynamicRigidBody {
id: dynamicTorusConvexHullOfNonConvexMesh
position: Qt.vector3d(2, 3, 1.5)
property bool inArea: false
scale: Qt.vector3d(0.01, 0.01, 0.01)
mass: 10 // kg
Model {
source: "meshes/newTorus.mesh"
materials: PrincipledMaterial {
baseColor: "#c07030"
metalness: 1.0
roughness: 0.5
}
}
collisionShapes: ConvexMeshShape {
id: torusShape3
source: "meshes/newTorus.mesh"
enableDebugDraw: viewport.debugView
}
}
// x-axis reference
Model {
materials: PrincipledMaterial {
baseColor: "red"
roughness: 1
}
source: "#Cube"
scale: "0.002, 0.002, 0.002"
position: "-0.5, 2, 4"
}
Model {
materials: PrincipledMaterial {
baseColor: "green"
roughness: 1
}
source: "#Cube"
scale: "0.002, 0.002, 0.002"
position: "2, 2, 4"
}
Model {
materials: PrincipledMaterial {
baseColor: "blue"
roughness: 1
}
source: "#Cube"
scale: "0.002, 0.002, 0.002"
position: "4.5, 2, 4"
}
// z-axis
Model {
materials: PrincipledMaterial {
baseColor: "cyan"
roughness: 1
}
source: "#Cube"
scale: "0.002, 0.002, 0.002"
position: "-0.5, 3, -1"
}
DynamicRigidBody {
id: hfTest
position: Qt.vector3d(0, 2, 1.5)
kinematicPosition: Qt.vector3d(0, 2, 1.5)
isKinematic: true
Model {
id: hfModel
geometry: HeightFieldGeometry {
extents: Qt.vector3d(5, 2, 5).times(scaleSlider.value)
source: "maps/heightfield.png"
smoothShading: false
}
materials: PrincipledMaterial {
baseColor: "#ff77ff"
roughness: 0.3
}
opacity: 0.6
}
collisionShapes: HeightFieldShape {
id: hfShape
extents: Qt.vector3d(5, 2, 5).times(scaleSlider.value)
source: "maps/heightfield.png"
enableDebugDraw: viewport.debugView
}
}
SequentialAnimation {
running: animateCheckBox.checked && physicsWorld.running
loops: -1
NumberAnimation {
target: hfTest
property: "kinematicPosition.x"
duration: 2000
from: 0
to: -2
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: hfTest
property: "kinematicPosition.x"
duration: 2000
from: -2
to: 0
easing.type: Easing.InOutQuad
}
}
DynamicRigidBody {
id: triangleMeshTest
position: Qt.vector3d(0, 0.6, 0)
eulerRotation: Qt.vector3d(0, 180, 0)
kinematicPosition: Qt.vector3d(0, 0.6, 0)
kinematicEulerRotation: Qt.vector3d(0, 180, 0)
isKinematic: true
property bool inArea: false
scale: Qt.vector3d(0.015, 0.01, 0.015).times(scaleSlider.value)
Model {
id: testModel
source: "meshes/field.mesh"
materials: PrincipledMaterial {
baseColor: "#5070a0"
roughness: 0.3
}
opacity: 1
}
collisionShapes: TriangleMeshShape {
id: triShape
source: "meshes/field.mesh"
enableDebugDraw: viewport.debugView
}
}
SequentialAnimation {
running: animateCheckBox.checked && physicsWorld.running
loops: -1
NumberAnimation {
target: triangleMeshTest
property: "kinematicEulerRotation.y"
duration: 5000
from: 180
to: -180
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: triangleMeshTest
property: "kinematicEulerRotation.y"
duration: 5000
from: -180
to: 180
easing.type: Easing.InOutQuad
}
}
// DynamicRigidBody {
// id: table
// y: -50
// isKinematic: true
// Model {
// id: tableModel
// source: "#Cube"
// materials: PrincipledMaterial {
// baseColor: "gray"
// }
// scale: Qt.vector3d(4, 1, 4)
// }
// collisionShapes: BoxShape {
// id: tableShape
// extents: Qt.vector3d(200, 50, 200)
// }
// }
Texture {
id: qtLogoTexture
source: "qt_logo_rect.png"
scaleV: 0.5
positionV: 0.2
}
Component {
id: doughnutComponent
Node {
id: thisNode
function randomInRange(min, max) {
return Math.random() * (max - min) + min;
}
eulerRotation: Qt.vector3d(randomInRange(0, 360),
randomInRange(0, 360),
randomInRange(0, 360))
position: Qt.vector3d(randomInRange(-1.5, 1.5),
randomInRange( 4, 30),
randomInRange(-1.5, 1.5))
property real sf: randomInRange(0.2, 0.45)
property color baseCol: Qt.hsla(randomInRange(0, 1), randomInRange(0.3, 0.7), randomInRange(0.4, 0.7), 1.0)
property bool grabbed: false
property bool isSphere: randomInRange(0, 1) < 0.5
property SphereShape sphereShape : SphereShape {
diameter: sf
enableDebugDraw: viewport.debugView
}
property ConvexMeshShape torusShape : ConvexMeshShape {
source: "meshes/newConvexTorus.mesh"
enableDebugDraw: viewport.debugView
scale: Qt.vector3d(sf, sf, sf).times(0.01)
}
DynamicRigidBody {
id: thisBody
mass: 1 //heavy donut
isKinematic: thisNode.grabbed
Model {
id: thisModel
source: isSphere ? "#Sphere" : "meshes/newTorus.mesh"
materials: PrincipledMaterial {
metalness: 1.0
roughness: randomInRange(0.3, 0.6)
baseColor: thisNode.grabbed ? "white" : baseCol
emissiveMap: qtLogoTexture
emissiveFactor: "0.2, 0.2, 0.2"
heightAmount: 0.5
}
scale: Qt.vector3d(sf, sf, sf).times(0.01)
pickable: true
property Node proxyNode: thisNode
}
collisionShapes: isSphere ? sphereShape : torusShape
}
}
}
Repeater3D {
id: rep
model: 400
delegate: doughnutComponent
}
} // scene
View3D {
id: viewport
width: radioSideBySide.checked ? parent.width/2 : parent.width
height: parent.height
visible: !radioDebug.checked
importScene: scene
environment: SceneEnvironment {
clearColor: "#d6dbdf"
backgroundMode: SceneEnvironment.Color
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.High
}
focus: true
property bool debugView: false
}
View3D {
id: viewport1
width: radioSideBySide.checked ? parent.width/2 : parent.width
height: parent.height
x: radioSideBySide.checked ? parent.width/2 : 0
visible: !radioScene.checked
environment: SceneEnvironment {
clearColor: "black"
backgroundMode: SceneEnvironment.Color
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.High
}
PerspectiveCamera {
id: camera2
position: camera1.position
eulerRotation: camera1.eulerRotation
clipFar: camera1.clipFar
clipNear: camera1.clipNear
}
}
WasdController {
keysEnabled: true
controlledObject: camera1
speed: 0.02
shiftSpeed: 0.2
Keys.onPressed: (event)=> {
if (keysEnabled) handleKeyPress(event);
if (event.key === Qt.Key_Space) {
physicsWorld.running = !physicsWorld.running
} else if (event.key === Qt.Key_G) {
viewport.debugView = !viewport.debugView
} else if (event.key === Qt.Key_H) {
physicsWorld.forceDebugDraw = !physicsWorld.forceDebugDraw
} else if (event.key === Qt.Key_T) {
tableShape.extents = "150, 100, 150"
tableModel.scale = "3, 2, 3"
}
}
Keys.onReleased: (event)=> { if (keysEnabled) handleKeyRelease(event) }
}
MouseArea {
anchors.fill: viewport
acceptedButtons: Qt.RightButton
property Node grabbedNode: null
onPressed: (mouse) =>
{
var result = viewport.pick(mouse.x, mouse.y);
if (result.objectHit) {
var pickedNode = result.objectHit.proxyNode;
console.log("PRESSED:", pickedNode)
pickedNode.grabbed = true
//pickedNode.y += 100
grabbedNode = pickedNode
}
}
onReleased:
{
if (grabbedNode) {
grabbedNode.grabbed = false
grabbedNode = null
}
}
}
ColumnLayout {
ColumnLayout {
RadioButton {
id: radioScene
checked: true
text: qsTr("Scene view")
}
RadioButton {
id: radioSideBySide
text: qsTr("Side by side")
}
RadioButton {
id: radioDebug
text: qsTr("Debug view")
}
}
Label {
text: "Scale: " + scaleSlider.value
}
Slider {
id: scaleSlider
focusPolicy: Qt.NoFocus
from: 0.5
to: 1.5
value: 1
stepSize: 0.1
}
CheckBox {
id: animateCheckBox
checked: false
text: qsTr("Animate")
}
}
}