Html 以像素分辨率使用WebGL画布,同时保留透视效果

Html 以像素分辨率使用WebGL画布,同时保留透视效果,html,canvas,html5-canvas,webgl,pixel,Html,Canvas,Html5 Canvas,Webgl,Pixel,我以前在这里见过这种类型的问题,但没有一个能给我一个完整的答案,所以我将发布我的代码,看看是否有人能给我一些见解。基本上,这个代码是有效的,但是我有一个神奇的z偏移量(高度*1.205)[不考虑宽度],我不知道为什么 设置尺寸并创建对齐向量: gl.viewportWidth = gl.canvas.width; gl.viewportHeight = gl.canvas.height; gl.viewportHalfWidth = gl.viewportWidth / 2; gl.viewpo

我以前在这里见过这种类型的问题,但没有一个能给我一个完整的答案,所以我将发布我的代码,看看是否有人能给我一些见解。基本上,这个代码是有效的,但是我有一个神奇的z偏移量(高度*1.205)[不考虑宽度],我不知道为什么

设置尺寸并创建对齐向量:

gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewportHalfWidth = gl.viewportWidth / 2;
gl.viewportHalfHeight = gl.viewportHeight / 2;
gl.viewportAspect = gl.viewportWidth / gl.viewportHeight;
gl.viewportZoom = -gl.viewportHeight * 1.205;
if (gl.alignmentTest) {
    gl.alignmentVertices = (new Buffer(    // TL, TM, BM, BR, TR, BL, TL
       [    1.0,                        -1.0,                    0.0,
        gl.viewportHalfWidth - 0.5,     -1.0,                    0.0,
        gl.viewportHalfWidth - 0.5, -(gl.viewportHeight - 1.0),  0.0,
        gl.viewportWidth - 1.0,     -(gl.viewportHeight - 1.0),  0.0,
        gl.viewportWidth - 1.0,         -1.0,                    0.0,
            1.0,                    -(gl.viewportHeight - 1.0),  0.0,
            1.0,                        -1.0,                    0.0], 3)).post();
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
mat4.perspective(45, gl.viewportAspect, 0.1, 1000.0, gl.perspective.current);
gl.perspective.post();    // ^ writes directly to current perspective buffer

gl.modelView.resetToIdentity();

gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

// Translate to pixel resolution
gl.modelView.push();
gl.modelView.translate([-gl.viewportHalfWidth, gl.viewportHalfHeight, gl.viewportZoom]);
gl.modelView.post();

// Alignment test?
if (gl.alignmentTest && gl.alignmentVertices) {
    gl.red.useAsAttribute(gl.shaderProg.vertexColour);
    gl.zero.vec2.useAsAttribute(gl.shaderProg.vertexTextureCoord);
    gl.alignmentVertices.drawAsPrimitives(gl.shaderProg.vertexPosition, gl.LINE_STRIP);
}

gl.disable(gl.BLEND);
绘制对齐向量:

gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewportHalfWidth = gl.viewportWidth / 2;
gl.viewportHalfHeight = gl.viewportHeight / 2;
gl.viewportAspect = gl.viewportWidth / gl.viewportHeight;
gl.viewportZoom = -gl.viewportHeight * 1.205;
if (gl.alignmentTest) {
    gl.alignmentVertices = (new Buffer(    // TL, TM, BM, BR, TR, BL, TL
       [    1.0,                        -1.0,                    0.0,
        gl.viewportHalfWidth - 0.5,     -1.0,                    0.0,
        gl.viewportHalfWidth - 0.5, -(gl.viewportHeight - 1.0),  0.0,
        gl.viewportWidth - 1.0,     -(gl.viewportHeight - 1.0),  0.0,
        gl.viewportWidth - 1.0,         -1.0,                    0.0,
            1.0,                    -(gl.viewportHeight - 1.0),  0.0,
            1.0,                        -1.0,                    0.0], 3)).post();
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
mat4.perspective(45, gl.viewportAspect, 0.1, 1000.0, gl.perspective.current);
gl.perspective.post();    // ^ writes directly to current perspective buffer

gl.modelView.resetToIdentity();

gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

// Translate to pixel resolution
gl.modelView.push();
gl.modelView.translate([-gl.viewportHalfWidth, gl.viewportHalfHeight, gl.viewportZoom]);
gl.modelView.post();

// Alignment test?
if (gl.alignmentTest && gl.alignmentVertices) {
    gl.red.useAsAttribute(gl.shaderProg.vertexColour);
    gl.zero.vec2.useAsAttribute(gl.shaderProg.vertexTextureCoord);
    gl.alignmentVertices.drawAsPrimitives(gl.shaderProg.vertexPosition, gl.LINE_STRIP);
}

gl.disable(gl.BLEND);
所涉及的线路是:

gl.viewportZoom = -gl.viewportHeight * 1.205;
以及:

此代码适用于任何大小

以下是700x300的屏幕截图:

另一台400x600:


所以问题是:为什么1.205这个神奇的比例因子会存在?或者我做错了什么使其成为必要?

我还没有计算出数学,但我猜这个因素是由透视投影矩阵的FOV和近平面产生的。大多数试图获得1:1像素的应用程序也不使用透视投影

如果你有理由使用透视图,那么我建议不要使用基于FOV的透视图计算,而是使用基于平截头体的(
glFrustum
-类似)-实际推导投影平截头体的效果要容易得多,你可以根据第一原理计算出校正系数,而不是手动调整


这本质上是一个三角问题。想象视锥体,或者更确切地说是视锥体(即,不被近平面和远平面切断);它的尖端位于“摄像机位置”,有四个斜面。传统定义的FOV等于顶面和底面之间的角度(这就是为什么,正如您所提到的,宽度没有影响)。但是,出于您的目的,您关心的参数不是角度,而是坡度(Z与X或Y移动的比率)-这就是任意图形的来源

如果我们看一下(我假设它使用的数学与透视操作使用的数学相同),它会说:
f=cotangent(fovy/2)
。这正是我们关心的计算。(如果试图重现此情况,请注意,数学库中的大多数trig函数以弧度表示角度,而不是以度表示。)

出现系数2是因为FOV通常作为全视角测量,但感兴趣的值是该值的一半,即“正前方”和“刚好在视图边缘”之间的角度

您可能知道,余切(或切线)函数的值可以解释为斜率。上面的斜率f精确地告诉你Z运动和X或Y运动之间的比率;例如,如果将对象缩放某个值
d
,并将其沿Z轴移动
f*d
,则该对象看起来不会改变大小。这可能正是您的
viewportZoom
正在执行的操作:

f / 2 = cot(45° / 2) / 2 ≈ 1.207106
这非常接近你的1.205。如果事实是这样,我还没有计算出2的因子是从哪里来的

你所需要做的就是计算
f
一次(或者它的倒数
tan(fovy/2)
取决于最后哪个更方便),然后使用它来计算“缩放”距离和投影矩阵



(顺便说一句,你的代码包含了很多不是WebGL的东西,例如,
缓冲区
发布
绘图原语
,等等。如果你提到你正在使用的库,这可能会有帮助。)

我还没有计算出数学,但我猜这个因素是由透视投影矩阵的视场和近平面引起的。大多数试图获得1:1像素的应用程序也不使用透视投影

如果你有理由使用透视图,那么我建议不要使用基于FOV的透视图计算,而是使用基于平截头体的(
glFrustum
-类似)-实际推导投影平截头体的效果要容易得多,你可以根据第一原理计算出校正系数,而不是手动调整


这本质上是一个三角问题。想象视锥体,或者更确切地说是视锥体(即,不被近平面和远平面切断);它的尖端位于“摄像机位置”,有四个斜面。传统定义的FOV等于顶面和底面之间的角度(这就是为什么,正如您所提到的,宽度没有影响)。但是,出于您的目的,您关心的参数不是角度,而是坡度(Z与X或Y移动的比率)-这就是任意图形的来源

如果我们看一下(我假设它使用的数学与透视操作使用的数学相同),它会说:
f=cotangent(fovy/2)
。这正是我们关心的计算。(如果试图重现此情况,请注意,数学库中的大多数trig函数以弧度表示角度,而不是以度表示。)

出现系数2是因为FOV通常作为全视角测量,但感兴趣的值是该值的一半,即“正前方”和“刚好在视图边缘”之间的角度

您可能知道,余切(或切线)函数的值可以解释为斜率。上面的斜率f精确地告诉你Z运动和X或Y运动之间的比率;例如,如果将对象缩放某个值
d
,并将其沿Z轴移动
f*d
,则该对象看起来不会改变大小。这可能正是您的
viewportZoom
正在执行的操作:

f / 2 = cot(45° / 2) / 2 ≈ 1.207106
这非常接近你的1.205。如果事实是这样,我还没有计算出2的因子是从哪里来的

你所需要做的就是计算
f
一次(或者它的倒数
tan(fovy/2)
取决于最后哪个更方便),然后使用它来计算“缩放”距离和投影矩阵


(顺便说一句,您的代码包含许多非WebGL的内容,例如
Buffer