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

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);

            }
        }

    }
}

相关文章:

  • TCP/IP原理详细解析
  • JavaScript 中 this 绑定丢失的陷阱:从 “is not a function“ 错误谈起
  • 处理动态分页:自动翻页与增量数据抓取策略-数据议事厅
  • 网络tcp协议设置,网络tcp协议设置不了
  • Linux笔记之通配符和正则表达式的区别
  • 领星ERP-FBA数据无缝对接用友U8系统的技术实践
  • 目标检测YOLO实战应用案例100讲-基于激光雷达点云的交通场景 三维车辆目标检测与跟踪算法研究(续)
  • windows本地AI知识库解决方案( pageassist + nomic + deepseek-r1:1.5b)
  • 改变 input 自动填充的背景颜色
  • Midjourney绘图参数详解:从基础到高级的全面指南
  • 卫星通信+5G+AI:遨游构建空天地一体化智慧应急通信网络
  • 第六章:响应式设计:让网页「见风使舵」
  • ReentrantLock源码和AQS
  • 【Vela学习】存储系统
  • 用android studio模拟器,模拟安卓手机访问网页,使用Chrome 开发者工具查看控制台信息
  • 全面解析Tomcat:简介、安装与配置指南
  • CentOS7离线部署安装Dify
  • Linux 提权
  • 工业节能新利器:第二类吸收式热泵与MVR热泵深度剖析
  • 【蓝桥】帮派弟位-DFS遍历树
  • 自已怎样网站/网络营销创意案例
  • 江都建设总部网站/武汉百度
  • 网站建设先做前台还是后台/学seo需要多久
  • 阿里巴巴国际站可以做网站吗/保定seo推广公司
  • 网站备案号被注销什么原因/广州seo网站管理
  • 网站开发属于哪个税收分类/谷歌海外广告投放推广