一、
在3d投影中新手最常迷惑的就是镜头(Camera)、屏幕、3d场景之间的关系了。下面示例的是透视相机效果,除此之外还有正交投影,但这里不涉及。
上图中near为从camera的近距截面,far为远距截面,在这两个面的范围内定义在屏幕上能显示的3D空间,其实就是个锥台,并经过投影计算,显示在screen面(屏幕)上。之所以需要near和far,我想可能是从渲染效率上考虑的。
二、
现在面临的问题: camera视角FOV,屏幕的尺寸,和可以显示3d场景的最大的范围,它们之间有怎样的数学关系??
1) 在相机垂直于地面的情况下,见下图:
cameraZ为相机高度,floorW为能看到的最大宽度,screenW为屏幕宽度,FOV为相机视角(field of view), d为相机到屏幕的深度。由相似三角形公式可得:
d / screenW = cameraZ / floorW
而 d = (screenW / 2) / tan(FOV/2)
所以,floorW = cameraZ * tan(FOV/2)*2 。
2) 在相机偏转有效的一个角度α,见下图:
W1 = cameraZ * tan(FOV/2 - α)
W2 = cameraZ * tan(FOV/2 + α)
floorW = W1 + W2 = cameraZ * ( tan(FOV/2 - α) + tan(FOV/2 + α))
PS: 不管相机怎么转动,平移,始终将屏幕和相机看成一个整体一起移动。相机到屏幕的垂点也总是在屏幕的中心点。
三、
在OpenGL、WebGL等中,如果想在屏幕中间画个400x300像素的2D矩形,那么该如何画?
在OpenGl等中定义屏幕为视口(Viewport),该视口的坐标系如下:
屏幕的四个顶点对应图上的四个坐标。屏幕坐标转换到视口坐标公式:
gl_X = ( pixel_X - screenW ) / screenW;
gl_Y = - (pixel_Y - screenH) / screenH;
所以,画400x300的2d矩形,只要将四个顶点在屏幕的像素坐标转换为GL坐标即可,并且Z坐标为零。
目前对3d的相机投影暂时研究到这里,也解决了我很久以来困扰的疑点,利用上面的数学公式,也还可以实现自己的投影相机,模拟三维效果。希望所写的东西能帮助别人。
最后,欢迎任何交流指正~