上一篇我们完成了2D渲染器,接下来要实现3D几何体的绘制。其实3D比2D没有多太多内容,无非就是多了几步空间变换和一个视角控制的部分。首先,我们设置一下视角,为之后的三维渲染做准备。
这里我们来简单谈谈空间变换。它的概念在unity渲染管线那篇文章中有详细介绍,大概就是要从模型空间变换到世界空间、变换到视角空间、变换到裁剪空间、变换到ndc空间、变换到屏幕坐标。因为这部分属于图形学入门的知识,再加上自己太懒不想打太多数学符号,因此直接上几张自己曾经做过的白板ppt:
好了,相信你对这几个空间变换有了一定的了解,那么接下来我们就补充一下Matrix类:
1 void Matrix::lookat(Vector3D camPos,Vector3D tarPos,Vector3D up){ 2 Vector3D xAxis,yAxis,zAxis; 3 zAxis=-(tarPos-camPos); 4 zAxis.normalize(); 5 xAxis=up.product(zAxis); 6 xAxis.normalize(); 7 yAxis=zAxis.product(xAxis); 8 yAxis.normalize(); 9 normalize(); 10 ele[0][0]=xAxis.x; 11 ele[0][1]=xAxis.y; 12 ele[0][2]=xAxis.z; 13 ele[1][0]=yAxis.x; 14 ele[1][1]=yAxis.y; 15 ele[1][2]=yAxis.z; 16 ele[2][0]=zAxis.x; 17 ele[2][1]=zAxis.y; 18 ele[2][2]=zAxis.z; 19 ele[0][3]=-(xAxis.dot(camPos)); 20 ele[1][3]=-(yAxis.dot(camPos)); 21 ele[2][3]=-(zAxis.dot(camPos)); 22 } 23 24 void Matrix::perspective(float fovy, float aspect, float near, float far){ 25 ele[0][0]=1/(aspect*tanf(fovy/2)); 26 ele[1][1]=1/(tanf(fovy/2)); 27 ele[2][2]=-((far+near)/(far-near)); 28 ele[2][3]=-(2*far*near)/(far-near); 29 ele[3][2]=-1; 30 } 31 32 void Matrix::viewPort(int left,int top,int width,int height){ 33 normalize(); 34 ele[0][0]=static_cast<float>(width)/2.0f; 35 ele[1][1]=-static_cast<float>(height)/2.0f; 36 ele[0][3]=static_cast<float>(left)+static_cast<float>(width)/2.0f; 37 ele[1][3]=static_cast<float>(top)+static_cast<float>(height)/2.0f; 38 }
其中lookat矩阵是从世界空间转换到视角空间的矩阵,perspective矩阵是从视角空间转换到裁剪空间的矩阵,viewport是从ndc空间转换到屏幕坐标的矩阵,要注意的是中间其实还有一步从裁剪空间坐标转移到ndc空间的变换,方法很简单,只需要给x、y、z、w都除以w即可,因此我没有单写它的矩阵,但大家千万不要忘了这一步。
在三维世界中,相机是一个非常重要的物体,它决定了视口的视野。由于一般情况下游戏引擎中的相机以对象的形式呈现,因此我把这里的相机单独做成了一个类。
1 #ifndef MAINCAMERA_H 2 #define MAINCAMERA_H 3 #include"vector3d.h" 4 5 class maincamera 6 { 7 public: 8 Vector3D pos,goal,up; 9 float fov,asp,near,far; 10 public: 11 maincamera(); 12 maincamera(Vector3D mpos,Vector3D mgoal,Vector3D mup,float mfov,float masp,float mnear,float mfar); 13 void rotateY(float angle); 14 };
首先相机作为一种对象(游戏物体),成员参数必须包括它在世界空间中的位置(pos)和旋转角度(这里使用的goal和up,分别表示相机看向的点以及相机自身的z轴方向,通过这两个向量可以唯一确定下来相机的旋转角度)。此外,在空间变换中我们知道:相机空间向裁剪空间变换时,其裁剪矩阵由相机的张角(fov)、asp(宽高比)、near(近裁剪面距离)、far(远裁剪面距离)来决定,因此这四个变量也必须要定义。
成员函数比较简单,构造函数种可以对相机的transform和属性参数进行设置,这里定义了一个rotateY函数,作用就是绕着Y轴旋转angle的角度,每帧调用rotateY就可以起到一种环绕浏览的效果。
1 #include "maincamera.h" 2 #include "vector4d.h" 3 #include "matrix.h" 4 #include "stdio.h" 5 6 maincamera::maincamera() 7 { 8 pos=Vector3D(0,4,-8); 9 goal=Vector3D(0,0,0); 10 up=Vector3D(0,1,0); 11 fov=45*3.14/180.f; 12 asp=1280/767.f; 13 near=1.f; 14 far=50.f; 15 } 16 maincamera::maincamera(Vector3D mpos, Vector3D mgoal, Vector3D mup, float mfov, float masp, float mnear, float mfar) 17 { 18 pos=mpos; 19 goal=mgoal; 20 up=mup; 21 fov=mfov; 22 asp=masp; 23 near=mnear; 24 far=mfar; 25 } 26 27 void maincamera::rotateY(float angle) 28 { 29 Vector4D pos4(pos.x,pos.y,pos.z,1); 30 Matrix rot; 31 rot.normalize(); 32 rot.rotationY(angle); 33 pos4=rot*pos4; 34 pos.setX(pos4.x); 35 pos.setY(pos4.y); 36 pos.setZ(pos4.z); 37 }
原文:https://www.cnblogs.com/puluomi/p/14605238.html