OpenGL3-着色器

169 阅读3分钟
着色器
  • 在之前的渲染管线的文章中,有讲到过管线流程有多个着色器,其中核心的有顶点着色器和片元着色器
  • 一个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);

}
  • 效果图