首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >用鼠标在OpenGL中拖动三维点的最佳方法?

用鼠标在OpenGL中拖动三维点的最佳方法?
EN

Stack Overflow用户
提问于 2015-05-28 16:23:54
回答 2查看 4.7K关注 0票数 2

用鼠标抓取拖动三维点的最佳方法是什么。问题不是采摘,而是在3D空间中的拖动。

我认为有两种方法,一种是使用gluUnProject将视图转到世界坐标,并翻译3D点。这种情况下的问题是,它只存在于具有深度值的曲面上(使用glReadPixels),如果鼠标离开表面,则根据gluUnProject的winZ组件给出最大或最小深度值。但在某些情况下不起作用。

第二种方法是使用GL_MODELVIEW_MATRIX沿XY、XZ、YZ平面拖曳。但是这个例子的问题是,我们怎么知道我们在XY,XZ或者YZ飞机上?我们怎么知道轨迹球的正面是在XY平面上,如果我们想要拖到侧面而不是前面的平面上呢?

那么,有没有办法给我精确的二维到三维坐标,这样我就可以轻松地把三维点拖向各个方向,而不考虑平面的情况?一定有一些方法,我看过3D软件,他们有完美的拖动功能。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-28 18:28:24

我习惯于有些天真地解决这些用户交互问题(也许不是以数学上最优的方式),但“足够好”考虑到它们不是非常关键的性能(用户交互部分,不一定是对场景的修改)。

对于对象的不受约束的自由拖动,使用unproject描述的方法很好地工作,通常会提供接近像素的完美拖动,只需稍作调整:

..。您不需要使用glReadPixels来提取屏幕深度,而是希望在用户选择和/或选择时使用几何对象/网格的概念。现在,只需投影该对象的中心点,以获得屏幕深度。然后,您可以在屏幕X/Y中拖动,保持从这个投影得到的相同的Z,并取消项目以获得从前一个中心到新中心的转换增量来转换对象。这也使它“感觉”,就像你从物体的中心拖动,这往往是相当直观的。

对于自动约束的拖动,一种快速的检测方法是首先抓取一个“视面正常”。一种快速的方法(可能会使数学家皱眉)使用那些你习惯的投影/反投影函数,就是在屏幕空间中取消在视口中心的两个点(一个是近z值,另一个是远z值),在这两个点之间得到一个单位向量。现在你可以用点积找到最接近正常轴的世界轴。另外两个世界轴定义了我们想要拖着的世界飞机。

然后,简单地使用这些方便的非投影函数来获得鼠标光标的光线。在此之后,您可以执行重复的射线/平面交叉,因为您正在拖动游标,以计算一个从三角洲的翻译矢量。

对于更灵活的约束,gizmo (也称为机械手,基本上是3D部件)可以派上用场,这样用户就可以根据他选择/拖动的gizmo的哪个部分来指示他想要什么样的拖动约束(平面、轴、无约束等等)。对于轴约束,射线/线或线/线相交是方便的。

按照注释中的要求,从视口检索光线(C++-ish伪代码):

代码语言:javascript
运行
AI代码解释
复制
// Get a ray from the current cursor position (screen_x and screen_y).
const float near = 0.0f;
const float far = 1.0f;
Vec3 ray_org = unproject(Vec3(screen_x, screen_y, near));
Vec3 ray_dir = unproject(Vec3(screen_x, screen_y, far));
ray_dir -= ray_org;

// Normalize ray_dir (rsqrt should handle zero cases to avoid divide by zero).
const float rlen = rsqrt(ray_dir[0]*ray_dir[0] + 
                         ray_dir[1]*ray_dir[1] + 
                         ray_dir[2]*ray_dir[2]);
ray_dir[0] *= rlen;
ray_dir[1] *= rlen;
ray_dir[2] *= rlen;

然后,我们用鼠标光标得到的光线做一个射线/平面交点,以确定当用户开始拖动时,光线在哪里与平面相交(交点将给我们一个3D点)。在此之后,它只是在用户拖动鼠标时,在重复执行过程中收集到的点之间通过增量来转换对象。物体在沿平面约束移动时,应直观地跟随鼠标。

轴拖动基本上是相同的想法,但是我们把光线变成一条线,并做一条线/线的交点(鼠标对轴约束的线,给我们一个最近的点,因为这些线通常不会完全相交),给我们一个3D点,我们可以利用这个三角形沿着约束轴来转换对象。

请注意,有一些棘手的边缘情况涉及轴/平面拖动约束。例如,如果一个平面垂直于观察平面(或接近),它可以将物体发射到无穷远。同样的情况下,轴沿垂直线拖动,就像试图从前视图(X/Y视图平面)沿Z轴拖动一样。因此,在这种情况下,检测直线/平面垂直(或接近)并防止拖曳是值得的,但这可以在基本概念生效之后完成。

另一个值得注意的技巧是隐藏鼠标光标,以改善某些情况下的“感觉”。例如,有了axis约束,鼠标光标可能会变得离轴本身很远,而且看起来/感觉很奇怪。因此,我已经看到许多商业包只是隐藏鼠标光标在本例中,以避免显示鼠标和gizmo/句柄之间的差异,因此它会感觉更自然一些。当用户释放鼠标按钮时,鼠标光标被移动到手柄的视觉中心。请注意,您不应该对平板电脑执行隐藏游标拖动操作(它们是一个例外)。

这种拾取/拖放/交叉的东西很难调试,所以它值得在婴儿步骤中解决。为自己设定一个小目标,就像点击某个视口中的鼠标按钮来创建光线一样。然后你可以绕着它转,确保射线在正确的位置上产生。接下来,您可以尝试一个简单的测试,看看该射线是否与世界上的一个平面(例如X/Y)平面相交,并创建/可视化射线与平面之间的交点,并确保这是正确的。采取小的,耐心的婴儿步,自己的步调,你会有顺利,自信的进展。试着一次做太多事情,你可能会有非常令人沮丧的、令人不快的进展,试图找出你的错误所在。

票数 6
EN

Stack Overflow用户

发布于 2015-05-28 20:24:09

这是一个非常有趣的图集。与您描述的颜色标记方法一样,z缓冲区也是一种方法。在这里,对同一主题也进行了类似的讨论:

Generic picking solution for 3D scenes with vertex-shader-based geometry deformation applied

OpenGL - Picking (fastest way) How to get object coordinates from screen coordinates?

这也类似于已经讨论过的对象选择,包括它们的优缺点:http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-an-opengl-hack/

实际上,我的答案是,没有唯一的最佳方法来做到这一点。正如你还提到的,他们有优点也有缺点。我个人喜欢暴饮暴食,因为它很容易,其结果是好的。此外,您不能使用屏幕空间在任何方向移动顶点,因为屏幕空间是2D的,并且没有唯一的方法将其映射回三维几何空间。希望它有帮助:)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30519214

复制
相关文章
java:从RGBA格式的图像数据byte[]创建BufferedImage对象
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/88680596
10km
2019/05/25
1.9K0
Python面向对象编程-类和对象-对象的创建和使用
在Python中,对象是一种数据结构,它封装了数据和行为,并允许对它们进行操作。对象是根据类定义的,它们具有类定义的属性和方法。本文将介绍如何在Python中创建和使用对象。
玖叁叁
2023/04/19
1.2K0
从对象复制到对象创建:用原型模式提升你的编程水平!
所谓浅拷贝,就是对象的成员属性是引用类型时,克隆后的新对象中的成员属性引用的依旧是原对象中成员属性的内存地址。也就是说:成员属性如果是引用类型,克隆的是内存地址;这个内存地址是不变的,指向的是同一个
程序视点
2023/06/06
4220
从对象复制到对象创建:用原型模式提升你的编程水平!
iOS上架之使用appuploader创建构建版本的流程​
1、打开appuploader软件​ 2、登录苹果开发者账号​ 3、点击appuploader右上角的设置​ 4、设置苹果app上传密码​ 5、开始上传ipa的安装包​
iOS程序应用
2023/04/17
4070
iOS上架之使用appuploader创建构建版本的流程​
深度学习应用:iOS 上的图像风格迁移
图像风格迁移,用 python 就可以实现,如果想要在手机上面(不联网)查看效果怎么办呢?
iOSDevLog
2019/02/20
1.1K0
Promise对象的创建与使用
为什么要使用promise? 它指定回调函数的方式更加灵活,当new出一个promise的时候,这个任务就立刻开始执行了,后面的回调函数会在异步执行完后进行回调,在没有promise之前就不一样了:
gzq大数据
2021/06/08
1K0
java 对象的创建与使用
HotSpot 是在 JIT 之后的一款 java 虚拟机的开源实现,sun 从 JDK 1.3.1 开始使用。 它主要使用 C++ 实现的,相对于 JIT,性能有大幅提高。 HotSpot 将部分代码直接编译为本地可执行代码,从而显著提升了性能。
用户3147702
2022/06/27
8880
java 对象的创建与使用
iOS-使用GCD单例创建管理对象
一·单例缓存全局变量 + (instancetype)E { static E *e; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //开启一个单例 e = [[e alloc] init]; }); return e; } 二·准备工作 在头文件暴露你所需要的属性or方法 @property (nonatomic,strong) NSString *hacker;
Wilbur-L
2021/09/02
5970
.net下灰度模式图像在创建Graphics时出现:无法从带有索引像素格式的图像创建graphics对象 问题的解决方案。
文章主要介绍了如何通过GDI+绘制椭圆,并给出了具体的实现代码和示例。主要步骤包括:定义一个基于GDI+的Bitmap对象,使用GraphicsPath绘制椭圆,将GraphicsPath转换为Bitmap,并使用RenderOptions.SetBitmapScalingMode进行缩放处理。
用户1138785
2018/01/03
5.7K1
.net下灰度模式图像在创建Graphics时出现:无法从带有索引像素格式的图像创建graphics对象 问题的解决方案。
面向对象编程是否走向了消亡?
【CSDN 编者按】作为一种程序设计思想,OOP 在最初诞生之际就收到了广大开发者的喜爱。但是在技术革新日益实践过程中,不少人发现面向对象的设计会使代码复杂化,难以理解而且难以测试,对此,后来有网友更是将 OOP 称之为是反模块化、反并行的,从而开启了一波又一波的吐槽模式。而论 OOP 在各个领域中的应用时,其是否真的有想象中那么糟糕?接下来,本文将带领大家一读 OOP 的兴衰成长史。
Python猫
2019/08/30
7270
面向对象编程是否走向了消亡?
9种日常JavaScript编程中经常使用的对象创建模式
今天这篇文章主要是跟大家分享9种日常JavaScript编程中经常使用的对象创建模式,利用各种技巧可以极大地避免了错误或者可以编写出非常精简的代码。希望对你有所帮助。
前端达人
2021/04/01
6470
【iOS 开发】同步快速判断视频是否可以播放
拿到一个视频的 url 地址(无论是远程还是本地),有时候在播放之前需要检测该视频是否可以播放(本地可能是文件损坏,远端地址情况更复杂),下面介绍两种适用不同情况的方法来实现。
KyXu
2019/04/11
2.2K0
Kotlin | 从线程到协程,你是否还存在 [同步] 上的使用疑问
在2022的今天,对于一个 Android 开发同学,如果你使用 Kotlin 作为主要开发语言,那么协程是必不可缺的 异步框架 。不过对于初学者来说,有时候依然存在一些理解问题或者使用上的不解。毕竟我们用了那么多年的回调与线程,突然转变思想,的确需要过程。
Petterp
2022/03/01
1.4K0
Kotlin | 从线程到协程,你是否还存在 [同步] 上的使用疑问
Javascript创建对象的学习和使用
1 <html> 2 <head> 3 <meta charset="utf-8"> 4 <title>javascript对象的学习</title> 5 </head>
别先生
2017/12/29
1.6K0
Javascript创建对象的学习和使用
对象的创建
new —> 到常量池中检查是否存在一个类的符号引用 —> 如果有,检查这个符号引用代表的类是否已被加载、解析、初始化 —> 没有,则执行类加载过程。
潇洒
2019/07/03
8740
ovirt 上创建vm模板的创建与使用
版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://blog.csdn.net/wh211212/article/details/79977816
shaonbean
2019/05/26
2K0
Python面向对象编程(上)
有几种不同的编程范式,面向对象编程(OOP)是Python语言中最流行的编程范式之一。
fanjy
2022/11/16
3980
Python面向对象编程(上)
非分区表是否可以创建分区索引?
有同事问一个问题, 一张非分区表,是否可以创建分区索引? 答案是可以,但分区索引的类型有限制。 MOS这篇文章给出了答案,以及一些例子,What Is The Global Partitioned I
bisal
2019/01/29
1.7K0
三十、是否可以使用 count(*)
一、是否可以使用 count(*) 在 SQL 中,COUNT() 函数返回匹配指定条件的函数。 序号COUNT用法作用描述1COUNT(*)返回总记录数,包含 NULL 值2COUNT(1)与COUNT(*)的作用一样3COUNT(column_name)返回指定列的数目,NULL值不统计4COUNT(DISTINCT column_name)返回指定列不同值的数目,NULL值不统计 Tip: COUNT(*) 与 COUNT(column_name) 的作用不一样,如果列值包含 NULL ,统计结果就
喵叔
2022/05/06
4980
java深拷贝的实现方式_接口可以创建对象吗
Cloneable接口与Serializable接口都是定义接口而没有任何的方法。Cloneable可以实现对象的克隆复制,Serializable主要是对象序列化的接口定义。很多时候我们涉及到对象的复制,我们不可能都去使用setter去实现,这样编写代码的效率太低。JDK提供的Cloneable接口正是为了解决对象复制的问题而存在。Cloneable结合Serializable接口可以实现JVM对象的深度复制。
全栈程序员站长
2022/11/04
1.5K0

相似问题

以编程方式创建ARReferenceImage

20

iOS 11.3.1上PWA中的getUserMedia()

13

是否可以通过编程方式使用iOS在用户的主屏幕上创建快捷图标按钮

27

是否可以通过编程方式创建EMF对象?

10

是否可以通过编程方式通过.xls创建iOS文件?

41
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档