Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Html WebGL:画布坐标到三维坐标_Html_Webgl - Fatal编程技术网

Html WebGL:画布坐标到三维坐标

Html WebGL:画布坐标到三维坐标,html,webgl,Html,Webgl,我试图找到我的WebGL视图端口的“左”边框,因为我想在那里绘制一些调试信息。(与大多数建模程序类似的轴迷你地图) 我当然可以得到包含WebGL视口的画布的宽度和高度 我真的很想知道如何计算二维画布坐标到三维坐标?在3d视口中查找左边框的最佳方法是什么 任何调查此事的人都应该阅读 或者看看GluProject()和GluUnproject() 我试图找到我的WebGL视图端口的“左”边框,因为我想在那里绘制一些调试信息。(像大多数建模程序一样的axis迷你地图)我当然可以获得包含WebGL视口

我试图找到我的WebGL视图端口的“左”边框,因为我想在那里绘制一些调试信息。(与大多数建模程序类似的轴迷你地图) 我当然可以得到包含WebGL视口的画布的宽度和高度

我真的很想知道如何计算二维画布坐标到三维坐标?在3d视口中查找左边框的最佳方法是什么


任何调查此事的人都应该阅读 或者看看GluProject()和GluUnproject()

我试图找到我的WebGL视图端口的“左”边框,因为我想在那里绘制一些调试信息。(像大多数建模程序一样的axis迷你地图)我当然可以获得包含WebGL视口的画布的宽度和高度


只需切换这些零件的视口和投影。您可以随时更改它们。

为了澄清DatenWalf的答案,3D空间和2D画布之间的坐标映射正是您想要的。您可以使用
gl.viewport
和传递给着色器的矩阵来控制它

gl.viewport
只需在画布上画出一个矩形像素即可。大多数情况下,这与画布的尺寸完全匹配,但在某些情况下,您只希望绘制画布的一部分。(例如,分屏游戏。)从这里开始,要绘制的画布区域将被称为视口。如果您愿意,您可以假设它与“画布”的含义相同

最简单的情况是,视口在X轴和Y轴上始终具有从-1到1的隐式坐标系。这是顶点着色器输出的
gl_位置
操作所在的空间。如果在(-1,-1)处输出顶点,它将位于视口的左下角。(1,1)处的顶点将位于右上角。(是的,我现在忽略了深度)使用这个,你可以构造设计成映射到那个空间的几何体,并在根本没有任何矩阵变换的情况下绘制它,但这可能有点尴尬

为了使生活更简单,我们使用投影矩阵。投影矩阵只是将几何体从任意三维空间转换为视口所需的-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);
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);
我不打算讨论所有这些值的含义,但您可以清楚地看到,我们使用画布的宽度和高度来帮助设置此投影。这使得它看起来不会因画布大小而拉伸或挤压。然而,归根结底,将空间中的任何3D点与该矩阵相乘将生成一个映射到-1:1空间的点,同时考虑到与“相机”的距离和其他一切。(它实际上可能超出了这个界限,但这仅仅意味着它不在相机上。)这就是让我们的3D场景看起来3D的原因

不过,也可以创建专门用于绘制二维几何图形的投影矩阵。这称为正交矩阵,设置通常如下所示:

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);
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元素之类的东西时,这就是您想要的矩阵类型

很好的一点是,因为这些只是传递给着色器的值,所以从一个绘制调用到下一个绘制调用,可以使用完全不同的矩阵。通常,您将使用透视矩阵绘制所有三维几何图形,然后使用正交矩阵绘制所有UI

如果这有点漫无边际,我道歉。我从来都不擅长解释那些数学方面的东西。

看到了吗

基本上,如果您想在2D中绘制,请使用2D着色器,不要尝试使用3D着色器

WebGL在clipspace中绘制,所以您只需将像素转换为剪辑空间

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);
}

为什么不直接使用一些重叠的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>

谢谢你的详细解释。我知道GL视口及其到[-1,-1]的映射。我可以看出,使用正交投影矩阵有助于在“2d”中进行渲染。然而,这会弄乱我所有的其他对象。也许我应该重新表述一下我的问题:你们如何将世界坐标转换成屏幕坐标?它会如何扰乱你们的其他对象?您将继续使用标准透视矩阵渲染它们。你只需要对二维元素使用正交矩阵,这就需要我在透视矩阵之间不断变换,我对此不太满意。此外,带有代表轴的“箭头”的模型仍然是三维的,而不是二维的。这真的很有帮助:这正是我显示FPS、顶点数量等所做的。我意识到我的问题应该是:如何将屏幕坐标转换为世界坐标,反之亦然。