OpenGL3.3鼠标拾取物体

本文翻译自:http://www.lighthouse3d.com/tutorials/opengl-selection-tutorial/

在3D场景中拾取或选择特定项目可能对某些应用程序很有用。可以通过单击一个对象来执行选择,这需要一种确定鼠标放置在哪个对象上的方法。

实现此目的的简单解决方案是使用颜色编码,以特定颜色绘制每个可拾取对象。读取鼠标所在的像素以提供颜色,从而可以识别物体。

选择模式下的渲染使用非常简单的着色器,将恒定的颜色应用于像素。颜色是一个统一变量,在绘制每个对象之前应将其设置为唯一值。

顶点着色器可以如下所示:

#version 330uniform mat4 m_pvm;in vec4 position;void main()
{gl_Position = m_pvm * position ;
}

片段着色器很简单:

#version 330uniform int code;out vec4 outputF;void main()
{outputF = vec4(code/255.0, 0, 0, 0);
}

重要的是,我们收到的code是整数而不是浮点数。在RGB模式下,每个分量只有256个可能的值,因此当您使用浮点数设置颜色时,OpenGL将选择最接近的可能颜色,这可能与您提供的值不完全相同。

请注意,我们将除以255.0,而不是除以255。使用后一种方法将是整数除法,结果也将是整数(0或1)。

如果有超过255个对象可供选择,则 uniformcode可以是ivec4类型。

假设我们的场景有4个国际象棋棋子,如下图所示:

在此示例中,我们有四个可点击的对象,我们将为其分配从1到4的代码。选择渲染例程的背景可以设置为黑色,因此零表示没有任何选择。使用选择程序时,我们将获得如下图像(对比度大大提高):


该图像将永远不会呈现给用户,因为选择渲染不会交换缓冲区。

以下例程接收鼠标窗口坐标,并执行必要的步骤来确定选择了哪个对象。首先调用选择渲染程序,然后再进行选择。然后,它从后台缓冲区读取像素并检查返回的颜色。

要读取像素,我们将使用函数glReadPixels
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *data);

参数:

  • x,y:要读取的矩形块的第一个像素的坐标
  • width,height:块的大小。
  • format:像素数据的格式:GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_RED, GL_GREEN, GL_BLUE, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA
  • type:像素分量的数据类型:GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, GL_HALF_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_UNSIGNED_INT_5_9_9_9_REV, or GL_FLOAT_32_UNSIGNED_INT_24_8_REV
  • data:返回的像素数据。
void processSelection(int xx, int yy) {unsigned char res[4];GLint viewport[4]; renderSelection();glGetIntegerv(GL_VIEWPORT, viewport);glReadPixels(xx, viewport[3] - yy, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, &res);switch(res[0]) {case 0: printf("Nothing Picked \n"); break;case 1: printf("Picked yellow\n"); break;case 2: printf("Picked red\n"); break;case 3: printf("Picked green\n"); break;case 4: printf("Picked blue\n"); break;default:printf("Res: %d\n", res[0]);}
}

为了获得正确的像素,我们必须将鼠标窗口坐标(左上角为原点)转换为帧缓冲区坐标(左下角的原点)。这要求我们知道视口的高度。函数glGetIntegerv可用于此目的,将GL_VIEWPORT作为第一个参数。返回变量viewport是一个包含4个项目的数组,该数组提供x和y视口窗口坐标(起点:左上角),然后是视口的宽度和高度。然后,可以读取像素,并正确解码检索到的颜色。

选择渲染程序必须遵循与常规程序有关几何变换的相同步骤,以使对象位于屏幕上的同一位置。通常,选择渲染程序是常规渲染程序的简化版本,其中仅绘制对象的子集,并且未设置任何图形效果,例如照明。

对象子集包括所有可点击的对象以及相关的遮挡物。这个想法是,如果某些棋子在用户看不见的空间内,则它们不应出现在颜色编码的图像中。这可以通过用与背景相同的颜色绘制遮挡物(例如房间的墙壁)来轻松实现。

void renderSelection(void) {glClearColor(0.0f, 0.0f, 0.0f, 0.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//set matrices to identity...// set camera as in the regular rendering function....// use the selection shaderglUseProgram(selectionProgramID);//perform the geometric transformations to place the first pawn...// set the uniform with the appropriate color codeglProgramUniform1i(selectionProgramID, codeVarLocation, 1);// draw first pawn...// repeat the above steps for the remaining objects, using different codes//don't swap buffers//glutSwapBuffers();// restore clear color if neededglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}

下载:

  • 带有完整源代码和着色器的VS2010项目(ZIP)

该项目需要glew和freeglut 或 glut。


欢迎关注我的公众号 江达小记

OpenGL3.3鼠标拾取物体相关推荐

  1. Unity3D 入门小技巧——鼠标拾取并移动物体

    一.鼠标拾取物体的原理 在Unity3D当中,想要在观察面(Aspect)中拾取物体(有碰撞属性)的方法一般如下: 1.声明一个观察的摄像机.一个从摄像机原点出发的射线Ray以及一个用于检测碰撞的Ra ...

  2. Unity3D 类似COC的鼠标拾取游戏物体并在限定区域摆放

    using UnityEngine; using System.Collections;public class MoveObject : MonoBehaviour {/// <summary ...

  3. Three.js - 鼠标拾取(射线追踪法)(十九)

    射线追踪法 射线追踪法是最常见的方法,因为three.js提供了Raycaster对象来实现它. 原理:从鼠标处发射一条射线,穿透场景的视椎体,通过计算,找出与射线相交的对象. Raycaster 属 ...

  4. DirectX11进阶5_硬件实例化与视锥体裁剪及鼠标拾取交互

    一.硬件实例化(Hardware Instancing) 硬件实例化指的是在场景中绘制同一个物体多次,但是是以不同的位置.旋转.缩放.材质以及纹理来绘制(比如一棵树可能会被多次使用以构建出一片森林). ...

  5. 鼠标拾取(光线拾取)

    作者:桑榆 QQ:934440653 有问题,评论留言,或qq联系 案例效果 鼠标拾取 主要代码 1.创建矩形 (1)6-8行限制随机产生的矩形的长.宽.纵深不超过20: (2)14-16行限制随机产 ...

  6. Unity鼠标拖动物体、按下鼠标左键旋转观察物体、鼠标滚轮缩放视野

    如题目所示,本文实现这三个效果.所有代码都在pc端成功运行,移植到手机端改变相应的判断条件即可,核心算法没有问题. 一. 鼠标拖拽移动物体 效果演示 源代码 public class mousedra ...

  7. 鼠标实现物体拖动带拖尾的效果

    今天,小编为大家分享一下,用鼠标拖动物体,还带一个小尾巴效果哈![+V:Anime__King] 1.新建一个unity项目,新建一个测试场景.一个MoveTo.cs类附加在GameObject(命名 ...

  8. 3d 数学(叉乘、四元素、四元素旋转、四元素和四元素相乘、鼠标控制物体旋转、发射子弹、环形发射子弹、子弹缓冲池)

    目录 1.叉乘 2.四元素 3.四元素旋转 4.四元素和四元素相乘 5.鼠标控制物体旋转 6.发射子弹 7.环形发射子弹 8.子弹缓冲池 1.叉乘 两个向量叉乘,得到一个新的向量,新向量跟原始两个向量 ...

  9. ue4 拾取物体注意问题

    拾取物体步骤: 1.创建物体 蓝图类,加上sphere collision和skeletalmesh(骨架网格体)(如果是静态网格体用staticMesh),细节面板skeletalmesh选择附加物 ...

最新文章

  1. 基于pytorch的模型压缩和模型剪枝Model Prune示例
  2. 什么是清华大学的“三好”学生?
  3. Vue2.0 入门 安装Vue-cli
  4. 利用Maya进行论文中网格动画数据的渲染
  5. Linux-通过XShell使用sz命令提示找不到
  6. SAP Spartacus Spinner控件显示原理
  7. redis将散裂中某个值自增_0基础掌握Django框架(49)Redis
  8. Oracle实现数据不存在则插入,数据存在则更新(insert or update)
  9. C#不同操作系统下,界面大小不一的原因
  10. Python 实现最简单的元胞自动机
  11. 乐高叉车wedo教案_乐高 WEDO自带12个活动教学参考书.pdf
  12. java while循环 计算机,Java while和do ... while循环 - 芒果文档
  13. 合唱队形(最大上升子序列)
  14. vue 高德地图点击获取坐标与地理位置
  15. hortonworks_具有在IBM POWER8上运行的Hortonworks Data Platform(HDP)的SAS软件
  16. cv2 在图片上画线
  17. Youtube 预装到系统后运行报错
  18. 调试WebService的一个很好的工具
  19. DIV和Table的水平、垂直居中
  20. 89.网络安全渗透测试—[常规漏洞挖掘与利用篇5]—[文件包含漏洞详解实战示例]

热门文章

  1. 冬季养胃的几个好习惯
  2. python scipy 插值函数
  3. 【Git实战技巧】恢复被强制推送push失踪的代码
  4. C++ int long long double 等数据范围!
  5. 鸟哥的Linux私房菜-基础学习篇(第三版)
  6. Windows安装docker,和配置镜像加速地址
  7. 红米K30至尊纪念版和红米K30 Pro有什么区别?
  8. RabbitMQ端口号解析
  9. 配置springboot使用c3p0连接池
  10. TF乘法之multiply、matmul、*