文章目录
统一变量
统一变量是一种能够直接将数据从应用程序传递到着色器阶段的变量。
统一变量分为两种形式:
一种是在默认区块中声明的统一变量
另一种是一致区块,该区块的值储存在缓存对象中
缺省区块统一变量
缺省区块统一变量,就是将统一变量放在OpenGL默认的区块当中(我们也可以自己设置区块)。
排列我们的统一变量
通过使用位置配置
限定符(layout qualifier)
,我们可以在着色器编码中指定统一变量的位置。OpenGL会尝试将指定的位置分配给着色器的统一变量。
layout (location = 17) uniform vec4 myUniform;
如果没有在着色器编码过程中为统一变量指定位置,那么OpenGL会自动为这些变量分配位置。我们可以调用
GLuint glGetUniformLocation(GLuint program, const GLchar* name);
获取program
程序中的名字为name
的变量位置
注意:如果统一变量没有使用,那么其名称可能在程序中“消失”
使用统一变量转换几何图形
自己封装的Shader类(改进)
Shader.h
#pragma once
#include "sb7.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <exception>
#include <vmath.h>
class Shader
{
public:
GLuint program;
public:
Shader();
Shader(const std::string vertexPath, const std::string fragmentPath);
Shader(const std::string vertexPath, const std::string tescPath, const std::string tesePath, const std::string fragmentPath);
//program对象使用
void use();
//设置统一变量
void setInt(const char* name, int data) const;
void setBool(const char* name, bool data) const;
void setFloat(const char* name, float data) const;
void setVec2(const char* name, vmath::vec2 data) const;
void setVec3(const char* name, vmath::vec3 data) const;
void setVec4(const char* name, vmath::vec4 data) const;
void setMat2(const char* name, vmath::mat2 data) const;
void setMat3(const char* name, vmath::mat3 data) const;
void setMat4(const char* name, vmath::mat4 data) const;
private:
//源代码
std::string shaderString;
const char* shaderSource;
//用于读取shader文件
std::ifstream shaderFile;
//转换源码
std::stringstream shaderSStream;
private:
//查错程序,是否有编译错误
void checkCompileErrors(unsigned int ID, std::string type);
//读取文件,并且创建着色器对象
void readShaderSource(std::string shaderFilePath);
//链接着色器
void linkShader(GLuint shaderObject, std::string type);
//设置顶点着色器
void setVertexShder(const std::string vertexPath);
//设置曲面细分控制着色器
void setTescShader(const std::string tescPath);
//设置曲面细分评估着色器
void setTeseShader(const std::string tesePath);
//设置片段着色器
void setFragmentShader(const std::string fragmentPath);
//获取一致区块的位置
GLuint getUniformLocation(const char* name) const;
};
Shader.cpp
#include "Shader.h"
Shader::Shader() {}
Shader::Shader(const std::string vertexPath, const std::string fragmentPath)
{
//创建程序对象
program = glCreateProgram();
setVertexShder(vertexPath);
setFragmentShader(fragmentPath);
}
Shader::Shader(const std::string vertexPath, const std::string tescPath, const std::string tesePath, const std::string fragmentPath)
{
//创建程序对象
program = glCreateProgram();
setVertexShder(vertexPath);
setFragmentShader(fragmentPath);
setTescShader(tescPath);
setTeseShader(tesePath);
}
//设置顶点着色器
void Shader::setVertexShder(const std::string vertexPath)
{
//读取shader源代码
readShaderSource(vertexPath);
//创建shader对象
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
//链接shader对象
linkShader(vertexShader, "VERTEX");
}
//设置曲面细分控制着色器
void Shader::setTescShader(const std::string tescPath)
{
//读取shader源代码
readShaderSource(tescPath);
//创建shader对象
GLuint tescShader;
tescShader = glCreateShader(GL_TESS_CONTROL_SHADER);
//链接shader对象
linkShader(tescShader, "TESC");
}
//设置曲面细分评估着色器
void Shader::setTeseShader(const std::string tesePath)
{
//读取shader源代码
readShaderSource(tesePath);
//创建shader对象
GLuint teseShader;
teseShader = glCreateShader(GL_TESS_EVALUATION_SHADER);
//链接shader对象
linkShader(teseShader, "TESE");
}
//设置片段着色器
void Shader::setFragmentShader(const std::string fragmentPath)
{
//读取shader源代码
readShaderSource(fragmentPath);
//创建shader对象
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//链接shader对象
linkShader(fragmentShader, "FRAGMENT");
}
GLuint Shader::getUniformLocation(const char* name) const
{
return glGetUniformLocation(program, name);
}
void Shader::use()
{
glUseProgram(program);
}
void Shader::setInt(const char* name, int data) const
{
glUniform1i(getUniformLocation(name), data);
}
void Shader::setBool(const char* name, bool data) const
{
glUniform1i(getUniformLocation(name), (int)data);
}
void Shader::setFloat(const char* name, float data) const
{
glUniform1f(getUniformLocation(name), data);
}
void Shader::setVec2(const char* name, vmath::vec2 data) const
{
glUniform2fv(getUniformLocation(name), 1, data);
}
void Shader::setVec3(const char* name, vmath::vec3 data) const
{
glUniform3fv(getUniformLocation(name), 1, data);
}
void Shader::setVec4(const char* name, vmath::vec4 data) const
{
glUniform4fv(getUniformLocation(name), 1, data);
}
void Shader::setMat2(const char* name, vmath::mat2 data) const
{
glUniformMatrix2fv(getUniformLocation(name), 1, GL_FALSE, data);
}
void Shader::setMat3(const char* name, vmath::mat3 data) const
{
glUniformMatrix3fv(getUniformLocation(name), 1, GL_FALSE, data);
}
void Shader::setMat4(const char* name, vmath::mat4 data) const
{
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, data);
}
//读取文件,并且创建着色器对象
void Shader::readShaderSource(std::string shaderFilePath)
{
//将上一个shader的源码清理
shaderSStream.str("");
memset(&shaderSource, '\0', sizeof(shaderSource));
//open shader file
if (!shaderFilePath.empty()) //判断文件路径是否为空
{
//文件路径不为空,打开文件
shaderFile.open(shaderFilePath);
shaderFile.exceptions(std::ifstream::badbit || std::ifstream::failbit);
try
{
if (!shaderFile.is_open()) //文件打开失败
{
throw std::exception("open fragment shader file fail");
}
//文件成功打开
//字符串流读取文件中的数据
shaderSStream << shaderFile.rdbuf();
//读完了,把文件关了
shaderFile.close();
//把源代码读入字符串中去
shaderString = shaderSStream.str();
//把string转成系数需要的const char *类型
shaderSource = shaderString.c_str();
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
}
//链接着色器
void Shader::linkShader(GLuint shaderObject, std::string type)
{
//将源代码读入shader对象
glShaderSource(shaderObject, 1, &shaderSource, NULL);
//编译shader对象中的源码
glCompileShader(shaderObject);
//检查着色器对象是否有误
checkCompileErrors(shaderObject, type);
//将shader对象附加到program对象上去
glAttachShader(program, shaderObject);
//链接program对象上的shader对象
glLinkProgram(program);
//查错
checkCompileErrors(program, "PROGRAM");
//完事,可以把shader对象删了
glDeleteShader(shaderObject);
}
/*
* 查错
*/
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);
std::cout << "shader compile error: " << infoLog << std::endl;
}
}
else
{
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "program linking error: " << infoLog << std::endl;
}
}
}
shader file
vertex shader
#version 450 core
layout(location = 0) in vec3 position;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
out VS_OUT
{
vec4 color;
} vs_out;
void main()
{
gl_Position = proj_matrix * mv_matrix * vec4(position, 1.0);
vs_out.color = vec4(position, 1.0) * 2.0 + vec4(0.5, 0.5, 0.5, 0.0);
}
fragment shader
#version 450 core
layout(location = 0) uniform vec4 icolor;
out vec4 color;
in VS_OUT
{
vec4 color;
} vs_out;
void main()
{
color = vs_out.color;
}
源码
#include "sb7.h"
#include <iostream>
#include "Shader.h"
#include <math.h>
#include <vmath.h>
class my_application : public sb7::application
{
public:
void startup()
{
static const float vertex_positiona[] =
{
-0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
-0.25f, 0.25f, -0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, -0.25f, 0.25f,
0.25f, -0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, -0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, -0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, -0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
0.25f, 0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, 0.25f,
0.25f, -0.25f, 0.25f,
-0.25f, -0.25f, 0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, 0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
0.25f, 0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, -0.25f
};
shader = new Shader("vs.vert", "fs.frag");
program = shader->program;
//创建vao对象
glCreateVertexArrays(1, &vao);
//绑定vao到上下文
glBindVertexArray(vao);
//创建vbo对象
glCreateBuffers(1, &vbo);
//绑定vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//为缓冲申请内存,并且赋予初始数据
glNamedBufferStorage(vbo, sizeof(vertex_positiona), vertex_positiona, GL_DYNAMIC_STORAGE_BIT);
//绑定缓冲到vao
glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(float) * 3);
//缓冲的布局
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
//指示vao的顶点属性从哪个绑定点缓冲哪数据
glVertexArrayAttribBinding(vao, 0, 0);
glEnableVertexArrayAttrib(vao, 0);
//深度测试
glEnable(GL_DEPTH_TEST);
}
void render(double currentTime)
{
GLfloat color[] = { 1.0, 1.0, 1.0, 1.0 };
glClearBufferfv(GL_COLOR, 0, color);
glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
GLfloat icolor[4] = {
(float)sin(currentTime) * 0.5 + 0.5,
(float)cos(currentTime) * 0.5 + 0.5,
0.0, 1.0
};
glUniform4fv(0, 1, icolor);
float aspect = (float)info.windowWidth / (float)info.windowHeight;
//投影矩阵
vmath::mat4 proj_matrix = vmath::perspective(50.f, aspect, 0.1f, 1000.f);
shader->use();
/*vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -4.0f) *
vmath::translate(sinf(2.1f * f) * 0.5f,
cosf(1.7f * f) * 0.5f,
sinf(1.3f * f) * cosf(1.5f * f) * 2.0f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 81.0f, 1.0f, 0.0f, 0.0f);*/
//渲染24个立方体
for (size_t i = 0; i < 24; i++)
{
float f = float(currentTime) * 0.3f + (float)i;
//model view矩阵
vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -5.f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 21.0f, 1.0f, 0.0f, 0.0f) *
vmath::translate(sinf(2.1f * f) * 2.0f, cosf(1.7f * f) * 2.0f, sinf(1.3f * f) * cosf(1.5f * f) * 2.0f);
shader->setMat4("mv_matrix", mv_matrix);
shader->setMat4("proj_matrix", proj_matrix);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}
void shutdown()
{
}
private:
Shader* shader;
GLuint program;
GLuint vao;
GLuint vbo;
};
DECLARE_MAIN(my_application);
效果
总结
统一变量就是可以一种从程序把数据传到着色器里面的数据类型。