OpenGL ES 2.0中的剪切平面

Emi*_*nus 21 opengl-es clipping opengl-es-2.0

我需要在OpenGL ES 2.0中的剪切平面下剪切几百个对象,并且会欣赏那些对这个OpenGL子集更有经验的人的想法.

在OpenGL ES 1.x中有glClipPlane.在桌面上,您在着色器中有glClipPlane或gl_ClipDistance.这两者都不适用于OpenGL ES 2.0.似乎这种功能完全消失了2.0.

似乎唯一的方法是:A)在片段着色器中运行平面方程,或者B)编写一个非常复杂的顶点着色器,如果它们位于平面后面,则将它们定位在平面上.

(a)与glClipPlane相比会很慢,因为在顶点着色器之后和片段着色器之前进行"常规"剪辑,每个片段仍然必须被部分处理和丢弃.

(B)很难在着色器之间进行兼容,因为我们不能丢弃顶点,我们必须将它们与平面对齐并调整那些"切割"的属性.如果不在纹理中发送所有顶点并对其进行采样,则无法在着色器中的顶点之间进行插值,这将非常昂贵.通常,无论如何都可能无法正确地插入数据.

我还想过将近平面与剪切平面对齐,这将是一种有效的解决方案.

在渲染整个场景并检查深度失败后绘制平面也不起作用(除非您看起来接近垂直于平面).

对单个对象起作用的是将平面绘制到深度缓冲区,然后使用glDepthFunc(GL_GREATER)渲染对象,但正如预期的那样,当其中一个对象位于另一个对象后面时,它不起作用.我试图建立在这个概念的基础上,但最终得到了与阴影卷非常相似的东西,同样昂贵.

那我错过了什么?你会如何在OpenGL ES 2.0中进行平面剪裁?

Cfr*_*Cfr 6

这是我在Vuforia SDK论坛上找到的两个解决方案.

  1. 使用Harri Smatt的着色器:

    uniform mat4 uModelM;
    uniform mat4 uViewProjectionM;
    attribute vec3 aPosition;
    varying vec3 vPosition;
    void main() {
      vec4 pos = uModelM * vec4(aPosition, 1.0);
      gl_Position = uViewProjectionM * pos;
      vPosition = pos.xyz / pos.w;
    }
    
    Run Code Online (Sandbox Code Playgroud)
    precision mediump float;
    varying vec3 vPosition;
    void main() {
      if (vPosition.z < 0.0) {
        discard;
      } else {
        // Choose actual color for rendering..
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用Alessandro Boccalatte的四倍深度缓冲:

    • 禁用颜色书写(即设置glColorMask(false, false, false, false);)
    • 渲染一个与标记形状匹配的四边形(即只是一个具有相同尺寸和标记位置/方向的四边形); 这只会被渲染到深度缓冲区中(因为我们在上一步中禁用了颜色缓冲区写入)
    • 启用颜色掩码(glColorMask(true, true, true, true);)
    • 渲染您的3D模型


Rab*_*d76 5

由于扩展EXT_clip_cull_distance在 OpenGL ES 2.0 中不可用(因为该扩展需要 OpenGL ES 3.0),因此必须模拟剪切。它可以通过丢弃片段在片段着色器中进行模拟。请参阅片段着色器 - 特殊操作

另请参阅OpenGL ES 着色语言 1.00 规范;6.4 跳跃;第 58 页

丢弃关键字仅允许在片段着色器中使用它可以在片段着色器中使用以放弃对当前片段的操作。该关键字导致片段被丢弃,并且不会发生任何缓冲区的更新。它通常用在条件语句中,例如:

if (intensity < 0.0)
    discard;
Run Code Online (Sandbox Code Playgroud)

模拟的着色器程序gl_ClipDistance可能如下所示:

顶点着色器:

attribute vec3 inPos;
attribute vec3 inCol;

varying vec3  vertCol;
varying float clip_distance;

uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
uniform vec4 u_clipPlane;

void main()
{   
    vertCol        = inCol;
    vec4 modelPos  = u_modelMat44 * vec4( inPos, 1.0 );
    gl_Position    = u_projectionMat44 * u_viewMat44 * viewPos;
    clip_distance  = dot(modelPos, u_clipPlane);
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

varying vec3  vertPos;
varying vec3  vertCol;
varying float clip_distance;

void main()
{
    if ( clip_distance < 0.0 )
        discard;
    gl_FragColor = vec4( vertCol.rgb, 1.0 );
} 
Run Code Online (Sandbox Code Playgroud)

以下 WebGL 示例演示了这一点。请注意,WebGL 1.0上下文与 OpenGL ES 2.0 API 非常一致。

if (intensity < 0.0)
    discard;
Run Code Online (Sandbox Code Playgroud)
attribute vec3 inPos;
attribute vec3 inCol;

varying vec3  vertCol;
varying float clip_distance;

uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
uniform vec4 u_clipPlane;

void main()
{   
    vertCol        = inCol;
    vec4 modelPos  = u_modelMat44 * vec4( inPos, 1.0 );
    gl_Position    = u_projectionMat44 * u_viewMat44 * viewPos;
    clip_distance  = dot(modelPos, u_clipPlane);
}
Run Code Online (Sandbox Code Playgroud)
varying vec3  vertPos;
varying vec3  vertCol;
varying float clip_distance;

void main()
{
    if ( clip_distance < 0.0 )
        discard;
    gl_FragColor = vec4( vertCol.rgb, 1.0 );
} 
Run Code Online (Sandbox Code Playgroud)


flu*_*ggo 0

我不知道这是否适用于 OpenGL ES,但 OpenGL 具有由 glEnable(GL_CLIP_DISTANCE0) 启用的 gl_ClipDistance 变化输出。启用后,图元将被剪裁,使得在顶点和几何着色器之后 gl_ClipDistance[0] >= 0。

剪辑距离可以指定为与世界空间平面方程的点积:

http://github.prideout.net/clip-planes/