有什么网站可以做微信app,女性开源网站,对于ICP而言 主要承担网站信息,上海中风险地区地图shader相信很多朋友们都听说过#xff0c;shader就是运行再GPU上的程序。虽然是这么说#xff0c;但是我们发现#xff0c;很多IDE开发工具比如说visual studio 没有办法直接去运行shader代码。这是因为#xff0c;许多编译器不会自动将shader文件编译成可执行的代码然后发… shader相信很多朋友们都听说过shader就是运行再GPU上的程序。虽然是这么说但是我们发现很多IDE开发工具比如说visual studio 没有办法直接去运行shader代码。这是因为许多编译器不会自动将shader文件编译成可执行的代码然后发送给GPUshader代码的编译需要开发人员手动动用GPU的shader编译接口将对应的代码编译成可执行的程序。在这里笔者就为大家介绍如何使用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
#pragma once#includeunordered_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_mapGLenum, std::string PreProcess(const std::string source);void Compile(const std::unordered_mapGLenum, std::string shaderSources);
private:uint32_t m_ShaderID;std::string m_Name;
};
Shader.cpp
#includeglad/glad.h
#includestring
#includearray
#includefstream
#includeiostream#includeShader.hstatic 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_mapGLenum, std::string Shader::PreProcess(const std::string source) {std::unordered_mapGLenum, 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_mapGLenum, std::string shaderSources) {unsigned int program glCreateProgram();//一次性至多编译两种着色器if (shaderSources.size() 2) {std::cout 一次性至多编译两种着色器 std::endl;__debugbreak();}std::arrayGLenum, 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::vectorchar 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 programglLinkProgram(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 characterstd::vectorchar infoLog(maxLength);glGetProgramInfoLog(program, maxLength, maxLength, infoLog[0]);// We dont 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
#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、读取对应的文件内容
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、确定着色器的类型以及每个着色器的代码
std::unordered_mapGLenum, std::string Shader::PreProcess(const std::string source) {std::unordered_mapGLenum, 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语法我们在进行文本处理的时候需要省略掉才行不然的话编译会失败这个只是用来告诉程序下面着色器代码是什么类型着色器的所以这里选择返回了一个字典用来存储着色器的类型和需要编译的程序。能够编译的是下面两段
#version 450 core
//标记为0的内存位置输入一个有两个分量的向量这是顶点的位置
layout(location 0) in vec2 v_Position;void main(){//顶点位置的数据进行赋值需要转换为齐次向量gl_Position vec4(v_Position,0.0f,1.0f);
}
#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、编译链接着色器
void Shader::Compile(const std::unordered_mapGLenum, std::string shaderSources) {//注册使用下面两个着色器的程序号unsigned int program glCreateProgram();//一次性至多编译两种着色器if (shaderSources.size() 2) {std::cout 一次性至多编译两种着色器 std::endl;__debugbreak();}std::arrayGLenum, 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::vectorchar 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 programglLinkProgram(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 characterstd::vectorchar infoLog(maxLength);glGetProgramInfoLog(program, maxLength, maxLength, infoLog[0]);// We dont 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);
}
上面大致流程就是注册程序的编号创建对应类型的着色器根据下面的代码
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。创建了对应的着色器类型过后就是对源码进行编译放入到程序当中检查这个程序能否顺利接入管线当中隔离开然后等待被调用。
使用用户自定义着色器
着色器使用主函数代码如下
#includeglad/glad.h
#includeGLFW/glfw3.h#include imgui.h
#include imgui_impl_glfw.h
#include imgui_impl_opengl3.h#includeiostream#includeFrameBuffer.h
#includeShader.hint main() {glfwInit();GLFWwindow* window glfwCreateWindow(640, 480, Triangles, NULL, NULL);glfwMakeContextCurrent(window);glfwSwapInterval(1); // Enable vsync// Setup Dear ImGui contextIMGUI_CHECKVERSION();ImGui::CreateContext();ImGuiIO io ImGui::GetIO(); (void)io;io.ConfigFlags | ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controlsio.ConfigFlags | ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controlsio.ConfigFlags | ImGuiConfigFlags_DockingEnable; // Enable Dockingio.ConfigFlags | ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows//io.ConfigViewportsNoAutoMerge true;//io.ConfigViewportsNoTaskBarIcon true;// Setup Dear ImGui styleImGui::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 backendsImGui_ImplGlfw_InitForOpenGL(window, true);ImGui_ImplOpenGL3_Init(#version 130);//需要初始化GLADif (!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 frameImGui_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_castvoid*(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);*/// RenderingImGui::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();}// CleanupImGui_ImplOpenGL3_Shutdown();ImGui_ImplGlfw_Shutdown();ImGui::DestroyContext();delete pFrameBuffer;delete pShader;glfwDestroyWindow(window);glfwTerminate();
}
得到的结果是 三角形被顺利染成了红色有人可能会说这也有点费了这么大的劲就把颜色改成了红色实在是有点无聊那让我们来做一些比较Cool的事。
我们修改一下着色器
#type vertex
#version 450 corelayout(location 0) in vec2 v_Position;void main(){gl_Position vec4(v_Position,0.0f,1.0f);
}#type fragment
#version 450 corelayout(location 0) out vec4 o_Color;
//增加的片段
uniform vec4 u_Color;void main(){o_Color u_Color;
}
主函数也修改一下
pShader-UBind();while (!glfwWindowShouldClose(window)) {pFrameBuffer-Bind();pShader-Bind();//新增片段pShader-UploadUniformFloat4(u_Color, colorEditor);glClear(GL_COLOR_BUFFER_BIT);
展示一下结果 我们现在可以通过ImGui上面的控件对三角形的颜色进行实时修改了不用去改动程序是不是很棒了。下面还是把整个主函数放出来如果对里面的FrameBuffer类不了解的可以看笔者的OpenGL渲染结果移至ImGui窗口上这篇文章同样有源代码希望对大家能有帮助。
#includeglad/glad.h
#includeGLFW/glfw3.h#include imgui.h
#include imgui_impl_glfw.h
#include imgui_impl_opengl3.h#includeiostream#includeFrameBuffer.h
#includeShader.hint main() {glfwInit();GLFWwindow* window glfwCreateWindow(640, 480, Triangles, NULL, NULL);glfwMakeContextCurrent(window);glfwSwapInterval(1); // Enable vsync// Setup Dear ImGui contextIMGUI_CHECKVERSION();ImGui::CreateContext();ImGuiIO io ImGui::GetIO(); (void)io;io.ConfigFlags | ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controlsio.ConfigFlags | ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controlsio.ConfigFlags | ImGuiConfigFlags_DockingEnable; // Enable Dockingio.ConfigFlags | ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows//io.ConfigViewportsNoAutoMerge true;//io.ConfigViewportsNoTaskBarIcon true;// Setup Dear ImGui styleImGui::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 backendsImGui_ImplGlfw_InitForOpenGL(window, true);ImGui_ImplOpenGL3_Init(#version 130);//需要初始化GLADif (!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 frameImGui_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_castvoid*(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);*/// RenderingImGui::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();}// CleanupImGui_ImplOpenGL3_Shutdown();ImGui_ImplGlfw_Shutdown();ImGui::DestroyContext();delete pFrameBuffer;delete pShader;glfwDestroyWindow(window);glfwTerminate();
}