GLSL数据类型
GLSL中包含C等其它语言大部分的默认基础数据类型:int、float、double、uint和bool。支持两种容器类型,分别是向量(Vector)和矩阵(Matrix)。
类型 | 含义 |
---|---|
vecn | 包含n 个float分量的默认向量 |
bvecn | 包含n 个bool分量的向量 |
ivecn | 包含n 个int分量的向量 |
uvecn | 包含n 个unsigned int分量的向量 |
dvecn | 包含n 个double分量的向量 |
一个向量的分量可以通过vec.x
这种方式获取,这里x
是指这个向量的第一个分量。你可以分别使用.x
、.y
、.z
和.w
来获取它们的第1、2、3、4个分量。GLSL也允许你对颜色使用rgba
,或是对纹理坐标使用stpq
访问相同的分量。
向量允许灵活的分量选择方式,叫做重组(Swizzling)。
//重组
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
Uniform
Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,uniform是全局的(Global)。
#version 330 core
out vec4 FragColor;
uniform vec4 ourColor;// 在fragmentShader中声明变量
void main()
{
FragColor = ourColor;
}
//获取运行的秒数
float timeValue = glfwGetTime();
float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
- 用glGetUniformLocation查询uniform ourColor的位置值。
- 通过glUniform4f函数设置uniform。
因为OpenGL在其核心是一个C库,所以它不支持类型重载,在函数参数不同的时候就要为其定义新的函数。glUniform是一个典型例子。这个函数有一个特定的后缀,标识设定的uniform的类型。可能的后缀有:
后缀 | 含义 |
---|---|
f | 函数需要一个float作为它的值 |
i | 函数需要一个int作为它的值 |
ui | 函数需要一个unsigned int作为它的值 |
3f | 函数需要3个float作为它的值 |
fv | 函数需要一个float向量/数组作为它的值 |
属性
float vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
顶点属性中增加了颜色属性 ,更新后的VBO内存数据
位置属性对应layout(location = 0),颜色属性对应layout(location = 1),取3位float,每组数据占用6个float,步长值为6个float,其中三个是位置,三个是颜色。位置属性从0开始,所有偏移值为0,颜色属性从3开始,偏移值为3。
// 位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);
输出效果
从文件中读取Shader
1.读取文件转为string,用到了#include <fastream>和#include<sstream
std::string vertexString;
std::string fragmentString;
std::ifstream vertexFile;
std::ifstream fragmentFile;
// 保证ifstream对象可以抛出异常
vertexFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
fragmentFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
//打开文件
vertexFile.open(vertexPath);
fragmentFile.open(fragmentPath);
if (!vertexFile.is_open() || !fragmentFile.is_open())
{
throw std::exception("open file error");
}
std::stringstream vertexShaderStream, fragmentShaderStream;
//读取文件的缓冲内容到数据流中
vertexShaderStream << vertexFile.rdbuf();
fragmentShaderStream << fragmentFile.rdbuf();
vertexFile.close();
fragmentFile.close();
//数据流转为string
vertexString = vertexShaderStream.str();
fragmentString = fragmentShaderStream.str();
}
catch (const std::exception& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << e.what() << std::endl;
}
2.创建编译着色器
unsigned int vertex, fragment;
int success;
char infoLog[512];
//顶点着色器
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertexSource, NULL);
glCompileShader(vertex);
// 打印编译错误
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(ID, 512, NULL, infoLog);
std::cout << "shader compile error:" << infoLog << std::endl;
};
//片元着色器
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragmentSource, NULL);
glCompileShader(fragment);
// 打印编译错误
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(ID, 512, NULL, infoLog);
std::cout << "shader compile error:" << infoLog << std::endl;
};
3.创建着色器程序,绑定顶点和片元着色器
// 着色器程序
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
// 打印连接错误(如果有的话)
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "program linking error:" << infoLog << std::endl;
}
// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
glDeleteShader(vertex);
glDeleteShader(fragment);
4.外部使用着色器
void Shader::use()
{
glUseProgram(ID);
}
#include "Shader.h"
//使用Shader
Shader* shaderProgram = new Shader("vertexSource.txt", "fragmentSource.txt");
shaderProgram->use();
完整代码
顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;// 位置变量的属性位置值为0的顶点坐标
layout (location = 1) in vec3 aColor;// 位置变量的属性位置值为1的颜色值
out vec4 vertexColor; //输出的颜色值
uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
vertexColor = vec4(aColor.x,aColor.y,aColor.z,1.0f);
}
片元着色器
#version 330 core
out vec4 FragColor; // 输出的片元颜色值
in vec4 vertexColor; // 输入的颜色值
void main()
{
FragColor = vertexColor;
}
Shader类
#pragma once
#include <string>
class Shader
{
public:
unsigned int ID;
std::string vertexString;
std::string fragmentString;
const char* vertexSource;
const char* fragmentSource;
Shader(const char* vertexPath, const char* fragmentPath);
~Shader();
void use();
void setBool(const std::string &name, bool value) const;
void setInt(const std::string &name, int value) const;
void setFloat(const std::string &name, float value) const;
private:
void checkCompileErrors(unsigned int ID, std::string type);
};
#include "Shader.h"
#include <GL/glew.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
unsigned int ID;
Shader::Shader(const char* vertexPath, const char* fragmentPath)
{
std::string vertexString;
std::string fragmentString;
std::ifstream vertexFile;
std::ifstream fragmentFile;
vertexFile.open(vertexPath);
fragmentFile.open(fragmentPath);
vertexFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
fragmentFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
if (!vertexFile.is_open() || !fragmentFile.is_open())
{
throw std::exception("open file error");
}
std::stringstream vertexShaderStream, fragmentShaderStream;
vertexShaderStream << vertexFile.rdbuf();
fragmentShaderStream << fragmentFile.rdbuf();
vertexFile.close();
fragmentFile.close();
vertexString = vertexShaderStream.str();
fragmentString = fragmentShaderStream.str();
}
catch (const std::exception& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << e.what() << std::endl;
}
const char* vertexSource = vertexString.c_str();
const char* 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);
}
void Shader::use()
{
glUseProgram(ID);
}
void Shader::setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
/// <summary>
/// 检测编辑错误
/// </summary>
/// <param name="ID"></param>
/// <param name="type"></param>
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_COMPILE_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "program linking error:" << infoLog << std::endl;
};
}
}
Comments NOTHING