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 )相关推荐

  1. html 生成唯一码,生成唯一32位ID编码代码,以满足对ID编号的唯一性加资源性解决问题...

    生成唯一32位ID编码代码,以满足对ID编号的唯一性加资源性解决问题 package com.huayu.common; /* * RandomGUID from http://www.javaexc ...

  2. 关于android设备唯一区分device id的取得

    2019独角兽企业重金招聘Python工程师标准>>> 有些apk为了区分唯一设备,需要用到一个device id. 1. 取得设备的MAC address    如果用户没有通过w ...

  3. mysql id div 1000000_Mysql数据自动ID编号,如何解决?

    Mysql数据自动ID编号,如何解决? 目前遇到了一个CD_ID MySQL数据库中无法自动编号,因TQmusic网站会员以前是从1开始自动编号,第一次调整编号已经在3年前,从1位数生成7位数的ID, ...

  4. Android能够获取到唯一的设备ID吗?

    Android是否有唯一的设备ID,如果有的话,该怎样快速有效获取? Settings.Secure#ANDROID_ID 返回Android ID ,是一个64位的16进制字符串 1 2 3 imp ...

  5. UE风格化Day11-用颜色ID处理贴图材质与模型分区问题

    把楼梯材质上完之后导出,发现大问题.. 之前不是说在maya里面分不同颜色材质,然后在SP里可以分开着色器嘛,然后导出的时候发现不对啊..导出的是每个着色器一套图,然后我一个模型还分成5个小模型,5个 ...

  6. 创建一个唯一的 session ID

    在网站开发的时候,常常需要生成一个唯一的的会话(session)id,这个会话 id 存储在 cookie 中或者在其它安全的地方.: create a unique session idinput ...

  7. OpenGL(一)——OpenGL入门

    1.概念 2D+透视 = 3D 3D术语: 光栅化:实际绘制或填充每个顶点之间的像素形成过程 着色:沿着顶点之间改变颜色值,能够轻松创建光照照射到一个立方体的效果 纹理贴图:将纹理图片附着到你绘图的图 ...

  8. 音视频开发(十四):OpenGL 与 OpenGL ES2区别

    什么是OpenGL ES? OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言.跨平台的编程接口规格的专业的图形程序接口.它用于三维图像(二维的亦可),是一个功能强 ...

  9. OpenGL 和 OpenGL ES基础知识

    当今许多视觉应用程序,从简单的游戏到高级工程领域,都使用OpenGL(Open Graphics Library)和OpenGL ES(OpenGL for Embedded Systems)作为其图 ...

最新文章

  1. 68页PPT,读懂中、美、德三国智能制造战略!
  2. Kafka 为什么那么快的 6 个原因!
  3. Socket.IO介绍:支持WebSocket、用于WEB端的即时通讯的框架
  4. vue 中的el表达式_Vue中vue.filter()的使用方法介绍(过滤)
  5. 栈的应用--进制转换
  6. MATLAB保存数据为dat格式,將matlab中數據保存為txt或dat格式
  7. 实时操作系统主流调度方法RMS
  8. 从发小(一起长大的玩伴)聚会引发的思考
  9. 自动,MySQL触发器,完整详细可收藏
  10. 【今日CV 计算机视觉论文速览 143期】Mon, 15 Jul 2019
  11. Mybatis框架 导入/导出功能的实现
  12. mysql+导入+306_mysql常用命令二
  13. 学习笔记_vnpy实战培训day04_作业
  14. usb管控软件_外发SMT贴片加工质量管控要求
  15. 稳健估计,P范数最小法
  16. 信息文档分工会在运动会象棋比赛中夺得佳绩
  17. Android开发布局 案例二
  18. 汉语字典_Android版最新官方版,汉语字典专业版2020
  19. 微信小程序获得二维码
  20. P124黎曼可积性刻画 的两个备注

热门文章

  1. mvc路由原理 php_PHP实战002:CodeIgniter安装和入门使用
  2. 天融信防火墙web配置_天融信协议转换交付系统震撼发布——IPv4/IPv6融合改造利器...
  3. 《Google软件测试之道》告诉你什么是测试
  4. c语言 recv_sin,C++_C语言中经socket接收数据的相关函数详解,recv()函数: 头文件:#incl - phpStudy...
  5. cad缺失字体补全工具_CAD图纸字体不全怎么办?只要修改字体映射表就可以轻松解决了...
  6. Python终端输出中文
  7. 谈谈我在敏捷开发中遇到的那些坑
  8. 计算机科学与技术毕业生简历,计算机科学与技术专业应届毕业生简历范文
  9. 用@Scheduled完成定时任务
  10. oracle日志不应用,dg报ORA-600日志不能应用