Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否有任何与顺序无关的透明技术适用于延迟着色?_C++_Opengl_Transparency_Deferred Shading - Fatal编程技术网

C++ 是否有任何与顺序无关的透明技术适用于延迟着色?

C++ 是否有任何与顺序无关的透明技术适用于延迟着色?,c++,opengl,transparency,deferred-shading,C++,Opengl,Transparency,Deferred Shading,我已经为我的OpenGL引擎调查了许多与顺序无关的透明方法,起初我认为我希望使用加权平均混合,以最大限度地提高速度 但是,我的引擎使用延迟着色,在选择混合技术时需要考虑这一点。理想情况下,我希望有一种技术不会要求我实现用于半透明对象的前向着色 在许多情况下,我需要使用透明度: 草/头发(抗锯齿剪切) 玻璃(彩色混合) 淡入淡出的对象 烟/云 水/液体(涉及折射,我知道这里不可能有真正的OIT) 火花/魔法/火焰(不需要点燃,可以使用添加剂混合,不用担心这些) 为了速度,我愿意牺牲图像的正确性

我已经为我的OpenGL引擎调查了许多与顺序无关的透明方法,起初我认为我希望使用加权平均混合,以最大限度地提高速度

但是,我的引擎使用延迟着色,在选择混合技术时需要考虑这一点。理想情况下,我希望有一种技术不会要求我实现用于半透明对象的前向着色

在许多情况下,我需要使用透明度:

  • 草/头发(抗锯齿剪切)
  • 玻璃(彩色混合)
  • 淡入淡出的对象
  • 烟/云
  • 水/液体(涉及折射,我知道这里不可能有真正的OIT)
  • 火花/魔法/火焰(不需要点燃,可以使用添加剂混合,不用担心这些)
为了速度,我愿意牺牲图像的正确性(因此我最初选择加权平均混合)。我不需要照亮每一层半透明对象,但我至少希望最前面的像素能够被正确照亮

我使用的是OpenGL3.x+核心上下文,所以我想避免使用任何需要OpenGL4.x的东西(就像使用它一样可爱),但我可以自由使用OpenGL2.x中不可用的任何东西

我的问题是:延迟着色的最佳顺序无关透明技术是什么?和/或:使用延迟着色时,照亮/着色半透明对象的最佳方法是什么


另外,有没有更好的方法来渲染不依赖混合的抗锯齿剪切(草/头发/树叶)?纯alpha测试往往会产生难看的别名。

< P>我不确定它是否适合您的延迟渲染器,但您可能会考虑加权、混合顺序无关透明性。有一个()和一个()以及很多其他的东西。它的速度相当快,因为它只使用一个不透明、一个透明和一个合成过程,并且与OpenGL 3.2+配合使用。
我实现了第一个版本,它工作得很好,这取决于你的场景和一个经过适当调整的权重函数,但在高alpha值方面存在问题。使用论文中的权重函数,我没有得到好的结果,但只是在使用线性、标准化的眼空间z值之后。
请注意,当使用OpenGL<4.0时,不能为每个缓冲区指定一个混合函数(glblendfunc),因此需要解决这个问题(请参阅第一篇文章)

  • 使用以下附件设置帧缓冲区:
    • 0:RGBA8,不透明
    • 1:RGBA16F,累加
    • 2:R16F,revealage
  • 清除附件#0到屏幕的清晰颜色(r、g、b、1),#1到(0,0,0,1)和#2到0
  • 将不透明几何体渲染到附件#0和深度缓冲区

    glEnable(GLU深度试验)
    glDepthMask(GL_TRUE)

  • 将透明几何体渲染到附件1和附件2。关闭深度缓冲区写入,但保持启用深度测试

    glDepthMask(GL_FALSE)
    glEnable(GL_混合物)
    glBlendEquation(GL_FUNC_ADD)
    glBlendFuncSeparate(GL_ONE、GL_ONE、GL_ZERO、GL_ONE减去SRC_ALPHA)

写入累积和恢复目标的碎片着色器部分如下所示:

uniform mat4 projectionMatrix;

layout (location = 1) out vec4 accum;
layout (location = 2) out float revealage;

/// @param color Regular RGB reflective color of fragment, not pre-multiplied
/// @param alpha Alpha value of fragment
/// param wsZ Window-space-z value == gl_FragCoord.z
void writePixel(vec3 color, float alpha, float wsZ) {
    float ndcZ = 2.0 * wsZ - 1.0;
    // linearize depth for proper depth weighting
    //See: https://stackoverflow.com/questions/7777913/how-to-render-depth-linearly-in-modern-opengl-with-gl-fragcoord-z-in-fragment-sh
    //or: https://stackoverflow.com/questions/11277501/how-to-recover-view-space-position-given-view-space-depth-value-and-ndc-xy
    float linearZ = (projectionMatrix[2][2] + 1.0) * wsZ / (projectionMatrix[2][2] + ndcZ);
    float tmp = (1.0 - linearZ) * alpha;
    //float tmp = (1.0 - wsZ * 0.99) * alpha * 10.0; // <-- original weighting function from paper #2
    float w = clamp(tmp * tmp * tmp * tmp * tmp * tmp, 0.0001, 1000.0);
    accum = vec4(color * alpha* w, alpha);
    revealage = alpha * w;
}
uniform sampler2DMS accumTexture;
uniform sampler2DMS revealageTexture;

in vec2 texcoordVar;
out vec4 fragmentColor;

void main() {
    ivec2 bufferCoords = ivec2(gl_FragCoord.xy);
    vec4 accum = texelFetch(accumTexture, bufferCoords, 0);
    float revealage = accum.a;
    // save the blending and color texture fetch cost
    /*if (revealage == 1.0) {
        discard;
    }*/
    accum.a = texelFetch(revealageTexture, bufferCoords, 0).r;
    // suppress underflow
    if (isinf(accum.a)) {
        accum.a = max(max(accum.r, accum.g), accum.b);
    }
    // suppress overflow
    if (any(isinf(accum.rgb))) {
        accum = vec4(isinf(accum.a) ? 1.0 : accum.a);
    }
    vec3 averageColor = accum.rgb / max(accum.a, 1e-4);
    // dst' = (accum.rgb / accum.a) * (1 - revealage) + dst * revealage
    fragmentColor = vec4(averageColor, revealage);
}
我的做法是:

  • 使用透明曲面的抖动渲染(aka)以低分辨率渲染整个场景,使用绘制ID(任何ID,只要它在帧中唯一)旋转抖动遮罩,渲染绘制ID、世界法线、FragDepth(请参见)、BRDF Alpha(请参见)到帧缓冲区
  • 您的照明(仅漫反射和镜面反射)、SSR或SSAO是否照常通过
  • 以正常分辨率(也称为“材质过程”)将不透明和“截止”曲面渲染为“不透明”帧缓冲区(OFB)
  • 创建2个“透明”帧缓冲区(FB0和FB1),FB1为FB0分辨率的一半
  • 渲染透明曲面而不混合到启用深度测试/写入的FB0
  • Blit FB0缓冲区深度位到FB1
  • 再次使用混合OIT将透明曲面渲染到FB1,但使用glDepthFunc(GL_更大)和glDepthMask(GL_FALSE),手动测试不透明曲面的深度以在着色器中丢弃(稍微慢一点,但可能无法绑定2个深度缓冲区)
  • 为OFB生成mipmap
  • 手动合成从FB1到OFB mip 0的最远透明曲面,在着色器中从OFB mip 1及以上进行采样(速度较慢,但允许失真和粗糙/彩色传输)
  • 再次为OFB生成mipmap
  • 合成从FB0到OFB mip 0最近的透明曲面,从OFB mip 1采样,该OFB mip 1现在包含来自FB1的透明曲面
有关如何进行合成以及如何构造“透明”帧缓冲区,请参见。 使用draw ID帧缓冲区和法线重建透明曲面,我使用简单的加权平均值,权重对应于当前法线点帧缓冲区的法线(法线点本身为1)

缺点:

  • 这不是一个过程,但您的第一个渲染和照明过程是在较低的分辨率下完成的,因此不会对性能造成太大影响,而且“最远”的透明曲面的分辨率是正常分辨率的一半
  • 在返回IBL之前,您只能获得4层透明度,但如果您将动态灯光用作回退解决方案,则可以。使用较大的抖动遮罩可以获得8层,但重建曲面的速度会较慢
好处:

  • 它允许像任何延迟渲染器一样使用大量灯光
  • 由于混合了差异渲染和正向渲染,因此它允许每个材质环境和BRDF查找表,这非常方便
  • 重查找技术(如SSR和SSAO)以较低的分辨率完成,这有助于提高性能
  • 像SSR和SSAO一样,照明是在低分辨率下进行的
  • 这样可以产生奇特的效果,如屏幕空间折射和透明表面
    void WritePixel(vec3 premultipliedReflect, float coverage)
    {
        float z = abs(CameraSpaceDepth);
        float w = clamp(pow(abs(1 / z), 4.f) * coverage * coverage, 6.1*1e-4, 1e5);
    
        out_0 = vec4(premultipliedReflect, coverage) * w;
        out_1 = vec4(1 - coverage); //so you can render without blending
    }
    
    vec4 accum = texelFetch(in_Buffer0, ivec2(gl_FragCoord.xy), 0);
    float r = texelFetch(in_Buffer1, ivec2(gl_FragCoord.xy), 0).r;
    out_Buffer0 = vec4(accum.rgb / clamp(accum.a, 6.1*1e-4, 6.55*1e5), r);