从外部读取shader文件:
先添加Shader类:
再创建vertexSource.txt和fragmentSource.txt两个文件:
如图填入shader:
在shader.h宣告:
在shader.cpp中从外部读档:
#include "Shader.h" #include <iostream> #include<fstream> #include <sstream> #define GLEW_STATIC #include <GL/glew.h> #include <GLFW/glfw3.h> using namespace std; Shader::Shader(const char* vertexPath,const char* fragmentPath) { // 1. 从文件路径中获取顶点/片段着色器 ifstream vertexFile; ifstream fragmentFile; stringstream vertexSStream; stringstream fragmentSStream; // 打开文件 vertexFile.open(vertexPath); fragmentFile.open(fragmentPath); vertexFile.exceptions(ifstream::failbit || ifstream::badbit); fragmentFile.exceptions(ifstream::failbit || ifstream::badbit); try { if (!vertexFile.is_open()||!fragmentFile.is_open())//没有打开,丢出异常 { throw exception("open file error"); } vertexSStream << vertexFile.rdbuf();//从硬盘读取资料 fragmentSStream << fragmentFile.rdbuf();//从硬盘读取资料 vertexString = vertexSStream.str();//转成字符串 fragmentString = fragmentSStream.str(); vertexSource = vertexString.c_str(); fragmentSource = fragmentString.c_str(); unsigned int vertex, fragment; vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vertexSource, NULL); glCompileShader(vertex); checkCompileErrors(vertex, "VERTEX");//异常报错提示 fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fragmentSource, NULL); glCompileShader(fragment); checkCompileErrors(fragment, "FRAGMENT");//异常报错提示 ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); glLinkProgram(ID); checkCompileErrors(ID, "PROGRAM");//异常报错提示 glDeleteShader(vertex); glDeleteShader(fragment); } catch (const std::exception&ex) { printf(ex.what());//如果错误就跳到这执行 } } void Shader::use() { glUseProgram(ID); } void Shader::checkCompileErrors(unsigned int ID, std::string type) //宣告 {//测试报错 int success; char infoLog[512]; if (type!="PROGRAM") { glGetShaderiv(ID, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(ID, 512, NULL, infoLog); cout << "shader compile error:" << infoLog << endl; } } else { glGetProgramiv(ID, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(ID, 512, NULL, infoLog); cout << "progam Linking error:" << infoLog << endl; } } };
main.cpp写入:
#include <iostream> #define GLEW_STATIC #include <GL/glew.h> #include <GLFW/glfw3.h> #include "Shader.h" float vertices[] = { -0.5f,-0.5f,0.0f,1.0f,0,0, 0.5f,-0.5f,0.0f,0,1.0f,0, 0.5f,0.5f,0.0f,0,0,1.0f, -0.5f,0.5f,0.0f,1.0f,0,1.0f }; unsigned int indices[] = { // 注意索引从0开始! 0, 1, 2, //第一个三角形 0, 2, 3 //第二个三角形 }; //函数在main之前存档 void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {//退出键关闭窗口 glfwSetWindowShouldClose(window, true); } } int main(int argc, char* argv[]) { glfwInit();//初始化和创建窗口 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//提示用主版本号为3 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//次版本号为3,即为3.3版本的OpenGL glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //open GLFW window GLFWwindow* window = glfwCreateWindow(800, 600, "Test window", NULL, NULL);//800*600的窗口 if (window == NULL) {//如果为空指针 //std::cout << "open window failed." << std::endl;//打印失败 printf("open window failes."); glfwTerminate();//终止 return -1; //return EXIT_FAILURE; } glfwMakeContextCurrent(window); //init GLEW glewExperimental = true; if (glewInit() != GLEW_OK) { printf("Init GLEW failed."); //std::cout << "glew init failed." << std::endl; glfwTerminate(); return -1;//-1代表不正常退出 } glViewport(0, 0, 800, 600);//前两个参数控制窗口左下角的位置,后两个参数设置可绘制的像素大小 //第一个参数表示我们打算将其应用到所有的三角形的正面和背面,第二个参数告诉我们用线来绘制 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//线框模式 //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//关掉线框模式 Shader* myshader = new Shader("vertexSource.txt", "fragmentSource.txt");//指针调用 unsigned int VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); unsigned int VBO;//顶点缓冲对象 glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO);//顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER,使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上 //调用glBufferData函数,它会把之前定义的顶点数据复制到缓冲的内存中 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); unsigned int EBO; glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); //顶点属性,顶点属性的大小(vec3),数据类型,是否数据被标准化,步长,强制类型转换(表示位置数据在缓冲中起始位置的偏移量) glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(6);//启用顶点属性 glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float))); glEnableVertexAttribArray(7);//启用顶点属性 while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0.2f, 0.3f, 0.3f, 1.0);//清屏颜色填充RGB,透明度 glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); myshader->use(); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//改为glDrawElements即可。6为索引个数,0表示偏移。 glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; }
运行结果:没错!
现在,修改vertexSource文件内容:
运行:没出现图像,并且命令窗口报异常。