目录

QQuick3D-Camera的介绍

QQuick3D-Camera的介绍

QQuick3D-Camera的介绍

Camera的概述

  1. Camera类继承于 Node;Camera定义了怎样将一个3D场景(Scene)投影到2D的表面上;一个场景至少需要一个Camera来可视化其内容。

  2. Camera 可以像场景中任何节点一样,被定位和旋转;Camera节点的位置和方向决定了Camera在场景中的位置及其朝向;Camera的默认方向是,其前向矢量指向负Z轴,其上向矢量指向正Y轴。

  3. QQuick3D提供以下几种类型相机:

    ** PerspectiveCamera**:透视投影相机,具有近大远小特点

    OrthographicCamera :正交投影相机,提供了一种平截头体线条平行的相机,使物体的感知比例不受其与相机距离的影响。这种相机的典型用例是CAD(计算机辅助设计)应用程序和制图

    FrustumCamera

    CustomCamera
    自定义相机,由用户自定义 投影矩阵
  4. 属性 frustumCullingEnabled : bool :当此属性为真时,相机平截头体之外的对象将被剔除,这意味着它们不会传递给渲染器。默认情况下,此属性设置为false。对于所有或大多数对象都在相机平截头体内的场景,平截头体剔除是一种不必要的性能开销。但对于大部分位于相机视野之外的复杂场景,启用平截头体剔除可能会提高性能

  5. 属性
    lookAtNode : Node
    Node 非空时,当lookAtNode 观察节点位置发生变化时,相机的位置会跟随发生变化;默认值为null
  6. 方法 vector3d lookAt(vector3d scenePos) :设置摄影机的旋转值,使其指向scenePos

  7. 方法 vector3d lookAt(QtQuick3D::Node node) :设置摄影机的旋转值,使其指向节点

  8. 方法 vector3d mapFromViewport(vector3d viewportPos) :将viewportPos从视口空间(viewPort Space)(2D)转换为全局场景空间(3D)。viewportPos的x和y值必须归一化,视口的左上角为[0,0],右下角为[1,1]。z值被解释为距截头体近剪裁平面的距离(clipNear)。如果viewportPos无法成功映射到场景中的某个位置,则返回[0,0,0]的位置。

  9. 方法 vector3d mapToViewport(vector3d scenePos) :将scenePos从全局场景空间(3D)转换到视口空间(2D)。返回的位置被归一化,视口的左上角为[0,0],右下角为[1,1]。返回的z值将包含从截头体的近剪裁平面(clipANear)到场景坐标中scenePos的距离。如果距离为负,则该点位于相机后面。如果scenePos无法成功映射到视口中的某个位置,则返回[0,0,0]的位置

Camera的实例代码

注意 代码中 “teapot.mesh” 这个网格,Qt 官方实例中有提供。

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick3D


//摄像机Demo
Item {
    id: root

    //场景需要 Model(mesh + Material),  Light, Camera, 3个元素
    Node{
        id: rootSceneNode                   //3D场景的根节点

        //平行光: 光源从无线远地方发射,类似于生活中太阳;平行光具有无限的范围,不会衰减;如果启用castsShadow,阴影将平行于灯光方向;
        //平行光实际上没有位置,因此移动它没有任何效果。光将始终沿光的Z轴方向发射。沿X或Y轴旋转灯光将改变发光方向。
        DirectionalLight {
            ambientColor: Qt.rgba(0.5, 0.5, 0.5, 1.0)
            brightness: 1.0
            eulerRotation.x: -25
        }

        Model {
            //Model 需要网格 + 材质
            source: "qrc:/qt/qml/text/3DDemo/teapot.mesh"
            y: -100
            scale: Qt.vector3d(50, 50, 50)
            materials: [
                PrincipledMaterial {
                    baseColor: "#41cd52"
                    metalness: 0.0
                    roughness: 0.1
                    opacity: 1.0
                }
            ]

            //沿着Y轴旋转,在xz所在平台旋转
            // PropertyAnimation on eulerRotation.y {
            //     loops: Animation.Infinite
            //     duration: 5000
            //     to: 0
            //     from: -360
            // }
        }

        //
        Node {
            //使用节点给摄像机设置动画。
            //Camera 做为Node 的子节点,可以通过Node节点的属性来定义相机的位置、旋转 之类属性;也会继承父节点的变换
            //透视投影:主要涉及 近平面(clipNear),远平面(clipFar),视野角(fiedOfView)
            id: idCamPNode
            PerspectiveCamera {
                id: cameraPerspectiveOne
                z: 600

                // onSceneRotationChanged: {
                //     console.log("onSceneRotationChanged = ",cameraPerspectiveOne.sceneRotation);
                // }

                // onScenePositionChanged: {
                //     console.log("onScenePositionChanged = ",cameraPerspectiveOne.scenePosition);
                // }

                // onSceneTransformChanged: {
                //     console.log("onSceneTransformChanged");
                // }
            }

            //
            PropertyAnimation on eulerRotation.y {
                loops: Animation.Infinite
                duration: 5000
                to: -360
                from: 0
            }

        }
    }


    View3D{
        id:idView3D
        anchors.fill: parent
        importScene: rootSceneNode
        camera: cameraPerspectiveOne


        MouseArea{
            anchors.fill: parent
            onClicked:(mouse)=> {
              var viewPos = Qt.vector3d(mouse.x /parent.width,mouse.y/parent.height,0);

            //同样的viewPos 因为Camera的位置在变化,造成映射到scene中值不一致
              var scenePos = cameraPerspectiveOne.mapFromViewport(viewPos);
              console.log("scenePos = ",scenePos, " viewPos = ",mouse.x,mouse.y);

            }
        }

    }
}