好吧,我们直接把glsl用字符串写进程序里的时代结束了……之前我们的glsl代码实际上是这个样子的:
之后我们的代码将会是这个样子的!:
是不是很诱人!!!那么我们就开始吧!
Shader类:
首先:你要新建一个C++类:
复制下面这些代码:(全是原教程的代码,我基本上没改,……也没看…………)
头文件(.h文件):
#pragma once #include <glad/glad.h> // include glad to get all the required OpenGL headers #include <string> #include <fstream> #include <sstream> #include <iostream> class Shader { public: // the program ID unsigned int ID; // constructor reads and builds the shader Shader(const GLchar* vertexPath, const GLchar* fragmentPath); // use/activate the shader //void use(); // utility uniform functions void setBool(const std::string &name, bool value) const; void setInt(const std::string &name, int value) const; void setFloat(const std::string &name, float value) const; };
.cpp文件:
#include "Shader.h" Shader::Shader(const char* vertexPath, const char* fragmentPath) { // 1. retrieve the vertex/fragment source code from filePath std::string vertexCode; std::string fragmentCode; std::ifstream vShaderFile; std::ifstream fShaderFile; // ensure ifstream objects can throw exceptions: vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { // open files vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); std::stringstream vShaderStream, fShaderStream; // read file's buffer contents into streams vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); // close file handlers vShaderFile.close(); fShaderFile.close(); // convert stream into string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch (std::ifstream::failure e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); // 2. compile shaders unsigned int vertex, fragment; int success; char infoLog[512]; // vertex Shader vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vShaderCode, NULL); glCompileShader(vertex); // print compile errors if any glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertex, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; }; // similiar for Fragment Shader fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fShaderCode, NULL); glCompileShader(fragment); // print compile errors if any glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragment, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; }; // shader Program ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); glLinkProgram(ID); // print linking errors if any glGetProgramiv(ID, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(ID, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } // delete the shaders as they're linked into our program now and no longer necessery glDeleteShader(vertex); glDeleteShader(fragment); }
void Shader::setBool(const std::string &name, bool value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); } void Shader::setInt(const std::string &name, int value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), value); } void Shader::setFloat(const std::string &name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); }
使用实例:
首先你需要把Shader.h加到你main.cpp(就是有main函数的.cpp文件)里:
#include "Shader.h"
然后建立一个Shader对象:
Shader myShaderProg("vtx.vs", "frag.fs");
两个初始参数分别是:vertexshader,fragmentshader的路径。我这边就把他们与main.cpp放在了一起。
然后是编辑这两个文件,我用的是vscood,因为里面有好用的高亮插件:
vtx.vs:
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 myC_a; out vec3 myC; void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); myC = myC_a; }
frag.fs:
#version 330 core in vec3 myC; out vec4 FragColor; void main() { FragColor = vec4(myC,1.0f); }
高亮插件:
最后是main.cpp(我的叫test.cpp):
// 1.头文件: #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include "Shader.h" // 5.OpenGL与窗口(main之前): void CBK_framebuffer_size(GLFWwindow* window, int w, int h) { glViewport(0, 0, w, h); } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } int main() { // 2.在创建窗口之前……: glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.创建窗口: GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // 4.在OpenGL之前……: if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // 5.OpenGL与窗口: glViewport(0, 0, 800, 600); glfwSetFramebufferSizeCallback(window, CBK_framebuffer_size); // OpenGL的配置: glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置背景色 // 绘图需要用的数据: float vertices[] = { // positions // colors 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top }; GLuint VBO; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); GLuint VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glBindVertexArray(0); Shader myShaderProg("vtx.vs", "frag.fs"); // 6.Render Loop: while (!glfwWindowShouldClose(window)) { processInput(window); glClear(GL_COLOR_BUFFER_BIT);//绘制背景色 // 这下面就可以写绘图的代码了 glUseProgram(myShaderProg.ID); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES,0,3); // 这上面是绘图的代码 glfwSwapBuffers(window); glfwPollEvents(); } // 7.程序结束之前: glfwTerminate(); return 0; }
运行结果如下: