opengl学习2

这个章节主要考虑通过opengl绘制一个简单的三角形。记录下来以备后面查阅。

OpenGL的处理管线主要有这些:顶点着色器、图元装配、几何着色器、光栅处理、片段着色器、混合测试这六部分。

顶点着色器主要将输入的顶点坐标变换为GPU内部识别的顶点坐标。

图元装配主要将输入的顶点按照用户的意图装配为图元,如点、线、圆等。

几何着色器则负责将根据图元装配的结果,按照用户需求转换为新的图元。

光栅处理,则负责将精确的坐标等使用像素来表述。

片段着色器则对各像素片段上的属性进行运算设置。

最后的混合测试可以对多个片段的关系进行设置。

目前较为常用的是设置顶点着色器和片段着色器。

         好,切入正题,绘制我们的三角形。

         三角形的顶点我们可以定义如下:

        float vertices[] = {  0.5f,  0.5f, 0.0f,

                        0.5f, -0.5f, 0.0f,

                       -0.5f, -0.5f, 0.0f,

                       -0.5f,  0.5f, 0.0f

};

接着可以定义顶点缓冲区对象(VBO),它主要对于顶点进行管理,将用户定义的数据直接在GPU上开辟空间处理。一般不管什么缓冲区,都需要如下步骤初始化,这里以VBO为例:

1、生成缓冲区   glGenBuffers(1, &VBO);

2、绑定缓冲区到缓冲区对象   glBindBuffer(GL_ARRAY_BUFFER, VBO);

3、设置缓冲区数据区

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

对于VAO也可这样定义:

glGenVertexArrays(1, &VAO);

glBindVertexArray(VAO);

对于EBO这样定义:

glGenBuffers(1, &EBO);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

最后对于这些数据缓冲区,需要设置其解析方式:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

glEnableVertexAttribArray(0);

glVertexAttribPointer的第一个参数,表示设置的是哪个shader变量,在shader中使用layout (location = 0)语句来设置。

glVertexAttribPointer第二个参数代表指定顶点的元素个数,如这里是三维坐标,那么有3个元素

glVertexAttribPointer第三个参数表示每个元素的类型,这里是float类型

glVertexAttribPointer第四个参数是顶点间存储的间距,这里由于顶点紧密排列,所以是顶点大小。

glVertexAttribPointer第四个参数暂时忽略吧

设置好缓冲区后,可以设置着色器熟悉。一般着色器使用需要如下几个步骤:

1、  创建着色器 vertexShader = glCreateShader(GL_VERTEX_SHADER);/*设置顶点着色器*/

2、  附加着色器源码, glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);

3、  编译着色器 glCompileShader(vertexShader);

检查着色器是否编译成功glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

4、  创建着色器程序  shaderProgram = glCreateProgram();

5、  添加着色器   glAttachShader(shaderProgram, fragmentShader);

6、  编译着色器   glLinkProgram(shaderProgram);

检测着色器是否成功 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);

7、  使用着色器:glUseProgram(shaderProgram);

8、  删除着色器:glDeleteShader(vertexShader);

这里着色器创建的是顶点着色器,如果是片段着色器,也一样进行创建,只是使用GL_FRAGMENT_SHADER宏来指定。

目前如果只使用VBO是绘制不出图像的,因为OpenGL默认必须要有VAO才可绘制。

使用VAO绘制,则调用glDrawArrays(GL_TRIANGLES, 0, 3);绘制三角形

如果使用EBO绘制,则调用glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);函数绘制三角形。

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

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

unsigned int indices[] = {
                            0, 1, 3,
                            1, 2, 3
                        };

const GLchar* vertexShaderSource = "#version 330 core\n"
                                    "layout (location = 0) in vec3 position;\n"
                                    "void main()\n"
                                    "{\n"
                                    "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
                                    "}\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"
                                        "out vec4 FragColor;\n"
                                        "void main()\n"
                                        "{\n"
                                        "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
                                        "}\0 ";


void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

int main() {
    
    unsigned int VBO;
    unsigned int vertexShader;
    unsigned int fragmentShader;
    unsigned int shadeProgram;
    unsigned int VAO;
    unsigned int EBO;
    int success;
    char infoLog[512];


    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);    

    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == nullptr)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    glfwSetKeyCallback(window, key_callback);
    
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (success == 0) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }


    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (success == 0)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT:COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    shadeProgram = glCreateProgram();
    glAttachShader(shadeProgram, vertexShader);
    glAttachShader(shadeProgram, fragmentShader);
    glLinkProgram(shadeProgram);
    glGetProgramiv(shadeProgram, GL_LINK_STATUS, &success);
    if (success == 0) {
        glGetProgramInfoLog(shadeProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM:LINK_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glUseProgram(shadeProgram);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glfwTerminate();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yy-86/p/9772715.html