这一部分应该是我好几周之前实现的了,这次写这篇文章也算是复习了。
这篇文章是站在已经配置好OPenGl的环境,用VS创建一共空项目为前提了。
首先是根据我看到的视频教程或者papers,都有说到其实渲染分成传统的光栅化和近些年的光线追踪。首先此处的渲染指的是从数据开始制造一张图片,
光栅化:这个我写过代码看过论文和视频教程,我个人的理解其实光栅化的核心就是投影(MVP)这个矩阵。说白了就是:你现在有一个三维模型的数据(处于某种坐标系下),然后你需要根据这些数据,再加上你设置的视点等通过投影把这个三维模型投影到二维平面上。
这个图就是OPenGL官网上的图形渲染管线图。是一个光栅化的过程,其中三个着色器为蓝色,意思是可编程,就是我们可以干预的过程。
光线追逐:这个是一个模拟场景中光线进入人眼睛的过程,我感觉这个核心是在计算每一个像素的颜色贡献值上面,简单理解就是这个像素接受到的光线越多就会越亮,所以光线追踪的效果会好一点,当然渲染时间也对应久一点,关于光追这一块我目前代码写的不多,论文和相关资料只是有些接触,所以就不多说了,以后有机会我再专门写有关光线追踪的文章吧!
开始画三角形吧!
第一步:开一个窗口,在main函数中使用如下代码:
1、初始化窗口的参数:
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
2、生成一个窗口:
GLFWwindow* window = glfwCreateWindow(800, 600, "MyLearnOpenGL", NULL, NULL);
3、GLFW允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入。初始化这个库
glfwTerminate();
4、创建OpenGl上下文
glfwMakeContextCurrent(window);
到这里就可以呼出一共OPenGL的800*600的窗口了。然后就可以快乐的在里面绘制你想的画面了。
第二步:三角形数据准备,在main函数中使用如下代码:
懒得手打了,直接截图吧,下面是代码,画一个三角形目前只用VAO和VBO足够。
unsigned int VAO,VBO; //这个可以理解为一共索引的标志
glGenVertexArrays(1, &VAO); //可以理解为生成一个存储数据的数组
glBindVertexArray(VAO);
//这个可以填多个模型。多个模型的用法
//unsigned int VBO[10];
//glGenVertexArrays(10, VBO);
glGenBuffers(1,&VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//vertices是事先声明好的一组float类型的数据
(对于多个模型可以用EBO,然后接下来本应该是对顶点,颜色,UV,纹理的处理,但是画一个三角形不需要,只用对位置信息进行处理)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);//此处的0代表的是顶点数据,可以给0-15,不能是16.这0-15就可以代表顶点,法线,uv坐标等。
进入下一步:
第三部:写着色器
基础的顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos;
void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); }
可以理解这个0对应上文中的 glVertexAttribPointer里面的参数0.
基础的片段着色器,(这个小三角不需要几何着色器):
#version 330 core
out vec4 FragColor;
void main() { FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); }
//设置的颜色
第四步:设置MVP矩阵和渲染回圈
写到这里,属实累了,,,
下面是MVP中的M和P。
glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)800 / (float)600, 0.1f, 100.0f);
V矩阵在渲染回圈中获取,这个循环的意思就是每一帧屏幕回更新一下,View矩阵写在里面的好处是将来如果我们控制画面里面的视点移动,他会随着这个循环更新。
glm::mat4 view;
view = camera.GetViewMatrix();代码很简单。
渲染回圈是这样写的,很简单得嘞!
循环里面首先包括:
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//先设置清屏颜色
glClear(GL_COLOR_BUFFER_BIT);
然后是对于我们设置的MVP矩阵绑定到我们的shader上面。
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "model"), 1, GL_FALSE, glm::value_ptr(model2));
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "proj"), 1, GL_FALSE, glm::value_ptr(proj));
很无语,写到这个地方发现自己搞错了,其实画一个三角形就不需要MVP矩阵,我们上文设置的vertices数据其实就是直接是在屏幕坐标上设置的了。我真的栓q、
好吧,请大家先忽略上文有关MVP的代码,其实渲染回圈里面只需要下面代码即可:
processInput(window);加上上面的glclear那几个函数
//使用我们的渲染器
glUseProgram(shaderProgram);
好吧在数据准备完成之后应该先调用我们写好的着色器了。这一部分我下篇给补上吧!!!啊啊啊
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
到这里就画出来了,然后是交换缓存,可以理解为每一次循环的更新。
glfwSwapBuffers(window);
glfwPollEvents();
跳出这个渲染回圈:
glfwTerminate();//上文初始化的这个库不要忘记给他清除了。
return 0;
行文至此,落笔之处皆是思念,哈哈哈,好吧,最近师兄师姐快毕业,估计他们会用到。
个人第一次写类似的文章,会有很多不足,希望大家多多包容,下一期我尽量让思路更通畅一些。包括刚刚写的时候发现的两个问题,其中一个还没有补全,如果有大佬发现其他问题,可以批评指出,万分感谢,最后十分感谢Piccolo这个社区平台。
上一篇文章中有个小伙伴让我分享一些学习OPENGL的心得:
目前学习这么多时间,我个人决定OPENGL这个语言,还是需要多练习,然后去揣摩当初为什么这样设计的,我现在还处于练习期,心得谈不上,只能说这个语言基本上能够满足科研的很多需求了。
在这里我今天发现我们社区有一位大佬开始更新有关Vulkan的教程,樱粉花蜜糖 支持一波!