簡體   English   中英

如何在iOS中正確地線性化OpenGL ES中的深度?

[英]How to correctly linearize depth in OpenGL ES in iOS?

我正在嘗試使用OpenGL為iOS應用程序渲染forrest場景。 為了使它更好一些,我想在場景中實現深度效果。 但是我需要OpenGL深度緩沖區的線性化深度值才能這樣做。 目前我在片段着色器中使用了一個計算(我在這里找到)。

因此我的terrain片段着色器看起來像這樣:

#version 300 es

precision mediump float;
layout(location = 0) out lowp vec4 out_color;

float linearizeDepth(float depth) {
    return 2.0 * nearz / (farz + nearz - depth * (farz - nearz));
}

void main(void) {
    float depth = gl_FragCoord.z;
    float linearized = (linearizeDepth(depth));
    out_color = vec4(linearized, linearized, linearized, 1.0);
}

但是,這會產生以下輸出:

結果輸出 正如你所看到的,你越遠“越遠”,得到的深度值就越“條紋”(特別是在船后面)。 如果地形圖塊靠近相機,輸出有點可以..

我甚至嘗試了另一種計算:

float linearizeDepth(float depth) {
    return 2.0 * nearz * farz / (farz + nearz - (2.0 * depth - 1.0) * (farz - nearz));
}

這導致了一個太高的價值,所以我通過划分來縮小它:

float linearized = (linearizeDepth(depth) - 2.0) / 40.0;

第二個結果輸出

然而,它給出了類似的結果。

那么如何在近平面和遠平面之間實現平滑,線性的過渡,沒有任何條紋? 有沒有人有類似的問題?

問題是你存儲了被截斷的非線性值,因此當你稍后查看深度值時,你會得到波動的結果,因為你失去了准確性,你離znear平面越遠。 無論你評價什么,你都不會獲得更好的結果,除非:

  1. 精度損失較低

    您可以更改znear,zfar值,使它們更接近。 盡可能多地放大znear,以便更准確的區域覆蓋更多的場景。

    另一個選擇是每個深度緩沖區使用更多位(16位太低)不確定是否可以在OpenGL ES中執行此操作,但在標准OpenGL中,您可以在大多數卡上使用24,32位。

  2. 使用線性深度緩沖

    因此將線性值存儲到深度緩沖區中。 有兩種方法。 一個是計算深度,因此在所有基礎操作之后,您將獲得線性值。

    另一種選擇是使用單獨的紋理/ FBO並將線性深度直接存儲到它。 問題是你不能在同一個渲染過程中使用它的內容。

[Edit1]線性深度緩沖區

要線性化深度緩沖區本身(而不僅僅是從中獲取的值),請嘗試:

頂點:

varying float depth;
void main()
    {
    vec4 p=ftransform();
    depth=p.z;
    gl_Position=p;
    gl_FrontColor = gl_Color;
    }

分段:

uniform float znear,zfar;
varying float depth; // original z in camera space instead of gl_FragCoord.z because is already truncated
void main(void)
    {
    float z=(depth-znear)/(zfar-znear);
    gl_FragDepth=z;
    gl_FragColor=gl_Color;
    }

在CPU端線性化的非線性深度緩沖區(就像你一樣): 中央處理器

線性深度緩沖GPU側(如您所願): GPU

場景參數是:

// 24 bits per Depth value
const double zang =   60.0;
const double znear=    0.01;
const double zfar =20000.0;

簡單的旋轉板覆蓋整個深度視野。 展位圖像由glReadPixels(0,0,scr.xs,scr.ys,GL_DEPTH_COMPONENT,GL_FLOAT,zed); 並在CPU端轉換為2D RGB紋理。 然后渲染為單個QUAD覆蓋單位矩陣的整個屏幕......

現在要從線性深度緩沖區獲取原始深度值,您只需執行以下操作:

z = znear + (zfar-znear)*depth_value;

我使用古老的東西只是為了保持這個簡單,所以把它移到你的個人資料......

請注意,我不在OpenGL ESIOS中進行編碼,所以我希望我沒有錯過與此相關的內容(我習慣於Win和PC)。

為了顯示差異,我將另一個旋轉的板添加到同一場景(因此它們相交)並使用彩色輸出(不再獲得深度):

相交

正如您所見,線性深度緩沖區要好得多(對於覆蓋大部分深度FOV的場景)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM