我以前在这里看过这类问题,但没有一个能给我一个完整的答案,所以我要发布我的代码,看看是否有人可以给我任何见解。基本上,这段代码有效,但我有一个神奇的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.viewportZoom = -gl.viewportHeight * 1.205;
和
gl.modelView.translate([-gl.viewportHalfWidth, gl.viewportHalfHeight, gl.viewportZoom]);
此代码适用于任何大小。
以下是700x300的屏幕截图:http://oi49.tinypic.com/2my9ir7.jpg
另一个是400x600:http://oi46.tinypic.com/i2irh3.jpg
所以问题是:为什么这个神奇的比例因子1.205存在?或者我认为有必要做些什么呢?
答案 0 :(得分:3)
我还没有计算出数学,但我猜这个因素来自你的透视投影矩阵的FOV和近平面。大多数试图获得1:1像素的应用程序也不使用透视投影。
如果您有理由使用透视,那么我建议不要使用基于FOV的透视计算,而是使用基于视锥体(glFrustum
- 相似) - 实际推导投影视锥的效果要容易得多,你可以从第一原理中找出修正因子,而不是手工调整。
这实质上是一个三角问题。想象一下视锥体,或者更确切地说是视锥体(即没有被近处和远处的平面切断);它的尖端位于“摄像机位置”和四个倾斜的面。传统定义的FOV等于顶面和底面之间的角度(这就是为什么,如你所说,宽度没有影响)。但是,出于您的目的,您关心的参数不是角度,而是斜率(Z与X或Y移动的比率) - 这是您的任意数字的来源。
如果我们看一下the documentation for good ol' gluPerspective
(我将假设使用与您的透视操作相同的数学运算),它会说: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
,post
,drawAsPrimitives
等等。如果你提到了什么,这将会有所帮助你正在使用的图书馆。)