💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
上一节中,我们认识了3D世界中最基础的一个概念——坐标系,并且了解了XNA中使用Vector3类型来表示。但是,由于引入了深度信息,所以在空间中的物体要想正确的投影出来,还缺少一个重要的道具——摄像机。 先来回想一下用摄像机或照相机的经历吧!对于同样的目标物体,有以下因素影响成像的结果:摄像机位置、摄像机方向、镜头参数。当摄像机所处的位置不同时,对物体的观察角度影响了成像的结果。当摄像机横向或竖向的角度不同时,成像也呈横向或竖向不同的角度。当使用不同焦距的镜头时,即使摄像机位置和方向都不变,成像的结果依然有差异。 由此可见,要想取得正确的成像结果,即正确的绘制渲染出3D空间中的物体,对摄像机的确定是非常重要的。换句话说,只有确定了摄像机和物体,才能得到确定的一个渲染结果。 那么对于如此复杂的摄像机信息,在XNA中要如何表示呢?这个还是得分两个部分来表述,一个部分用于表示摄像机的位置、朝向的目标位置、向上的方向这三个视点属性,相当于把摄像机固定下来;另一部分用于表示摄像机的视角、成像的长宽比、投影参数这三个属性,相当于把镜头和像纸信息固定下来。下面我们分别来看一下这两部分在XNA中的表示方法。 在计算机图形学中,我们知道3D世界实际上就是矩阵,以后在3D世界中的大量操作的实质全是矩阵运算,所以我们要先介绍一下矩阵。当然不是介绍数学概念,而是XNA中的Matrix类。 XNA提供了Matrix类用于表示矩阵,它是一个4X4矩阵,可以进行数学运算,还提供了一些方法用于创建矩阵。常用的构造方法有两种,一是构造单位矩阵: Matrix matrix=Matrix. Identity; 另一种是创建特殊矩阵,Matrix类提供了一组以Create开头的静态方法用于创建需要的矩阵。 回到摄像机的表示当中来,对于摄像机的位置信息,实际上就利用了Matrix类的CreateLookAt()方法来创建一个视点的矩阵,方法原型是: public static Matrix CreateLookAt(Vector3cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector); 三个参数分别对应前述的摄像机位置、朝向、向上的方向。 对于镜头信息,还要稍微复杂一点,我们需要先了解一下投影。看下面的投影示意图(注:图片来源于网络)。实际上我们要定义的不是真正镜头上的焦距、光圈,而是这个这平截头体的信息。这个平截头体就是投影矩阵,位于该体以外的物体将无法成像。对于这个平截头体,我们需要确定的参数包括:视角即可视范围,通常是45度角;长宽比;近平面;远平面。有了这4个参数,也就把镜头的信息定义完了。 ![](https://box.kancloud.cn/2016-04-08_570727f9ea69d.gif) 同样的,Matrix类提供了CreatePerspectiveFieldOfView()方法来创建投影矩阵,该方法原型是: public static MatrixCreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, floatnearPlaneDistance, float farPlaneDistance); 4个参数对应的就是平截头体的4个值。 至此,我们使用了两个矩阵才把摄像机信息确定下来,这两个矩阵也可以称为视图矩阵和投影矩阵。由于摄像机在3D开发中用得比较多,所以我们定义一个Camera类来简化摄像机的构造,在以后的代码中可以方便的使用。该类的代码如下: ~~~ public class Camera : Microsoft.Xna.Framework.GameComponent { public Matrix view{get;protected set;} public Matrix projection { get; protected set; } public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up, float fieldOfView, float aspectRatio, float nearPlaneDistance,float farPlaneDistance) : base(game) { view = Matrix.CreateLookAt(pos, target, up); projection = Matrix.CreatePerspectiveFieldOfView(fieldOfView,aspectRatio,nearPlaneDistance,farPlaneDistance); } /// <summary> /// Allows the game component to perform any initialization it needs to before starting /// to run. This is where it can query for any required services and load content. /// </summary> public override void Initialize() { base.Initialize(); } /// <summary> /// Allows the game component to update itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> public override void Update(GameTime gameTime) { base.Update(gameTime); } } ~~~ 好了,本节的内容就到这里吧,有了摄像机,后边就可以开始开发工作了。 ——欢迎转载,请注明出处 [http://blog.csdn.net/caowenbin](http://blog.csdn.net/caowenbin) ——