相机:以鼠标点为中心缩放(使用OpenGL+QT开发三维CAD)

很多软件中(Auto CAD、ODA等)支持以鼠标点为中心进行放缩操作,有什么黑科技吗?

本章节为相机原理和实现的补充内容,支持鼠标放缩时以鼠标点为中心进行放缩。

对应视频课程已上线,欢迎观看和支持~

https://www.bilibili.com/cheese/play/ss168681371

学习!《从零开发一款三维CAD软件(OpenGL/QT/C++)》课程上线啦

图片

31.相机:缩放时以鼠标点为中心

在三维软件中,‌以鼠标点为中心缩放可以做到保持聚焦点位置不变,达到视觉上的“中心点聚焦”。这种技术常用于电影镜头语言和游戏场景设计中,通过动态调整视角和物体大小,使用户始终关注特定区域。

31.1.思考和讨论

通常我们会通过鼠标滚轮事件实现场景缩放,而在场景中进行缩放时,会以相机当前的Position(也就是视点)为观察位置进行缩放,通过滚轮滑动的方向和幅度来更新相机的Zoom

回顾

你应该还记得在顶点着色器中将坐标点转换为裁剪坐标过程中需要经过modelMatrixviewMatrixprojectionMatrix的处理,而projectionMatrix的构造与Zoom有关系,当然还与近平面远平面宽高比有关。

在不考虑鼠标位置进行缩放时,会以固定的Position进行观察,而仅仅改变Zoom的大小,这样会出现无论鼠标在场景中任何位置进行滚动,缩放行为都不会考虑鼠标位置,也就是不会考虑我们当前关注的位置。为了实现以鼠标点为中心的缩放,我们还需要更新相机的Position来实现聚焦点的“固定”,这也意味着我们需要同时更新viewMatrixprojectionMatrix

想象和思考

在原理和实现讲解之前,我们先一起想象一下。

  • 鼠标在(curPx,curPy)像素位置进行滚轮放大,当前视角下场景会放大,我们现在看到的范围更小了(也更清晰了),这也意味着(curPx,curPy)像素原本对应的场景位置(curScenePos)可能移出我们屏幕范围了!

怎么样让它固定在(curPx,curPy)像素位置而不是移动呢?

在上述情景想象中,

  • 观察矩阵viewMatrix没有任何变化(也就是观察空间中的效果没有变化);

  • 而由于Zoom的变化,透视平截头体的范围变小了,可见的场景空间变小了(近平面远平面尺寸变小了);

  • (curPx,curPy)

    像素原本对应的场景位置(curScenePos)可能已经不在透视平截头体的范围内了,当然该像素现在对应到另一个场景位置(nextScenePos)了;

我们需要把(curPx,curPy)像素位置固定在对应的场景位置上,那么移动相机的Position就好了,让它靠近原本聚焦点(对应的场景位置)。是的,其实逻辑挺简单的,至于要移动多少?那就移动curScenePos - nextScenePos

nextScenePos怎么计算?以相同的(curPx,curPy)depth来计算场景空间坐标系对应位置就好了。

31.2.原理

我们先不考虑透视投影或者正交投影的概念(这和当前的逻辑原理没有什么关系)。在Zoom更新后,平截头体的范围变化了,(curPx,curPy)屏幕像素对应了新的场景位置(nextScenePos),我们只需要(通过平移Position)把这个位置“平移”到原本对应的场景位置(curScenePos),这样聚焦的目标就“固定”住了。

偏移Position,实现鼠标点的聚焦
图:偏移Position,实现鼠标点的聚焦

 

上图展示了缩放前后、Position平移前后的逻辑示意:

  1. 缩放前鼠标像素位置对应一个场景空间位置curScenePos(为我们聚焦的位置);

  2. 放大后,curScenePos不可见了,而鼠标像素位置对应了另一个场景空间位置nextScenePos了;

  3. 我们把Camera.Position移动(curScenePos - nextScenePos)向量,鼠标像素位置重新对应到了原本的curScenePos

  4. 这样就实现‌了保持聚焦点位置不变的以鼠标点为中心缩放。

31.3.关键代码

void ProcessMouseScroll(float yoffset)
{
//  scale by the mouse hover point if it's pixes is validQVector3D curPt;
float depth;
bool hoverValid = ViewerSetting::mouseScaleByCenter && GetScenePoint(ViewerSetting::currentMousePos[0], ViewerSetting::currentMousePos[1], curPt, depth);//  modify zoom
float downValue = 1.0f;
float upValue = 89.f/*45.0f*/;Zoom -= (float)yoffset;
if (Zoom < downValue)Zoom = downValue;
if (Zoom > upValue)Zoom = upValue;if (hoverValid){
//  cal point of current pixesQVector3D nextPt;GetScenePoint(ViewerSetting::currentMousePos[0], ViewerSetting::currentMousePos[1], depth, nextPt);//  move PositionPosition += (curPt - nextPt);}
}

思考

为什么在计算nextPt时的depth参数要用此前curPt对应的值呢?读者可自行思考。

31.4.效果

效果视频:https://www.bilibili.com/video/BV15zG3zzEgK/

也可在《课程视频》中进行观看,有详细的讲解~

学习!《从零开发一款三维CAD软件(OpenGL/QT/C++)》课程上线啦


专注于图形学(渲染和几何算法)、数据处理、并行计算相关研究和研发,欢迎交流~

学习!《从零开发一款三维CAD软件(OpenGL/QT/C++)》课程上线啦

系列课程已上线,详细的视频讲解,打下扎实的图形学基础,欢迎大家观看和支持~

往期文章:

  • GLViewer:添加ViewCube

  • 学习!《从零开发一款三维CAD软件(OpenGL/QT/C++)》课程上线啦

  • OpenGL模板缓冲:实现亮显外轮廓效果

  • 2025 想从事工业软件开发要掌握哪些知识?

  • 30.抗锯齿(anti aliasing):使用OpenGL+QT开发三维CAD

  • MSAA抗锯齿技术的不足和优化(PPAA)

  • 相机:Camera原理讲解(使用OpenGL+QT开发三维CAD)

  • 开发三维CAD:实现框选和反选功能

  • 图形学:一分钟看懂网格剖分原理(耳切法)

  • 视图立方体:ViewCube的绘制(使用OpenGL+QT开发三维CAD)


图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90551.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90551.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

​​XAMPP安全升级指南:修复CVE-2024-4577漏洞,从PHP 8.2.12升级至PHP 8.4.10​​

​​1. 背景与漏洞概述​​ 近期,PHP官方披露了一个高危漏洞 ​​CVE-2024-4577​​,该漏洞影响PHP 8.2.x及更早版本,可能导致远程代码执行(RCE)或信息泄露。由于XAMPP默认捆绑的PHP版本(如8.2.12)可能受此漏洞影响,建议用户尽快升级至最新的​​PHP 8.4.10​​(或官…

ES 压缩包安装

以下是 Elasticsearch (ES) 通过 .tar.gz 压缩包安装的详细步骤&#xff08;适用于 Linux/macOS 系统&#xff09;&#xff1a; 1. 准备工作 1.1 检查系统依赖 Java 环境&#xff1a;ES 需要 JDK&#xff0c;推荐 OpenJDK 11/17&#xff08;ES 7.x/8.x 兼容版本&#xff09;。…

RoboRefer:面向机器人视觉-语言模型推理的空间参考

25年6月来自北航、北大和北京智源的论文“RoboRefer: Towards Spatial Referring with Reasoning in Vision-Language Models for Robotics”。 空间参考是实体机器人与三维物理世界交互的基本能力。然而&#xff0c;即使有了强大的预训练视觉-语言模型 (VLM)&#xff0c;近期方…

【Unity】MiniGame编辑器小游戏(十)连连看【Link】

更新日期:2025年7月9日。 项目源码:获取项目源码 索引 连连看【Link】一、游戏最终效果二、玩法简介三、正式开始1.定义游戏窗口类2.规划游戏窗口、视口区域3.方块 Block①.定义方块类②.生成方块所有类型③.生成连连看棋盘④.绘制方块阵列4.连线 Line①.点击方块连线②.尝试…

Enable ADB Debugging Before Connect

If you don’t enable Developer Options and turn on USB Debugging before plugging in the cable, adb devices won’t detect the phone because the Android system doesn’t trust the connection yet. Here’s what you need to do step-by-step to fix this:✅ 1. Enab…

从互联网电脑迁移Dify到内网部署Dify方法记录

一、在互联网电脑上准备迁移文件1. 保存 Docker 镜像# 获取所有 Dify 相关镜像&#xff08;根据实际容器名调整&#xff09; docker ps --filter "namedify" --format "{{.Image}}" | sort -u > dify-images.list# 保存镜像为 .tar 文件 docker save $(…

【EGSR2025】材质+扩散模型+神经网络相关论文整理随笔(一)

MatSwap: Light-aware material transfers in images介绍任务&#xff1a;输入一张拍摄图像、示例材质纹理图像&#xff08;这里跟BRDF无关&#xff0c;通常我们讲到材质一般指的是SVBRDF&#xff0c;但是这里的材质指的只是纹理&#xff09;、用户为拍摄图像指定的遮罩区域&am…

饿了么el-upload上传组件报错:TypeError: ***.upload.addEventListener is not a function

在本地上传没有报这个错误&#xff0c;部署到服务器后会报这个错误&#xff0c;一开始以为是服务器配置等什么原因&#xff0c;但是一想这个报错应该还是在前端&#xff0c;接口都还没请求&#xff0c;不可能到后台去&#xff0c;后面搜了好几个AI也没有找到想要的答案或解决方…

淘宝直播与开源链动2+1模式AI智能名片S2B2C商城小程序的融合发展研究

摘要&#xff1a;本文聚焦于淘宝直播这一以“网红”内容为主的社交电商平台&#xff0c;深入分析其特点与流量入口优势。同时&#xff0c;引入开源链动21模式AI智能名片S2B2C商城小程序这一新兴概念&#xff0c;探讨二者融合的可能性与潜在价值。通过分析融合过程中的技术、市场…

【macos用镜像站体验】Claude Code入门使用教程和常用命令

一、下载安装nodejs # macOS 用户安装nodejs brew update brew install node二、安装官方Claude Code # 安装 Claude Code npm install -g anthropic-ai/claude-code # 查看版本 claude --version三、正式使用&#xff08;国内镜像站&#xff09; 今天发现的一个镜像站&…

算法学习笔记:11.冒泡排序——从原理到实战,涵盖 LeetCode 与考研 408 例题

在排序算法的大家族中&#xff0c;冒泡排序是最基础也最经典的算法之一。它的核心思想简单易懂&#xff0c;通过重复地走访待排序序列&#xff0c;一次比较两个相邻的元素&#xff0c;若它们的顺序错误就把它们交换过来&#xff0c;直到没有需要交换的元素为止。虽然冒泡排序的…

Linux小白学习基础内容

记录第一天重新学习2025/7/10 15&#xff1a;467/10 17&#xff1a;02这里面一个命令带多个参数举例&#xff08;多个参数之间用空格隔开&#xff09;ls&#xff08;命令&#xff09; ~ / /etc/&#xff08;参数&#xff09; :这里就是同时查看主机的家目录&#xff0c;根目…

从零开始搭建深度学习大厦系列-2.卷积神经网络基础(5-9)

(1)本人挑战手写代码验证理论&#xff0c;获得一些AI工具无法提供的收获和思考&#xff0c;对于一些我无法回答的疑问请大家在评论区指教&#xff1b; (2)本系列文章有很多细节需要弄清楚&#xff0c;但是考虑到读者的吸收情况和文章篇幅限制&#xff0c;选择重点进行分享&…

【iOS设计模式】深入理解MVC架构 - 重构你的第一个App

目录 一、MVC模式概述 二、创建Model层 1. 新建Person模型类 2. 实现Person类 三、重构ViewController 1. 修改ViewController.h 2. 重构ViewController.m 四、MVC组件详解 1. Model&#xff08;Person类&#xff09; 2. View&#xff08;Storyboard中的UI元素&#x…

前端项目集成lint-staged

lint-staged (lint-staged) 这个插件可以只针对进入git暂存区中的代码进行代码格式检查与修复&#xff0c;极大提升效率&#xff0c;避免扫描整个项目文件&#xff0c;代码风格控制 eslint prettier stylelint 看这两篇文章 前端项目vue3项目集成eslint9.x跟prettier 前端项…

李宏毅genai笔记:模型编辑

0 和post training的区别直接用post training的方法是有挑战的&#xff0c;因为通常训练资料只有一笔而且之后不管问什么问题&#xff0c;都有可能只是这个答案了1 模型编辑的评估方案 reliability——同样的问题&#xff0c;需要是目标答案generalization——问题&#xff08;…

Oracle:union all和union区别

UNION ALL和UNION在Oracle中的主要区别体现在处理重复记录、性能及结果排序上&#xff1a;处理重复记录‌UNION‌&#xff1a;自动去除重复记录&#xff0c;确保最终结果唯一。‌UNION ALL‌&#xff1a;保留所有记录&#xff0c;包括完全重复的行。性能表现‌UNION‌&#xff…

[C#/.NET] 内网开发中如何使用 System.Text.Json 实现 JSON 解析(无需 NuGet)

在实际的企业开发环境中&#xff0c;尤其是内网隔离环境&#xff0c;开发人员经常面临无法使用 NuGet 安装外部包的问题。对于基于 .NET Framework 4.8 的应用&#xff0c;JSON 解析是一个常见的需求&#xff0c;但初始项目中往往未包含任何 JSON 处理相关的程序集。这时&#…

JVM(Java 虚拟机)的介绍

JVM原理JVM 核心架构与工作流程1. 类加载机制&#xff08;Class Loading&#xff09;2. 运行时数据区&#xff08;Runtime Data Areas&#xff09;堆&#xff08;Heap&#xff09;方法区&#xff08;Method Area&#xff09;:元空间&#xff08;Metaspace&#xff09;公共区域虚…

Qt 信号槽的扩展知识

Qt 信号槽的扩展知识一、信号与槽的重载Qt信号与槽的重载问题注意事项示例场景二、一个信号连接多个槽1、直接连接多个槽2、使用lambda表达式连接3、连接顺序控制4、断开特定连接5、自动连接方式三、 多个信号连接一个槽基本连接语法使用QSignalMapper区分信号源&#xff08;Qt…