本文是总结性C++面向对象封装,文件动态加载,数据动态添加,颜色动态添加,纹理动态添加。主要封装3大块:
1. 上下文环境封装()
2. 数据(顶点、颜色与纹理)加载封装;
3. 着色器的编译与连接封装
4. 测试文件
- 文件清单
文件名 | 说名 |
---|---|
gl_env.h | 环境头文件 |
gl_env.cpp | 环境实现文件 |
gl_data.h | 数据头文件 |
gl_data.cpp | 数据实现文件 |
gl_shader.h | 着色器头文件 |
gl_shader.cpp | 着色器实现文件 |
gl05_multi_texture.cpp | 调用测试文件 |
- 编译命令行
g++ -omain gl05_multi_texture.cpp gl_env.cpp gl_data.cpp gl_shader.cpp -lglfw -lglew -framework opengl
一、准备
1. 图片
-
bird.png
图片 -
texture.png
图片
2. 图像加载库
-
stb_image.h
,可以网络搜索下载
3. GLSL脚本
脚本放在目录glsl_script
下。
- 顶点着色器脚本
glsl05_v_multi_texture.glsl
#version 410 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;
layout (location = 2) in vec2 aCoord;
out vec4 vColor;
out vec2 vCoord;
void main(){
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
vColor = aColor;
vCoord = aCoord;
}
- 片着色器脚本
glsl05_f_multi_texture.glsl
#version 410 core
in vec4 vColor;
in vec2 vCoord;
uniform sampler2D sTexture_bird;
uniform sampler2D sTexture_texture;
out vec4 FragColor;
void main(){
FragColor = mix(texture(sTexture_bird, vCoord), texture(sTexture_texture, vCoord), 0.5) * vColor;
}
环境封装
头文件gl_env.h
#ifndef GL_ENV_H
#define GL_ENV_H
#include
#include // 该include之前必须先 #include
typedef void (*render_callback)(); // 回调绘制函数
struct GL_Env {
///////////////////////////////////////////////////
GLFWwindow* win;
///////////////////////////////////////////////////
void context(const char* title); // 初始化OpenGL上下文,使用GLFW框架
void opengl(); // 加载OpenGL
void destroy(); // 释放环境
void run(render_callback render_cb); // 开始绘制
};
#endif
实现文件gl_env.cpp
#include "gl_env.h"
void GL_Env::context(const char* title){
if(!glfwInit()){
return; // 给异常转移处理,这里暂时不处理
}
// 设置提示
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
win = glfwCreateWindow(600,400, title, NULL, NULL);
if(!win){
return; // 给异常转移处理,这里暂时不处理
}
glfwMakeContextCurrent(win);
}
void GL_Env::opengl(){
if(glewInit() != GLEW_OK){
return; // 留给异常转移处理,这里暂时不处理
}
}
void GL_Env::destroy(){
glfwTerminate();
}
void GL_Env::run(render_callback render_cb){
GLdouble oldTime = glfwGetTime();
while(!glfwWindowShouldClose(win)){
if(glfwGetTime() - oldTime > 0.1){
render_cb(); // 绘制函数回调
glfwSwapBuffers(win);
oldTime = glfwGetTime();
}
glfwPollEvents(); // 无阻塞消息处理
}
}
数据封装
头文件gl_data.h
#ifndef GL_DATA_H
#define GL_DATA_H
#include
struct GL_Data{
///////////////////////////////////////////////////
GLuint vertexArrayID; // 数据缓冲
GLushort texture_channel[8];
int id;
/**
* 实际定点数组可以多个,然后实现切换,这里只创建一个
*/
GL_Data();
///////////////////////////////////////////////////
void initVertextArrays(); // 初始化定点数组
void addData( // 传送数据到shader
const GLfloat *data, // 数据
GLsizeiptr size, // 数据缓冲长度
GLuint index, // shader中参数位置
GLint num); // 单位数据个数
void updateIndex( // 对定点数据进行索引
const GLuint *data, // 定点数组
GLsizeiptr size); // 数组大小
///////////////////////////////////////////////////
void addTexture(const char *fileName,int *width, int *height, int *depth);
///////////////////////////////////////////////////
void open();
void close();
};
#endif
实现文件gl_data.cpp
#include "gl_data.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
GL_Data::GL_Data(){
id = 0;
texture_channel[0] = GL_TEXTURE0;
texture_channel[1] = GL_TEXTURE1;
texture_channel[2] = GL_TEXTURE2;
texture_channel[3] = GL_TEXTURE3;
texture_channel[4] = GL_TEXTURE4;
texture_channel[5] = GL_TEXTURE5;
texture_channel[6] = GL_TEXTURE6;
texture_channel[7] = GL_TEXTURE7;
}
void GL_Data::initVertextArrays(){
glGenVertexArrays(1, &vertexArrayID);
}
void GL_Data::open(){
glBindVertexArray(vertexArrayID);
}
void GL_Data::close(){
glBindVertexArray(0);
}
void GL_Data::addData(const GLfloat *data, GLsizeiptr size, GLuint index, GLint num){
// 先激活vertexArrayID
GL_Data::open();
// 对数据进行缓冲
GLuint bufferID;
glGenBuffers(1, &bufferID);
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
// 完成拷贝后,释放缓冲
// glDeleteBuffers(1, &bufferID); // 不能删除,数据还需要使用
// 顶点属性
glVertexAttribPointer(index, num, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(index);
GL_Data::close(); // 停止vertexArrayID的激活
}
void GL_Data::updateIndex(const GLuint *data, GLsizeiptr size){
GLuint indexID;
glGenBuffers(1, &indexID);
GL_Data::open(); // 注意开始定点数组
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
GL_Data::close();
}
void GL_Data::addTexture(const char *fileName, int *width, int *height, int *depth){
GLuint textureID;
glGenTextures(1, &textureID);
glActiveTexture(texture_channel[id]);
glBindTexture(GL_TEXTURE_2D, textureID);
// 加载图像
unsigned char *data = stbi_load(fileName, width, height, depth, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, *width, *height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D); // 生成类型为2D的纹理映射
// 释放图像
stbi_image_free(data);
id ++;
}
着色器封装
头文件gl_shader.h
#ifndef GL_SHADER_H
#define GL_SHADER_H
#include
struct GL_Shader{
///////////////////////////////////////////////////
GLuint programID;
///////////////////////////////////////////////////
void initProgram();
void compileShaderFromFile(const char* fileName, GLenum shaderType); // 加载编译脚本
void compileShaderFromString(const char* scriptString, GLenum shaderType); // 加载编译脚本
void link(); // 连接脚本为Shader程序
void setUniform_1i(const char *name, GLint index);
///////////////////////////////////////////////////
void open();
void close();
};
#endif
实现文件gl_shader.cpp
#include "gl_shader.h"
#include // 文件流
#include // 字符串缓冲流
void GL_Shader::initProgram(){
programID = glCreateProgram();
}
void GL_Shader::open(){
glUseProgram(programID);
}
void GL_Shader::close(){
glUseProgram(0);
}
void GL_Shader::compileShaderFromFile(const char* fileName, GLenum shaderType){
// 打开文件
std::ifstream fShader(fileName);
// 读取数据到缓冲
std::stringstream bufferScript;
bufferScript << fShader.rdbuf();
// 从缓冲转为字符串对象
std::string strScript = bufferScript.str();
// 把字符串对象转为C字符数组
const char *scriptCode = strScript.c_str();
// 编译
GL_Shader::compileShaderFromString(scriptCode, shaderType);
}
void GL_Shader::compileShaderFromString(const char* scriptString, GLenum shaderType){
GLuint shader;
shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &scriptString, NULL);
glCompileShader(shader);
glAttachShader(programID, shader);
glDeleteShader(shader);
}
void GL_Shader::link(){
GL_Shader::open();
glLinkProgram(programID);
GL_Shader::close();
}
void GL_Shader::setUniform_1i(const char *name, GLint index){
GL_Shader::open();
GLint location = glGetUniformLocation(programID, name);
glUniform1i(location, index); // 设置纹理对象为索引为0,
GL_Shader::close();
}
测试代码gl05_multi_texture.cpp
#include "gl_env.h"
#include "gl_data.h"
#include "gl_shader.h"
#include
// 环境
GL_Env env;
// 定点数组
GL_Data data;
// 着色器
GL_Shader shader;
void render();
int main(int argc, const char** argv) {
env.context("Shader框架总结");
env.opengl();
///////////////////////////////////////////////////
data.initVertextArrays();
GLfloat vertices[] = { // 平面三角形
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
data.addData(vertices, sizeof(vertices), 0, 3); // 开启Shader第一个参数位置,顶点3个一组。
GLuint indices[] = {0, 1, 2};
data.updateIndex(indices,sizeof(indices));
GLfloat colors[] ={ // 三角形三个定点对应的颜色
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
data.addData(colors, sizeof(colors), 1, 4);
GLfloat coords[] ={ // 三角形三个定点对应的纹理
1.0f, 0.0f,
0.0f, 1.0f,
0.0f, 0.0f
};
data.addData(coords, sizeof(coords), 2, 2);
int w, h, d;
data.addTexture("bird.png", &w, &h, &d);
std::cout << w << "," << h << "," << d << std::endl;
data.addTexture("texture.png", &w, &h, &d);
std::cout << w << "," << h << "," << d << std::endl;
///////////////////////////////////////////////////
shader.initProgram();
shader.compileShaderFromFile("./glsl_script/glsl05_v_multi_texture.glsl", GL_VERTEX_SHADER);
shader.compileShaderFromFile("./glsl_script/glsl05_f_multi_texture.glsl", GL_FRAGMENT_SHADER);
shader.link();
shader.setUniform_1i("sTexture_bird", 0);
shader.setUniform_1i("sTexture_texture", 1);
// 加载纹理
///////////////////////////////////////////////////
env.run(render);
env.destroy();
return 0;
}
void render(){
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
data.open(); // 开启顶点
shader.open();
// glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形
glDrawElements(GL_TRIANGLES,3, GL_UNSIGNED_INT, 0);
shader.close();
data.close(); // 关闭顶点
}
// g++ -omain gl05_multi_texture.cpp gl_env.cpp gl_data.cpp gl_shader.cpp -lglfw -lglew -framework opengl
-
测试运行效果