Opengl es 每对象后处理

Opengl es 每对象后处理,opengl-es,post-processing,Opengl Es,Post Processing,假设我需要渲染以下场景: 两个立方体,一个黄色,另一个红色 红色立方体需要用红光“发光”,黄色立方体不发光 立方体围绕着共同的重心旋转 摄像机被放置在一个位置 这样当红色发光的立方体靠近摄像机时, 它会部分阻挡黄色立方体,当黄色立方体 在靠近摄像机的地方,它部分挡住了红色发光的摄像机 如果没有辉光,场景渲染起来就很简单。使用光晕,我可以看到至少两种渲染方式: 方式1 将黄色立方体渲染到屏幕上 计算红色立方体在屏幕上的最终位置(简单,我们有顶点+模型视图矩阵),因此将其渲染到屏幕外 FBO刚好足够

假设我需要渲染以下场景:

  • 两个立方体,一个黄色,另一个红色
  • 红色立方体需要用红光“发光”,黄色立方体不发光
  • 立方体围绕着共同的重心旋转
  • 摄像机被放置在一个位置 这样当红色发光的立方体靠近摄像机时, 它会部分阻挡黄色立方体,当黄色立方体 在靠近摄像机的地方,它部分挡住了红色发光的摄像机
  • 如果没有辉光,场景渲染起来就很简单。使用光晕,我可以看到至少两种渲染方式:

    方式1

  • 将黄色立方体渲染到屏幕上
  • 计算红色立方体在屏幕上的最终位置(简单,我们有顶点+模型视图矩阵),因此将其渲染到屏幕外 FBO刚好足够大(为发光留有余量);一定要保存 纹理的深度
  • 对FBO进行后处理并使其发光
  • 现在最难的部分是:将FBO与屏幕合并。我们需要考虑深度(我们存储在纹理中),所以看起来 就像我们需要做的那样:

    a) 渲染带有FBO颜色附件纹理的四边形。
    b) 适当地设置ModelView矩阵( 我们需要通过一些向量移动纹理,因为我们有意 在步骤2中,将红色立方体渲染为小于屏幕FBO的形状(对于 速度原因!)
    c)在“合并”片段着色器中,我们需要编写 来自FBO深度附着纹理(而不是来自 FragCoord.z)
  • 途径2

  • 将两个立方体渲染到屏幕外FBO;设置模板,使红色立方体的无障碍部分标记为1
  • 对FBO进行后期处理,使标记区域变得模糊,并将其混合以产生光晕
  • 将FBO点到屏幕上
  • 方法1是可行的,但它的主要问题是速度,即步骤4c。在片段着色器中写入gl_FragDepth将禁用早期z测试

    方法2也可以工作,看起来应该快得多,但它不能给出100%的正确结果。 问题是,当红色立方体部分被黄色立方体阻挡时,当我们模糊红色立方体中靠近黄色立方体的像素时,它们会变得“淡黄色”,即越近的黄色立方体会“爬行”到辉光中

    我想我可以通过以下方法来解决上述问题:当我正在模糊时,当我读取的像素深度突然降低时(意味着我们只是从一个更远处的对象跳到一个更近的对象),停止模糊,但这意味着模糊时纹理访问的次数是原来的两倍(除了获取颜色纹理,我们还需要继续获取深度纹理)和模糊片段着色器中的条件语句。我没有尝试过,但我不相信它会比方法1快,即使这样也不会给出100%的正确结果(靠近黄色立方体边界的红色像素仅受红色立方体可见部分的影响,而不是整个(-blurRadius,+blurRadius)区域的影响,因此在该区域中,光晕不会100%相同)

    有没有人对如何最好地实现这种“每对象后处理”有什么建议

    编辑:

    我正在写的是一种用于图形效果的OpenGL ES库。客户可以给它提供一系列指令,比如“获取此网格,使用此网格对其进行纹理处理,将以下矩阵变换应用于其ModelView矩阵,将以下扭曲应用于其顶点,将以下片段效果集渲染到以下对象”g帧缓冲区'

    在我的库中,我已经有了我称之为“矩阵效果”(修改模型视图)“顶点效果”(各种顶点扭曲)和“片段效果”(每个片段RGBA的各种变化)。 现在我正在尝试添加我称之为“后处理”的效果,这是第一个效果。我定义了效果,我看到的效果与您上面描述的完全一样

    效果应用于整个网格;因此现在我需要我称之为“每个对象后处理”的东西

    该库主要针对“2.5D”用途,如移动应用程序中的GPU加速UI、2-2.5D游戏(想想Candy Crush),等等。我怀疑人们是否真的会在任何真正的3D大型游戏中使用它。 因此,FPS虽然总是很重要,但比通常情况下要不那么重要

    我非常努力地保持API“网格本地”,即渲染管道只知道它正在渲染的当前网格。关于上述问题的主要抱怨是,它必须知道我们要渲染到给定帧缓冲区的整个集合网格。也就是说,如果“网格本地性”不可能或无法使用po有效地完成st处理效果,那么我想我将不得不放弃它(并使我的教程更加复杂)

    昨天我在想:

    # 'Almost-Mesh-local' algorithm for rendering N different Meshes, some of them glowing
    
    Create FBO, attach texture the size of the screen to COLOR0, another texture 1/4 the size of the screen to COLOR1.
    Enable DEPTH test, clear COLOR/DEPTH
    
    FOREACH( glowing Mesh )
       {
       use MRT to render it to COLOR0 and COLOR1 in one go
       }  
    
    Detach COLOR1, attach STENCIL texture
    Set up STENCIL so that the test always passes and writes 1s when Depth test passes
    Switch off DEPTH/COLOR writes
    
    FOREACH( glowing Mesh )
       {
       enlarge it by N% (amount of GLOW needs to be modifiable!) 
       render to STENCIL   // i.e. mark the future 'glow' regions with 1s in stencil   
       }
    
    Set up STENCIL so that test always passes and writes 0 when Depth test passes
    Switch on DEPTH/COLOR writes
    
    FOREACH( not glowing Mesh )
       {
       render to COLOR0/STENCIL/DEPTH  // now COLOR0 contains everything rendered, except for the GLOW. STENCIL marks the unobstructed glowing areas with 1s 
       }
    
    Blur the COLOR1 texture with BLUR radius 'N'
    Merge COLOR0 and COLOR1 to the screen in the following way:
    
    IF ( STENCIL==0 ) take pixel from COLOR0
    ELSE              blend COLOR0 and COLOR1
    END
    
    这不是网格局部(我们仍然需要能够首先处理所有“发光”网格),尽管我称之为“几乎网格局部”,因为它仅根据应用于网格的效果区分网格,而不是根据哪个网格在哪里或哪个网格阻挡了哪个网格

    当两个发光的网格相互阻碍时(混合不必按正确的顺序进行),它也可能会出现问题。尽管发光是半透明的,我希望最终的外观会或多或少正常

    看起来它甚至可以通过做一个巨大的运算变成一个完全的“网格局部”算法

    FOREACH(Mesh) 
      {
      if( glowing )
         {
    
         }
      else 
         {
    
         }
      }
    

    尽管在每次循环迭代中,必须从FBO连接和分离材料,并以不同的方式设置模具为代价。

    下意识的建议是进行混合:

  • 计算红色立方体在屏幕上的最终位置,因此将其渲染到足够大的屏幕外FBO(或与屏幕大小相同的FBO,因为在活着的情况下创建FBO可能效率不高);不要担心深度,这只是你想要的颜色
  • 将两个立方体渲染到