初衷
LearnOpenGL的教程看了很多遍,基本熟悉了对OpenGL API的调用,熟悉了顶点到像素点的绘制过程,以及不同的坐标系的效果,旋转矩阵的作用等。但想要深入了解图形API的内部渲染原理,得自己实现一遍才能有更清晰的体会,脱离GPU,用CPU实现绘制。这个项目旨在:
1.熟练c++语法;
2.熟悉图形渲染管线过程;
3.熟悉基础矩阵变换;
本小白的理解能力有限,希望错误的地方,读者可以帮忙指出来,共同讨论~
参考
[1]闫令琪大神的图形学课
[2]杨超大大的项目,放上大佬的某乎链接与项目链接github
[3]LearnOpenGL网站的知识
基础功能/代码层级
期待能实现简单立方体的绘制(纹理+光照+视图变换),球体的绘制,模型的读取。
然后我也不知道哪天能写完。。。代码层级?首先先画个三角形出来吧:
三角形的光栅化
OpenGL渲染流程
手撕光栅化流程代码的原因,就是想深入理解OpenGL渲染管线的具体细节。在写前,最好理清楚大致的pipeline流程,而不至于迷失在架构上。
配置好OpenGL上下文(窗口)后,将程序员定义的顶点数据发送给顶点着色器,顶点着色器中将传入的坐标利用几个坐标系转换矩阵进行变换(主要是Model,View,Projection这三种矩阵),得到的坐标信息再经过Viewport函数转换为屏幕上的对应位置,这样得到的位置数据再传入光栅器进行光栅化(这里就是我们要手撕代码自己实现的重点之一)生成对应的片元。光栅化后的像素点信息传入片元着色器计算最终颜色,然后再进行深度测试模板测试,如果一个片元通过所有的测试,就可以被直接绘制到帧缓存中了。
P.S.一个“片元”可以被视为一个“候选的像素”,因为片元着色器计算完片元的像素值后,该片元可能在后面的深度测试模板测试中被遮挡住,所以也可能不绘制。
下面放一张我自己制的比较好理解的图。
窗口的调用
本项目就简化对窗口调用部分,使用visual studio的win32项目的窗口。简单理解了win32窗口调用与绘制的关系,就可以上手撸OpenGL管线了。
ATOM MyRegisterClass(HINSTANCE hInstance);//设置窗口类属性
BOOL InitInstance(HINSTANCE, int);//创建一个全局窗口实例,为后文的窗口操作准备
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//消息回调函数,对窗口的操作都在这里完成
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LunaScene* scene;
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)//win32项目的入口函数,就类似控制台程序的main()函数
因为OpenGL的管线操作,就是一系列的流程,顶点变换,光栅化,片元裁剪等都有自己的顺序,所以我们在scene类中定义顶点vertex,方便管理对顶点的操作(比如顶点坐标的各种变换,顶点属性的存储)。场景scene最好是全局的,方便控制。
在InitInstance()函数中,初始化场景。
在WndProc()函数中,通过键盘,鼠标等改变顶点坐标,实现对场景的控制。
class LunaScene;//场景类,内含对目标物体的属性,以及各种操作的函数
class Lmesh; //网格类,存储一个具体目标的属性;
class LMatrix;//矩阵类,坐标变换的基础
添加双缓冲区,设置viewport部分
为了避免闪烁,在WndProc的WM_CREATE函数中创建了后备缓冲区,句柄是hdc_back_buffer,在WM_PAINT中将场景scene绘制到后备缓冲区,再将缓冲区内容调到屏幕上。
因为是对简单的三角形初始化,我直接给顶点赋值(0.0,0.5),(0.5,-0.5),(-0.5,-0.5),跳过了乘以MVP矩阵的构建(but出来混还是得还的- -后面还要加上)和裁剪坐标系,只要对顶点乘以viewport变换矩阵就可以了。
由上面两图可见,光栅化前要对标准化的设备坐标(-1.0-1.0)转换到屏幕的像素点坐标,比如该项目定义的(800,600)中去。
这里,要构建viewport转换矩阵,然后左乘到坐标向量上去,就完成转换了。
三角形光栅化
该项目的光栅化采用基础的扫描线法(小白懒 没调研其他的更快的方法)。
并不难,考虑清楚三角形的形状,避免遗漏一些形状。
具体三角形的扫描光栅化,这篇讲的比较细
考虑好各种三角形之后,就可以具体进行扫描光栅化了。举一个栗子,就上图一个普通的平底三角形而言。执行从y0到y1的逐行绘制。每一行都要计算XL与XR。
下一篇记录对鼠标键盘的消息响应,以显示立方体在屏幕上的显示结果。