﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-前进的路上-随笔分类-OpenGL</title><link>http://www.cppblog.com/wc250en007/category/13981.html</link><description>前进的路上</description><language>zh-cn</language><lastBuildDate>Mon, 23 Jul 2012 08:02:48 GMT</lastBuildDate><pubDate>Mon, 23 Jul 2012 08:02:48 GMT</pubDate><ttl>60</ttl><item><title>glBlendFunc颜色混合</title><link>http://www.cppblog.com/wc250en007/archive/2012/07/18/184088.html</link><dc:creator>Let me see see</dc:creator><author>Let me see see</author><pubDate>Wed, 18 Jul 2012 09:32:00 GMT</pubDate><guid>http://www.cppblog.com/wc250en007/archive/2012/07/18/184088.html</guid><wfw:comment>http://www.cppblog.com/wc250en007/comments/184088.html</wfw:comment><comments>http://www.cppblog.com/wc250en007/archive/2012/07/18/184088.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wc250en007/comments/commentRss/184088.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wc250en007/services/trackbacks/184088.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 混合是什么呢？混合就是把两种颜色混在一起。具体一点，就是把某一像素位置原来的颜色和将要画上去的颜色，通过某种方式混在一起，从而实现特殊的效果。假设我们需要绘制这样一个场景：透过红色的玻璃去看绿色的物体，那么可以先绘制绿色的物体，再绘制红色玻璃。在绘制红色玻璃的时候，利用&#8220;混合&#8221;功能，把将要绘制上去的红色和原来的绿色进行混合，于是得到一种新的颜色，看上去就好像玻璃是半透明的。...&nbsp;&nbsp;<a href='http://www.cppblog.com/wc250en007/archive/2012/07/18/184088.html'>阅读全文</a><img src ="http://www.cppblog.com/wc250en007/aggbug/184088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wc250en007/" target="_blank">Let me see see</a> 2012-07-18 17:32 <a href="http://www.cppblog.com/wc250en007/archive/2012/07/18/184088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GLUT框架</title><link>http://www.cppblog.com/wc250en007/archive/2010/06/19/glutFrame.html</link><dc:creator>Let me see see</dc:creator><author>Let me see see</author><pubDate>Sat, 19 Jun 2010 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/wc250en007/archive/2010/06/19/glutFrame.html</guid><wfw:comment>http://www.cppblog.com/wc250en007/comments/118229.html</wfw:comment><comments>http://www.cppblog.com/wc250en007/archive/2010/06/19/glutFrame.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wc250en007/comments/commentRss/118229.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wc250en007/services/trackbacks/118229.html</trackback:ping><description><![CDATA[通过 C语言编写 GLUT 程序, 你需要以下三个文件: <br>GLUT.H - 你需要在你的源代码中包含这个文件. 通常情况下, 这个文件应该放在你系统的包含目录下的 GL 文件夹中 <br>GLUT.LIB (SGI windows版本) 以及 glut32.lib (微软版本) - 这个文件必须被连接到你的程序中, 确保它放在 LIB 目录中 <br>glut32.dll (Windows) 和 glut.dll (SGI Windows版本) - 根据你所使用的OpenGL选择一个, 如果你正在使用微软公司的版本, 那么你必须选择 glut32.dll. 你应该把DLL放置在你的系统文件夹中<br>设置Visual C/C++ 6.0<br>Visual C/C++的工程有两个重要选项: Console (控制台) 和 Win32. 应用程序将会有两个窗口: 一个控制台窗口, 以及一个 OpenGL 窗口. 选择 Win32 仍然可以让你在不需要关心Windows程序设计的情况下编写 GLUT 程序. 你需要做以下设置: <br>选择 Project -&gt; settings <br>选择 Link 选项卡 <br>从 Category 中选择 Output <br>在 Entry-point synmbol 文本框中键入 mainCRTStartup<br>对于已存在的控制台工程, 有一个简单的办法将它转换成Win32应用程序: <br>根据上面的步骤修改入口点 <br>在 Project options 文本框中用 subsystem:windows 覆盖 subsystem:console<br>或者你可以直接在你的源代码开头处添加:<br><br>代码 <br><br>// #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) <br><br>注意: 这是一行注释<br>如此一来, 应用程序就不会出现控制台窗口, 而只是一个 OpenGL 窗口了. 在Visual C/C++ 中你需要一下步骤来连接一个 GLUT 程序: <br>选择 Proejct/Settings <br>选择 LINK 选项卡 <br>添加一下文件到 Object/library: opengl32.lib glut32.lib glu32.lib<br>请注意: 我同时添加了glu32.lib 和 opengl32.lib. 他们是标准OpenGL库.<br><br>好的,现在一切准备就绪, 我们可以开始编写 GLUT 应用程序了. 如果有任何不清楚的地方, 请您告诉我, 您的回馈非常之重要.<br><br>在这一节中, 我们将会建造应用程序的主函数(main function). 主函数将会将会完成程序的初始化并启动事件处理循环. 所有函数都有一个前缀 glut , 初始化函数的前缀是 glutInit. 我们首先必须调用函数 glutInit.<br><br>代码 <br><br>void glutInit(int *argc, char **argv); <br>//参数:<br>//argc - 一个指向主函数 argc 变量的 未经修改 的指针. <br>//argv - 一个指向主函数 argv 变量的 未经修改 的指针. <br> <br>初始化 GLUT 本身以后, 我们将会定义我们的窗口. 首先, 我们建立窗口的位置, 例如: 在窗口的左上角. 要实现这个功能, 我们需要调用函数 glutWindowsPosition.<br><br>代码 <br><br>void glutInitWindowPosition(int x, int y); <br>//参数:<br>//x- 距离屏幕左边的像素数. 默认值是 -1, 由Windows系统决定窗口的位置. 如果没有没有采用默认值, 那么你应该使用一个合适正值作为实参.<br>//y- 距离屏幕屏幕顶端的像素数, 其余同上.<br>请注意, 这些参数只是给窗口管理器的一个建议值. 我们创建的窗口可能会处于不同的位置上, 不过这很少发生. 接下来我们要决定窗口的大小, 为了做到这一点, 我们需要使用函数 glutInitWindowSize.<br><br>代码 <br><br>void glutInitWindowSize(int width, int height); <br>参数:<br>width - 窗口的宽度<br>height - 窗口的高度<br> <br>同样的, 高和宽也只是一个建议值, 请避免使用负值.<br>然后我们需要定义显示模式, 我们使用 glutInitDisplayMode 函数.<br><br>代码 <br><br>void glutInitDisplayMode(unsigned int mode) <br>参数:<br>mode - 指定显示模式<br>//mode 参数是一个 GLUT 预定义常数的复合布尔型 (位或). 你可以使用 mode 来指定颜色, 以及缓冲区的数量和类型.<br><br>这些常数是:<br>GLUT_RGBA or GLUT_RGB - 默认颜色模式 <br>GLUT_INDEX - 颜色索引(?) 模式<br><br>显示模式允许你选择单或双缓冲区窗口. 相关常数是:<br>GLUT_SINGLE - 单缓冲区窗口 <br>GLUT_DOUBLE - 双缓冲区, 平滑动画需要<br><br>这里还有更多关于缓冲区的常数:<br>GLUT_ACCUM - 聚集缓冲区 <br>GLUT_STENCIL - The stencil buffer (...翻译不出来) <br>GLUT_DEPTH - 深度缓冲区<br><br>现在, 假如你想要创建一个RGB窗口, 单缓冲以及一个深度缓冲区. 你需要把相关的常数去 OR 在一起来创建一个正确的常口<br><br>代码 <br>...<br>glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT DEPTH);<br>...<br>经过以上步骤, 我们可以调用 glutCreateWindow 函数了<br><br>代码 <br><br>int glutCreateWindow(char *title); <br><br>参数:<br>title - 窗口标题<br> <br>glutCreateWindows 函数的返回值是索创建窗口的标示符. 你以后会用到这个标示符.<br>现在, 我们把上面的代码集合起来, 看看一次完整的窗口初始化:<br><br>代码 <br><br>#include <br><br>void main(int argc, char **argv) {<br>glutInit(&amp;argc, argv);<br>glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);<br>glutInitWindowPosition(100,100);<br>glutInitWindowSize(320,320);<br>glutCreateWindow("3D Tech- GLUT Tutorial");<br>}<br> <br>请注意包含文件, 我们需要 GLUT 的包含文件.<br><br>如果你运行了这段代码, 那么你将看到一个黑色的控制台窗口, 但是没有任何OpenGL窗口, 几秒钟以后, 这个窗口也消失了. 在我们开始渲染之前 我们还要做两件事情: 首先是告诉 GLUT 系统负责渲染的函数:<br>我们来创建一个渲染函数的例子. 这个函数将会清空颜色缓冲区, 并画出两个三角形:<br><br>代码 <br><br>void renderScene(void) {<br>glClear(GL_COLOR_BUFFER_BIT);<br>glBegin(GL_TRIANGLES);<br> glVertex3f(-0.5,-0.5,0.0);<br> glVertex3f(0.5,0.0,0.0);<br> glVertex3f(0.0,0.5,0.0);<br>glEnd();<br>glFlush();<br>}<br><br>你可以给函数起任意的名字. 然而, 你必须告诉 GLUT 来使用这个函数进行渲染. 这叫做 注册回叫(callback) 函数. GLUT 将会在需要渲染的时候呼叫这个函数. 现在我们来告诉 GLUT 一旦我们的窗口被破坏(注意: 当窗口第一次被创建的时候, 这个函数也会被呼叫)<br>, 就调用renderScene函数. GLUT 中有一个函数接受一个函数指针作为参数, 它将这个指针指向的函数作为渲染函数. <br><br>代码 <br><br>void glutDisplayFunc(void (*func)(void)); <br>参数:<br>func - 渲染函数指针, NULL在这里非法 <br> <br>One last thing missing, that is telling GLUT that we're ready to get in the application event processing loop. GLUT provides a function that gets the application in a never ending loop, always waiting for the next event to process. The GLUT function is glutMainLoop, and the syntax is as follows: <br><br>我们最后要做, 就是让程序进入事件处理循环. GLUT 给我们准备了一个函数来使程序进入一个无限循环(死循环), 永远在等待下一个需要处理的事件. 这个函数就是 glutMainLoop:<br><br>代码 <br><br>void glutMainLoop(void) <br> <br>The code so far is presented bellow. Note that we've added an include statement in order to start using standard OpenGL functions, like glClear, glBegin, glVertex3f, and glEnd. <br><br>以下是完整的代码. 我们添加了一个新的包含文件, 以便于我们使用OpenGL的函数, 比如 glClear, glBegin, glVertex3f 和 glEnd.<br><br>如果你运行这你将会看到一个控制台窗口, 然后是一个画有白色三角形OpenGL窗口<br><br>代码 <br><br>#include "gl/glut.h"<br>void renderScene(void) {<br>glClear(GL_COLOR_BUFFER_BIT);<br>glBegin(GL_TRIANGLES);<br>glVertex3f(-0.5,-0.5,0.0);<br>glVertex3f(0.5,0.0,0.0);<br>glVertex3f(0.0,0.5,0.0);<br>glEnd();<br>glFlush();<br>}<br><br>void main(int argc, char **argv) {<br>glutInit(&amp;argc, argv);<br>glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);<br>glutInitWindowPosition(100,100);<br>glutInitWindowSize(320,320);<br>glutCreateWindow("3D Tech- GLUT Tutorial");<br>glutDisplayFunc(renderScene);<br>glutMainLoop();<br>}<br><br><br>、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、<br>转自：<a href="http://blog.tianya.cn/blogger/post_show.asp?BlogID=80680&amp;PostID=2276189&amp;idWriter=0&amp;Key=0">http://blog.tianya.cn/blogger/post_show.asp?BlogID=80680&amp;PostID=2276189&amp;idWriter=0&amp;Key=0</a><br><br>出现无法解析符号：<br>
<ol>
    <li class=alt><span>1&gt;GEARS.obj&nbsp;:&nbsp;error&nbsp;LNK2019:&nbsp;无法解析的外部符号&nbsp;___glutInitWithExit@12，该符号在函数&nbsp;_glutInit_ATEXIT_HACK@8&nbsp;中被引用 &nbsp;&nbsp;</span></li>
    <li class=""><span>1&gt;GEARS.obj&nbsp;:&nbsp;error&nbsp;LNK2019:&nbsp;无法解析的外部符号&nbsp;___glutCreateWindowWithExit@8，该符号在函数&nbsp;_glutCreateWindow_ATEXIT_HACK@4&nbsp;中被引</span></li>
</ol>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glut.h的文件内容</span><span>于是，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note&nbsp;that&nbsp;the&nbsp;__glut*WithExit&nbsp;routines&nbsp;should&nbsp;NEVER&nbsp;be&nbsp;called&nbsp;directly.&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;To&nbsp;avoid&nbsp;the&nbsp;atexit&nbsp;workaround,&nbsp;#define&nbsp;GLUT_DISABLE_ATEXIT_HACK.&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在#include&nbsp;&lt;GL/glut.h&gt;前面加上了一句：&nbsp;</span><span class=preprocessor></span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span><span class=preprocessor><font color=#808080>#define&nbsp;GLUT_DISABLE_ATEXIT_HACK&nbsp;</font></span><span>&nbsp;&nbsp;<br></span></span></p>
<span><br>参考GLUTAPI：<a href="http://www.opengl.org/documentation/specs/glut/spec3/spec3.html">http://www.opengl.org/documentation/specs/glut/spec3/spec3.html</a><br><a title=GLUTFrame下载 href="http://www.cppblog.com/Files/wc250en007/OpenGL/GLUTFrame.rar">GLUTFrame实例下载</a></span>
<img src ="http://www.cppblog.com/wc250en007/aggbug/118229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wc250en007/" target="_blank">Let me see see</a> 2010-06-19 11:11 <a href="http://www.cppblog.com/wc250en007/archive/2010/06/19/glutFrame.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用OpenGL实现三维坐标的鼠标拣选（ 二 ）</title><link>http://www.cppblog.com/wc250en007/archive/2010/06/07/SelectObj.html</link><dc:creator>Let me see see</dc:creator><author>Let me see see</author><pubDate>Mon, 07 Jun 2010 06:56:00 GMT</pubDate><guid>http://www.cppblog.com/wc250en007/archive/2010/06/07/SelectObj.html</guid><wfw:comment>http://www.cppblog.com/wc250en007/comments/117319.html</wfw:comment><comments>http://www.cppblog.com/wc250en007/archive/2010/06/07/SelectObj.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wc250en007/comments/commentRss/117319.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wc250en007/services/trackbacks/117319.html</trackback:ping><description><![CDATA[我们可以通过gluUnProject函数来求得世界坐标<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ILGameModule::getWorldPos(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;x,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;y,&nbsp;vec3</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;vWorld&nbsp;)<br><img id=Codehighlighter1_61_756_Open_Image onclick="this.style.display='none'; Codehighlighter1_61_756_Open_Text.style.display='none'; Codehighlighter1_61_756_Closed_Image.style.display='inline'; Codehighlighter1_61_756_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_61_756_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_61_756_Closed_Text.style.display='none'; Codehighlighter1_61_756_Open_Image.style.display='inline'; Codehighlighter1_61_756_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_61_756_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_61_756_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX&nbsp;vx&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(JFIX)x;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX&nbsp;vy&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(JFIX)camera</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">viewport.h&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;y;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX&nbsp;winz&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">.f;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;glReadBuffer(GL_FRONT);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;glReadPixels(&nbsp;(JINT)vx,&nbsp;(JINT)vy,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;GL_DEPTH_COMPONENT,&nbsp;GL_FLOAT&nbsp;,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">winz&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">winz&nbsp;=&nbsp;getWinDepth(&nbsp;camera,&nbsp;1.f&nbsp;);</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;GLdouble&nbsp;model[&nbsp;</span><span style="COLOR: #000000">16</span><span style="COLOR: #000000">&nbsp;];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;GLdouble&nbsp;project[</span><span style="COLOR: #000000">16</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;mat4&nbsp;matView&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;camera</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">modelView.transpose();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;mat4&nbsp;matProj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;camera</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">projection.transpose();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pm&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;matView.ptr();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;matProj.ptr();<br><img id=Codehighlighter1_512_581_Open_Image onclick="this.style.display='none'; Codehighlighter1_512_581_Open_Text.style.display='none'; Codehighlighter1_512_581_Closed_Image.style.display='inline'; Codehighlighter1_512_581_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_512_581_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_512_581_Closed_Text.style.display='none'; Codehighlighter1_512_581_Open_Image.style.display='inline'; Codehighlighter1_512_581_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">16</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;)</span><span id=Codehighlighter1_512_581_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_512_581_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model[i]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(GLdouble)(pm[i]);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;project[i]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(GLdouble)(pj[i]);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;GLdouble&nbsp;lx,ly,lz;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;gluUnProject(&nbsp;vx,&nbsp;vy,&nbsp;winz,&nbsp;model,project,(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">camera</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">viewport,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lx,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ly,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lz&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;vWorld.x&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(JFIX)lx;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;vWorld.y&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(JFIX)ly;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;vWorld.z&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(JFIX)lz;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<br>求出的世界坐标MS不符合我们的要求，例如我点击了世界坐标的点击屏幕(sx,sy),利用getWorldPos还原后的世界坐标为（100，100，20 ），在（100，100，20）这个点画模型，<br>&nbsp;的确在鼠标点击位置，问题出现了: 还原后的世界坐标Z = 20,但是我们画的物体的高度要求是0的话，紧贴地面，会出现模型浮空<br>&nbsp;仅仅将Z=0，却使得点击仿佛偏移了<br><img height=236 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/selectObj.jpg" width=632 border=0><br>我们需要知道在拣选射线和我们想指定的高度面（如Z=0面）的交点，这个交点可定也在拣选射线上 vIntersection&nbsp; = vWorld + vOffset;<br>即在我们得到的世界坐标基础上，加上拣选射线的一个偏移值就得到了我们的交点（X', Y', 0 ）<br><img height=249 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/selectObj2.jpg" width=522 border=0><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #008000">//</span><span style="COLOR: #008000">vWorld世界坐标&nbsp;PLANE_Z&nbsp;Z平面,&nbsp;Z=0平面,返回和当前面相交的交点</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">snapWorldPos(&nbsp;vWorld,&nbsp;PLANE_Z,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">vWorld&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ILGameModule::snapWorldPos(&nbsp;vec3</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;vWorld,&nbsp;JINT&nbsp;nPlane,&nbsp;JFIX&nbsp;dist,&nbsp;vec3</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pOut&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // dist就是当前相交的面，以后也可以传入当前地形的高度getHeight(vWorld)<br><img id=Codehighlighter1_173_593_Open_Image onclick="this.style.display='none'; Codehighlighter1_173_593_Open_Text.style.display='none'; Codehighlighter1_173_593_Closed_Image.style.display='inline'; Codehighlighter1_173_593_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_173_593_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_173_593_Closed_Text.style.display='none'; Codehighlighter1_173_593_Open_Image.style.display='inline'; Codehighlighter1_173_593_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_173_593_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_173_593_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;vec3&nbsp;vdir&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;camera</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">pos&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;vWorld;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;vdir.normalise();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;vec3&nbsp;vPlane;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">switch</span><span style="COLOR: #000000">(&nbsp;nPlane&nbsp;)<br><img id=Codehighlighter1_263_404_Open_Image onclick="this.style.display='none'; Codehighlighter1_263_404_Open_Text.style.display='none'; Codehighlighter1_263_404_Closed_Image.style.display='inline'; Codehighlighter1_263_404_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_263_404_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_263_404_Closed_Text.style.display='none'; Codehighlighter1_263_404_Open_Image.style.display='inline'; Codehighlighter1_263_404_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_263_404_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_263_404_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;PLANE_X:&nbsp;vPlane&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vec3(&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;);&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;PLANE_Y:&nbsp;vPlane&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vec3(&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;);&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;PLANE_Z:&nbsp;vPlane&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vec3(&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;);&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX&nbsp;rate;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JFIX&nbsp;nf&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vdir.dot(vPlane);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;nf&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">.f&nbsp;)&nbsp;rate&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">.f;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rate&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;dist&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;vWorld.dot(vPlane)&nbsp;)</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">nf;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img id=Codehighlighter1_547_591_Open_Image onclick="this.style.display='none'; Codehighlighter1_547_591_Open_Text.style.display='none'; Codehighlighter1_547_591_Closed_Image.style.display='inline'; Codehighlighter1_547_591_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_547_591_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_547_591_Closed_Text.style.display='none'; Codehighlighter1_547_591_Open_Image.style.display='inline'; Codehighlighter1_547_591_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;pOut&nbsp;)</span><span id=Codehighlighter1_547_591_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_547_591_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vdir&nbsp;</span><span style="COLOR: #000000">*=</span><span style="COLOR: #000000">&nbsp;rate;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pOut&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vWorld&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;vdir;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<img src ="http://www.cppblog.com/wc250en007/aggbug/117319.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wc250en007/" target="_blank">Let me see see</a> 2010-06-07 14:56 <a href="http://www.cppblog.com/wc250en007/archive/2010/06/07/SelectObj.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用OpenGL实现三维坐标的鼠标拣选（一 ） 转</title><link>http://www.cppblog.com/wc250en007/archive/2010/06/05/OpenGLSelect.html</link><dc:creator>Let me see see</dc:creator><author>Let me see see</author><pubDate>Sat, 05 Jun 2010 10:45:00 GMT</pubDate><guid>http://www.cppblog.com/wc250en007/archive/2010/06/05/OpenGLSelect.html</guid><wfw:comment>http://www.cppblog.com/wc250en007/comments/117235.html</wfw:comment><comments>http://www.cppblog.com/wc250en007/archive/2010/06/05/OpenGLSelect.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wc250en007/comments/commentRss/117235.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wc250en007/services/trackbacks/117235.html</trackback:ping><description><![CDATA[使用OpenGL实现三维坐标的鼠标拣选<br>Implementation of RIP（Ray-Intersection-Penetration）<br>3D Coordinates Mouse Selection Using OpenGL <br>顾 露 （武汉理工大学 计算机系 中科院智能设计与智能制造研究所 湖北武汉 430070）<br>摘要（Abstract）：<br>本文提出并实现一种用于三维坐标拣选的RIP（Ray-Intersection-Penetration）方法。介绍了如何在已经渲染至窗口的三维场景<br>中，使用鼠标或者相关设备拣选特定三维对象的方法。此方法对于正交投影或透视投影均有效，相对于OpenGL自带的选择与反馈机制，本方法无论是拣选精度<br>还是算法实现效率均高出许多，是一种比较通用的解决方案。关键词（Keywords） 正交投影（Ortho-Projection）、透视投影（Perspective-Projection）<br>世界坐标系、屏幕坐标系、三维拣选、OpenGL <br>一、简介（Introduction）<br>OpenGL是一种比较&#8220;纯粹&#8221;的3D图形API，一般仅用于三维图形的渲染，对于特定领域的开发者（如游戏开发者）而言，如果选择使用<br>OpenGL进行开发，类似碰撞检测的机制就都需要自行编写了。但是由于鼠标在图形程序中的应用非常非常之广泛（例如现在已经很少有PC游戏能完全地脱离<br>鼠标），OpenGL在图形库的基础上添加了选择与反馈机制（Select &amp;<br>Feedback）来满足用户使用鼠标实时操作三维图形的需要。但由于种种原因，我们需要更为特殊的选择机制以满足特定需求，在这里我们提出了一种简单迅<br>速的RIP（Ray-Intersection-Penetration）方法，可以满足绝大多数典型应用的需要。<br>二、相关研究（Related Work） 用过OpenGL选择与反馈机制的开发者，或多或少可能都会觉得它难以令人满意。大致表现在下面几个方面：<br>一、 编写程序比较繁琐。<br>想要使用选择反馈机制就需要切换渲染模式，操作命名堆栈，计算拣选矩阵，检查选中记录，这些繁琐的步骤很容易出错，而且非常不便于调试，只会降低工作效率和热情。二、 只能做基于图元的选定。<br>如<br>下图（1 &#8211; a），使用GL_TRIANGLES绘制了一个三角形，三个顶点分别为<br>P1、P2和P3。若使用该机制，你将只能判断是否在三维场景中选中了这个三角形（用户点击处是否在P1、P2和P3的范围内），而无法判断用户是点击了<br>这个三角形哪一部分（是左边的m区域内还是右边的n区域内），因为所绘制的P1、P2和P3本身构成的三角形就是一个基本图元，对于拣选机制而言是不可分<br>的。当然，把这个三角形拆成两个三角形再分别进行测试也是一个可行的方案，可是看看图（1 &#8211; b），这可怎么拆呢？还有图（1 &#8211;<br>c）呢？另外，如果n和m两个平面不共面呢？对于使用者而言，OpenGL提供的拣选机制功能的确有限。<br><img height=245 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/select.jpg" width=514 border=0><br>三、降低了渲染效率。<br>OpenGL<br>中的选择和反馈是与普通渲染方式不同的一种特殊的渲染方式。我们使用时一般是先在帧缓存中渲染普通场景，然后进入选择模式重绘场景，此时帧缓存的内容并无<br>变化。也就是说，为了选择某些物体，我们需要在一帧中使用不同的渲染方式将其渲染两遍。我们知道对对象进行渲染是比较耗时的操作，当场景中需要选择的对象<br>多而杂的时候，采用这个机制是非常影响速度的。<br>另外在OpenGL红宝书中介绍了一种简便易行的办法：在后缓冲中使用不同的颜色重绘所有对象，每个对象用一个单色来标示其颜色，这样画好之后我们读取鼠<br>标所在点的颜色，就能够确定我们拣选了哪个物体。这种方法有一个缺陷，当场景中需要选择的对象的数目超出一定限度时，可能会出现标识数的溢出。对于这个问<br>题，红宝书给出的解决办法就是多次扫描。实践证明这种方法的确简便易行，但仍有不少局限性，而且做起来并不比第一种机制方便多少。限于篇幅，不再赘述。三、具体描述（Related Work） 看过了上面两种方法，我们会发现这两种方法都不是十分的方便，而且使用者不能对其进行完全的控制，不能精确地判定鼠标定位与实际的世界空间中三维坐标的关系。那么有什么更好的办法能够更简单更精确地对其加以控制呢？ 实际上此处给出的解决方案十分简单，就是一个很普通也很有用的 GLU 函数 gluUnProject()。<br>此函数的具体用途是将一个OpenGL视区内的二维点转换为与其对应的场景中的三维坐标。<br>转换过程如下图所示（由点P在窗口中的XY坐标得到其在三维空间中的世界坐标）：<br><img height=210 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/select2.jpg" width=538 border=0><br>这个函数在glu.h中的原型定义如下：int APIENTRY gluUnProject (<br>GLdouble winx, <br>GLdouble winy, <br>GLdouble winz, <br>const GLdouble modelMatrix[16], <br>const GLdouble projMatrix[16], <br>const GLint viewport[4], <br>GLdouble *objx, <br>GLdouble *objy, <br>GLdouble *objz);　　其中前三个值表示窗口坐标，中间三个分别为模型视图矩阵（Model/View Matrix），投影矩阵（Projection Matrix）和视区（ViewPort），最后三个为输出的世界坐标值。　　可能你会问：窗口坐标不是只有X轴和Y轴两个值么，怎么这里还有Z值？这就要从二维空间与三维空间的关系说起了。　<br>　众所周知，我们通过一个放置在三维世界中的摄像机，来观察当前场景中的对象。通过使用诸如gluPerspective()<br>这样的OpenGL函数，我们可以设置这个摄像机所能看到的视野的大小范围。这个视野的边界所围成的几何体是一个标准的平截头体（Frustum），可以<br>看做是金字塔状的几何体削去金字塔的上半部分后形成的一个台状物，如果还原成金字塔状，就得到了通常我们所说的视锥（View<br>Frustum）这个视锥的锥顶就是视点（View Point）也就是摄像机所在的位置。平截头体，视锥以及视点之间的关系，如下图所示：<br><img height=317 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/select3.jpg" width=324 border=0><br>在上面的图中，远裁剪面ABCD和近裁剪面A&#8217;B&#8217;C&#8217;D&#8217;构成了平截头体，加上虚线部分就是视锥，顶点O就是摄像机所在的视点。我们在窗口中所能看到的东东，全部都在此平截头体内。这跟前面的窗口坐标Z值有什么关系呢？看下图<br><img height=304 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/select4.jpg" width=344 border=0><br>如<br>此图所示，点P和点P&#8217;分别在远裁剪面ABCD和近裁剪面A&#8217;B&#8217;C&#8217;D&#8217;上。我们点击屏幕上的点P，反映到视锥中，就是选中了所有的从点P到点P&#8217;的<br>点。举个形象的例子，这就像是我们挽弓放箭，如果射出去的箭近乎笔直地飞出（假设力量非常之大近乎无穷），从挽弓的地点直至击中目标，在这条直线的轨迹上<br>任何物体都将被一穿而过。对应这里的情况，用户单击鼠标获得屏幕上的某一点，即是指定了从视点指向屏幕深处的某一方向，也就确定了屏幕上某条从O点出发的<br>射线（在图中即为OP）。在这里，我们称呼其为拣选射线。<br>因此，从窗口的XY坐标，我们仅仅只能获得一条出发自O点的拣选射线，并不能得到用户想要的点在这条射线上的确切位置。<br>这时候窗口坐标的Z值就能派上用场了。我们通过Z值，来指定我们想要的点在射线上的位置。假如用户点击了屏幕上的点（100,100）得到了这条射线OP，那么我们传入值1.0f就表示近裁剪面上的P点，而值0.0f则对应远裁剪面上的P&#8217;点。<br>这<br>样，我们通过引入一个窗口坐标的Z值，就能指定视锥内任意点的三维坐标。与此同时，我们还解决了前面红宝书给出的方法中存在的缺陷——同一位置上重叠物体<br>的选择问题。解决办法是：从屏幕坐标得到射线之后，分别让重叠的物体与该射线求交，得到的交点，然后根据这些与视点的远近确定选择的对象。如此我们就不必<br>受&#8220;仅仅只能选取屏幕中离观察者最近的物体&#8221;的限制了。这样一来，如果需要的话，我们甚至可以用代码来作一定的限定，通过判断交点与视点的距离，使得与该<br>拣选射线相交的物体中，离视点远的对象才能被选取，这样就能够对那些暂时被其他对象遮住的物体进行选取。<br>至于如何求拣选射线与对象的交点，在各种图形学的书中的数学部分均有讲述，在此不再赘述。<br>四、例程（Sample Code Fragment）<br><br>前面讲述了RIP方法，现在我们来看如何编写代码以实现之，以及一些需要注意的问题。<br>由于拣选射线以线段形式存储更加便于后面的计算，况且我们可以直接得到纵跨整个平截头体的线段（即前面图中的线段PP&#8217;），故我们直接计算出这条连接远近裁剪面的线段。我们将拣选射线的线段形式称之为拣选线段。 <br>在下面的代码前方声明有两个类Point3f和LineSegment这分别表示由三个浮点数构成的三维空间中的点，以及由两个点构成的空间中的一条线段。<br>应注意代码中用到了类Point3f的一个需要三个浮点参数的构造函数，以及类LineSegment的一个需要两个点参数的构造函数。<br>获取拣选射线的例程如下所示（使用C++语言编写）：class Point3f;<br>class LineSegment;<br>LineSegment GetSelectionRay(int mouse_x, int mouse_y) {<br>// 获取 Model-View、Projection 矩阵 &amp; 获取Viewport视区<br>GLdouble modelview[16];<br>GLdouble projection[16];<br>GLint viewport[4];<br>glGetDoublev (GL_MODELVIEW_MATRIX, modelview);<br>glGetDoublev (GL_PROJECTION_MATRIX, projection);<br>glGetIntegerv (GL_VIEWPORT, viewport); GLdouble world_x, world_y, world_z; // 获取近裁剪面上的交点<br>gluUnProject( (GLdouble) mouse_x, (GLdouble) mouse_y, 0.0, <br>modelview, projection, viewport, <br>&amp;world_x, &amp;world_y, &amp;world_z); <br>Point3f near_point(world_x, world_y, world_z); // 获取远裁剪面上的交点<br>gluUnProject( (GLdouble) mouse_x, (GLdouble) mouse_y, 1.0, <br>modelview, projection, viewport, <br>&amp;world_x, &amp;world_y, &amp;world_z); <br>Point3f far_point(world_x, world_y, world_z); return LineSegment(near_point, far_point);<br>}<br><br>如果你是使用Win32平台进行开发，那么应当注意传入正确的参数。因为无论是使用Win32 API 还是DirectInput<br>来获取鼠标坐标，得到的Y值都应取反后再传入。因为OpenGL默认的原点在视区的左下角，Y轴从左下角指向左上角，而Windows默认的原点在窗口的<br>左上角，而Y轴方向与OpenGL相反，从左上角指向左下角。如下图所示：<br><img height=169 alt="" src="http://www.cppblog.com/images/cppblog_com/wc250en007/select5.jpg" width=491 border=0><br>我们可以看到代码被注释分为了三个部分：获取当前矩阵及视区，获取近裁剪面的交点，获取远裁剪面的交点。<br>我们通过OpenGL提供的查询函数轻松得到当前的ModelView和Projection矩阵，以及当前的Viewport（视区，也就是窗口的客户端区域，如果整个窗口区域用于OpenGL渲染的话）。<br>获得两个裁剪面上的交点的代码基本上是一样的，唯一的不同点是我们前面曾经详细地讨论过的窗口的Z坐标。不错，这个坐标表示的就是&#8220;深浅&#8221;的概念。它的值从点P&#8217;到点P的变化是从0.0f逐渐增至1.0f。此处类似于OpenGL的深度测试机制。<br>在得到两个交点之后，我们使用它们通过返回语句直接构建一条线段。在这里仅仅作为实例代码，故简捷清晰地直接返回线段对象，而没有通过引用参数来提高效率。<br>此<br>时用户可以使用这个函数来判断所选择的对象了。只需在需要的地方判断对象是否与此线段相交即可判断对象是否被选中，还可以通过进一步计算其交点位置来得到<br>详细的交点信息。这些计算均是常见的计算机图形学与三维数学计算，比如线段与三角形求交，线段与面求交，线段与球体求交，线段与柱体或锥体求交，等等。请<br>参考所列出的计算机图形学书籍。<br>五、结论（Conclusion）<br><br>在本文中，我们介绍了一种行之有效的三维坐标拾取方法，主要使用GLU库中的实用工具实现。这种方法速度快，效率高，能在不必重新绘制对象的前提下完成拣选工作。对比OpenGL自带的拣选机制来看，RIP的确在各种方面均有一定的优势。<br>六、参考文献（Reference） 【1】《OpenGL Programming Guide》<br>OpenGL ARB Mason Woo, Jackie Heider, Tom Davis, Dave Shreiner<br>【2】《OpenGL Reference Manual》<br>OpenGL ARB<br>【3】《Computer Graphics》<br>Donald Heam, M. Pauline Baker<br>【4】《Computer Graphics using OpenGL 2nd Edition》<br>F.S. Hill, JR.<br>
<img src ="http://www.cppblog.com/wc250en007/aggbug/117235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wc250en007/" target="_blank">Let me see see</a> 2010-06-05 18:45 <a href="http://www.cppblog.com/wc250en007/archive/2010/06/05/OpenGLSelect.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>