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;
		};
	}
	
}
最后更新于 2022-06-23