是否可以使用 QML Quick3D View3D 动态加载 .OBJ 文件?

问题描述

我在 QML (Qt 5.15/6.0.0) 中加载和显示 3D 模型 (.obj) 时遇到问题。我尝试了以下 3 种技术,但它们似乎都有独特的问题。

  1. 在我自己的 .obj 加载器中使用 QQuickItem 和 OpenGL。这可以工作,但我想利用 Qt 在质量渲染、简化模型加载和摆脱 OpenGL 特定绘制代码的潜力方面提供的强大功能

  2. 来自 Qt3D 模块的 Scene3D。这有效,但它在退出时崩溃。我已经尝试了建议的解决方法,但它们都未能防止崩溃,或者如果我确实防止了崩溃,那么我的模型将无法正确加载或显示

  3. 一个 来自 Quick 3D 的 View3D。这似乎是未来的最佳选择,但缺点似乎是我需要使用 balsam 预处理 obj 文件,以便将其转换为 qt .mesh 格式。我宁愿避免这一步,因为我希望用户能够加载他们自己的模型(obj、step 等)

需要能够设置网格和纹理源。使用带有网格的 Scene3D 可以做到这一点,但我没有看到使用带有模型对象的 View3D 的相同选项。

理想情况下,我可以使用 qml Qt3D.Render::Mesh 项或 Qt3DRender::QMesh 动态加载对象文件,然后使用该网格在 View3D 中进行渲染。或者使用自定义 QQuick3DGeometry 加载模型并可以添加为 QtQuick3D::Mode.geometry。

我是否在这里遗漏了什么,或者我是否试图混合两个不兼容的模块:Qt3D 和 Quick3D?模型可以动态加载到 View3D 中而不将其转换为 .mesh 文件吗?

解决方法

使用SceneLoader

此代码是您可以在 Scene3d 中导入 .obj 文件的示例:

import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Scene3D 2.0
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
import QtQuick.Controls.Material 2.12

ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("3D Viewer")

header: ToolBar
{
    Material.theme: Material.Dark

    ToolButton
    {
        text: "Open 3D Model"
        onPressed:
        {
            fileDialog.open()
        }
    }
}

FileDialog
{
    id: fileDialog
    onAccepted:
    {
        sceneLoader.source = fileDialog.fileUrl
        print(fileDialog.fileUrl)
        mainScene3d.forceActiveFocus()


    }
}

Scene3D
{
    id:mainScene3d
    anchors.fill: parent
    focus: true
    hoverEnabled: true

    aspects: ["input","logic","render"]
    cameraAspectRatioMode: Scene3D.AutomaticAspectRatio

    Entity
    {
        id: sceneRoot

        Camera
        {
            id: camera
            projectionType: CameraLens.PerspectiveProjection
            fieldOfView: 30
            aspectRatio: 16/9
            nearPlane : 0.1
            farPlane : 100.0
            position: Qt.vector3d( 10.0,0.0,10.0 )
            upVector: Qt.vector3d( 0.0,1.0,0.0 )
            viewCenter: Qt.vector3d( 0.0,0.0 )
        }

        OrbitCameraController
        {
            camera: camera
        }

        components: [
            RenderSettings
            {
                activeFrameGraph: ForwardRenderer
                {
                    clearColor:"#333333"
                    camera: camera
                }
            },InputSettings
            {
            }
        ]

        Entity
        {
            id: monkeyEntity
            components: [
                SceneLoader
                {
                    id: sceneLoader
                }
            ]
        }
    }
}
}

Output screenshot