2012-01-24 329 views
3

我想找到我的WebGL視圖端口的「左」邊框,因爲我想繪製一些調試信息。 (最喜歡的建模程序的軸迷你地圖有) 我肯定可以得到含有WebGL的視口中的畫布的寬度和高度。WebGL:畫布座標到三維座標

我真的想知道如何去計算2D座標到三維座標?在三維視口中找到左邊界的最佳方法是什麼?


任何人都希望進入這個應該讀 http://webglfactory.blogspot.com/2011/05/how-to-convert-world-to-screen.html或看看GluProject()和GluUnproject()

回答

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元素的東西時,這就是你想要的矩陣類型!

好的部分是,因爲這些只是您傳遞給着色器的值,您可以使用完全不同的矩陣從一個繪製調用到下一個。通常,您將使用透視矩陣繪製所有3D幾何圖形,然後使用正交矩陣繪製所有UI。

道歉,如果這有點散漫。我從來都不擅長解釋所有這些數學問題。

+0

感謝您的長篇解釋更新。我知道GL視口及其映射到[-1,-1]。我可以看到使用正交投影矩陣可以有助於在「2d」中進行渲染。然而,這會弄亂我所有的其他對象。也許我應該改寫一下我的問題:如何將世界轉換爲屏幕座標? – Tom

+0

它會如何混淆你的其他對象?您將繼續使用您的標準透視矩陣呈現它們。您只需要爲2D元素使用正交矩陣。 – Toji

+0

那麼,這將需要我不斷改變視角矩陣,我對此並不滿意。 此外,表示軸的「箭頭」的模型仍然是3d而不是2d。 – Tom

1

我試圖找到我的WebGL的視口的「左」的邊界,因爲我想在那裏畫出一些調試信息。 (最喜歡的建模程序的軸迷你地圖有)我肯定可以得到含有WebGL的視口中的畫布的寬度和高度。

只需切換視口和這些部分的投影。您可以隨時更改它們。

0

http://games.greggman.com/game/webgl-fundamentals

基本上,如果你想在2D繪製使用2D渲染,不要試圖用3D渲染搞亂。

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