[英]Are there any Order-Independent Transparency techniques suitable for deferred shading?
我已經為我的 OpenGL 引擎調查了許多與順序無關的透明度方法,起初我想我想使用加權平均混合,以最大限度地提高速度。
但是,我的引擎使用延遲着色,在選擇混合技術時需要考慮到這一點。 理想情況下,我想要一種不會要求我實現前向着色以用於半透明對象的技術。
在許多情況下,我需要使用透明度:
為了速度,我願意犧牲圖像的正確性(因此我最初選擇了加權平均混合)。 我不需要每一層半透明物體都被點亮,但我至少希望最前面的像素被正確點亮。
我正在使用 OpenGL 3.x+ 核心上下文,所以我想避免任何需要 OpenGL 4.x 的東西(就像使用一樣可愛),但我可以自由使用 OpenGL 2 中沒有的任何東西。 X。
我的問題是:延遲着色的最佳順序無關透明度技術是什么?,和/或:使用延遲着色時對半透明對象進行照明/着色的最佳方法是什么?
PS有沒有更好的方法來渲染不依賴混合的抗鋸齒切口(草/頭發/葉子)? 純 alpha 測試往往會產生丑陋的混疊。
我不確定它是否適合您的延遲渲染器,但您可能會考慮加權、混合順序無關的透明度。 有一個沒有彩色傳輸( web )的舊版本和一個支持彩色傳輸( web )和許多其他東西的新版本。 它非常快,因為它只使用一種不透明、一種透明和一種合成通道,並且可以與 OpenGL 3.2+ 一起使用。
我實現了第一個版本,效果很好,具體取決於您的場景和適當調整的權重函數,但在高 alpha 值方面存在問題。 我用論文中的加權函數沒有得到好的結果,但只有在使用線性、歸一化的眼空間 z 值之后。
請注意,當使用 OpenGL < 4.0 時,您無法為每個緩沖區指定混合函數 (glBlendFunci),因此您需要解決該問題(請參閱第一篇論文)。
將不透明幾何體渲染到附件 #0 和深度緩沖區。
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
將透明幾何體渲染到附件 #1 和 #2。 關閉深度緩沖區寫入,但啟用深度測試。
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_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;
}
綁定附件紋理 #1 和 #2,並通過使用合成着色器繪制四邊形將它們合成到附件 #0。
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
用於合成的片段着色器如下所示:
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);
}
我這樣做的方式:
有關如何進行合成以及如何構建“透明”幀緩沖區的信息,請參閱Morgan McGuire 的博客。 使用繪制 ID 幀緩沖區和法線重建透明表面,我使用簡單的加權平均值,權重對應於當前法線點幀緩沖區的法線(法線點本身為 1)。
缺點:
好處:
我的混合 OIT 權重函數(具有相同不透明度的更近的表面總是獲得更高的權重):
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);
請參見本關於“CameraSpaceDepth”與此有關FP值
這是該模型的結果,帶有臟亂的 POC,您可以看到粗糙的表面傳輸:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.