c++实现软光栅(二)实现立方体的绘制&几个视图矩阵变换&投影矩阵推导


首先放一张图震文^^
小白制的图
下文的讨论都和这个变换过程密切相关。并且本文不对基础的线性代数进行介绍,比如向量,矩阵,逆,转置的概念就不介绍了(本小白比较懒==)。

顶点数据分析

想从变换一个立方体的坐标开始着手。每一个物体都有自己的local坐标系,比如一个简单的正方体,它就自己的local坐标系。

如何变换到世界空间:Model_Matrix

缩放rotate_matrix

把缩放放在前面介绍,就是因为在具体的操作时,要先对向量左乘上rotate_matrix,(如果先平移or旋转再进行缩放的,可能会把平移or旋转的距离也缩放了,可以实验验证一下)。
旋转矩阵比较简单,如下图左边的矩阵。将这个矩阵乘在向量左边就得到最终的变换后的坐标(向量)了。
在这里插入图片描述

旋转

对于绕坐标轴的旋转矩阵,栗子:绕x轴顺时针旋转theta角度,如下图的第一个公式。绕y轴顺时针旋转theta角度,绕z轴顺时针旋转theta角度类似。
绕x、y、z轴旋转的矩阵
当然只是绕固定轴是无法满足需求的,伟大的数学家们找到了下面的绕任意轴的旋转矩阵公式。其中(Rx ,Ry ,Rz )表示任意旋转轴
在这里插入图片描述

平移

在这里插入图片描述

如何变换到摄像机空间:View_Matrix

经过上一步的变换,此时的正方体坐标已经不再是local空间里的了,而是对应到世界空间中的位置(比如我们可以规定它先缩放至原来1/2,向x轴方向移动100,绕x轴旋转45°,得到的8个点的坐标一定和原来是不同的)。
但是我们希望从上帝视角观察一个物体,犹如在画面中扛着摄像机记录一个画面(想象第一人称设计游戏的画面),就必须要计算物体在摄像机空间的坐标。
贴上一个大佬的文章,讲的比较详细。

计算View_Matrix主要就是要理解,R基和T基,T-1 就是逆变换一个物体需要的平移矩阵逆,RT 就是逆变换一个物体需要的旋转矩阵转置(其实本来是逆,但是正交矩阵的转置和逆是相等的,而转置又比较好计算,所以你懂啦),乘一下就是View_Matrix:C-1了。下面的表达式中,U表示右向量,V表示上向量,N表示目标指向相机的向量,T表示摄像机在世界空间的坐标
真理尽在闫令琪大佬的视频中
在这里插入图片描述
在这里插入图片描述

如何使视图更加符合人眼视角(产生近大远小效果):Projection_Matrix

要知道两种投影方式:正交投影和透视投影

  • 正交投影更接近真实世界的点线面特征,仿佛就把三维空间的物体直接拍到二维平面上的投影。正交投影矩阵见下图(来自闫令琪大神的课程讲义)
    在这里插入图片描述
    然后根据闫神的讲义,推导的正交矩阵如下:
    在这里插入图片描述

  • 透视投影要把原先的立方体不规则的压缩一下,然后再拍在二维屏幕上。预知矩阵推导请戳闫佬教程。传送门~
    把空间压成一个四棱锥箱子
    再通过透射投影拍到屏幕上去。
    注意:在OpenGL中NDC使用的是左手坐标系(投影矩阵交换了左右手),在闫神的讲解中使用的完全是右手坐标系。所以推导的公式可能有些不同。下面这个为右手坐标系下的透视投影矩阵
    在这里插入图片描述
    但是注意,在OpenGL中此时最好使用左手坐标系,把上面公式中的1改为-1,这样才能避免在后面的除以w(实际就是除z)操作中坐标的正负值颠倒。
    本文的项目使用的是左手坐标系,代码中所用公式如下:
    在这里插入图片描述

在这里插入图片描述
图示如下,其中a就是fov
在这里插入图片描述

裁剪空间具体做了啥

假如你进行透视投影变换,那么此时的坐标(x,y,z,w)的w值就不是原先设定的1了,如果直接将向量值左乘以Viewport_Matrix传到屏幕空间,那么是绝对画不出任何图形的,所以要在此时将w值变为1,即向量的所有分量都除以w就可。此时x,y,z的范围都在(-1.1)。本文和一些说法在此处有些不同,因为本文没有同OpenGL一样在投影时变换左右手坐标系。

如何变换到屏幕像素点空间: Viewport_Matrix

就是将每个点(x,y,z,w)中的x,y对应到屏幕空间具体的像素值。
具体的转换这篇讲的很细(是的我又偷懒了==)传送门

深度测试

x值,y值已经通过Viewport_Matrix变换到屏幕空间了,z值也变换到0-1的范围了。在x值和y值的约束下进行绘制比较好理解,就是一行行扫描光栅化就行了。但是每个点的z值决定了该点会不会被绘制出来。如何计算z值?(即给定三角形的三个顶点像素坐标[x,y,z,w],和屏幕某点像素点坐标[x,y],如何计算像素点的z值)
给三角形的三个顶点,插值出三角形内任意一点的z值方法:
重心坐标法(“重心坐标” 不是 “重心”)就是求出该点的重心坐标
在这里插入图片描述
重心坐标法的思想戳这里
上图公式可以看出,给定要求顶点的[x,y],三个顶点的[x,y,z]就可以通过计算出alpha,beta,gamma得出所求顶点的z值。
得到的z值是线性平均
最后 终于画出了汪==下一篇介绍透视投影带来的几种需要透视矫正的情况。
在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现三维空间,我们可以使用OpenGL进行渲染,而要实现可拖动的立方体,我们需要添加交互的功能。 以下是一个简单的示例代码,用于在窗口中显示一个可拖动的立方体: ```c++ #include <GL/glut.h> int winW = 640, winH = 480; // 窗口大小 GLfloat angleX = 0.0f, angleY = 0.0f; // 按照X和Y轴旋转的角度 GLfloat lastX, lastY; // 上一次鼠标的位置 void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); glRotatef(angleX, 1.0f, 0.0f, 0.0f); glRotatef(angleY, 0.0f, 1.0f, 0.0f); glutWireCube(2.0f); glutSwapBuffers(); } void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { lastX = x; lastY = y; } } void motion(int x, int y) { angleY += (x - lastX) * 0.1f; angleX += (y - lastY) * 0.1f; lastX = x; lastY = y; glutPostRedisplay(); } void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (GLfloat)w / (GLfloat)h, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(winW, winH); glutCreateWindow("Draggable Cube"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion); glEnable(GL_DEPTH_TEST); glutMainLoop(); return 0; } ``` 在这个示例代码中,我们使用了OpenGL的GLUT库来创建窗口并进行渲染。我们在`display`函数中绘制了一个线框立方体,使用`glTranslatef`和`glRotatef`函数来控制立方体的位置和旋转。在`mouse`和`motion`函数中,我们捕捉鼠标的移动并更新旋转角度,在`reshape`函数中设置视口和投影矩阵。 你可以通过按下鼠标左键并拖动来旋转立方体

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值