2012-01-24 7 views
3

WebGLビューポートの「左」境界線を見つけようとしています。そこにいくつかのデバッグ情報を描画したいからです。 (ほとんどのモデリングプログラムのような軸のミニマップがあります) 私は確かにWebGLビューポートを含むキャンバスの幅と高さを取得できます。WebGL:キャンバス座標を3D座標に合わせる

2次元キャンバス座標を3次元座標に計算する方法を知りたいですか? 3dビューポートで左の枠線を見つけるのに最も良い方法は何でしょうか?この覗く


誰もが http://webglfactory.blogspot.com/2011/05/how-to-convert-world-to-screen.htmlを読んだり、GluProject()とGluUnproject()を見てみなければならない私はWebGLのビューポートの「左」の境界線を見つけようとしています

答えて

6

datenwolfの答えを明確にするために、3D空間と2Dキャンバスの間の座標マッピングは、まさにあなたが望むものです。 gl.viewportと、シェーダに渡す行列で制御します。

gl.viewportは、描画しているキャンバス上のピクセルの四角形を単にブロックします。ほとんどの場合、これはキャンバスの大きさに正確に一致しますが、一部しか描かないシナリオがいくつかあります。 (例えば画面分割ゲーム)あなたが描いているキャンバスの領域は、ここからのビューポートと呼ばれます。あなたが望むなら、それは "キャンバス"と同じことを意味すると考えることができます。

最も簡単なことですが、ビューポートは、常にX軸とY軸の両方に-1から1までの暗黙の座標系を持ちます。これは、頂点シェーダの出力であるgl_Positionの出力空間です。(-1、-1)で頂点を出力すると、ビューポートの左下隅に表示されます。 (1、1)の頂点は右上になります。 (そう、今は奥行きを無視しています)これを使用すると、その空間にマップするように設計されたジオメトリを作成し、マトリックス変換を一切行わずに描画することができますが、少し面倒です。

私たちは人生を楽にするために、投影行列を使用します。投影行列は、任意の3D空間からジオメトリをビューポートで必要な-1から1の空間に変換するものです。最も一般的なものは遠近法マトリックスです。どのようにあなたはそれはあなたが使用するライブラリに依存ビット異なります作成しますが、一般的に、それはこのようなものです:

var fov = 45; 
var aspectRatio = canvas.width/canvas.height; 
var near = 1.0; 
var far = 1024.0; 
var projectionMat = mat4.perspective(fov, aspect, near, far); 

私はすべてのそれらの値が何を意味するかに入るつもりはありませんが、あなたははっきりことがわかりますキャンバスの幅と高さを使用して、この投影を設定しています。キャンバスのサイズに応じて、伸ばしたり縮んだりしないようにすることができます。しかし、それはすべて、宇宙の3Dポイントを取り、それをこのマトリックスで掛ければ、「カメラ」からの距離と他のすべてを考慮に入れて、その-1から1スペースに写像するポイントを生み出すということです。 (それは実際にはその境界の外に出るかもしれませんが、それは単にそれがカメラ外にあることを意味します)。それが3Dシーンを3Dに見せる理由です。

しかし、2Dジオメトリを描画するための投影行列を作成することもできます。これは、正投影行列と呼ばれ、セットアップは一般的に次のようになります。

var left = 0; 
var top = 0; 
var right = canvas.width; 
var bottom = canvas.height; 
var near = 1.0; 
var far = 1024.0; 
var projectionMat = mat4.ortho(left, right, bottom, top, near, far); 

この行列は、それは完全に自分の位置のz成分を無視することで透視行列とは異なります。代わりに、この行列はピクセルのようなフラット座標を-1から1の範囲に変換します。そのため、あなたのシーンは3Dでは見えませんが、画面上に物が現れる場所を厳密に制御する方が簡単です。上の行列を使って、頂点に(16,16,0)を付けると、キャンバス上の(16,16)に表示されます(ビューポートはキャンバスと同じ次元であると仮定します)。そのため、フラットなUI要素のようなものを描きたい場合、これはあなたが望むマトリックスのタイプです!

これらの値はシェーダに渡す値なので、1回の描画呼び出しから次の描画呼び出しまでに全く異なる行列を使用できます。通常は、すべての3Dジオメトリを透視マトリックスで描画し、すべてのUIを正投影マトリックスで描画します。

これはちょっとしたことでしたがお詫び申し上げます。私はその数学的なことをすべて説明することが大変なことは一度もありませんでした。あなたは2Dで描画したい2Dシェーダを使用する場合

+0

おかげでそれを更新することができます。 GLビューポートとそのマッピングを[-1、-1]に認識しています。直交投影行列を使うことは "2d"でのレンダリングに役立つことがわかります。しかし、これは私の他のすべてのオブジェクトを台無しにするでしょう。多分私は少し質問を言い換えるべきです:世界をスクリーン座標に変換するにはどうしたらいいですか? – Tom

+0

それはあなたの他のオブジェクトをどのように混乱させるでしょうか?標準的なパースペクティブマトリックスでそれらをレンダリングし続けます。 2D要素には、オルト行列を使用する必要があります。 – Toji

+0

これは、私には視点のマリシティの間で絶えず変化する必要があり、私はそれにはかなり満足していません。 さらに、軸を表す「矢印」のモデルはまだ3dであり、2dではありません。 – Tom

1

I理由そこに多くのデバッグ情報を描画したいと考えています。 (ほとんどのモデリングプログラムのように軸のミニマップがあります)私は確かにWebGLビューポートを含むキャンバスの幅と高さを取得できます。

これらの部分のビューポートと投影を切り替えるだけです。いつでも変更することができます。

0

は、3Dシェーダをいじってみてくださいませんが、基本的にhttp://games.greggman.com/game/webgl-fundamentals

を参照してください。

WebGLはクリップスペースを描画するので、ピクセルからクリップスペースに変換するだけで済みます。

attribute vec2 a_position; 

uniform vec2 u_resolution; 

void main() { 
    // convert positions from pixels to 0.0 to 1.0 
    vec2 zeroToOne = a_position/u_resolution; 

    // convert from 0->1 to 0->2 
    vec2 zeroToTwo = zeroToOne * 2.0; 

    // convert from 0->2 to -1->+1 (clipspace) 
    vec2 clipSpace = zeroToTwo - 1.0; 

    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); 
} 
0

いくつかのオーバーレイされたHTMLを使用するのはなぜですか。

<html> 
<head> 
    <style> 
    #container { 
    position: relative; 
    } 
    #debugInfo { 
    position: absolute; 
    top: 0px; 
    left: 0px; 
    background-color: rgba(0,0,0,0.7); 
    padding: 1em; 
    z-index: 2; 
    color: white; 
    } 
    </style> 
</head> 
<body> 
    <div id="container"> 
    <canvas></canvas> 
    <div id="debugInfo">There be info here!</div> 
    </div> 
</body> 
</html> 

あなたは、長い説明のための

var debugInfo = document.getElementById("debugInfo"); 
debugInfo.innerHTML = "some info"; 
+0

これは、FPS、頂点の数などを表示するのとまったく同じです私の質問は、画面座標を世界座標に変換する方法とその逆を行う方法でした。 – Tom

関連する問題