OpenGL可以绘制点、线、三角形,这些简单的东西叫做图元,多数3D模型通常是由许多三角形的图元构成。图元由顶点组成。顶点可以从文件读取并由C++/OpenGL应用载入缓冲区或直接在C++文件中硬编码字符串或直接在GLSL代码中。在加载顶点之前,C++/OpenGL应用必须编译并链接合适的GLSL顶点着色器和片段着色器程序,之后将它们载入管线。
C++/OpenGL应用同时负责通知OpenGL构建三角形,通过调用函数glDrawArrays(),管线中的GLSL代码开始执行。所有的顶点都会被传入顶点着色器。着色器对每个顶点执行一次,这些执行过程通常是并行的。
glDrawArrays (GLenum mode, GLint first, GLsizei count);
mode参数是图元的类型——对于三角形用GL_TRIANGLES。First参数表示从哪个顶点开始绘制(通常是顶点0,即第一个顶点),count是要绘制的顶点总数。
将GLSL程序载入着色器
1、 使用C++获取GLSL着色器代码,从文件或字符串中读取
2、 创建OpenGL着色器对象并将GLSL着色器代码加载进着色器对象
3、 用OpenGL命令编译并连接着色器对象,并将其安装进GPU
OpenGL中点的默认大小为1像素。
窗口中央有一个蓝色的点的代码如下。
main.cpp
(#include列表与之前同) #define numVAOs 1 GLuint renderingProgram; GLuint vao[numVAOs]; GLuint createShaderProgram() { const char* vshaderSource = "#version 460 \n" "void main(void) \n" "{ gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }"; const char* fshaderSource = "#version 460 \n" "out vec4 color; \n" "void main(void) \n" "{ color = vec4(0.0, 0.0, 1.0, 1.0); }"; GLuint vShader = glCreateShader(GL_VERTEX_SHADER); // 创建类型 GL_VERTEX_SHADER 的着色器,返回引用它的序号 GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER); // 创建类型 GL_FRAGMENT_SHADER 的着色器,返回引用它的序号 glShaderSource(vShader, 1, &vshaderSource, NULL); // 将GLSL代码从字符串载入空着色器对象中 glShaderSource(fShader, 1, &fshaderSource, NULL); glCompileShader(vShader); // 编译各着色器 glCompileShader(fShader); GLuint vfProgram = glCreateProgram(); // 创建程序对象,并储存指向它的整数ID glAttachShader(vfProgram, vShader); // 将着色器加入程序对象 glAttachShader(vfProgram, fShader); glLinkProgram(vfProgram); // 让GLSL编译器确保它们的兼容性 return vfProgram; } void init(GLFWwindow* window){ renderingProgram = createShaderProgram(); glGenVertexArrays(numVAOs, vao); glBindVertexArray(vao[0]); } void display(GLFWwindow* window, double currentTime) { glUseProgram(renderingProgram); // 将含有两个已编译着色器的程序载入OpenGL管线阶段(在GPU上),没有运行着色器,只是将着色器加载进硬件 glDrawArrays(GL_POINTS, 0, 1); // 启动管线处理过程 } (main函数与之前同)
字符串 vshaderSource 是顶点着色器中硬编码了一个顶点。顶点着色器的主要目标是将顶点发送给管线。内置变量 gl_Position 用来设置顶点在3D空间的坐标位置,并发送至下一个管线阶段。GLSL数据类型 vec4 用来存储4元组。
顶点接下来将沿着管线移动到光栅着色器,它们在这里被转换成像素位置。最终这些像素到达片段着色器 fshaderSource 。片段着色器的目的是给将要展示的像素赋予RGB颜色。本例中是蓝色。"out" 标签表明 color 变量是输出变量。在顶点着色器中 gl_Position 是预定义的输出变量,所以并不是必须给它指定 "out" 标签。
当准备将数据集发送给管线时是以缓冲区形式发送的,这些缓冲区最后都会被存入顶点数组对象(Vertex Array Object, VAO)中,即使应用程序没有用到任何缓冲区,OpenGL仍然需要在使用着色器的时候至少有一个创建好的 VAO,所以 init() 后两行用来创建OpenGL要求的 VAO。
glShaderSource()有4个参数:
1、着色器对象;2、着色器源代码中的字符串数量;3、包含源代码的字符串指针;4、指定一个长度数组,其中包括给定着色器程序中每行代码的字符串的整数长度。如果设为NULL,OpenGL将会自动从以 NULL 结尾的字符串中构建这个数组。
glShaderSource(GLuint shader, GLsizei count, const GLchar *const* string, const GLint* length);
结果如下:
在display()中加入下面代码,放在 glDrawArrays() 前面
glPointSize(30.0f);
当光栅化阶段从顶点着色器收到顶点时,它会为一个大小是30像素的点设置像素颜色值。
结果如下: