Hazel Game Engine (029) OpenGL Shader

If there are errors in the code, terminology, etc. in the text, please correct me

foreword

  • of this program

    Use the shader to make the rendered triangles have colors, and the code of the light shader is abstracted into the Shader class (currently only a preliminary abstract class)

  • About Shaders

    • Tell the GPU what to do with the vertex data we send from the CPU to the GPU

    • Shaders are small programs that run on the GPU, corresponding to different stages of rendering management.

    • Shaders are very self-contained programs because they cannot communicate with each other; the only communication between them is through input and output.

  • related sites

    https://www.khronos.org/opengl/wiki/Shader_Compilation

project related

the code

  • Add Shader class

    #pragma once
    #include <string>
    	class Shader{
          
          
    	public:
    		Shader(const std::string& vertexSrc, const std::string& fragmentSrc);
    		~Shader();
    		void Bind() const;
    		void Unbind() const;
    	private:
    		uint32_t m_RendererID;
    	};
    }
    
    #include "hzpch.h"
    #include "Shader.h"
    #include <glad/glad.h>
    namespace Hazel {
          
          
    	Shader::Shader(const std::string& vertexSrc, const std::string& fragmentSrc){
          
          
    		// 1.1.创建顶点着色器对象
    		GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    		// Send the vertex shader source code to GL
    		// Note that std::string's .c_str is NULL character terminated.
    		// 1.2.附加顶点着色器源码到顶点着色器对象中
    		const GLchar* source = vertexSrc.c_str();
    		glShaderSource(vertexShader, 1, &source, 0);
    		// 1.3.编译顶点着色器对象
    		glCompileShader(vertexShader);
    		// 1.4.检查是否编译成功
    		GLint isCompiled = 0;
    		glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);
    		if (isCompiled == GL_FALSE){
          
          
    			// 1.4.2编译失败可以打印报错信息
    			GLint maxLength = 0;
    			glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
    			// The maxLength includes the NULL character
    			std::vector<GLchar> infoLog(maxLength);
    			glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);
    			// We don't need the shader anymore.
    			glDeleteShader(vertexShader);
    			HZ_CORE_ERROR("{0}", infoLog.data());
    			HZ_CORE_ASSERT(false, "Vertex shader compilation failure!");
    			return;
    		}
    		// 片段着色器一样
    		// 2.1.创建片段着色器对象
    		GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    		// Send the fragment shader source code to GL
    		// Note that std::string's .c_str is NULL character terminated.
    		// 2.2.附加片段着色器源码到片段着色器对象中
    		source = fragmentSrc.c_str();
    		glShaderSource(fragmentShader, 1, &source, 0);
    		// 2.3.编译片段着色器对象
    		glCompileShader(fragmentShader);
    		// 2.4.检查是否编译成功
    		glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);
    		if (isCompiled == GL_FALSE){
          
          
    			// 2.4.2编译失败可以打印报错信息
    			GLint maxLength = 0;
    			glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
    			// The maxLength includes the NULL character
    			std::vector<GLchar> infoLog(maxLength);
    			glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);
    			// We don't need the shader anymore.
    			glDeleteShader(fragmentShader);
    			// Either of them. Don't leak shaders.
    			glDeleteShader(vertexShader);
    			HZ_CORE_ERROR("{0}", infoLog.data());
    			HZ_CORE_ASSERT(false, "Fragment shader compilation failure!");
    			return;
    		}
    		// Vertex and fragment shaders are successfully compiled.
    		// Now time to link them together into a program.
    		// Get a program object.
    		// 3.1创建着色器程序对象
    		m_RendererID = glCreateProgram();
    		GLuint program = m_RendererID;
    		// 3.2附加着色器对象给着色器程序对象
    		glAttachShader(program, vertexShader);
    		glAttachShader(program, fragmentShader);
    		// 3.3链接着色器程序对象
    		glLinkProgram(program);
    		// 3.4可以检查链接是否成功
    		// Note the different functions here: glGetProgram* instead of glGetShader*.
    		GLint isLinked = 0;
    		glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);
    		if (isLinked == GL_FALSE){
          
          
    			GLint maxLength = 0;
    			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
    			// The maxLength includes the NULL character
    			std::vector<GLchar> infoLog(maxLength);
    			glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
    			// We don't need the program anymore.
    			glDeleteProgram(program);
    			// Don't leak shaders either.
    			glDeleteShader(vertexShader);
    			glDeleteShader(fragmentShader);
    			HZ_CORE_ERROR("{0}", infoLog.data());
    			HZ_CORE_ASSERT(false, "Shader link failure!");
    			return;
    		}
    		// 4.删除着色器对象
    		// Always detach shaders after a successful link.
    		glDetachShader(program, vertexShader);
    		glDetachShader(program, fragmentShader);
    	}
    	Shader::~Shader(){
          
          
    		glDeleteProgram(m_RendererID);
    	}
    	void Shader::Bind() const{
          
          
    		glUseProgram(m_RendererID);
    	}
    	void Shader::Unbind() const{
          
          
    		glUseProgram(0);
    	}
    }
    
  • Application

    Application::Application()
    {
          
          
        HZ_CORE_ASSERT(!s_Instance, "引用已经存在");
        s_Instance = this;
    
        // 1.1Application创建窗口
        m_Window = std::unique_ptr<Window>(Window::Create());
        // 1.2Application设置窗口事件的回调函数
        m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
    
        // 将ImGui层放在最后
        m_ImGuiLayer = new ImGuiLayer();
        PushOverlay(m_ImGuiLayer);
    
        // 使用OpenGL函数渲染一个三角形
        // 顶点数据
        float vertices[3 * 3] = {
          
          
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            0.0f,  0.5f, 0.0f
        };
        unsigned int indices[3] = {
          
           0, 1, 2 }; // 索引数据
        // 0.生成顶点数组对象VAO、顶点缓冲对象VBO、索引缓冲对象EBO
        glGenVertexArrays(1, &m_VertexArray);
        glGenBuffers(1, &m_VertexBuffer);
        glGenBuffers(1, &m_IndexBuffer);
        // 1. 绑定顶点数组对象
        glBindVertexArray(m_VertexArray);
        // 2. 把我们的CPU的顶点数据复制到GPU顶点缓冲中,供OpenGL使用
        glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        // 3. 复制我们的CPU的索引数据到GPU索引缓冲中,供OpenGL使用
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
        // 4. 设定顶点属性指针,来解释顶点缓冲中的顶点属性布局
        glEnableVertexAttribArray(0);// 开启glsl的layout = 0输入
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
        // 着色器代码
        std::string vertexSrc = R"(
    			#version 330 core
    
    			layout(location = 0) in vec3 a_Position;
    			out vec3 v_Position;
    			void main()
    			{
    				v_Position = a_Position;
    				gl_Position = vec4(a_Position, 1.0);	
    			}
    		)";
        std::string fragmentSrc = R"(
    			#version 330 core
    
    			layout(location = 0) out vec4 color;
    			in vec3 v_Position;
    			void main()
    			{
    				color = vec4(v_Position * 0.5 + 0.5, 1.0);
    			}
    		)";
        m_Shader.reset(new Shader(vertexSrc, fragmentSrc));
    	// 在头文件的std::unique_ptr<Shader> m_Shader;
    }
    void Application::Run(){
          
          
        while (m_Running)
        {
          
          
            glClearColor(0.1f, 0.1f, 0.1f, 1);
            glClear(GL_COLOR_BUFFER_BIT);
            // 5.绑定着色器
            m_Shader->Bind();
            // 6.绑定顶点数组对象,并绘制
            glBindVertexArray(m_VertexArray);
            glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
    
    
    • explain

      • fragment shader

        color = vec4(v_Position * 0.5 + 0.5, 1.0);

        vertex position*0.5 + 0.5;

        In this way, the vertex color will not be black, such as vertex color: -0.5->0.25

      • Shader source strings surrounded by R

        // 原始的-不美观
        string s = "#version 330 core\n"
        "asf\n"
        "adf\n"
        // 用R包围-好
        string s = R"(
        	#version 330 core
        	....
        )"
        

Effect

Please add a picture description

  • illustrate

    Three vertex colors are determined, and the color of the area fragments enclosed by them will be linearly interpolated according to the three vertex colors

Please add a picture description

Guess you like

Origin blog.csdn.net/qq_34060370/article/details/131388746