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

【Overload游戏引擎细节分析】鼠标键盘控制摄像机原理

在上文中分析了摄像机类的实现,在计算投影视图矩阵时需要给摄像机输入其位置及转动四元数。这两个量一般通过鼠标键盘来控制,从而达到控制摄像机的目的。本文分析一下其控制原理。

Overload的摄像机控制实现在类CameraController中,其有三个个方法HandleCameraPanning、HandleCameraFPSMouse、HandleCameraOrbit、HandleCameraZoom是鼠标控制摄像机的平移、绕自身转动、绕特定点转动、缩放。还有一个方法,HandleCameraFPSKeyboard是键盘控制摄像机。其头文件如下,已删除本文不关注的代码及字段。

namespace OvEditor::Core
{class CameraController{private:// 控制摄像机的平移void HandleCameraPanning(const OvMaths::FVector2& p_mouseOffset, bool p_firstMouse);// 控制摄像机绕物体进行旋转void HandleCameraOrbit(const OvMaths::FVector2& p_mouseOffset, bool p_firstMouse);// 鼠标控制摄像机旋转void HandleCameraFPSMouse(const OvMaths::FVector2& p_mouseOffset, bool p_firstMouse);// 控制滚轮放大缩小void HandleCameraZoom();// 键盘控制摄像机void HandleCameraFPSKeyboard(float p_deltaTime);void UpdateMouseState();private:OvRendering::LowRenderer::Camera& m_camera; // 当前摄像机OvMaths::FVector3& m_cameraPosition; // 当前摄像机的位置OvMaths::FQuaternion& m_cameraRotation; // 当前摄像机的旋转四元数};
}

这四个函数就是通过改变m_cameraPosition、m_cameraRotation从而达到控制摄像机的目的。

一、鼠标控制缩放HandleCameraZoom
鼠标控制缩放的代码如下:

void OvEditor::Core::CameraController::HandleCameraZoom()
{m_cameraPosition += m_cameraRotation * OvMaths::FVector3::Forward * ImGui::GetIO().MouseWheel;
}

OvMaths::FVector3::Forward是固定矢量(0,0,1),其与m_cameraRotation相乘获取当前摄像机的Z轴,也叫Forward量,或可称为摄像机的指向。Imgui可获取鼠标滚轮的转动量,与Forward相乘,累加到摄像机位置上,产生摄像机拉进或拉远的效果。在其他软件中,我还见到过通过改变视口的大小实现缩放的,这种改变摄像机位置方式感觉更直观。

二、鼠标控制平动HandleCameraPanning

void OvEditor::Core::CameraController::HandleCameraPanning(const OvMaths::FVector2& p_mouseOffset, bool p_firstMouset)
{// 根据设置的拖动速度计算增量auto mouseOffset = p_mouseOffset * m_cameraDragSpeed;// 摄像机位置沿着Right、Up轴移动m_cameraPosition += m_cameraRotation * OvMaths::FVector3::Right * mouseOffset.x;m_cameraPosition -= m_cameraRotation * OvMaths::FVector3::Up * mouseOffset.y;
}

p_mouseOffset是鼠标移动矢量,是二维向量,但摄像机坐标系有三个轴,所以只能控制两个轴的平动。

三、鼠标控制绕自身转动HandleCameraFPSMouse
这个函数实现摄像机绕自身原点转动。p_firstMouse是当鼠标按下是为true,转动过程中为false。当第一次转动时,先将转动转换为欧拉角,RemoveRoll是对欧拉角做特殊处理,看着像是为了克服万向节死锁,没看太明白,有用的时候再来深究吧。

void OvEditor::Core::CameraController::HandleCameraFPSMouse(const OvMaths::FVector2& p_mouseOffset, bool p_firstMouse)
{auto mouseOffset = p_mouseOffset * m_mouseSensitivity;if (p_firstMouse){m_ypr = OvMaths::FQuaternion::EulerAngles(m_cameraRotation);m_ypr = RemoveRoll(m_ypr);}m_ypr.y -= mouseOffset.x;m_ypr.x += -mouseOffset.y;m_ypr.x = std::max(std::min(m_ypr.x, 90.0f), -90.0f);m_cameraRotation = OvMaths::FQuaternion(m_ypr);
}

鼠标偏移量改变欧拉角,注意其改变的值是x、y分量,最后再转换为四元数。

四、摄像机绕特殊点旋转HandleCameraOrbit
这个实际软件中使用也很多。这个相对于绕摄像机原点旋转多了平移分量,会同时改变摄像机的位置与姿态。

void OvEditor::Core::CameraController::HandleCameraOrbit(const OvMaths::FVector2& p_mouseOffset, bool p_firstMouse)
{auto mouseOffset = p_mouseOffset * m_cameraOrbitSpeed; // 鼠标偏移量if (p_firstMouse){m_ypr = OvMaths::FQuaternion::EulerAngles(m_cameraRotation); // 转换为欧拉角m_ypr = RemoveRoll(m_ypr); // 可能是为了解决万向节死锁m_orbitTarget = &EDITOR_EXEC(GetSelectedActor()).transform.GetFTransform();m_orbitStartOffset = -OvMaths::FVector3::Forward * OvMaths::FVector3::Distance(m_orbitTarget->GetWorldPosition(), m_cameraPosition); // 摄像机需要平移的量(摄像机局部坐标系下)}m_ypr.y += -mouseOffset.x;  // 对欧拉角进行改变m_ypr.x += -mouseOffset.y;m_ypr.x = std::max(std::min(m_ypr.x, 90.0f), -90.0f);auto& target = EDITOR_EXEC(GetSelectedActor()).transform.GetFTransform();OvMaths::FTransform pivotTransform(target.GetWorldPosition());OvMaths::FTransform cameraTransform(m_orbitStartOffset); // 设置摄像机平移量cameraTransform.SetParent(pivotTransform); pivotTransform.RotateLocal(OvMaths::FQuaternion(m_ypr)); // 将绕的点进行旋转m_cameraPosition = cameraTransform.GetWorldPosition();  // 获取摄像机位置m_cameraRotation = cameraTransform.GetWorldRotation(); // 获取摄像机转角
}

其原理是将围绕的点进行旋转,再平移获取摄像机的位置及姿态。

五、键盘控制摄像机平动HandleCameraFPSKeyboard
这个函数原理类似于鼠标平动,都是线用转动四元数获取当前轴,给位置一个增量即可,这里就不详细分析了。

相关文章:

【Overload游戏引擎细节分析】鼠标键盘控制摄像机原理

在上文中分析了摄像机类的实现,在计算投影视图矩阵时需要给摄像机输入其位置及转动四元数。这两个量一般通过鼠标键盘来控制,从而达到控制摄像机的目的。本文分析一下其控制原理。 Overload的摄像机控制实现在类CameraController中,其有三个个…...

VScode运行SVN拉下来的项目

安装依赖包 pnpm install 启动程序 查看package.json文件中的serve,根据这个启动 pnpm dev 在浏览器使用http://localhost:8848/访问...

jmeter集成kafka测试

Kafka的使用 查看kafka的topic ./kafka-topics --bootstrap-server 10.1.9.84:9092 --list 查看topic信息 ./kafka-topics --bootstrap-server 10.1.9.84:9092 --describe --topic topic_example_1 创建topic 创建topic名为test,分区数为8,副本数为…...

Java面试题-UDP\TCP\HTTP

UDP UDP特性 (1)UDP是无连接的:发送数据之前不需要像TCP一样建立连接,也不需要释放连接,所以减少了发送和接收数据的开销 (2)UDP 使用尽最大努力交付:即不保证可靠交付 &#xff0…...

使用WPF模仿Windows记事本界面

本次仅模仿Windows记事本的模样&#xff0c;并未实现其功能。 所有代码如下&#xff1a; <Window x:Class"控件的基础使用.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/…...

【目标检测】Co-DETR:ATSS+Faster RCNN+DETR协作的先进检测器(ICCV 2023)

论文&#xff1a;DETRs with Collaborative Hybrid Assignments Training 代码**&#xff1a;https://github.com/Sense-X/Co-DETR 文章目录 摘要一、简介二、本文方法2.1.概述2.2.协同混合分配训练2.3. 定制的正 Query 生成2.4. Co-DETR为何有效1、丰富编码器的监督2、通过减少…...

iOS QQ登录SDK升级后报错Duplicate interface definition for class ‘TencentOAuth‘修复

起因 最近发现QQ登录SDK sdk-Lite3.3.8 TencentOpenAPI 在部分手机上会崩溃到初始化位置_tencentOAuth [[TencentOAuth alloc] initWithAppId:appid andDelegate:self];&#xff0c; 比如&#xff1a;iPhone6p 版本12.5.4&#xff0c;iPhone8p 版本14.1&#xff0c;iPad版本1…...

laravel中锁以及事务的简单使用

一、首先来说一下什么是共享锁&#xff1f;什么是排他锁&#xff1f; 共享&#xff1a;我可以读 写 加锁 , 别人可以 读 加锁。 排他&#xff1a;只有我 才 可以 读 写 加锁 , 也就是说&#xff0c;必须要等我提交事务&#xff0c;其他的才可以操作。 二、简单例子实现加锁 锁…...

Vue+openlayers+projs4实现坐标转换

一、背景 有一堆点数据&#xff0c;需要在地图上标记&#xff0c;只知参考北京54坐标系或西安80坐标系&#xff0c;但具体是哪种不清楚&#xff0c;这时候就需要坐标转换。ps&#xff1a;EPSG&#xff1a;3857&#xff08;openlayers参照的坐标系&#xff09; 二、思路 1、研…...

09 创建型模式-建造者模式

1.建造者模式介绍&#xff1a; 建造者模式 (builder pattern), 也被称为生成器模式 , 是一种创建型设计模式 定义: 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不 同的表示。 2.建造者模式要解决的问题 建造者模式可以将部件和其组装过程分开&am…...

4.9 多协议标记交换MPLS

思维导图&#xff1a; 前言&#xff1a; **4.9 多协议标记交换MPLS笔记** 1. **定义与背景**&#xff1a; - MPLS (多协议标记交换) 是一种由 IETF 开发的新协议。 - “多协议”意味着 MPLS 的上层可以使用多种协议。 - 该协议综合了多家公司的技术&#xff0c;如 C…...

【经历】在职8个月->丰富且珍贵

在职8个月->丰富且珍贵 2021-3~2021-11&#xff1a;面试进入一家做400电话的公司&#xff0c;我进入公司时&#xff0c;加上我只有四个人(老板、人事、业务)&#xff0c;开发只有我&#xff0c;所以&#xff1a;产品~设计~前端~后端~测试~上线~维护~培训&#xff0c;只有我自…...

使用GH(命令行)在本地提出Github上的issue、PR,合并PR

使用GH&#xff08;命令行&#xff09;在本地提出Github上的issue、PR&#xff0c;合并PR 前言 Github上的一些操作使用Git命令是无法完成的&#xff0c;因此正常流程就是在网页端进行。等一下&#xff0c;你让程序员用网页进行&#xff1f;果然&#xff0c;有命令行工具可以…...

@Scheduled定时器

Scheduled定时器 一、基本使用二、参数说明fixedDelayfixedRateinitialDelaycron 三、cron 表达式参数说明实用性的案例 四、Scheduled注意事项五、配置文件1、fixedDelay2、fixedRate3、cron 一、基本使用 Scheduled // 由Spring定义&#xff0c;用于将方法设置为调度任务。…...

Xshell+screen解决ssh连接 服务器掉线的问题

Linux screen命令解决SSH远程服务器训练代码断开连接后运行中断_linux screen ssh-CSDN博客 Linux命令之screen命令_linux screen_恒悦sunsite的博客-CSDN博客 使用教程&#xff1a; 这里粗略介绍一下 &#xff08;1&#xff09;xshell xftp&#xff08;xshell点这个&#…...

coding_v3

面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 数组/字符串 1.LC88【合并两个有序数组】 def solve(nums1, m, nums2, n):p1, p2 m-1, n-1tail m n -1while p1 > 0 or p2 > 0:if p1 -1:nums1[tail] nums2[p2]p2…...

Elasticsearch:什么是余弦相似度?

余弦相似度是数据科学、文本分析和机器学习领域的基本概念。 如果你想知道什么是余弦相似度或者它如何在现实世界的应用程序中使用&#xff0c;那么你来对地方了。 本指南旨在让你深入了解相似性是什么、其数学基础、优点及其在不同领域的各种应用。读完本指南后&#xff0c;你…...

【每日一题Day352】LC1726同积元组 | 哈希表+排列组合

同积元组【LC1726】 给你一个由 不同 正整数组成的数组 nums &#xff0c;请你返回满足 a * b c * d 的元组 (a, b, c, d) 的数量。其中 a、b、c 和 d 都是 nums 中的元素&#xff0c;且 a ! b ! c ! d 。 思路 求出所有二元组的积及其出现次数&#xff0c;假设某个积出现的次…...

react中在js文件里定义的变量,如何在less文件里去使用该变量

在 React 中&#xff0c;如果在 JS 文件中定义了变量&#xff0c;可以使用 CSS Modules 的方式将变量导出到 LESS 文件中。 以下是示例代码&#xff1a; // index.js import React from react; import styles from ./styles.module.less;const color red;function App() {re…...

TIA博途中通过SCATTER指令实现将字节BYTE拆分成单个位的具体方法示例

TIA博途中通过SCATTER指令实现将字节BYTE拆分成单个位的具体方法示例 例如: 我们想判断某个字节中各个位的状态是1还是0 ,如何实现呢? 这里介绍通过SCATTER指令拆分字节的方法,仅供大家参考。 首先,我们先了解以下SCATTER指令的基本功能和使用方法: 如下图所示,在基本指…...

VMware Unlocker 3.0:终极指南 - 在Windows/Linux上免费运行macOS虚拟机

VMware Unlocker 3.0&#xff1a;终极指南 - 在Windows/Linux上免费运行macOS虚拟机 【免费下载链接】unlocker VMware Workstation macOS 项目地址: https://gitcode.com/gh_mirrors/unloc/unlocker 想在普通电脑上体验macOS系统吗&#xff1f;VMware Unlocker 3.0正是…...

NVIDIA Profile Inspector终极指南:如何通过驱动级调优彻底解决游戏卡顿问题

NVIDIA Profile Inspector终极指南&#xff1a;如何通过驱动级调优彻底解决游戏卡顿问题 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 你是否遇到过游戏帧率突然骤降、画面出现撕裂&#xff0c;或者操…...

XUnity.AutoTranslator终极指南:快速实现Unity游戏多语言翻译

XUnity.AutoTranslator终极指南&#xff1a;快速实现Unity游戏多语言翻译 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 你是否因为语言障碍而错过了许多精彩的Unity游戏&#xff1f;XUnity.AutoTransla…...

统一过程模型和统一过程方法对比分析

统一过程模型(Unified Process Model,简称 UP)和统一过程方法(Rational Unified Process,简称 RUP)是软件工程领域中两个紧密相关但又有本质区别的概念。本文将从定义、范围、来源、应用等方面进行详细对比分析。 一、基本定义 维度 统一过程模型(UP) 统一过程方法(RU…...

**链路追踪实战:用Go语言打造分布式系统的“心跳图谱”**在微服务架构日益普及的今天,一

链路追踪实战&#xff1a;用Go语言打造分布式系统的“心跳图谱” 在微服务架构日益普及的今天&#xff0c;一个请求可能跨越多个服务、几十个中间件甚至上百个节点。当问题出现时&#xff0c;传统的日志排查方式早已力不从心。这时&#xff0c;链路追踪&#xff08;Tracing&am…...

**Shader优化实战:从冗余计算到性能跃升的极致之旅**在图形渲染领域,**Shader性能优化**早已不是锦上添花的技术

Shader优化实战&#xff1a;从冗余计算到性能跃升的极致之旅 在图形渲染领域&#xff0c;Shader性能优化早已不是锦上添花的技术点&#xff0c;而是决定项目成败的核心环节。尤其是在移动端、VR/AR或高帧率游戏开发中&#xff0c;一个低效的着色器可能直接导致掉帧、发热甚至崩…...

**发散创新:用Python构建高可用合成数据生成器,赋能AI训练与测试**在人工智能飞速发展的今天,高质量的数

发散创新&#xff1a;用Python构建高可用合成数据生成器&#xff0c;赋能AI训练与测试 在人工智能飞速发展的今天&#xff0c;高质量的数据已成为模型训练的核心驱动力。然而&#xff0c;真实数据往往存在隐私敏感、分布不均、标注成本高等问题。为此&#xff0c;合成数据&…...

Swarm模式已过时?Docker 27原生调度引擎升级指南,3天完成零停机迁移

第一章&#xff1a;Swarm模式的历史定位与Docker 27调度范式跃迁Docker Swarm 曾是 Docker 原生容器编排的基石&#xff0c;自 Docker 1.12 起以内置模式&#xff08;Swarm Mode&#xff09;正式取代独立的 Swarm 工具链&#xff0c;标志着轻量级、声明式集群管理的开端。它以去…...

3种方法让普通鼠标秒变Mac神器:Mac Mouse Fix终极安装指南

3种方法让普通鼠标秒变Mac神器&#xff1a;Mac Mouse Fix终极安装指南 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 还在为Mac上的鼠标体验不…...

用 OpenClaw 构建个人知识库:从几百字到 10 万字,让 AI 真正懂你

为什么只有聊天记录还不够&#xff1f; 最近很多人都在用 OpenClaw&#xff0c;都在说”它是我的私人助手”。 甚至有人做了一个开源项目&#xff08;https://github.com/titanwings/colleague-skill&#xff09;&#xff0c;可以导入前同事的聊天记录&#xff0c;生成对应的 S…...