着色器
- 在之前的渲染管线的文章中,有讲到过管线流程有多个着色器,其中核心的有顶点着色器和片元着色器
- 一个OpenGL程序中,C++代码做的事情只是在CPU中申请开辟一块内存缓冲区用于保存顶点的坐标和颜色等数据,但没有进行图形的绘制。真正绘制操作是由顶点着色器和片元着色器完成。
顶点着色器:
- 不管多复杂的场景,都是由最基础的顶点数据组成,然后生成基本图元,最后才构成复杂的物体,所以首先我们要操作顶点数据,怎么操作?使用顶点着色器。
- 顶点着色器的主要工作是接收到顶点数据,经过计算确定顶点在屏幕的什么位置,接着传递到下一个管线阶段。为了计算顶点数据对应再屏幕上的位置,需要用到变换矩阵,当有光照时,需要计算当前顶点的颜色。
片元着色器:
- 片元着色器主要决定某个片元的颜色是什么,经过光栅化操作后,已经知道了图形在屏幕上的像素位置,通过片元着色器可以确定给这个像素渲染什么颜色
- 如果有纹理贴图效果,还需要通过纹理采样器和纹理坐标位置,获取纹理图像的像素值进行绘制
着色器语言GLSL
- 着色器程序在OpenGL中使用GLSL(着色器语言)进行编程,以字符串的方式进行编码,要使用还需要经过一系列步骤,包括:
- 创建着色器对象(顶点和片元着色器对象共两个):glCreateShader();
- 指定着色器对象的代码:glShaderSource()
- 编译着色器对象:glCompileShader()
- 创建程序对象: glCreateProgram()
- 为程序对象分配着色器对象:glAttachShader()
- 链接程序对象:glLinkProgram()
GLuint createShaderProgram(){
const char *vertex_shader =
"#version 410 \n"
"void main(void){ \n"
" gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n"
"} \n";
const char *fragment_shader =
"#version 410 \n"
"out vec4 color; \n"
"void main(void){ \n"
" color = vec4(0.0, 0.0, 1.0, 1.0); \n"
"} \n";
// 创建着色器对象
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
// 创建着色器程序
GLuint vfProgram = glCreateProgram();
// 加载着色器代码
glShaderSource(vShader, 1, &vertex_shader, NULL);
glShaderSource(fShader, 1, &fragment_shader, NULL);
// 编译着色器对象
glCompileShader(vShader);
glCompileShader(fShader);
// 着色器程序绑定着色器对象(两个)
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
// 链接着色器程序
glLinkProgram(vfProgram);
return vfProgram;
}
右手坐标系
- OpenGL处理的是三维图形,具有X,Y,Z轴,当我们面向屏幕时,X轴时水平的(正方向为右),Y轴时垂直的(正方向向上),Z轴垂直于屏幕(正方向向外),且坐标系原点(0.0,0.0,0.0)在屏幕中心,这套坐标系也叫右手坐标系
实战:在屏幕上绘制一个蓝色的点
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
#define numVAOs 1
GLuint renderProgram;
GLuint vao[numVAOs];
// 创建着色器程序
GLuint createShaderProgram(){
...
}
void init(GLFWwindow* window) {
renderProgram = createShaderProgram();
// 创建vao,并绑定
glGenVertexArrays(numVAOs, vao);
glBindVertexArray(vao[0]);
}
void display(GLFWwindow* window, double currentTime) {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(renderProgram);
glPointSize(30.0);
glDrawArrays(GL_POINTS, 0, 1);
}
int main(void) {
if (!glfwInit()) {
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(600, 600, "OpenGL Demo", NULL, NULL);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
exit(EXIT_FAILURE);
}
glfwSwapInterval(1);
init(window);
while (!glfwWindowShouldClose(window)) {
display(window, glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
- 效果图