zoukankan      html  css  js  c++  java
  • 在openGL里写一个Shader

    1、总体代码

    draw一个三角形,自写vertex着色器和fregment着色器,三角形染红色。

    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    #include <iostream>
    
    static unsigned int CompileShader( unsigned int type, const std::string& source)
    {
        unsigned int id = glCreateShader(type);
        const char* src = source.c_str();
        glShaderSource(id, 1, &src,nullptr);
        glCompileShader(id);
    
        //TODO:Error handling
        int result;
        glGetShaderiv(id, GL_COMPILE_STATUS, &result);
        if (result == GL_FALSE)
        {
            int length;
            glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
            char* message = (char*)alloca(length * sizeof(char));
    
            glGetShaderInfoLog(id, length, &length, message);
            std::cout << "Failed to compile " <<(type == GL_VERTEX_SHADER ? "vertex" : "fragment") << "shader!" 
                << std::endl;
            std::cout << message << std::endl;
            glDeleteShader(id);
        }
    
        return id;
    }
    
    static unsigned int CreateShader(const std::string& vectexShader, const std::string& fragmentShader)
    {
       unsigned int program = glCreateProgram();
       unsigned int vs = CompileShader(GL_VERTEX_SHADER, vectexShader);
       unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
    
       glAttachShader(program, vs);
       glAttachShader(program, fs);
       glLinkProgram(program);
       glValidateProgram(program);
    
       glDeleteShader(vs);
       glDeleteShader(fs);
    
       return program;
    }
    
    int main(void)
    {
        GLFWwindow* window;
    
        /* Initialize the library */
        if (!glfwInit())
            return -1;
        
        /* Create a windowed mode window and its OpenGL context */
        window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
        if (!window)
        {
            glfwTerminate();
            return -1;
        }
    
        /* Make the window's context current */
        glfwMakeContextCurrent(window);
    
        if (glewInit() != GLEW_OK)
            std::cout << "GLEW INIT ERR" << std::endl;
    
        std::cout << glGetString(GL_VERSION) << std::endl;
    
        float position[6] = {
            -0.5f, -0.5f,
             0.0f,  0.5f,
             0.5f, -0.5f,
        };
    
        unsigned int buffer;
        glGenBuffers(1, &buffer);
        glBindBuffer(GL_ARRAY_BUFFER, buffer);
        glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);
    
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
    
        std::string vertexShader =
            "#version 330 core
    "
            "
    "
            "layout(location = 0) in vec4 position;
    "
            "void main()
    "
            "{
    "
            "    gl_Position = position;
    "
            "}
    ";
    
        std::string fragmentShader =
            "#version 330 core
    "
            "
    "
            "layout(location = 0) out vec4 color;
    "
            "void main()
    "
            "{
    "
            "    color = vec4(1.0, 0.0, 0.0, 1.0);
    " //RGB
            "}
    ";
    
        unsigned int shader = CreateShader(vertexShader, fragmentShader);
        glUseProgram(shader);
    
    
        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            glClear(GL_COLOR_BUFFER_BIT);
    
            glDrawArrays(GL_TRIANGLES, 0, 3);
    
            /* Swap front and back buffers */
            glfwSwapBuffers(window);
    
            /* Poll for and process events */
            glfwPollEvents();
        }
    
        glDeleteProgram(shader);
    
        glfwTerminate();
        return 0;
    }
    

    2、解析

    具体的gl函数文档可以见这个网站: opengl文档.
    一个十分好用的中文网站:learnOpenGL-CN

    • glGenBuffers glGenBuffers:生成缓冲区对象名称

      • 声明:void glGenBuffers( GLsizei n,
        GLuint * buffers);
      • 参数:
        • n :Specifies the number of buffer object names to be generated.指定要生成的缓冲区对象名称的数目。
        • buffers :Specifies an array in which the generated buffer object names are stored. 指定存储生成的缓冲区对象名称的数组。
      • 说明:
        glGenBuffers returns n buffer object names in buffers. There is no guarantee that the names form a contiguous set of integers; however, it is guaranteed that none of the returned names was in use immediately before the call to glGenBuffers.
        unsigned int objectId = 0;
        glGenObject(1, &objectId);//我们首先创建一个对象,然后用一个id保存它的引用(实际数据被储存在后台)
        
        返回n个缓冲对象名称,不能保证名字会组成一个连续的整数集,但是能保证在调用glGenBuffers前没有被立即使用过。
    • glBindBuffer glBindBuffer
      ///查看文档即可,这里不做简单翻译了。

    修改优化代码(去掉烦人的字符串)

    cherno的方式,使用独立文件,#include ,注意和上述的区别
    [1]头文件
    [2]static ShaderProgramSource ParseShader(const std::string& filepath) 函数
    这里main.cpp

    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    #include <iostream>
    
    #include <fstream>
    #include <string>
    #include <sstream>
    
    struct ShaderProgramSource
    {
        std::string VertexSource;
        std::string FragmentSource;
    };
    
    static ShaderProgramSource ParseShader(const std::string& filepath)
    {
        std::ifstream stream(filepath);
    
        enum class ShaderType
        {
            NONE = -1,
            VERTEX = 0,
            FRAGMENT = 1
        };
        ShaderType type = ShaderType::NONE;
    
        std::string line;
        std::stringstream ss[2];
        while (getline(stream, line))
        {
            //找到一行不等于无效字符串位置,自定义语法令牌,(custom syntax token)
            if (line.find("#shader") != std::string::npos)
            {
                if (line.find("vertex") != std::string::npos)
                    //set mode to  vertex
                    type = ShaderType::VERTEX;
                else if (line.find("fragment") != std::string::npos)
                    //set mode to fragment
                    type = ShaderType::FRAGMENT;
            }
            else
            {
                ss[(int)type] << line << '
    ';
            }
        }
    
        return { ss[0].str(),ss[1].str() };
    }
    
    static unsigned int CompileShader( unsigned int type, const std::string& source)
    {
        unsigned int id = glCreateShader(type);
        const char* src = source.c_str();
        glShaderSource(id, 1, &src,nullptr);
        glCompileShader(id);
    
        //TODO:Error handling
        int result;
        glGetShaderiv(id, GL_COMPILE_STATUS, &result);
        if (result == GL_FALSE)
        {
            int length;
            glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
            char* message = (char*)alloca(length * sizeof(char));
    
            glGetShaderInfoLog(id, length, &length, message);
            std::cout << "Failed to compile " <<(type == GL_VERTEX_SHADER ? "vertex" : "fragment") << "shader!" 
                << std::endl;
            std::cout << message << std::endl;
            glDeleteShader(id);
        }
    
        return id;
    }
    
    
    static unsigned int CreateShader(const std::string& vectexShader, const std::string& fragmentShader)
    {
       unsigned int program = glCreateProgram();
       unsigned int vs = CompileShader(GL_VERTEX_SHADER, vectexShader);
       unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
    
       glAttachShader(program, vs);
       glAttachShader(program, fs);
       glLinkProgram(program);
       glValidateProgram(program);
    
       glDeleteShader(vs);
       glDeleteShader(fs);
    
       return program;
    }
    
    int main(void)
    {
        GLFWwindow* window;
    
        /* Initialize the library */
        if (!glfwInit())
            return -1;
        
        /* Create a windowed mode window and its OpenGL context */
        window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
        if (!window)
        {
            glfwTerminate();
            return -1;
        }
    
        /* Make the window's context current */
        glfwMakeContextCurrent(window);
    
        if (glewInit() != GLEW_OK)
            std::cout << "GLEW INIT ERR" << std::endl;
    
        std::cout << glGetString(GL_VERSION) << std::endl;
    
        float position[6] = {
            -0.5f, -0.5f,
             0.0f,  0.5f,
             0.5f, -0.5f,
        };
    
        unsigned int buffer;
        glGenBuffers(1, &buffer);
    	glBindBuffer(GL_ARRAY_BUFFER, buffer);
    	glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);
    
        glEnableVertexAttribArray(0); //启用索引0
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
    
        ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
        std::cout << "VERTEX" << std::endl;
        std::cout << source.VertexSource << std::endl;
        std::cout << "FRAGMENT" << std::endl;
        std::cout << source.FragmentSource << std::endl;
        
        unsigned int shader = CreateShader(source.VertexSource, source.FragmentSource);
        glUseProgram(shader);
    
        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            glClear(GL_COLOR_BUFFER_BIT);
    
            glDrawArrays(GL_TRIANGLES, 0, 3);
    
            /* Swap front and back buffers */
            glfwSwapBuffers(window);
    
            /* Poll for and process events */
            glfwPollEvents();
        }
    
       // glDeleteProgram(shader);
    
        glfwTerminate();
        return 0;
    }
    

    下面是 res/shaders/Basic.shader的文件

    #shader vertex
    #version 330 core
    
    layout(location = 0) in vec4 position;
    void main()
    {
        gl_Position = position;
    };
    
    #shader fragment
    #version 330 core
    
    layout(location = 0) out vec4 color;
    void main()
    {
        color = vec4(0.2, 0.3, 0.5, 1.0); //RGB
    };
    

    其实没什么区别

    4、使用索引

    当我们绘制一个正方形的时候,其实就是绘制俩个三角形,我们可以把上述的position增加为6组顶点坐标,进行相应改变,就可以绘制了,但是实际上,我们只需要四个顶点坐标就可以完成绘制(有重复节点,斜对角线)这个时候我们可以使用索引的方式
    其他代码相同(shader什么的)

    int main(void)
    {
        GLFWwindow* window;
    
        /* Initialize the library */
        if (!glfwInit())
            return -1;
        
        /* Create a windowed mode window and its OpenGL context */
        window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
        if (!window)
        {
            glfwTerminate();
            return -1;
        }
    
        /* Make the window's context current */
        glfwMakeContextCurrent(window);
    
        if (glewInit() != GLEW_OK)
            std::cout << "GLEW INIT ERR" << std::endl;
    
        std::cout << glGetString(GL_VERSION) << std::endl;
    
        float position[] = {
            -0.5f,  -0.5f, // 0
             0.5f,  -0.5f, // 1
             0.5f,   0.5f, // 2 
            -0.5f,   0.5f  // 3        
        };
        unsigned int indices[] =
        {
            0, 1, 2,
            2, 3, 0
        };
    
        unsigned int buffer;
        glGenBuffers(1, &buffer);
    	glBindBuffer(GL_ARRAY_BUFFER, buffer);
    	glBufferData(GL_ARRAY_BUFFER, 6 * 2 * sizeof(float), position, GL_STATIC_DRAW);
    
        glEnableVertexAttribArray(0); //启用索引0
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
    
    
        unsigned int ibo;
        glGenBuffers(1, &ibo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 *  sizeof(unsigned int), indices, GL_STATIC_DRAW);
    
        ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
        //std::cout << "VERTEX" << std::endl;
        //std::cout << source.VertexSource << std::endl;
        //std::cout << "FRAGMENT" << std::endl;
        //std::cout << source.FragmentSource << std::endl;
        
        unsigned int shader = CreateShader(source.VertexSource, source.FragmentSource);
        glUseProgram(shader);
    
        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            glClear(GL_COLOR_BUFFER_BIT);
    
           // glDrawArrays(GL_TRIANGLES, 0, 6);
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT,nullptr);
    
            /* Swap front and back buffers */
            glfwSwapBuffers(window);
    
            /* Poll for and process events */
            glfwPollEvents();
        }
    
       // glDeleteProgram(shader);
    
        glfwTerminate();
        return 0;
    }
    
  • 相关阅读:
    余额宝数据架构阅读
    VS提示This function or variable may be unsafe,The POSIX name for this item is deprecated
    VS中新建QT空项目找不到头文件的问题
    指针
    循环for do while continue break,达夫设备
    GUI程序弹出控制台打印输出信息
    ctime、chrono以及所有和时间有关的内容
    python安装
    文件:fstream,FILE,CFile,filesystem,以及路径目录
    C++异常处理、Dump文件、断言、静态断言、日志文件
  • 原文地址:https://www.cnblogs.com/EvansPudding/p/12823789.html
Copyright © 2011-2022 走看看