zoukankan      html  css  js  c++  java
  • Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(2)

    Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(2)

    上一篇里介绍了Color-Coded Picking的思路和最基本的实现。在处理GL_POINTS时已经没有问题,但是处理GL_LINES、GL_TRIANGLES等时会遇到同一图元的各个顶点颜色不同的问题,这就不能正确拾取了,本篇来解决这个问题。

    对于GL_LINES,可以用 int objectID = gl_VertexID / 2; 来使得每个线段图元的两个顶点颜色分别相同;对于GL_TRIANGLES,则用 int objectID = gl_VertexID / 3; 。但是这个方法无法应用到存在共享顶点的GL_LINE_STRIP、GL_TRIANGLE_STRIP、GL_LINE_LOOP等情况。所以要另辟蹊径。

    ShadeMode

    首先介绍一下glShadeMode()这个函数。就是靠它才解决了本文的问题。

    glShadeMode()

    在(https://www.opengl.org/sdk/docs/man2/xhtml/glShadeModel.xml)有它的专业解释,里面有这样一张表格。

    Primitive Type of Polygon i

    Vertex

    Single polygon ( i == 1 )

    1

    Triangle strip

    i + 2

    Triangle fan

    i + 2

    Independent triangle

    3 × i

    Quad strip

    2 × i + 2

    Independent quad

    4 × i

    这个表格的意思是:在 glShadeMode(GL_FLAT); 状态下,在绘制某种图元时,其颜色由第i个顶点的颜色决定。(其实就是由定义一个图元的最后一个顶点的颜色决定)

    单看表格难以理解,用下面的Demo进行说明。

    这个Demo绘制了8个顶点,其位置和颜色如下(同上图左侧所示)

     1 gl.Color(0, 0, 0);
     2 gl.Vertex(0, 0);
     3 
     4 gl.Color(1f, 0, 0);
     5 gl.Vertex(0, 1);
     6 
     7 gl.Color(0, 1f, 0);
     8 gl.Vertex(1, 0);
     9 
    10 gl.Color(1f, 1f, 0);
    11 gl.Vertex(1, 1);
    12 
    13 gl.Color(0, 0, 1f);
    14 gl.Vertex(2, 0);
    15 
    16 gl.Color(1f, 0, 1f);
    17 gl.Vertex(2, 1);
    18  
    19 gl.Color(0, 1f, 1f);
    20 gl.Vertex(3, 0);
    21 
    22 gl.Color(1f, 1f, 1f);
    23 gl.Vertex(3, 1);
    Demo 模型

    下面分别看一下在 glShadeMode(GL_SMOOTH); 和 glShadeMode(GL_FLAT); 模式下,用这个8个顶点绘制各种图元的情况。

    这是GL_SMOOTH 模式下的GL_LINE_STRIP。

    这是GL_FLAT模式下的GL_LINE_STRIP。

    这是GL_SMOOTH 模式下的GL_TRIANGLES。

     

    这是GL_FLAT 模式下的GL_TRIANGLES。

    这是GL_SMOOTH 模式下的GL_TRIANGLE_STRIP。

    这是GL_FLAT模式下的GL_TRIANGLE_STRIP。

    这是GL_SMOOTH 模式下的GL_QUAD_STRIP。

     

    这是GL_FLAT 模式下的GL_QUAD_STRIP。

    您可以点此下载此Demo慢慢对比。

    GL_FLAT的作用

    通过上面一节的观察可以看到,GL_FLAT模式下,各种类型的图元的颜色都是由绘制它的最后一个顶点的颜色给出的。

    这么绝妙的颜色分配方案简直就是为了解决本文的问题而设计的。

    我们只需在做Picking的绘制时,在GL_FLAT状态下绘制图元,就可以用glReadPixel()获取到应拾取的图元的最后一个顶点的编号。根据上一节的表格,很容易推算出此编号代表的图元。

    'flat' in GLSL

    不过这又带来一个小问题:glShadeMode();在使用Shader+VBO时是无效的。不过Modern OpenGL必然要有能代替它的功能:GLSL里的flat关键字。给in/out变量附加一个flat,就相当于Legacy OpenGL里调用了glShadeMode(GL_FLAT);

    flat out vec4 pass_Color; // glShadeMode(GL_FLAT); in legacy opengl.

    flat in vec4 pass_Color; // glShadeMode(GL_FLAT); in legacy opengl.

    这也是本文与上一篇的程序中唯一的区别。

    未完待续

    拾取一个VBO里的单个图元的问题已经彻底解决了。那么来看下一个问题:一个场景里可能会有多个VBO,此时每个VBO的gl_VertexID都是从0开始的,那么如何区分不同VBO里的图元呢?我们下回分解。

  • 相关阅读:
    Hibernate之Query接口的uniqueResult()方法
    一个安静的地方
    AJAX实现简单的省市二级联动
    为了你们,而活着。
    PL/SQL Developer 连接远程Oracle数据库
    dotfuscator混淆的问题
    查询表内属于主键的列SQLServer2005
    关于net2.0里面新出现的类backgroundworker的应用 引用自http://www.cnblogs.com/dlwang2002/archive/2006/12/07/585093.html
    SQLServer int to base16
    数据库查询问题日期格式
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/modern-opengl-picking-primitive-in-VBO-2.html
Copyright © 2011-2022 走看看