【OpenGL】鼠标点击获取世界坐标

2023-11-22 16:50

本文主要是介绍【OpenGL】鼠标点击获取世界坐标,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【OpenGL】鼠标点击获取世界坐标

标签(空格分隔): OpenGL


起因

因为最近在做图形学相关毕设,需要时间鼠标交互获取三维坐标(世界坐标系)。于是在网上查了一些博客与资料,放进自己代码中,效果怎么都不对。于是才自己静下心来,好好研究。

OpenGL中的坐标系

OpenGL总共有5个坐标系,它们分别是:

  • 局部空间或称物体空间
  • 世界空间
  • 观察空间或称视觉空间
  • 裁剪空间
  • 屏幕空间

下面我按照我自己的理解简单说明一下这5个空间。
局部空间:即所有的物体在创建时,都会处在坐标原点的位置。
image_1cd4ib15a1ot1o03162o181q1nmkp.png-29.1kB
世界空间:我们需要在将不同的物体指定到各自的位置,这时就是需要运用到平移,缩放,旋转等矩阵操作,就是为了将物体从局部空间变化到世界空间。
image_1cd4ickdm14ck12291bba1qrnba516.png-29.3kB
观察空间:世界空间中不仅有物体,还有观察点(视点),物体以视点为原点所得到的坐标就是物体在观察空间中的坐标。
image_1cd4imfl3jgq1hsfdasj3eg3023.png-66kB
裁剪空间:将投影范围通过插值转化为CVV(Clip Coordinate System)以便于裁剪
image_1cd4jhmj617gp31b9vphin3j12g.png-93.3kB
屏幕空间:裁剪后的物体通过插值,计算出在窗口中的坐标,从而绘制出来。
image_1cd4jv57k13vhdhv1c5b6k10ti3d.png-65.4kB

下图是坐标系的变换流程图:
微信图片_20180510180848.jpg-1913.3kB

从一个空间变换为另一个空间(即从一个基变化为另一个基)是由矩阵来实现的。

局部空间到世界空间的变化矩阵称为模型矩阵
世界空间到观察空间的变化矩阵称为观察矩阵,具体矩阵推导请看:【转载】推导相机变换矩阵
观察空间到裁剪空间的变化矩阵称为投影矩阵,具体矩阵推导请看:【转载】深入探索透视投影变换

通过鼠标点击获取三维坐标

网上百度的代码基本都是这样:

void Get3Dpos(int x, int y, fVector3* pp) {GLint viewport[4];GLdouble modelview[16];GLdouble projection[16];GLfloat winX, winY, winZ;GLdouble object_x, object_y, object_z;int mouse_x = x;int mouse_y = y;glGetDoublev(GL_MODELVIEW_MATRIX, modelview);glGetDoublev(GL_PROJECTION_MATRIX, projection);glGetIntegerv(GL_VIEWPORT, viewport);winX = (float)mouse_x;winY = (float)viewport[3] - (float)mouse_y - 1.0f;glReadBuffer(GL_BACK);glReadPixels(mouse_x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)winZ, modelview, projection, viewport, &object_x, &object_y, &object_z);*pp.x = object_x;*pp.y = object_y;*pp.z = object_z;
}

经过我在程序中测试,得到的坐标应该是视点坐标。而我想实现的是获得世界坐标系。这里就需要用矩阵对坐标系进行变化,由视点坐标系变为世界坐标系。

根据博客推导相机变换矩阵,观察矩阵的表示形式为(TR)-1,因此,从视点坐标变为世界坐标需要进行的变换为(TR)。
设视点的是世界坐标为(Tx,Ty,Tz),视点的UVN系统的基为UVN

T= 100001000010TxTyTz1(1) (1) T = [ 1 0 0 T x 0 1 0 T y 0 0 1 T z 0 0 0 1 ]

R= UxUyUz0VxVyVz0NxNyNz00001(2) (2) R = [ U x V x N x 0 U y V y N y 0 U z V z N z 0 0 0 0 1 ]

M=T×R= UxUyUz0VxVyVz0NxNyNz0TxTyTz1(4) (4) M = T × R = [ U x V x N x T x U y V y N y T y U z V z N z T z 0 0 0 1 ]

所以,上述代码中求出的pp(pp.x, pp.y, pp.z, 1),最后左乘上矩阵M,即可得到三维世界坐标。

//根据屏幕坐标得到视点空间坐标
void Get3Dpos(int x, int y, fVector3* pp) {GLint viewport[4];GLdouble modelview[16];GLdouble projection[16];GLfloat winX, winY, winZ;GLdouble object_x, object_y, object_z;int mouse_x = x;int mouse_y = y;glGetDoublev(GL_MODELVIEW_MATRIX, modelview);glGetDoublev(GL_PROJECTION_MATRIX, projection);glGetIntegerv(GL_VIEWPORT, viewport);winX = (float)mouse_x;winY = (float)viewport[3] - (float)mouse_y - 1.0f;glReadBuffer(GL_BACK);glReadPixels(mouse_x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)winZ, modelview, projection, viewport, &object_x, &object_y, &object_z);*pp.x = object_x;*pp.y = object_y;*pp.z = object_z;
}//根据视点空间坐标得到世界空间坐标
GetWorldPos(int x,int y){//得到观察空间的坐标fVector3 pp;Pick(x, y, &pp);//求视点的UVN系统fVector3 U, V, N;                   //fVector3为自定义向量类fVector3 up = {0.0,1.0,0.0};fVector3 eye, direction;            //视点坐标与观察点坐标N = eye - direction                 //矢量减法U = N.cross(up);                    //矢量叉乘V = N.cross(U);N.normalize();                      //矢量归一化U.normalize();V.normalize();//求世界坐标fVector3 worldpos = { 0.0f,0.0f,0.0f };worldpos.x = U.x * pp.x + V.x * pp.y + N.x * pp.z + eye.x;worldpos.x = U.y * pp.x + V.y * pp.y + N.y * pp.z + eye.y;worldpos.z = U.z * pp.x + V.z * pp.y + N.z * pp.z + eye.z;
}
效果

select.gif-1405.8kB

这篇关于【OpenGL】鼠标点击获取世界坐标的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/411548

相关文章

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元,传统键盘输入方式正悄然进化。以往,面对实体键盘,我们常需目光游离于屏幕与键盘之间,以确认指尖下的精准位置。而屏幕键盘虽直观可见,却常因占据屏幕空间,迫使我们在操作与视野间做出妥协,频繁调整布局以兼顾输入与界面浏览。 幸而,韦季李输入法的横空出世,彻底颠覆了这一现状。它不仅对输入界面进行了革命性的重构,更巧妙地将鼠标这一传统外设融入其中,开创了一种前所未有的交互体验。 想象

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Unity3D自带Mouse Look鼠标视角代码解析。

Unity3D自带Mouse Look鼠标视角代码解析。 代码块 代码块语法遵循标准markdown代码,例如: using UnityEngine;using System.Collections;/// MouseLook rotates the transform based on the mouse delta./// Minimum and Maximum values can

简单的角色响应鼠标而移动

actor类 //处理移动距离,核心是找到角色坐标在世界坐标的向量的投影(x,y,z),然后在世界坐标中合成,此CC是在地面行走,所以Y轴投影始终置为0; using UnityEngine; using System.Collections; public class actor : MonoBehaviour { public float speed=0.1f; CharacterCo

C# 防止按钮botton重复“点击”的方法

在使用C#的按钮控件的时候,经常我们想如果出现了多次点击的时候只让其在执行的时候只响应一次。这个时候很多人可能会想到使用Enable=false, 但是实际情况是还是会被多次触发,因为C#采用的是消息队列机制,这个时候我们只需要在Enable = true 之前加一句 Application.DoEvents();就能达到防止重复点击的问题。 private void btnGenerateSh

JS和jQuery获取节点的兄弟,父级,子级元素

原文转自http://blog.csdn.net/duanshuyong/article/details/7562423 先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。 JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素。 <div id="test"><div></div><div></div

vcpkg子包路径批量获取

获取vcpkg 子包的路径,并拼接为set(CMAKE_PREFIX_PATH “拼接路径” ) import osdef find_directories_with_subdirs(root_dir):# 构建根目录下的 "packages" 文件夹路径root_packages_dir = os.path.join(root_dir, "packages")# 如果 "packages"

Weex入门教程之4,获取当前全局环境变量和配置信息(屏幕高度、宽度等)

$getConfig() 获取当前全局环境变量和配置信息。 Returns: config (object): 配置对象;bundleUrl (string): bundle 的 url;debug (boolean): 是否是调试模式;env (object): 环境对象; weexVersion (string): Weex sdk 版本;appName (string): 应用名字;

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD