【问题标题】:webgl and glsl pickingwebgl 和 glsl 采摘
【发布时间】:2013-05-30 02:37:28
【问题描述】:

我正在从头开始实施 webgl 拾取,并决定采用 GLSL 路线,以反对光线相交测试。

所以我将整个场景渲染到一个单独的帧缓冲区中,为每个对象分配一个唯一的颜色,该颜色作为统一变量传递给片段着色器。 当渲染场景时,我 gl.readPixels() 缓冲区,并在单击坐标处获取颜色值(我反转坐标系统以说明 GL 与浏览器坐标系统不同)。

我遇到的问题是着色器表示传递给 gl_FragColor 着色器输出的颜色,因为 vec4 浮动,每个颜色通道的范围为 0.0-1.0,而 gl.readPixels() 将颜色通道返回为 0-255 范围内的整数...执行此转换会损失一些精度,并且可能会产生拾取错误(如果场景中有很多对象(超过 255 个),或者如果整数到浮点舍入更大,那么区分不同对象 ID 所需的粒度)。

有没有人知道如何解决这个问题,或者指出我正确的方向? readPixels() 可以返回 0.0-1.0 范围内颜色通道的浮点值吗? 我可以打包分布在多个通道上的单个对象 ID(这样我就不仅限于单个通道并且只能选择 255 个对象吗?)

感谢您的帮助

【问题讨论】:

    标签: 3d glsl webgl picking


    【解决方案1】:

    不幸的是,虽然您可以使用 OES_texture_float 扩展来渲染浮点帧缓冲区纹理,但您似乎仍然无法使用 readPixels 将它们读取为浮点数(请参阅 https://bugzilla.mozilla.org/show_bug.cgi?id=681903https://groups.google.com/forum/#!topic/webgl-dev-list/s83_IvYbPM4

    看起来这是一个未来的功能,但似乎还没有在任何地方实现。

    如果您因为成本太高而避免进行光线相交测试,则最好为您的对象使用优化的结构,例如边界卷或八叉树/kd-trees。

    【讨论】:

    • 我最终使 glsl 按颜色选择解决方案起作用。关键是将 0-255-range->0.0-1.0-range 转换(除以 255)后的精度限制为小数点后 2 位……除了引入错误之外……
    • 有道理,但我认为小数点后 2 位仍然会引入一些精度错误。例如,23/255 = 0.09019607843 和 24/255 = 0.09411764705。即使你四舍五入,这两个值都映射到 0.09。
    【解决方案2】:

    我知道在 OpenGL 中,您可以从指针创建纹理(我的意思是,获取指针指向的内存片段作为纹理的内容)。 我相信相反的过程也可能,但不太确定如何以及是否可以完成。比如:

    *p = myTexture;     // texture -> pointer
    my_data = p[i][j];  // read byte data
    

    如果可以做到,那么您可以将内容读取为字节数据,然后将其转换为浮点数(或任何适合您的方式)。但是,如果这甚至可能以及如何在 JavaScript 中完成,那么这个问题仍然存在......不过,我会这样做。

    希望这会有所帮助。

    【讨论】:

    • 不幸的是,据我所知,WebGL 并没有提供对帧缓冲区数据的原始访问权限……但我又不是 webgl 专家。
    【解决方案3】:

    在 WebGL 中存在一些将浮点数从 GPU 读取到 CPU 的技巧:

    http://lab.concord.org/experiments/webgl-gpgpu/webgl.html

    更具体:

    【讨论】:

      【解决方案4】:

      这是一个老问题,但只是提供......

      我能否打包分布在多个通道上的单个对象 ID(这样 我不限于单个频道,只能选择 255 对象)?

      您可以可靠地对 8 位 gl.readPixels 检索到的每个颜色分量进行 8 位编码。在您的片段着色器中,您可以使用 float redComponent = float(intObjectId) / 255.0。如果你把它放在 gl_FragColor 中,它会可靠地返回它开始的数字,如果它是在 0 到 255 之间。不需要四舍五入。

      你可以通过模和除法编码一个更大的整数,比如

          int objectId = 12345; // up to 65535...
          float f = float(objectId);
          // put low 8 bits into .r, and next 8 bits into .g
          gl_FragColor = vec4(mod(f,256.) / 255., mod(floor(f / 256.0), 256.0) / 255.0, 0,1);
      

      要知道的是,范围从浮点 [0.0, 1.0] 映射到整数 [0,255]。它们映射到范围的中间,所以 0.0 到 0.5/255 映射到 0,0.5/255 到 1.5/255 映射到 1,依此类推。非常稳定!

      【讨论】:

        【解决方案5】:

        OpenGL specification 准确地说明了从 int 到 float 以及从 float 到 int 的转换应该如何进行。

        请参阅第 2.3.5 节,“定点数据转换”:

        • 从整数类型到浮点数的转换应该通过除以 2^b-1 来完成,即在字节的情况下为 255.0,如david van brink 的回答。
        • GPU 从浮点类型到整数类型的转换总是通过舍入到最接近的整数来完成。只要内部帧缓冲区格式具有足够的精度,这应该没问题:8 位无符号整数、16 位浮点数(具有 10 位尾数)和 32 位浮点数都适用于此目的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-23
          • 2021-07-04
          相关资源
          最近更新 更多