OpenGL编译用户着色器shader

shader 相信很多朋友们都听说过,shader 就是运行再GPU 上的程序。虽然是这么说,但是我们发现,很多IDE 开发工具比如说visual studio 没有办法直接去运行shader 代码。这是因为,许多编译器不会自动将shader 文件编译成可执行的代码然后发送给GPUshader 代码的编译需要开发人员手动动用GPUshader 编译接口,将对应的代码编译成可执行的程序。在这里,笔者就为大家介绍,如何使用OpenGL 提供的API 编译用户自己的shader程序。

Shader

OpenGL渲染管线

这里先为大家介绍一下OpenGL渲染管线如下图所示

事实上在一众着色器当中,只有顶点着色器和片元着色器是必须的,其他都是可选的。具体想要了解更多,可以去看一些资料或者书籍,比如笔者手上的这本《OpenGL编程指南》

OpenGL shader

OpenGL 支持的 shader 语法是 OpenGL shader language 简称是glsl 。这个shader 语法和**C++**基本上是大同小异,很快就可以轻松上手。

话说到这里,让我们回顾一下上一篇文章OpenGL渲染结果移至ImGui窗口上,有细心的本有不难发现,我并没有去编译用户着色器,而且必要的顶点着色器和片元着色器都没有进行编写,但是我们仍然得到我们想要的渲染结果。其原因是,OpenGL 自带默认的着色器,所以对于初学者来说,可以尽可能使用少的代码去实现自己想要的结果,这就是为什么图形接口的学习一般都是从OpenGL开始学起。

OpenGL着色器编译

Shader 类

这里笔者写了一个Shader类,整体的代码如下

Shader.h

cpp 复制代码
#pragma once

#include<unordered_map>
typedef unsigned int GLenum;

class Shader {
public:
	Shader(const std::string& filePath);
	~Shader();
	void Bind();
	void UBind();

	void UploadUniformFloat4(const std::string& name, float* value);

private:
	std::string ReadFile(const std::string& filePath);
	std::unordered_map<GLenum, std::string> PreProcess(const std::string& source);
	void Compile(const std::unordered_map<GLenum, std::string>& shaderSources);
private:
	uint32_t m_ShaderID;
	std::string m_Name;
};

Shader.cpp

cpp 复制代码
#include<glad/glad.h>
#include<string>
#include<array>
#include<fstream>
#include<iostream>

#include"Shader.h"

static GLenum ShaderTypeFromString(const std::string& type) {
	if (type == "vertex")
		return GL_VERTEX_SHADER;
	else if (type == "fragment" || type == "pixel")
		return GL_FRAGMENT_SHADER;

	std::cout << "Unknown shader type" << std::endl;
	return 0;
}

Shader::Shader(const std::string& filePath) :m_ShaderID(0) {
	std::string source = ReadFile(filePath);
	auto shaderSource = PreProcess(source);
	Compile(shaderSource);

	auto lastSlash = filePath.find_last_of("/\\");
	lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1;
	auto lastDot = filePath.rfind('.');
	auto count = lastDot == std::string::npos ? filePath.size() - lastSlash : lastDot - lastSlash;
	m_Name = filePath.substr(lastSlash, count);
}

Shader::~Shader() {
	glDeleteProgram(m_ShaderID);
}

void Shader::Bind(){
	glUseProgram(m_ShaderID);
}

void Shader::UBind(){
	glUseProgram(0);
}

void Shader::UploadUniformFloat4(const std::string& name, float* value) {
	int location = glGetUniformLocation(m_ShaderID, name.c_str());
	glUniform4f(location, value[0], value[1], value[2], value[3]);
}

std::string Shader::ReadFile(const std::string& filePath) {
	std::string result;
	std::ifstream in(filePath, std::ios::in | std::ios::binary);
	if (in) {
		in.seekg(0, std::ios::end);
		result.resize(in.tellg());
		in.seekg(0, std::ios::beg);
		in.read(&result[0], result.size());
		in.close();
	}
	else {
		std::cout << "着色器文件没有正常打开" << std::endl;
		__debugbreak();
	}

	return result;
}

std::unordered_map<GLenum, std::string> Shader::PreProcess(const std::string& source) {
	std::unordered_map<GLenum, std::string> shaderSources;

	const char* typeToken = "#type";
	size_t typeTokenLength = strlen(typeToken);
	size_t pos = source.find(typeToken,0);

	while (pos != std::string::npos) {
		size_t eol = source.find_first_of("\r\n", pos);
		if (eol == std::string::npos) {
			std::cout << "着色器语法出错" << std::endl;
			__debugbreak();
		}

		size_t begin = pos + typeTokenLength + 1;
		std::string type = source.substr(begin, eol - begin);

		if (!ShaderTypeFromString(type)) {
			std::cout << "这是一个不合法的着色器类型" << std::endl;
			__debugbreak();
		}

		size_t nextLinePos = source.find_first_of("\r\n", eol);
		pos = source.find(typeToken, nextLinePos);
		shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos, pos - (nextLinePos == std::string::npos ? source.size() - 1 : nextLinePos));
	}

	return shaderSources;
}

void Shader::Compile(const std::unordered_map<GLenum, std::string>& shaderSources) {
	unsigned int program = glCreateProgram();
	//一次性至多编译两种着色器
	if (shaderSources.size() < 2) {
		std::cout << "一次性至多编译两种着色器" << std::endl;
		__debugbreak();
	}

	std::array<GLenum, 2> glShaderIDs;
	int glShaderIDIndex = 0;
	for (auto& kv : shaderSources) {
		GLenum type = kv.first;
		const std::string& source = kv.second;

		unsigned int shader = glCreateShader(type);

		const char* sourceCStr = source.c_str();
		glShaderSource(shader, 1, &sourceCStr, 0);

		glCompileShader(shader);

		int isCompiled = 0;
		glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);

		if (isCompiled == GL_FALSE) {
			int maxLength = 0;
			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);

			std::vector<char> infoLog(maxLength);
			glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);

			glDeleteShader(shader);

			std::cout << "着色器编译出错:" << infoLog.data() << std::endl;
			__debugbreak();
			break;
		}

		glAttachShader(program, shader);
		glShaderIDs[glShaderIDIndex++] = shader;
	}

	m_ShaderID = program;

	// Link our program
	glLinkProgram(program);

	// Note the different functions here: glGetProgram* instead of glGetShader*.
	int isLinked = 0;
	glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);

	if (isLinked == GL_FALSE) {
		int maxLength = 0;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

		// The maxLength includes the NULL character
		std::vector<char> infoLog(maxLength);
		glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);

		// We don't need the program anymore.
		glDeleteProgram(program);

		for (auto id : glShaderIDs)
			glDeleteShader(id);

		std::cout << "用户着色器链接失败:" << infoLog.data() << std::endl;
		__debugbreak();
		return;
	}

	for (auto id : glShaderIDs)
		glDetachShader(program, id);
}

着色器代码

TextureShader.glsl

cpp 复制代码
#type vertex
#version 450 core
//标记为0的内存位置输入一个有两个分量的向量,这是顶点的位置
layout(location = 0) in vec2 v_Position;

void main(){
    //顶点位置的数据进行赋值,需要转换为齐次向量
	gl_Position = vec4(v_Position,0.0f,1.0f);
}

#type fragment
#version 450 core
//标记为0的内存位置输出一个有四个分量的向量,这是像素的颜色
layout(location = 0) out vec4 o_Color;

void main(){
	o_Color = vec4(0.8f,0.2f,0.3f,1.0f);
}

着色器介绍

上面虽然是一个着色器文件,其实这里面写了两个着色器,一个是顶点着色器,一个是片元着色器。#type vertex 下面的是顶点着色器,#type fragment下面的是片元着色器。为什么这两个要一起写了?前面也介绍了,这两个着色器是必需要有的,所以笔者推荐这个着色器最好就是一起写。顶点着色器必须要有输入数据,片元着色器必须要有输出数据,不然屏幕上就看不到任何东西。

着色器编译

笔者将其分成了3个步骤进行

1、读取对应的文件内容

cpp 复制代码
std::string Shader::ReadFile(const std::string& filePath) {
	std::string result;
	std::ifstream in(filePath, std::ios::in | std::ios::binary);
	if (in) {
		in.seekg(0, std::ios::end);
		result.resize(in.tellg());
		in.seekg(0, std::ios::beg);
		in.read(&result[0], result.size());
		in.close();
	}
	else {
		std::cout << "着色器文件没有正常打开" << std::endl;
		__debugbreak();
	}

	return result;
}

TextureShader.glsl 当中的文本信息全部转换成一个string类型当中进行存储。

2、确定着色器的类型,以及每个着色器的代码

cpp 复制代码
std::unordered_map<GLenum, std::string> Shader::PreProcess(const std::string& source) {
	std::unordered_map<GLenum, std::string> shaderSources;

	const char* typeToken = "#type";
	size_t typeTokenLength = strlen(typeToken);
	size_t pos = source.find(typeToken,0);

	while (pos != std::string::npos) {
		size_t eol = source.find_first_of("\r\n", pos);
		if (eol == std::string::npos) {
			std::cout << "着色器语法出错" << std::endl;
			__debugbreak();
		}

		size_t begin = pos + typeTokenLength + 1;
		std::string type = source.substr(begin, eol - begin);

		if (!ShaderTypeFromString(type)) {
			std::cout << "这是一个不合法的着色器类型" << std::endl;
			__debugbreak();
		}

		size_t nextLinePos = source.find_first_of("\r\n", eol);
		pos = source.find(typeToken, nextLinePos);
		shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos, pos - (nextLinePos == std::string::npos ? source.size() - 1 : nextLinePos));
	}

	return shaderSources;
}

对于OpenGL 来说我们不光要告诉它需要编译的代码,还要告诉它编译的着色器代码是什么类型的着色器代码。在前面可以看到TextureShader.glsl 当中有 #type vertex 这样的语句,这个并不是glsl语法,我们在进行文本处理的时候需要省略掉才行,不然的话编译会失败,这个只是用来告诉程序下面着色器代码是什么类型着色器的,所以这里选择返回了一个字典,用来存储着色器的类型和需要编译的程序。能够编译的是下面两段

cpp 复制代码
#version 450 core
//标记为0的内存位置输入一个有两个分量的向量,这是顶点的位置
layout(location = 0) in vec2 v_Position;

void main(){
    //顶点位置的数据进行赋值,需要转换为齐次向量
	gl_Position = vec4(v_Position,0.0f,1.0f);
}
cpp 复制代码
#version 450 core
//标记为0的内存位置输出一个有四个分量的向量,这是像素的颜色
layout(location = 0) out vec4 o_Color;

void main(){
	o_Color = vec4(0.8f,0.2f,0.3f,1.0f);
}

他们已经被分开存储了。

3、编译链接着色器

cpp 复制代码
void Shader::Compile(const std::unordered_map<GLenum, std::string>& shaderSources) {
	//注册使用下面两个着色器的程序号
    unsigned int program = glCreateProgram();
	//一次性至多编译两种着色器
	if (shaderSources.size() < 2) {
		std::cout << "一次性至多编译两种着色器" << std::endl;
		__debugbreak();
	}

	std::array<GLenum, 2> glShaderIDs;
	int glShaderIDIndex = 0;
	for (auto& kv : shaderSources) {
		GLenum type = kv.first;
		const std::string& source = kv.second;
        //注册对饮类型的着色器
		unsigned int shader = glCreateShader(type);

		const char* sourceCStr = source.c_str();
		glShaderSource(shader, 1, &sourceCStr, 0);
        //编译着色器源码
		glCompileShader(shader);

		int isCompiled = 0;
		glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
        //检查着色器是否编译失败
		if (isCompiled == GL_FALSE) {
			int maxLength = 0;
			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);

			std::vector<char> infoLog(maxLength);
			glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);

			glDeleteShader(shader);

			std::cout << "着色器编译出错:" << infoLog.data() << std::endl;
			__debugbreak();
			break;
		}
        //将着色器加入到这个程序当中
		glAttachShader(program, shader);
		glShaderIDs[glShaderIDIndex++] = shader;
	}

	m_ShaderID = program;

	// Link our program
	glLinkProgram(program);

	// Note the different functions here: glGetProgram* instead of glGetShader*.
	int isLinked = 0;
	glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);
    //检查程序是否能够链接成功
	if (isLinked == GL_FALSE) {
		int maxLength = 0;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

		// The maxLength includes the NULL character
		std::vector<char> infoLog(maxLength);
		glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);

		// We don't need the program anymore.
		glDeleteProgram(program);

		for (auto id : glShaderIDs)
			glDeleteShader(id);

		std::cout << "用户着色器链接失败:" << infoLog.data() << std::endl;
		__debugbreak();
		return;
	}

	for (auto id : glShaderIDs)
		glDetachShader(program, id);
}

上面大致流程就是,注册程序的编号,创建对应类型的着色器,根据下面的代码

cpp 复制代码
static GLenum ShaderTypeFromString(const std::string& type) {
	if (type == "vertex")
		return GL_VERTEX_SHADER;
	else if (type == "fragment" || type == "pixel")
		return GL_FRAGMENT_SHADER;

	std::cout << "Unknown shader type" << std::endl;
	return 0;
}

可以知道 #type vertex 对应的着色器类型就是GL_VERTEX_SHADER#type fragment 对应的着色器类型就是GL_FRAGMENT_SHADER。创建了对应的着色器类型过后就是对源码进行编译,放入到程序当中,检查这个程序能否顺利接入管线当中,隔离开然后等待被调用。

使用用户自定义着色器

着色器使用,主函数代码如下

cpp 复制代码
#include<glad/glad.h>
#include<GLFW/glfw3.h>

#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

#include<iostream>

#include"FrameBuffer.h"
#include"Shader.h"

int main() {
	glfwInit();

	GLFWwindow* window = glfwCreateWindow(640, 480, "Triangles", NULL, NULL);

	glfwMakeContextCurrent(window);
	glfwSwapInterval(1); // Enable vsync

	// Setup Dear ImGui context
	IMGUI_CHECKVERSION();
	ImGui::CreateContext();
	ImGuiIO& io = ImGui::GetIO(); (void)io;
	io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
	io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
	io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;         // Enable Docking
	io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;       // Enable Multi-Viewport / Platform Windows
	//io.ConfigViewportsNoAutoMerge = true;
	//io.ConfigViewportsNoTaskBarIcon = true;
	
	// Setup Dear ImGui style
	ImGui::StyleColorsDark();
	//ImGui::StyleColorsLight();

	// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
	ImGuiStyle& style = ImGui::GetStyle();
	if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
	{
		style.WindowRounding = 0.0f;
		style.Colors[ImGuiCol_WindowBg].w = 1.0f;
	}

	// Setup Platform/Renderer backends
	ImGui_ImplGlfw_InitForOpenGL(window, true);
	ImGui_ImplOpenGL3_Init("#version 130");

	//需要初始化GLAD
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	float positions[6] = {
		-0.5f, -0.5,
		0.0f, 0.5f,
		0.5f, -0.5f
	};

	GLuint buffer = 0;

	glGenBuffers(1, &buffer);
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), NULL);
	glEnableVertexAttribArray(0);

	bool show_demo_window = true;
	ImVec2 viewPortSize(640,480);
	float colorEditor[4] = {1.0f, 1.0f, 1.0f, 1.0f};

	FrameBuffer *pFrameBuffer = new FrameBuffer(640, 480);
	Shader* pShader = new Shader("assets/shaders/TextureShader.glsl");
	pShader->UBind();

	while (!glfwWindowShouldClose(window)) {
		pFrameBuffer->Bind();
		pShader->Bind();
		glClear(GL_COLOR_BUFFER_BIT);

		glDrawArrays(GL_TRIANGLES, 0, 3);
		pFrameBuffer->UBind();

		// Start the Dear ImGui frame
		ImGui_ImplOpenGL3_NewFrame();
		ImGui_ImplGlfw_NewFrame();
		ImGui::NewFrame();

		ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());

		ImGui::Begin("ViewPort");
		viewPortSize = ImGui::GetContentRegionAvail();
		if (viewPortSize.x * viewPortSize.y > 0 && (viewPortSize.x != pFrameBuffer->GetWidth() || viewPortSize.y != pFrameBuffer->GetHeight())) {
			pFrameBuffer->Resize(viewPortSize.x, viewPortSize.y);
			glViewport(0, 0, viewPortSize.x, viewPortSize.y);
		}
		uint32_t textureID = pFrameBuffer->GetColorAttachment();
		ImGui::Image(reinterpret_cast<void*>(textureID), viewPortSize, { 0,1 }, { 1,0 });
		ImGui::End();

		ImGui::Begin("ColorEditor");
		ImGui::ColorEdit4("##colorEditor", colorEditor);
		ImGui::End();

		/*if(show_demo_window)
			ImGui::ShowDemoWindow(&show_demo_window);*/

		// Rendering
		ImGui::Render();
		
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

		if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
		{
			GLFWwindow* backup_current_context = glfwGetCurrentContext();
			ImGui::UpdatePlatformWindows();
			ImGui::RenderPlatformWindowsDefault();
			glfwMakeContextCurrent(backup_current_context);
		}

		glfwSwapBuffers(window);

		glfwPollEvents();
	}

	// Cleanup
	ImGui_ImplOpenGL3_Shutdown();
	ImGui_ImplGlfw_Shutdown();
	ImGui::DestroyContext();

	delete pFrameBuffer;
	delete pShader;

	glfwDestroyWindow(window);
	glfwTerminate();
}

得到的结果是

三角形被顺利染成了红色,有人可能会说这也有点费了这么大的劲,就把颜色改成了红色,实在是有点无聊,那让我们来做一些比较Cool的事。

我们修改一下着色器

cpp 复制代码
#type vertex
#version 450 core

layout(location = 0) in vec2 v_Position;

void main(){
	gl_Position = vec4(v_Position,0.0f,1.0f);
}

#type fragment
#version 450 core

layout(location = 0) out vec4 o_Color;
//增加的片段
uniform vec4 u_Color;

void main(){
	o_Color = u_Color;
}

主函数也修改一下

cpp 复制代码
pShader->UBind();

	while (!glfwWindowShouldClose(window)) {
		pFrameBuffer->Bind();
		pShader->Bind();
        //新增片段
		pShader->UploadUniformFloat4("u_Color", colorEditor);
		glClear(GL_COLOR_BUFFER_BIT);

展示一下结果

我们现在可以通过ImGui 上面的控件对三角形的颜色进行实时修改了,不用去改动程序,是不是很棒了。下面还是把整个主函数放出来,如果对里面的FrameBuffer 类不了解的可以看笔者的OpenGL渲染结果移至ImGui窗口上这篇文章,同样有源代码,希望对大家能有帮助。

cpp 复制代码
#include<glad/glad.h>
#include<GLFW/glfw3.h>

#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

#include<iostream>

#include"FrameBuffer.h"
#include"Shader.h"

int main() {
	glfwInit();

	GLFWwindow* window = glfwCreateWindow(640, 480, "Triangles", NULL, NULL);

	glfwMakeContextCurrent(window);
	glfwSwapInterval(1); // Enable vsync

	// Setup Dear ImGui context
	IMGUI_CHECKVERSION();
	ImGui::CreateContext();
	ImGuiIO& io = ImGui::GetIO(); (void)io;
	io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
	io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
	io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;         // Enable Docking
	io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;       // Enable Multi-Viewport / Platform Windows
	//io.ConfigViewportsNoAutoMerge = true;
	//io.ConfigViewportsNoTaskBarIcon = true;
	
	// Setup Dear ImGui style
	ImGui::StyleColorsDark();
	//ImGui::StyleColorsLight();

	// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
	ImGuiStyle& style = ImGui::GetStyle();
	if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
	{
		style.WindowRounding = 0.0f;
		style.Colors[ImGuiCol_WindowBg].w = 1.0f;
	}

	// Setup Platform/Renderer backends
	ImGui_ImplGlfw_InitForOpenGL(window, true);
	ImGui_ImplOpenGL3_Init("#version 130");

	//需要初始化GLAD
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	float positions[6] = {
		-0.5f, -0.5,
		0.0f, 0.5f,
		0.5f, -0.5f
	};

	GLuint buffer = 0;

	glGenBuffers(1, &buffer);
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), NULL);
	glEnableVertexAttribArray(0);

	bool show_demo_window = true;
	ImVec2 viewPortSize(640,480);
	float colorEditor[4] = {1.0f, 1.0f, 1.0f, 1.0f};

	FrameBuffer *pFrameBuffer = new FrameBuffer(640, 480);
	Shader* pShader = new Shader("assets/shaders/TextureShader.glsl");
	pShader->UBind();

	while (!glfwWindowShouldClose(window)) {
		pFrameBuffer->Bind();
		pShader->Bind();
		pShader->UploadUniformFloat4("u_Color", colorEditor);
		glClear(GL_COLOR_BUFFER_BIT);

		glDrawArrays(GL_TRIANGLES, 0, 3);
		pFrameBuffer->UBind();

		// Start the Dear ImGui frame
		ImGui_ImplOpenGL3_NewFrame();
		ImGui_ImplGlfw_NewFrame();
		ImGui::NewFrame();

		ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());

		ImGui::Begin("ViewPort");
		viewPortSize = ImGui::GetContentRegionAvail();
		if (viewPortSize.x * viewPortSize.y > 0 && (viewPortSize.x != pFrameBuffer->GetWidth() || viewPortSize.y != pFrameBuffer->GetHeight())) {
			pFrameBuffer->Resize(viewPortSize.x, viewPortSize.y);
			glViewport(0, 0, viewPortSize.x, viewPortSize.y);
		}
		uint32_t textureID = pFrameBuffer->GetColorAttachment();
		ImGui::Image(reinterpret_cast<void*>(textureID), viewPortSize, { 0,1 }, { 1,0 });
		ImGui::End();

		ImGui::Begin("ColorEditor");
		ImGui::ColorEdit4("##colorEditor", colorEditor);
		ImGui::End();

		/*if(show_demo_window)
			ImGui::ShowDemoWindow(&show_demo_window);*/

		// Rendering
		ImGui::Render();
		
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

		if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
		{
			GLFWwindow* backup_current_context = glfwGetCurrentContext();
			ImGui::UpdatePlatformWindows();
			ImGui::RenderPlatformWindowsDefault();
			glfwMakeContextCurrent(backup_current_context);
		}

		glfwSwapBuffers(window);

		glfwPollEvents();
	}

	// Cleanup
	ImGui_ImplOpenGL3_Shutdown();
	ImGui_ImplGlfw_Shutdown();
	ImGui::DestroyContext();

	delete pFrameBuffer;
	delete pShader;

	glfwDestroyWindow(window);
	glfwTerminate();
}
相关推荐
Yang-Never4 天前
Shader -> BitmapShader贴图着色器详解
android·开发语言·kotlin·android studio·贴图·着色器
Yang-Never6 天前
Shader -> SweepGradient扫描渐变着色器详解
android·java·kotlin·android studio·着色器
周振超的7 天前
使用Qt和OpenGL实现一个旋转的各面颜色不一致的立方体及知识点分析
开发语言·qt·着色器
山楂树の10 天前
Threejs 自定义片元着色器 做UV动画
3d·图形渲染·webgl·着色器·uv
吃豆腐长肉1 个月前
着色器 (三)
opengl·着色器
吃豆腐长肉1 个月前
opengl 着色器 (四)最终章收尾
opengl·着色器
浅陌sss1 个月前
UnityShaderLab 实现黑白着色器效果
着色器
程序员正茂2 个月前
Unity着色器Shader根据到某点的距离显示不同颜色
unity·shader·着色器
小春熙子2 个月前
Unity图形学之着色器之间传递参数
unity·游戏引擎·技术美术·着色器