用唯一的颜色id编号实现OpenGL选择功能(OpenGL Selection Using Unique Color IDs )
OpenGL Selection Using Unique Color IDs
用唯一的颜色id编号实现OpenGL选择功能
引言
有好几种方式可以实现物体拾取. 利用 OpenGL你可以利用专用的选择缓冲区,可以让你选择场景里的物体,每个物体已经预先给定唯一编号。. 这种方法的入门可以在这儿找到: OpenGL:导学:拾取
这儿还有另一种方法,这种方法不仅可以用在OpenGL apps下,也可以用在 DirectX apps. 例为了这篇导学,下面给出的代码将使用OpenGL.
它是如何起作用的
本来这种方法就是有效的,是因为每一个物体都被赋予了一个唯一的颜色在我们的场景中. 既然我们用24位颜色结构,这意味着我们可以有很多的物体可以有唯一的颜色。如果我们希望知道那个物体被使用者单击了,我们仅仅需要按照下面的做即可:
把场景纹理渲染,光线,雾效关闭了
用唯一的颜色渲染每一个物体
读取鼠标单击处的颜色缓冲区后面的数据
遍历物体列表来查看颜色id是否匹配
如果找到了一个,我们实现了一次选择
这是极其容易引用的并且不是依赖于API函数。
因此我们必须要做的第一件事,就是为我们场景里的每一物体声明一个基类。这个基类必须要注意初始化每一个物体的颜色id。这个可以在类中声明一个静态变量来实现。
gColorID[3], 并将它设置为黑色(0, 0, 0). 从这儿,每一个物体被建立,gColorID是递增的。第一个元素或红色通道首先递增赋值。然后当它的值递增到255, 它将被重新设回到0 并给第二个元素或绿色通道递增赋值。第三个也就是蓝色通道做相同处理。
class BaseObject
{
private:
unsigned char m_colorID[3];
static unsigned char gColorID[3];
public:
BaseObject()
{
m_colorID[0] = gColorID[0];
m_colorID[1] = gColorID[1];
m_colorID[2] = gColorID[2];
gColorID[0]++;
if(gColorID[0] > 255)
{
gColorID[0] = 0;
gColorID[1]++;
if(gColorID[1] > 255)
{
gColorID[1] = 0;
gColorID[2]++;
}
}
}
~BaseObject() {};
};
unsigned char BaseObject::gColorID[3] = {0, 0, 0};
现在我们在我们的游戏或app中声明的每一个类都应该继承这个基类。所以假设你想要声明一个场景物体类,你可以简单的插入一个函数仅用它的颜色id来渲染物体。因此在下面的示例代码中在picking函数的下部就是来渲染场景物体用一个固定的颜色,物体的颜色id颜色是特别的.
class SceneObject : public BaseObject
{
private:
float m_position[3];
string m_name;
public:
SceneObject();
~SceneObject();
void Render();
void Picking()
{
// 设置网格位置
glPushMatrix();
glTranslatef(m_position[0], m_position[1], m_position[2]);
glColor3f(m_colorID[0]/255.0f, m_colorID[1]/255.0f, m_colorID[2]/255.0f);
// 在这儿渲染物体的顶点
glPopMatrix();
}
};
class SceneObject : public BaseObject
{
private:
float m_position[3];
string m_name;
public:
SceneObject();
~SceneObject();
void Render();
void Picking()
{
//设置网格位置
glPushMatrix();
glTranslatef(m_position[0], m_position[1], m_position[2]);
glColor3f(m_colorID[0]/255.0f, m_colorID[1]/255.0f, m_colorID[2]/255.0f);
//在这儿渲染物体的顶点
glPopMatrix();
}
};
现在和注明的那样在我们需要关闭纹理,光线和雾效之前。我们可能仅仅是想要单击鼠标按键时才显示物体选择。所以在鼠标按键事件中,我们渲染场景中每一个物体到颜色缓冲区,读取颜色信息并搜寻我们的物体列表。
void MouseDownEvent(int x, int y)
{
// 关闭纹理,光线和雾效
glDisable(GL_TEXTURE_2D);
glDisable(GL_FOG);
glDisable(GL_LIGHTING);
// 渲染场景里的每一个物体
// 假设每一个物体被存储在一个叫SceneObjects的容器里
list<SceneObject *>::iterator itr = SceneObjects.begin();
while(itr != SceneObjects.end())
{
(*itr)->Picking();
itr++;
}
// 从帧缓存中获取颜色信息
unsigned char pixel[3];
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
// 现在我们拾取的屏幕像素被存储到pixel[3]
// 所以我们遍历我们的物体列表来搜寻我们选择选择的物体
itr = SceneObjects.begin();
while(itr != SceneObjects.end())
{
if((*itr)->m_colorID[0] == pixel[0] && (*itr)->m_colorID[1] == pixel[1] && (*itr)->m_colorID[2] == pixel[2])
{
// 选择出标记的物体
SetSelected((*itr);
break;
}
itr++;
}
}
那就是它!程序运行相当迅速,取决于你的场景中有多少物体。它是独立的API并且可以被直接执行。如果因为一些疯狂的原因,你感觉仅仅用24位不能表示你场景里的所有的物体,那么你可以把alpha通道增加到每一个物体的colorI D中,然后再读取像素,你可以把GL_RGB改为GL_RGBA。
unsigned char pixels[4];
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
同样的,你们中有些人可能会想为什么在glReadPixels的y坐标要这样写,我们传递进去的参数是
viewport[3] - y
这是因为OpenGL 设置窗口的方式的原因, 不同的是窗口的左下角是原点。而在Windows 中左上角是原点,我们必须用窗口的高度减去鼠标的y坐标来获得正确的OpenGL 窗口y坐标。
为了在实践中看一下这项技术的效果,你可以在运行地面编辑软件Freeworld3D。这个软件用了这项技术.不仅仅是为了实现物体选择,还为了当平移,旋转和缩放物体时实现轴线选择(Axis selection不知道翻译的真却不?) This software uses this technique, not only for object selection, but also for Axis selection when translating, rotating and scaling objects. 这是一个很强大并且很灵活的实现拾取的方法。
从这儿可以检索到原文 http://gpwiki.org/index.php/OpenGL_Selection_Using_Unique_Color_IDs
这几天为了实现物体的颜色拾取功能,遇到问题了,于是把这个给翻译了一下,希望对大家有所帮助……
用唯一的颜色id编号实现OpenGL选择功能(OpenGL Selection Using Unique Color IDs )相关推荐
- html 生成唯一码,生成唯一32位ID编码代码,以满足对ID编号的唯一性加资源性解决问题...
生成唯一32位ID编码代码,以满足对ID编号的唯一性加资源性解决问题 package com.huayu.common; /* * RandomGUID from http://www.javaexc ...
- 关于android设备唯一区分device id的取得
2019独角兽企业重金招聘Python工程师标准>>> 有些apk为了区分唯一设备,需要用到一个device id. 1. 取得设备的MAC address 如果用户没有通过w ...
- mysql id div 1000000_Mysql数据自动ID编号,如何解决?
Mysql数据自动ID编号,如何解决? 目前遇到了一个CD_ID MySQL数据库中无法自动编号,因TQmusic网站会员以前是从1开始自动编号,第一次调整编号已经在3年前,从1位数生成7位数的ID, ...
- Android能够获取到唯一的设备ID吗?
Android是否有唯一的设备ID,如果有的话,该怎样快速有效获取? Settings.Secure#ANDROID_ID 返回Android ID ,是一个64位的16进制字符串 1 2 3 imp ...
- UE风格化Day11-用颜色ID处理贴图材质与模型分区问题
把楼梯材质上完之后导出,发现大问题.. 之前不是说在maya里面分不同颜色材质,然后在SP里可以分开着色器嘛,然后导出的时候发现不对啊..导出的是每个着色器一套图,然后我一个模型还分成5个小模型,5个 ...
- 创建一个唯一的 session ID
在网站开发的时候,常常需要生成一个唯一的的会话(session)id,这个会话 id 存储在 cookie 中或者在其它安全的地方.: create a unique session idinput ...
- OpenGL(一)——OpenGL入门
1.概念 2D+透视 = 3D 3D术语: 光栅化:实际绘制或填充每个顶点之间的像素形成过程 着色:沿着顶点之间改变颜色值,能够轻松创建光照照射到一个立方体的效果 纹理贴图:将纹理图片附着到你绘图的图 ...
- 音视频开发(十四):OpenGL 与 OpenGL ES2区别
什么是OpenGL ES? OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言.跨平台的编程接口规格的专业的图形程序接口.它用于三维图像(二维的亦可),是一个功能强 ...
- OpenGL 和 OpenGL ES基础知识
当今许多视觉应用程序,从简单的游戏到高级工程领域,都使用OpenGL(Open Graphics Library)和OpenGL ES(OpenGL for Embedded Systems)作为其图 ...
最新文章
- 68页PPT,读懂中、美、德三国智能制造战略!
- Kafka 为什么那么快的 6 个原因!
- Socket.IO介绍:支持WebSocket、用于WEB端的即时通讯的框架
- vue 中的el表达式_Vue中vue.filter()的使用方法介绍(过滤)
- 栈的应用--进制转换
- MATLAB保存数据为dat格式,將matlab中數據保存為txt或dat格式
- 实时操作系统主流调度方法RMS
- 从发小(一起长大的玩伴)聚会引发的思考
- 自动,MySQL触发器,完整详细可收藏
- 【今日CV 计算机视觉论文速览 143期】Mon, 15 Jul 2019
- Mybatis框架 导入/导出功能的实现
- mysql+导入+306_mysql常用命令二
- 学习笔记_vnpy实战培训day04_作业
- usb管控软件_外发SMT贴片加工质量管控要求
- 稳健估计,P范数最小法
- 信息文档分工会在运动会象棋比赛中夺得佳绩
- Android开发布局 案例二
- 汉语字典_Android版最新官方版,汉语字典专业版2020
- 微信小程序获得二维码
- P124黎曼可积性刻画 的两个备注
热门文章
- mvc路由原理 php_PHP实战002:CodeIgniter安装和入门使用
- 天融信防火墙web配置_天融信协议转换交付系统震撼发布——IPv4/IPv6融合改造利器...
- 《Google软件测试之道》告诉你什么是测试
- c语言 recv_sin,C++_C语言中经socket接收数据的相关函数详解,recv()函数:
头文件:#incl - phpStudy...
- cad缺失字体补全工具_CAD图纸字体不全怎么办?只要修改字体映射表就可以轻松解决了...
- Python终端输出中文
- 谈谈我在敏捷开发中遇到的那些坑
- 计算机科学与技术毕业生简历,计算机科学与技术专业应届毕业生简历范文
- 用@Scheduled完成定时任务
- oracle日志不应用,dg报ORA-600日志不能应用