javascript - WebGL 透视相机 Canvas 大小调整问题

标签 javascript matrix 3d webgl

编辑:已确认问题不是矩阵,而是 Canvas 。 Canvas 似乎在调整大小,但实际上它正在剪切模型的部分内容,直到我进行整个刷新。

实时预览:http://jsfiddle.net/B5B8k/6/

我将 C++ 底层引擎代码移植到 Javascript,并设置了一个由 6 个顶点(2 个三 Angular 形)组成的基本正方形,并尝试渲染它。我现在发现问题与 Canvas 有关。 Canvas 的大小正在调整为窗口的内部宽度和窗口的内部高度。每当窗口被拉伸(stretch)时, Canvas 的一部分仍然是“gl.clear”颜色,它覆盖了我正在渲染的任何内容。

this.getPerspective = function(fov, aspect, zNear, zFar) {
    var yMax = zNear * Math.tan(fov * Math.PI / 360);
    var yMin = -yMax;
    var xMin = yMin * aspect;
    var xMax = yMax * aspect;
    return this.getFrustrum(xMin, xMax, yMin, yMax, zNear, zFar);
};
this.getFrustrum = function(left, right, bottom, top, zNear, zFar) {
    var X = 2*zNear/(right-left);
    var Y = 2*zNear/(top-bottom);
    var A = (right+left)/(right-left);
    var B = (top+bottom)/(top-bottom);
    var C = -(zFar + zNear)/(zFar - zNear);
    var D = -2*zFar*zNear/(zFar - zNear);

    return new Mat4(X,0,A,0, 0,Y,B,0, 0,0,C,D, 0,0,-1,0);
};

此函数接受“数字”:

  • fov(以度为单位)

  • 宽高比(窗口宽度/窗口高度)

  • z 靠近裁剪平面

  • 和 z 远剪裁平面。

如果您需要查看更多代码,请询问。

最佳答案

简短的回答是您需要调用gl.viewport,如下所示

gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

您可以在 resize 中调用它,但可以说您应该在 draw 函数中调用它,因为将来如果您使用帧缓冲区对象,则每次都需要调用它您切换到与 Canvas 大小不同的帧缓冲区。

长版本是您永远不应该使用 window.innerWidthwindow.innerHeight 因为这些硬编码您的应用程序只能在完整窗口中运行。相反,请使用canvas.clientWidth和canvas.clientHeight,因为它们在所有情况下都适用,例如 Canvas 仅覆盖页面的一部分,例如带有设置列的3D编辑器,或嵌入,如文章中。

最重要的是,对于像您的应用程序一样不断呈现的应用程序,最好出于同样的原因调用调整每个帧的大小。

function draw() {
   resize();
   ...

调整大小这样写

        function resize() {
            var width = canvas.clientWidth;
            var height = canvas.clientHeight;
            if (canvas.clientWidth != width ||
                canvas.clientHeight != height) {
              canvas.width = canvas.clientWidth;
              canvas.height = canvas.clientHeight;
              perspective = new Mat4()
              perspective = perspective.getPerspective(60, canvas.clientWidth / canvas.clientHeight, 0.1, 100);
              perspective.mat[3][3] = 1;
              perspective = perspective.mul(new Mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -5, 0, 0, 0, 1));
           }
        }

原因是,虽然 resize 事件在窗口大小调整时起作用,但如果 Canvas 因其他原因调整大小则无济于事。再说一遍,在所有情况下每帧调用 resize 都有效,而仅在 resize 事件上调用 resize 仅在一种特定情况下有效。

您甚至可以在绘制函数中移动 perspective.mat 操作代码,因为如果将来您绘制到帧缓冲区(例如绘制阴影贴图),您将不得不更改您的无论如何,透视矩阵。虽然每帧做尽可能少的工作当然是一个好主意,但在大型方案中,每帧您只会计算一次或两次透视矩阵,而稍后随着对象的增多,您可能会计算大量的东西在绘制循环中,因此计算透视矩阵所花费的时间相对来说是最小的成本。

最后,循环末尾的 gl.useProgram(0) 对于 WebGL 无效,并且会在 JavaScript 控制台中生成大量错误。

关于javascript - WebGL 透视相机 Canvas 大小调整问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24173270/

相关文章:

python - DeprecationWarning : Non-string object detected for the array ordering. 请改为传入 'C' 、 'F' 、 'A' 或 'K'

java - 在 infovis javascript 中下载 Spacetree 中的子节点

javascript - jQuery .lastLoad 的几个事件

javascript - 如何在非编辑模式下隐藏输入文本,然后在单击 Lotus Web 表单中的编辑命令按钮时启用输入文本

javascript - Highcharts 仪表不呈现文本

r - 将方阵分解成对

c - 矩阵从左上到右下的导航,只向右或向下移动?

c# - 3d 对象未渲染

.net - .NET 中的凸包生成

r - 如何按数据框或矩阵中的不同行进行子集化?