当前位置: 首页 > article >正文

qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记

qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记

文章目录

  • qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记
    • 1.例程运行效果
    • 2.例程缩略图
    • 3.项目文件列表
    • 4.main.qml
    • 5.main.cpp
    • 6.CMakeLists.txt

1.例程运行效果

在这里插入图片描述

运行该项目需要自己准备一个模型文件

2.例程缩略图

在这里插入图片描述

3.项目文件列表

runtimeloader/
├── CMakeLists.txt
├── main.cpp
├── main.qml
├── qml.qrc
└── runtimeloader.pro

1 directory, 5 files

4.main.qml

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts

import Qt.labs.platform
import QtCore

import QtQuick3D
import QtQuick3D.Helpers
import QtQuick3D.AssetUtils

// 创建一个窗口根节点,设置窗口大小和显示状态
Window {
    id: windowRoot
    visible: true
    width: 1280
    height: 720

    property url importUrl; // 用于导入模型的URL

    //! [base scene] 基础场景
    View3D {
        id: view3D
        anchors.fill: parent // 填充父窗口
        environment: SceneEnvironment {
            id: env
            backgroundMode: SceneEnvironment.SkyBox // 背景模式为天空盒
            lightProbe: Texture {
                textureData: ProceduralSkyTextureData{} // 使用程序化天空纹理
            }
            InfiniteGrid {
                visible: helper.gridEnabled // 是否显示网格
                gridInterval: helper.gridInterval // 网格间隔
            }
        }

        camera: helper.orbitControllerEnabled ? orbitCamera : wasdCamera // 根据控制器选择相机

        // 设置方向光源
        DirectionalLight {
            eulerRotation.x: -35
            eulerRotation.y: -90
            castsShadow: true // 启用阴影
        }

        Node {
            id: orbitCameraNode
            PerspectiveCamera {
                id: orbitCamera // 轨道相机
            }
        }

        // 第一人称相机(WASD控制)
        PerspectiveCamera {
            id: wasdCamera
            onPositionChanged: {
                // 更新相机的近远裁剪面
                let distance = position.length()
                if (distance < 1) {
                    clipNear = 0.01
                    clipFar = 100
                } else if (distance < 100) {
                    clipNear = 0.1
                    clipFar = 1000
                } else {
                    clipNear = 1
                    clipFar = 10000
                }
            }
        }

    //! [base scene]
        // 重置视图的函数
        function resetView() {
            if (importNode.status === RuntimeLoader.Success) {
                helper.resetController()
            }
        }

        //! [instancing] 实例化
        RandomInstancing {
            id: instancing
            instanceCount: 30 // 设置实例数量
            position: InstanceRange {
                property alias boundsDiameter: helper.boundsDiameter
                from: Qt.vector3d(-3*boundsDiameter, -3*boundsDiameter, -3*boundsDiameter); // 位置范围
                to: Qt.vector3d(3*boundsDiameter, 3*boundsDiameter, 3*boundsDiameter)
            }
            color: InstanceRange { from: "black"; to: "white" } // 颜色范围
        }
        //! [instancing]

        QtObject {
            id: helper
            property real boundsDiameter: 0 // 场景边界的直径
            property vector3d boundsCenter // 场景中心
            property vector3d boundsSize // 场景大小
            property bool orbitControllerEnabled: true // 是否启用轨道控制器
            property bool gridEnabled: gridButton.checked // 是否启用网格
            property real cameraDistance: orbitControllerEnabled ? orbitCamera.z : wasdCamera.position.length() // 相机与中心的距离
            property real gridInterval: Math.pow(10, Math.round(Math.log10(cameraDistance)) - 1) // 网格间隔计算

            // 更新场景边界信息
            function updateBounds(bounds) {
                boundsSize = Qt.vector3d(bounds.maximum.x - bounds.minimum.x,
                                         bounds.maximum.y - bounds.minimum.y,
                                         bounds.maximum.z - bounds.minimum.z)
                boundsDiameter = Math.max(boundsSize.x, boundsSize.y, boundsSize.z)
                boundsCenter = Qt.vector3d((bounds.maximum.x + bounds.minimum.x) / 2,
                                           (bounds.maximum.y + bounds.minimum.y) / 2,
                                           (bounds.maximum.z + bounds.minimum.z) / 2 )

                wasdController.speed = boundsDiameter / 1000.0 // 更新控制器速度
                wasdController.shiftSpeed = 3 * wasdController.speed
                wasdCamera.clipNear = boundsDiameter / 100
                wasdCamera.clipFar = boundsDiameter * 10
                view3D.resetView() // 重置视图
            }

            // 重置控制器
            function resetController() {
                orbitCameraNode.eulerRotation = Qt.vector3d(0, 0, 0)
                orbitCameraNode.position = boundsCenter
                orbitCamera.position = Qt.vector3d(0, 0, 2 * helper.boundsDiameter)
                orbitCamera.eulerRotation = Qt.vector3d(0, 0, 0)
                orbitControllerEnabled = true
            }

            // 切换控制器
            function switchController(useOrbitController) {
                if (useOrbitController) {
                    let wasdOffset = wasdCamera.position.minus(boundsCenter)
                    let wasdDistance = wasdOffset.length()
                    let wasdDistanceInPlane = Qt.vector3d(wasdOffset.x, 0, wasdOffset.z).length()
                    let yAngle = Math.atan2(wasdOffset.x, wasdOffset.z) * 180 / Math.PI
                    let xAngle = -Math.atan2(wasdOffset.y, wasdDistanceInPlane) * 180 / Math.PI

                    orbitCameraNode.position = boundsCenter
                    orbitCameraNode.eulerRotation = Qt.vector3d(xAngle, yAngle, 0)
                    orbitCamera.position = Qt.vector3d(0, 0, wasdDistance)

                    orbitCamera.eulerRotation = Qt.vector3d(0, 0, 0)
                } else {
                    wasdCamera.position = orbitCamera.scenePosition
                    wasdCamera.rotation = orbitCamera.sceneRotation
                    wasdController.focus = true
                }
                orbitControllerEnabled = useOrbitController
            }
        }

        //! [runtimeloader] 运行时加载器
        RuntimeLoader {
            id: importNode
            source: windowRoot.importUrl // 导入模型的URL
            instancing: instancingButton.checked ? instancing : null // 实例化开关
            onBoundsChanged: helper.updateBounds(bounds) // 更新场景边界
        }
        //! [runtimeloader]

        //! [bounds] 场景边界
        Model {
            parent: importNode
            source: "#Cube" // 默认使用立方体模型
            materials: PrincipledMaterial {
                baseColor: "red" // 设置基础颜色为红色
            }
            opacity: 0.2 // 设置模型透明度
            visible: visualizeButton.checked && importNode.status === RuntimeLoader.Success // 根据条件显示模型
            position: helper.boundsCenter
            scale: Qt.vector3d(helper.boundsSize.x / 100,
                               helper.boundsSize.y / 100,
                               helper.boundsSize.z / 100)
        }
        //! [bounds]

        //! [status report] 状态报告
        Rectangle {
            id: messageBox
            visible: importNode.status !== RuntimeLoader.Success // 如果导入失败,显示错误消息
            color: "red"
            width: parent.width * 0.8
            height: parent.height * 0.8
            anchors.centerIn: parent
            radius: Math.min(width, height) / 10
            opacity: 0.6
            Text {
                anchors.fill: parent
                font.pixelSize: 36
                text: "Status: " + importNode.errorString + "\nPress \"Import...\" to import a model" // 显示错误信息
                color: "white"
                wrapMode: Text.Wrap
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
        }
        //! [status report]
    }

    //! [camera control] 相机控制
    OrbitCameraController {
        id: orbitController
        origin: orbitCameraNode
        camera: orbitCamera
        enabled: helper.orbitControllerEnabled // 根据状态启用或禁用轨道控制器
    }
    WasdController {
        id: wasdController
        controlledObject: wasdCamera
        enabled: !helper.orbitControllerEnabled // 根据状态启用或禁用WASD控制器
    }
    //! [camera control]

    // 界面控制面板
    Pane {
        width: parent.width
        contentHeight: controlsLayout.implicitHeight
        RowLayout {
            id: controlsLayout
            Button {
                id: importButton
                text: "Import..."
                onClicked: fileDialog.open() // 打开文件对话框
                focusPolicy: Qt.NoFocus
            }
            Button {
                id: resetButton
                text: "Reset view"
                onClicked: view3D.resetView() // 重置视图
                focusPolicy: Qt.NoFocus
            }
            Button {
                id: visualizeButton
                checkable: true
                text: "Visualize bounds" // 显示场景边界
                focusPolicy: Qt.NoFocus
            }
            Button {
                id: instancingButton
                checkable: true
                text: "Instancing" // 开启实例化
                focusPolicy: Qt.NoFocus
            }
            Button {
                id: gridButton
                text: "Show grid" // 显示网格
                focusPolicy: Qt.NoFocus
                checkable: true
                checked: false
            }
            Button {
                id: controllerButton
                text: helper.orbitControllerEnabled ? "Orbit" : "WASD" // 切换控制器
                onClicked: helper.switchController(!helper.orbitControllerEnabled)
                focusPolicy: Qt.NoFocus
            }
            RowLayout {
                Label {
                    text: "Material Override"
                }
                ComboBox {
                    id: materialOverrideComboBox
                    textRole: "text"
                    valueRole: "value"
                    implicitContentWidthPolicy: ComboBox.WidestText
                    onActivated: env.debugSettings.materialOverride = currentValue // 选择材质覆盖
                    model: [
                        { value: DebugSettings.None, text: "None"},
                        { value: DebugSettings.BaseColor, text: "Base Color"},
                        { value: DebugSettings.Roughness, text: "Roughness"},
                        { value: DebugSettings.Metalness, text: "Metalness"},
                        { value: DebugSettings.Diffuse, text: "Diffuse"},
                        { value: DebugSettings.Specular, text: "Specular"},
                        { value: DebugSettings.ShadowOcclusion, text: "Shadow Occlusion"},
                        { value: DebugSettings.Emission, text: "Emission"},
                        { value: DebugSettings.AmbientOcclusion, text: "Ambient Occlusion"},
                        { value: DebugSettings.Normals, text: "Normals"},
                        { value: DebugSettings.Tangents, text: "Tangents"},
                        { value: DebugSettings.Binormals, text: "Binormals"},
                        { value: DebugSettings.F0, text: "F0"}
                    ]
                }
            }
            CheckBox {
                text: "Wireframe" // 启用或禁用线框模式
                checked: env.debugSettings.wireframeEnabled
                onCheckedChanged: {
                    env.debugSettings.wireframeEnabled = checked
                }
            }
        }
    }

    // 文件对话框,允许用户选择glTF模型文件
    FileDialog {
        id: fileDialog
        nameFilters: ["glTF files (*.gltf *.glb)", "All files (*)"]
        onAccepted: importUrl = file // 选择文件后导入
        Settings {
            id: fileDialogSettings
            category: "QtQuick3D.Examples.RuntimeLoader"
            property alias folder: fileDialog.folder
        }
    }

    // 调试视图切换按钮
    Item {
        width: debugViewToggleText.implicitWidth
        height: debugViewToggleText.implicitHeight
        anchors.right: parent.right
        Label {
            id: debugViewToggleText
            text: "Click here " + (dbg.visible ? "to hide DebugView" : "for DebugView")
            anchors.right: parent.right
            anchors.top: parent.top
        }
        MouseArea {
            anchors.fill: parent
            onClicked: dbg.visible = !dbg.visible // 切换调试视图可见性
            DebugView {
                y: debugViewToggleText.height * 2
                anchors.right: parent.right
                source: view3D
                id: dbg
                visible: false
            }
        }
    }
}

5.main.cpp

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifdef HAS_MODULE_QT_WIDGETS
# include <QApplication>
#endif
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QtQuick3D/qquick3d.h>

int main(int argc, char *argv[])
{
#ifdef HAS_MODULE_QT_WIDGETS
    QApplication app(argc, argv);
#else
    QGuiApplication app(argc, argv);
#endif
    app.setOrganizationName("The Qt Company");
    app.setOrganizationDomain("qt.io");
    app.setApplicationName("Runtime Asset Loading Example");

    const auto importUrl = argc > 1 ? QUrl::fromLocalFile(argv[1]) : QUrl{};
    if (importUrl.isValid())
        qDebug() << "Importing" << importUrl;

    QSurfaceFormat::setDefaultFormat(QQuick3D::idealSurfaceFormat(4));

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    engine.load(url);

    if (engine.rootObjects().isEmpty()) {
        qWarning() << "Could not find root object in" << url;
        return -1;
    }

    QObject *topLevel = engine.rootObjects().value(0);
    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);

    if (window)
        window->setProperty("importUrl", importUrl);

    return app.exec();
}

6.CMakeLists.txt

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

cmake_minimum_required(VERSION 3.16)
project(runtimeloader LANGUAGES CXX)

set(CMAKE_AUTOMOC ON)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick Quick3D Widgets)

qt_add_executable(runtimeloader
    main.cpp
)

set_target_properties(runtimeloader PROPERTIES
    WIN32_EXECUTABLE TRUE
    MACOSX_BUNDLE TRUE
)

target_link_libraries(runtimeloader PUBLIC
    Qt::Core
    Qt::Gui
    Qt::Quick
    Qt::Quick3D
)

if(TARGET Qt::Widgets)
    target_compile_definitions(runtimeloader PUBLIC
        HAS_MODULE_QT_WIDGETS
    )

    target_link_libraries(runtimeloader PUBLIC
        Qt::Widgets
    )
endif()

qt_add_qml_module(runtimeloader
    URI Example
    VERSION 1.0
    QML_FILES main.qml
    NO_RESOURCE_TARGET_PATH
)

install(TARGETS runtimeloader
    BUNDLE  DESTINATION .
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

qt_generate_deploy_qml_app_script(
    TARGET runtimeloader
    OUTPUT_SCRIPT deploy_script
    MACOS_BUNDLE_POST_BUILD
    NO_UNSUPPORTED_PLATFORM_ERROR
    DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
install(SCRIPT ${deploy_script})

http://www.kler.cn/a/527444.html

相关文章:

  • 动态规划每日一练(四)
  • Xposed-Hook
  • IO进程线程复习
  • 数据结构 前缀中缀后缀
  • 【设计模式-行为型】备忘录模式
  • AI常见的算法和例子
  • 合并2个排序的链表
  • DeepSeek是什么,最近到底经历了什么?它能干什么?
  • 注册谷歌账号
  • Linux:多线程[2] 线程控制
  • 10.5 LangChain Model I/O 深度解析:如何用标准化接口打通大模型开发的“任督二脉”?
  • 2 MapReduce
  • 【思维导图】并发编程
  • 答疑解惑:如何监控EMC unity存储系统磁盘重构rebuild进度
  • 实战:利用百度站长平台加速网站收录
  • Agent 高频知识汇总:查漏补缺参考大全
  • 大模型本地化部署(Ollama + Open-WebUI)
  • 《TCP 网络编程实战:开发流程、缓冲区原理、三次握手与四次挥手》
  • 【4Day创客实践入门教程】Day1 工具箱构建——开发环境的构建
  • 数据包的发送流程
  • Linux命令汇总
  • 力扣017_最小覆盖字串题解----C++
  • AI学习指南HuggingFace篇-Datasets 库入门
  • [EAI-028] Diffusion-VLA,能够进行多模态推理和机器人动作预测的VLA模型
  • 研发的护城河到底是什么?
  • 双指针c++