Qt Quick 3D - Principled Material Example

/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/
import QtQuick import QtQuick3D Item { id: root required property Node origin required property Camera camera property real speed: 1 property real xSpeed: 0.1 property real ySpeed: 0.1 property bool xInvert: false property bool yInvert: true property bool mouseEnabled: true readonly property bool inputsNeedProcessing: status.useMouse || status.isPanning implicitWidth: parent.width implicitHeight: parent.height Connections { target: camera function onZChanged() { // Adjust near/far values based on distance let distance = camera.z if (distance < 1) { camera.clipNear = 0.01 camera.clipFar = 100 } else if (distance < 100) { camera.clipNear = 0.1 camera.clipFar = 1000 } else { camera.clipNear = 1 camera.clipFar = 10000 } } } DragHandler { id: dragHandler target: null enabled: mouseEnabled acceptedModifiers: Qt.NoModifier onCentroidChanged: { mouseMoved(Qt.vector2d(centroid.position.x, centroid.position.y), false); } onActiveChanged: { if (active) mousePressed(Qt.vector2d(centroid.position.x, centroid.position.y)); else mouseReleased(Qt.vector2d(centroid.position.x, centroid.position.y)); } } DragHandler { id: ctrlDragHandler target: null enabled: mouseEnabled acceptedModifiers: Qt.ControlModifier onCentroidChanged: { panEvent(Qt.vector2d(centroid.position.x, centroid.position.y)); } onActiveChanged: { if (active) startPan(Qt.vector2d(centroid.position.x, centroid.position.y)); else endPan(); } } PinchHandler { id: pinchHandler target: null enabled: mouseEnabled property real distance: 0.0 onCentroidChanged: { panEvent(Qt.vector2d(centroid.position.x, centroid.position.y)) } onActiveChanged: { if (active) { startPan(Qt.vector2d(centroid.position.x, centroid.position.y)) distance = root.camera.z } else { endPan() distance = 0.0 } } onScaleChanged: { camera.z = distance * (1 / scale) } } TapHandler { onTapped: root.forceActiveFocus() } WheelHandler { id: wheelHandler orientation: Qt.Vertical target: null enabled: mouseEnabled onWheel: event => { let delta = -event.angleDelta.y * 0.01; camera.z += camera.z * 0.1 * delta } } function mousePressed(newPos) { root.forceActiveFocus() status.currentPos = newPos status.lastPos = newPos status.useMouse = true; } function mouseReleased(newPos) { status.useMouse = false; } function mouseMoved(newPos: vector2d) { status.currentPos = newPos; } function startPan(pos: vector2d) { status.isPanning = true; status.currentPanPos = pos; status.lastPanPos = pos; } function endPan() { status.isPanning = false; } function panEvent(newPos: vector2d) { status.currentPanPos = newPos; } function processInputs() { if (root.inputsNeedProcessing) status.processInput(); } Timer { id: updateTimer interval: 16 repeat: true running: root.inputsNeedProcessing onTriggered: { processInputs(); } } QtObject { id: status property bool useMouse: false property bool isPanning: false property vector2d lastPos: Qt.vector2d(0, 0) property vector2d lastPanPos: Qt.vector2d(0, 0) property vector2d currentPos: Qt.vector2d(0, 0) property vector2d currentPanPos: Qt.vector2d(0, 0) function negate(vector) { return Qt.vector3d(-vector.x, -vector.y, -vector.z) } function processInput() { if (useMouse) { // Get the delta var rotationVector = origin.eulerRotation; var delta = Qt.vector2d(lastPos.x - currentPos.x, lastPos.y - currentPos.y); // rotate x var rotateX = delta.x * xSpeed if (xInvert) rotateX = -rotateX; rotationVector.y += rotateX; // rotate y var rotateY = delta.y * -ySpeed if (yInvert) rotateY = -rotateY; rotationVector.x += rotateY; origin.setEulerRotation(rotationVector); lastPos = currentPos; } if (isPanning) { let delta = currentPanPos.minus(lastPanPos); delta.x = -delta.x delta.x = (delta.x / root.width) * camera.z delta.y = (delta.y / root.height) * camera.z let velocity = Qt.vector3d(0, 0, 0) // X Movement let xDirection = origin.right velocity = velocity.plus(Qt.vector3d(xDirection.x * delta.x, xDirection.y * delta.x, xDirection.z * delta.x)); // Y Movement let yDirection = origin.up velocity = velocity.plus(Qt.vector3d(yDirection.x * delta.y, yDirection.y * delta.y, yDirection.z * delta.y)); origin.position = origin.position.plus(velocity) lastPanPos = currentPanPos } } } }