デプス値

最終更新日28 Aug 2017 05:17

depth-value.png

デプスバッファには何が入っているのか?

デプスバッファの値をそのままgl_FragColorに渡しても真っ白になって何も見えない
いったいどんな値が入っているのか?
near~farの範囲の値が入っています[4]
ウィンドウ座標でのzとも呼ばれます。
じゃあ(far-near)で割って0~1の範囲にしよう!と思ってやっても、
デプス値の範囲は巨大すぎてうまく可視化できません[3]
白っぽい絵になってしまいます。
デプス値はカメラに近いほど精度が高く、遠いほど精度が低いという線形じゃない変化の仕方をしています[5]
透視投影変換する過程で分母がzに来るからでしょうね。きっと。
なのでlinearizeする必要があります。
このlinearizeはウィンドウ座標であるデプス値をカメラ座標に変換することでもあります。

float linearizeDepth(in vec2 uv)
{
    float near= 0.5;
    float far  = 2000.0;
    float depth = texture2D(depthTexture, uv).x;
    return (2.0 * near) / (far + near - depth * (far - near));
}

投影行列の値を使って座標変換の過程をおいつつlinearlize
ソース参照元[7]
投影行列の成分の値はここ参照
float linearizeDepth(in vec2 uv)
{
        float depth = texture2D(depthTexture, uv).x;
    //正規化デバイス座標の範囲 -1~1に変換する
    float ndc_z = -2.0 * depth + 1.0;
    //カメラ座標における値
    float eye_z = projection_matrix[3][2] / (ndc_z  - projection_matrix[2][2]);
    //白黒で見えるようにするため正規化
    return -eye_z/far;
}
  • projection_matrix[3][2]=-2fn/(f-n)
  • projection_matrix[2][2]=-(f+n)/(f-n)

クリップ座標のzを可視化する

デプスバッファをテクスチャとして取ってこずにシェーダ内でやる方法
gl_DepthRangeというそれらしき組み込みのuniform変数も使ってみたけど、なぜかgl_DepthRange.diffは常に1で使い物にならなかった。
なので仕方なくuniform変数でdepthRangeを渡しました。
頂点シェーダ

varying vec4 vPos;
void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    vPos = gl_Position;//clip coordinate
}

フラグメントシェーダ
varying vec4 vPos;
uniform float depthRange;
void main() {
        float depth = vPos.z/depthRange;
    gl_FragColor.rgb = vec3(depth,depth,depth);
    gl_FragColor.a = 1.0;
}

デモ


カメラのnear-farの幅、つまりフラスタムが広すぎに設定するとやはりうまくグラデーションにはならない。
今回はカメラの設定こんなかんじにしました

    var camera = new THREE.PerspectiveCamera(75, width / height,  1, 1500);
    camera.position.z = 1000;

地面ぽい板はフラスタムめいっぱいはみ出るぐらいの大きさに設定し、
TorusKnotGeometryの大きさは400ぐらい

フルソースコード

<script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script>
 <script type="x-shader/x-vertex" id="vshader">
varying vec4 vPos;
void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    vPos = gl_Position;//clip coordinate
}
    </script>
 <script type="x-shader/x-fragment" id="fshader">
varying vec4 vPos;
uniform float depthRange;
void main() {
    float depth = vPos.z/depthRange;
    gl_FragColor.rgb = vec3(depth,depth,depth);
    gl_FragColor.a = 1.0;
}
    </script>
  <script>
    var width = 600;
    var  height =300;
    var scene = new THREE.Scene(); 
    var camera = new THREE.PerspectiveCamera(75, width / height,  1, 1500);
    camera.position.z = 1000;
 
    var renderer = new THREE.WebGLRenderer({ alpha: true ,antialias:true});
    renderer.setClearColor( new THREE.Color(0xffffff),0.0);//背景色
    renderer.setSize(width,height); // Set the size of the WebGL viewport.
    document.body.appendChild(renderer.domElement); // Append the WebGL viewport to the DOM.
    var material = new THREE.ShaderMaterial({
       uniforms:{
         depthRange:{value:camera.far-camera.near}
        },
        vertexShader: document.getElementById('vshader').textContent,
        fragmentShader: document.getElementById('fshader').textContent
    });
    var planeGeometry = new THREE.PlaneGeometry( 10000, 10000, 10, 10 );//大きさ1000*100,分割数10*10
    var planeMesh = new THREE.Mesh( planeGeometry, material );
    planeMesh.position.y = -100;
    planeMesh.rotation.x = -90 * 2 * Math.PI / 360; //左に角度いれるとラジアンに変換
    scene.add(planeMesh) 
    var geometry = new THREE.TorusKnotGeometry(400, 100, 100, 16);
 
    var torus= new THREE.Mesh(geometry, material);
    scene.add(torus);
 
    var render = function () {
      torus.rotation.x += 0.01; 
      torus.rotation.y += 0.01;
 
      renderer.render(scene, camera);
      requestAnimationFrame(render);
    };
 
    render();
  </script>
</body>

カメラ座標から取ってくる、デプスっぽい値

ローカル座標×モデルビュー行列
カメラ座標になります
そのカメラ座標のzの値を見てみると、通常見えてる物は負の値になってると思います。
正負反転させると、デプス値っぽい値が取れます。
ここでの値は、カメラからの距離です。
注意しないといけないので、カメラからの円心状に広がる距離ではなく、
ニアー面と平行なデプスの値と言うことです。
見えてる範囲のものは

「値-near値」〜「far値」

これを、正規化するには、nearとfarの値を使いましょう。
もし、ニアーでの値0,ローカル座標の原点を1,farでの値2になるような
デプスパラメータのようなものを作りたいならば、

(デプス値-near値)/(カメラとの距離値-near値)

です。
あるいは単純に

デプス値/カメラとの距離値

でもローカル座標の原点を1にすることが出来ます。


window-coordinate


ファイル

サポートサイト Wikidot.com window-coordinate