2012-01-24 164 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