OpenGL学习——自定义Shader工具类
从文件读取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_hShader.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_hTrianglesFile.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;
}运行结果:
