从文件读取Vertex Shader 和 Fragment Shader的工具类。

代码如下:

Shader.h

#ifndef Shader_h
#define Shader_h

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

class Shader
{
public:
    Shader();

    Shader(const GLchar* vsPath, const GLchar* fragPath);

    ~Shader();

public:
    void init(const GLchar* vsPath, const GLchar* fragPath);

    void useProgram();

    GLint getUniformLocation(const GLchar* uniformName);

private:
    //create vertex shader
    void createVertexShader(const GLchar* vsPath);

    //create fragment shader
    void createFragmentShader(const GLchar* fragPath);

    //create shader program
    void createShaderProgram();

    //load string from file
    std::string loadFile(const GLchar* filePath);

private:
    GLuint _vertexShader;
    GLuint _fragmentShader;
    GLuint _shaderProgram;

};


#endif //Shader_h

Shader.cpp

#include "Shader.h"

Shader::Shader(){
}

Shader::Shader(const GLchar* vsPath, const GLchar* fragPath){
    init(vsPath, fragPath);
}

Shader::~Shader(){
}

void Shader::init(const GLchar* vsPath, const GLchar* fragPath){
    this->createVertexShader(vsPath);
    this->createFragmentShader(fragPath);
    this->createShaderProgram();
}

void Shader::useProgram(){
    glUseProgram(this->_shaderProgram);
}

GLint Shader::getUniformLocation(const GLchar* uniformName){
    GLint uniLocation = glGetUniformLocation(_shaderProgram, uniformName);
    return uniLocation;
}


void Shader::createVertexShader(const GLchar* vsPath){
    //compile vertex shader source
    std::string vertexShaderStr = this->loadFile(vsPath);
    const char *vertexShaderSrc = vertexShaderStr.c_str();
    std::cout << "vertexShaderSrc:\n" << vertexShaderSrc;
    //GLuint vertexShader;                                     // shader object
    _vertexShader = glCreateShader(GL_VERTEX_SHADER);         // create vertex shader object
    glShaderSource(_vertexShader, 1, &vertexShaderSrc, NULL); // shader source attach to shader object
    glCompileShader(_vertexShader);                           // compile shader
    //compile result check
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &success);
    if (!success){
        glGetShaderInfoLog(_vertexShader, 512, NULL, infoLog);
        std::cout << "vertex shader source compile failed...\n" << infoLog << std::endl;
        std::cout << vertexShaderSrc;
    }
}


void Shader::createFragmentShader(const GLchar* fragPath){
    //compile fragment shader source
    std::string fragmentShaderStr = this->loadFile(fragPath);
    const char *fragmentShaderSrc = fragmentShaderStr.c_str();
    std::cout << "\n\nfragmentShaderSrc:\n" << fragmentShaderSrc;
    //GLuint fragmentShader;
    _fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(_fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(_fragmentShader);
}


void Shader::createShaderProgram(){
    if (_vertexShader == NULL || _fragmentShader == NULL){
        return;
    }
    //shader program, link vertex shader object and fragment shader object
    //GLuint shaderProgram;
    _shaderProgram = glCreateProgram();               // create shader program
    glAttachShader(_shaderProgram, _vertexShader);     // attach vertex shader
    glAttachShader(_shaderProgram, _fragmentShader);   // attach fragment shader
    glLinkProgram(_shaderProgram);                    // linking
    //check link result
    GLint success;
    GLchar infoLog[512];
    glGetProgramiv(_shaderProgram, GL_LINK_STATUS, &success);
    if (!success){
        glGetProgramInfoLog(_shaderProgram, 512, NULL, infoLog);
        std::cout << "shader program linking failed...\n" << infoLog << std::endl;
        return;
    }
    //delete vertex shader object and fragment shader object
    glDeleteShader(_vertexShader);
    glDeleteShader(_fragmentShader);
}


//load string from file
std::string Shader::loadFile(const GLchar* filePath){
    std::ifstream fileStream;
    fileStream.exceptions(std::ifstream::badbit);
    try{
        fileStream.open(filePath);
        std::stringstream ss;
        ss << fileStream.rdbuf();
        fileStream.close();
        return ss.str();
    }
    catch (std::ifstream::failure e){
        std::cout << "read file failed, filePath = " << filePath <<std::endl;
    }
    return NULL;
}

使用方法:

const GLchar* vsPath = "D:\\code\\OpenGL\\opengl-learn\\hi-opengl\\003-shader\\triangles.vs";
const GLchar* fragPath = "D:\\code\\OpenGL\\opengl-learn\\hi-opengl\\003-shader\\triangles.frag";
Shader shader(vsPath, fragPath);

while (...)
{
shader.useProgram();
drawSomthing();
}


使用实例:
TrianglesFile.h

#ifndef  TrianglesFile_h
#define  TrianglesFile_h

#include "Shader.h"

class TrianglesFile
{
public:
    TrianglesFile();

    ~TrianglesFile();

public:
    virtual void init();

    virtual void draw();

private:
    Shader* _shader;

};

#endif // TrianglesFile_h

TrianglesFile.cpp

#include "TrianglesFile.h"

TrianglesFile::TrianglesFile(){
}

TrianglesFile::~TrianglesFile(){
    delete _shader;
}


void TrianglesFile::init(){
    // x,y,z  opengl coordinates, the vertex data, three 3d point in normalized device coordinates
    GLfloat vertexs[] = {
        -0.6f, 0.9f, 0.0f, 0.0f, 0.0f, 1.0f,    // top
        -0.3f, 0.2f, 0.0f, 0.0f, 1.0f, 0.0f,    // left down
        -0.9f, 0.2f, 0.0f, 1.0f, 0.0f, 0.0f,    // right down
    };
    //define VAO, vertex array object
    //GLuint VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO); // bind vertex array object
    //define VBO, vertex buffer object
    GLuint VBO;
    glGenBuffers(1, &VBO);                                                   // gen buffer object
    glBindBuffer(GL_ARRAY_BUFFER, VBO);                                      // bind buffer to the target
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW); // copy vertex data to VBO
    //set vertex attribute point, position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    //set vertex attribute point, color
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(sizeof(GLfloat)* 3));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);//unbind vertex array object

    //create shader program
    const GLchar* vsPath = "D:\\code\\OpenGL\\opengl-learn\\hi-opengl\\003-shader\\triangles.vs";
    const GLchar* fragPath = "D:\\code\\OpenGL\\opengl-learn\\hi-opengl\\003-shader\\triangles.frag";
    this->_shader = new Shader(vsPath, fragPath);
}

void TrianglesFile::draw(){
    //use shader programs
    this->_shader->useProgram();

    //set uniform value
    GLfloat currentTime = glfwGetTime();                          // current time
    GLfloat redColor = (sin(6 * currentTime) + 1.0f) / 2.0f;   // sin value, like [0.0f, 1.0f]
    GLfloat blueColor = (cos(6 * currentTime) + 1.0f) / 2.0f;
    GLfloat alphaValue = (sin(6 * currentTime) + 1.0f) / 2.0f;
    GLint uniColorLocation = this->_shader->getUniformLocation("uniColor");
    glUniform4f(uniColorLocation, redColor, 0.0f, blueColor, 1.0f);    // reset uniform color

    //draw the triangles
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);
}

triangles.vs

#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 color;
out vec4 vertexColor;

void main () {
  gl_Position = vec4(pos, 1.0);
  //vertexColor = vec4(0.99f, 0.5f, 0.2f, 1.0f);
  vertexColor = vec4(color, 1.0f);
}

triangles.frag

#version 330 core
in  vec4 vertexColor;
out vec4 color;
uniform  vec4 uniColor;    // define uniform color

void main () {
  //color = vertexColor;     // set out color as vertex color
  //color = uniColor;        // set out color as unifrom color
  color = vertexColor + uniColor / 10;
}

运行结果:

12-23 10:08