假设我需要渲染以下场景:
如果不是发光,那么渲染场景将是微不足道的。随着光芒,我可以看到至少2种渲染方式:
第1天
- 将黄色立方体渲染到屏幕上。
- 计算红色立方体最终会在屏幕上显示的位置(很简单,我们有顶点+模型视图矩阵),因此将其渲染到屏幕外 FBO足够大(为发光留下余量);一定要保存 深度到纹理。
- 对FBO进行后处理并发光。
- 现在困难的部分:将FBO与屏幕合并。我们需要考虑深度(我们已经存储在纹理中)所以看起来 我们需要做以下事情:
醇>
a)渲染四边形,用FBO的颜色附件进行纹理化 b)适当地设置ModelView矩阵( 我们需要通过一些向量来移动纹理,因为我们是故意的 在步骤2中将红色立方体渲染为小于屏幕FBO(对于 速度原因!)))c)合并'片段着色器,我们需要写 来自FBO的深度附件纹理的gl_FragDepth(而不是来自 FragCoord.z)WAY2
- 将两个立方体渲染到屏幕外的FBO;设置模板,以便红色立方体的无障碍部分标记为1。
- 对FBO进行后处理,使标记区域变得模糊,并将其混合以产生光晕
- 将FBO Blit到屏幕
醇>
WAY 1有效,但主要问题是速度,即步骤4c。在片段着色器中写入gl_FragDepth会禁用早期的z-test。
WAY 2也有点工作,看起来应该快得多,但它不会给出100%正确的结果。 问题是当红色立方体被黄色部分部分遮挡时,红色立方体中接近黄色立方体的像素会变黄“黄色”。当我们模糊它们时,即更接近的黄色立方体“悄悄地”。发光。
我想我可以解决上述问题,当我模糊时,当我正在阅读的像素突然在深度减少时停止模糊(意味着我们只是从另一个物体跳到更近的物体)但这意味着模糊时纹理访问量的两倍(除了获取COLOR纹理,我们需要继续获取DEPTH纹理),以及模糊片段着色器中的条件语句。我没有尝试,但我不相信它会比第1天更快,甚至不会给出100%正确的结果(靠近黄色立方体边界的红色像素只是受红色立方体可见部分的影响,而不是整个(-blurRadius,+ blurRadius)区域,所以在这个区域内,发光不会100%相同)。
有人会建议如何最好地实现这样的对象后期处理' ?
修改
我写的是一种用于图形效果的OpenGL ES库。客户端可以给它一些指令,例如'取这个Mesh,用它构造它,将它的ModelView矩阵应用于下面的矩阵变换,将下面的扭曲应用到它的顶点,下面的一组片段效果,渲染到下面的Framebuffer'。
在我的图书馆里,我已经拥有了我所说的基质效应' (修改模型视图)'顶点效果' (各种顶点扭曲)和“片段效应”#39; (RGBA每片段的各种变化)。 现在我正在尝试添加我称之为“后处理”的内容。效果,这个' GLOW'成为他们中的第一个。我定义了效果,我完全按照你的描述进行了视觉。
效果应用于整个网格;因此,现在我需要我称之为“每个对象的后期处理”。
图书馆主要针对的是2.5D'用法,如移动应用程序中的GPU加速UI,2-2.5D游戏(想想Candy Crush)等等。我怀疑人们实际上会将它用于任何真正的3D大型游戏。 所以FPS虽然总是很重要,但通常不那么重要。
我非常努力地保持API' Mesh-local',即渲染管道只知道它正在渲染的当前Mesh。关于上述内容的主要抱怨是它必须知道我们将要渲染到给定Framebuffer的整个集合网格。话虽这么说,如果'网格局部'使用后处理效果是不可能或无法有效完成的,那么我想我必须放弃它(并使我的教程更复杂)。
昨天我在想这个:
# '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
这不是Mesh-local(我们仍然需要能够处理所有'发光' Meshes优先)虽然我称它为“几乎是Mesh-local'因为它只根据应用于它们的效果来区分网格,而不是哪个网格在哪里或哪个会阻碍它们。
当两个GLOWING Meshes相互阻塞时,它也可能会出现问题(混合不必按正确的顺序进行),尽管GLOW是半透明的,我希望最终的外观或多或少都可以。
看起来它甚至可以变成一个完全' Mesh-local'做一个巨人的算法
FOREACH(Mesh)
{
if( glowing )
{
}
else
{
}
}
虽然代价是必须在FBO中附加和分离内容并在每次循环迭代时以不同方式设置STENCILS。
答案 0 :(得分:0)
一个下意识的建议是做混合动力: