Search code examples
qtqmlqt3d

QML 3D - change size (expand/reduce) of model rendered in UI to fit in the current window


I am rendering a 3D model using Mesh by reading from a .obj file, and I am trying to change its size dynamically to take the parent window's dimensions. Is there a way to resize the object? Currently when I run the app the model takes roughly half the height and one-third of the width of the main-window, and I am not sure where it picks it up from.

I have tried to use viewportRect in ForwardRenderer but that did not change the display. I was also trying to figure out if zooming with the camera would be possible, but from what I saw in the docs the zoom scale factor needs hardcoded integer values and again I need it to be dynamic.

The current display is like this -

screenshot

Here is my code -

main.qml

Rectangle {
    id: rootWindow
    color: "black"

    Visualizer {}
}

Visualizer.qml

import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Extras 2.12
import Qt3D.Input 2.12
import QtQuick.Scene3D 2.12
import QtQuick 2.12 as QQ2

Scene3D {
    id: scene3d
    anchors.fill: parent
    focus: true
    aspects: ["input", "logic"]
    cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
    Entity {
        id: sceneRoot

        Camera {
            id: camera
            projectionType: CameraLens.PerspectiveProjection
            fieldOfView: 45
            nearPlane: 0.1
            farPlane: 1000.0
            position: Qt.vector3d(0.0, 0.0, 40.0)
            upVector: Qt.vector3d(0.0, 1.0, 0.0)
            viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
        }

        FirstPersonCameraController {
            camera: camera
        }

        components: [
            RenderSettings {
                activeFrameGraph: ForwardRenderer {
                    camera: camera
                    clearColor: "transparent"
                    Viewport {
                        id: viewport
                        normalizedRect: Qt.rect(0, 0, 1, 1)
                    }
                }
            },
            InputSettings {
                id: inputSettings
            }
        ]

        PhongMaterial {
            id: material
        }

        Mesh {
            id: sphereMesh
//             source: "images/face3d/face_bse_mesh.obj"
            source: "images/robo-obj-pose4/source/d2f0cff60afc40f5afe79156ec7db657.obj"
        }

        Transform {
            id: modelTransform
            property real userAngle: 0.0
            matrix: {
                var m = Qt.matrix4x4()
                m.rotate(userAngle, Qt.vector3d(0, 1, 0))
//                 m.translate(Qt.vector3d(20, 0, 0))
                return m
            }
        }

        QQ2.NumberAnimation {
            target: modelTransform
            property: "userAngle"
            duration: 10000
            from: 0
            to: 360

            loops: QQ2.Animation.Infinite
            running: true
        }

        Entity {
            id: sphereEntity
            components: [sphereMesh, material, modelTransform]
        }

        OrbitCameraController{
            id: orbitCamera
            camera: camera
        }
    }
}

Solution

  • So after a lot of asking around I have found the solution to this. It's a fairly simple enough trick.

    You just need to add the following code in the Mesh, and that takes care of resizing the model in it's containing window.

    Mesh {
        ----
        onStatusChanged: {
            if(status == Mesh.Ready)
                camera.viewAll()
        }
    }
    

    Sometimes while rendering the model its edges tend to go beyond the boundaries of the parent window. Adding some anchors.margins in the root Scene3D usually takes care of that.