zoukankan      html  css  js  c++  java
  • OpenGL之shader着色器的应用,三色渐变的三角形

    学习自:

    https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_7

    首先放一张效果图:

    本次教程,将着色器单独定义了一个类,方便代码阅读与编写。

    1,首先新建要给shader类:shader_s.h

    (1)shader_s.h

     1 #ifndef SHADER_H
     2 #define SHADER_H
     3 
     4 #include <glad/glad.h> // 包含glad来获取所有的必须OpenGL头文件
     5 
     6 #include <string>
     7 #include <fstream>
     8 #include <sstream>
     9 #include <iostream>
    10 
    11 
    12 class Shader
    13 {
    14 public:
    15     // 程序ID
    16     unsigned int ID;
    17 
    18     // 构造器读取并构建着色器
    19     Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
    20     // 使用/激活程序
    21     void use();
    22     // uniform工具函数
    23     void setBool(const std::string &name, bool value) const;
    24     void setInt(const std::string &name, int value) const;
    25     void setFloat(const std::string &name, float value) const;
    26 private:
    27     void checkCompileErrors(unsigned int shader, std::string type);
    28 };
    29 
    30 #endif

    (2)将头文件中的方法逐一实现

    注意的是,我们类的写法,与链接中的写法有不同之处。

    #include "shader_s.h"
    
    Shader::Shader(const GLchar * vertexPath, const GLchar * fragmentPath)
    {
        // 1. 从文件路径中获取顶点/片段着色器
        std::string vertexCode;
        std::string fragmentCode;
        std::ifstream vShaderFile;
        std::ifstream fShaderFile;
        // 保证ifstream对象可以抛出异常:
        vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        try
        {
            // 打开文件
            vShaderFile.open(vertexPath);
            fShaderFile.open(fragmentPath);
            std::stringstream vShaderStream, fShaderStream;
            // 读取文件的缓冲内容到数据流中
            vShaderStream << vShaderFile.rdbuf();
            fShaderStream << fShaderFile.rdbuf();
            // 关闭文件处理器
            vShaderFile.close();
            fShaderFile.close();
            // 转换数据流到string
            vertexCode = vShaderStream.str();
            fragmentCode = fShaderStream.str();
        }
        catch (std::ifstream::failure e)
        {
            std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
        }
        const char* vShaderCode = vertexCode.c_str();
        const char * fShaderCode = fragmentCode.c_str();
        // 2. 编译着色器
        unsigned int vertex, fragment;
        // 顶点着色器    vs
        vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vShaderCode, NULL);
        glCompileShader(vertex);
        checkCompileErrors(vertex, "VERTEX");
        // 片段着色器    fs
        fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fShaderCode, 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);
    }
    
    void Shader::checkCompileErrors(unsigned int shader, std::string type)
    {
        int success;
        char infoLog[1024];
        if (type != "PROGRAM")
        {
            glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
            if (!success)
            {
                glGetShaderInfoLog(shader, 1024, NULL, infoLog);
                std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "
    " << infoLog << "
     -- --------------------------------------------------- -- " << std::endl;
            }
        }
        else
        {
            glGetProgramiv(shader, GL_LINK_STATUS, &success);
            if (!success)
            {
                glGetProgramInfoLog(shader, 1024, NULL, infoLog);
                std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "
    " << infoLog << "
     -- --------------------------------------------------- -- " << std::endl;
            }
        }
    }

    2,主程序的使用

    注意,我们的50行,在使用类的构造方法时候,传入的两个字符串表示的是我们的两个本地文件地址,这两个文件,表示的是,我们的两个shader脚本,需要我们的手动创建,并且加入代码。

    两个脚本在最后给出。

     (1)主程序TestShader.cpp

    有一点需要注意的是,在vs中,我们自定义的类,如果要引用,用的是双引号 “”

    也就是 #include "shader_s.h" 跟链接中的也有区别

      1 #include <glad/glad.h>
      2 #include <GLFW/glfw3.h>
      3 
      4 #include "shader_s.h"
      5 
      6 #include <iostream>
      7 
      8 void framebuffer_size_callback(GLFWwindow* window, int width, int height);
      9 void processInput(GLFWwindow *window);
     10 
     11 // settings
     12 const unsigned int SCR_WIDTH = 800;
     13 const unsigned int SCR_HEIGHT = 600;
     14 
     15 int main()
     16 {
     17     // glfw: initialize and configure
     18     // ------------------------------
     19     glfwInit();
     20     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
     21     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
     22     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     23 
     24 #ifdef __APPLE__
     25     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
     26 #endif
     27 
     28     // glfw window creation
     29     // --------------------
     30     GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
     31     if (window == NULL)
     32     {
     33         std::cout << "Failed to create GLFW window" << std::endl;
     34         glfwTerminate();
     35         return -1;
     36     }
     37     glfwMakeContextCurrent(window);
     38     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
     39 
     40     // glad: load all OpenGL function pointers
     41     // ---------------------------------------
     42     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
     43     {
     44         std::cout << "Failed to initialize GLAD" << std::endl;
     45         return -1;
     46     }
     47 
     48     // build and compile our shader program
     49     // ------------------------------------
     50     Shader ourShader("../res/shader.vs", "../res/shader.fs"); // you can name your shader files however you like
     51 
     52     // set up vertex data (and buffer(s)) and configure vertex attributes
     53     // ------------------------------------------------------------------
     54     float vertices[] = {
     55         // 位置信息         // 颜色信息
     56          0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // 右下
     57         -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // 左下
     58          0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // 顶部 
     59     };
     60 
     61     unsigned int VBO, VAO;
     62     glGenVertexArrays(1, &VAO);
     63     glGenBuffers(1, &VBO);
     64     //首先绑定顶点数组对象,然后绑定并设置顶点缓冲区,然后配置顶点属性。    
     65     glBindVertexArray(VAO);
     66 
     67     glBindBuffer(GL_ARRAY_BUFFER, VBO);
     68     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
     69 
     70     // 位置属性
     71     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
     72     glEnableVertexAttribArray(0);
     73     // 颜色属性
     74     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
     75     glEnableVertexAttribArray(1);
     76     /*
     77     glVertexAttribPointer 指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置。
     78     void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer);
     79     参数:
     80     (1)index
     81     指定要修改的顶点属性的索引值
     82     (2)size
     83     指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
     84     (4)type
     85     指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
     86     (5)normalized
     87     指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)。
     88     (6)stride
     89     指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。
     90     (7)pointer
     91     指定第一个组件在数组的第一个顶点属性中的偏移量。该数组与GL_ARRAY_BUFFER绑定,储存于缓冲区中。初始值为0;
     92     */
     93 
     94     // 循环渲染
     95     while (!glfwWindowShouldClose(window))
     96     {
     97         // input
     98         // -----
     99         processInput(window);
    100 
    101         // render
    102         // ------
    103         glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    104         glClear(GL_COLOR_BUFFER_BIT);
    105 
    106         // render the triangle
    107         ourShader.use();
    108         glBindVertexArray(VAO);
    109         glDrawArrays(GL_TRIANGLES, 0, 3);
    110 
    111         // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
    112         // -------------------------------------------------------------------------------
    113         glfwSwapBuffers(window);
    114         glfwPollEvents();
    115     }
    116 
    117     // optional: de-allocate all resources once they've outlived their purpose:
    118     // ------------------------------------------------------------------------
    119     glDeleteVertexArrays(1, &VAO);
    120     glDeleteBuffers(1, &VBO);
    121 
    122     // glfw: terminate, clearing all previously allocated GLFW resources.
    123     // ------------------------------------------------------------------
    124     glfwTerminate();
    125     return 0;
    126 }
    127 
    128 // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
    129 // ---------------------------------------------------------------------------------------------------------
    130 void processInput(GLFWwindow *window)
    131 {
    132     if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    133         glfwSetWindowShouldClose(window, true);
    134 }
    135 
    136 // glfw: whenever the window size changed (by OS or user resize) this callback function executes
    137 // ---------------------------------------------------------------------------------------------
    138 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    139 {
    140     // make sure the viewport matches the new window dimensions; note that width and 
    141     // height will be significantly larger than specified on retina displays.
    142     glViewport(0, 0, width, height);
    143 }

    (2) 脚本编写

    TestShader是我的项目名,然后新建文件夹res,存放我们的脚本,然后创建两个脚本,名字自己取就好,主程序中对应好就好了。

    a)顶点着色器(Vetex Shader)shader.vs

    #version 330 core
    layout (location = 0) in vec3 aPos;   // 位置变量的属性位置值为 0 
    layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
    
    out vec3 ourColor; // 向片段着色器输出一个颜色
    
    void main()
    {
        gl_Position = vec4(aPos, 1.0);
        ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
    }

    b)片段着色器(fragment Shader)shader.fs

    1 #version 330 core
    2 out vec4 FragColor;  
    3 in vec3 ourColor;
    4 
    5 void main()
    6 {
    7     FragColor = vec4(ourColor, 1.0);
    8 }

    3,最后运行我们的程序,就可以得到下面的效果图:

  • 相关阅读:
    第四次实验报告
    第三次实验报告
    循环结构课后反思
    第二次实验报告
    第一次实验报告1
    第一次作业
    第二次实验报告 总结
    第九章实验报告
    第八章实验报告
    第六次实验报告
  • 原文地址:https://www.cnblogs.com/icyhusky/p/10686294.html
Copyright © 2011-2022 走看看