OpenGL学习(一)——画一个三角形

OpenGL学习(一)——画一个三角形

作为一个刚接触opengl的程序员,我想的地方开始介绍glew和glfw。介绍一些基本的函数。
先贴代码。来自Joey de Vries的《Learn OpenGL》
#include <iostream>
#include <GL/glew.h>

#include <GLFW/glfw3.h>

// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);

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 color;\n"
    "void main()\n"
    "{\n"
    "color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";


int main()
{
    glfwInit();
    //create a window
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

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

    // Set the required callback functions
   glfwSetKeyCallback(window, key_callback);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        std::cout << "Failed to initialize GLEW" << std::endl;
        return -1;
    }

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);

    //vertex shader
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);

    //将vertex shader的代码赋给对象,并进行编译
   glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
   glCompileShader(vertexShader);

   //check whether compile ok
   GLint success;
   GLchar infoLog[512];
   glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
   //if not success, print the error
   if(!success)
   {
     glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
     std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" <<
     infoLog << std::endl;
   }

   //fragment shader
   GLuint fragmentShader;
   fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
   glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
   glCompileShader(fragmentShader);

   //creating a program object
   GLuint shaderProgram;
   shaderProgram = glCreateProgram();

   //attach previous shaders and link them
   glAttachShader(shaderProgram, vertexShader);
   glAttachShader(shaderProgram, fragmentShader);
   glLinkProgram(shaderProgram);

   //check whether link ok
   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
   if(!success) {
   glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
   }

   //delete the shader
   glDeleteShader(vertexShader);
   glDeleteShader(fragmentShader);

   GLfloat firstTriangle[] = {
           -0.9f, -0.5f, 0.0f,  // Left
           -0.0f, -0.5f, 0.0f,  // Right
           -0.45f, 0.5f, 0.0f,  // Top
       };
       GLfloat secondTriangle[] = {
            0.0f, -0.5f, 0.0f,  // Left
            0.9f, -0.5f, 0.0f,  // Right
            0.45f, 0.5f, 0.0f   // Top
       };

     GLuint VBOs[2], VAOs[2];
     glGenVertexArrays(2, VAOs); // We can also generate multiple VAOs or buffers at the same time
     glGenBuffers(2, VBOs);
    //first triangle
     glBindVertexArray(VAOs[0]);
     glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
     glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle,GL_STATIC_DRAW);
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
     glEnableVertexAttribArray(0);
     glBindVertexArray(0);
    //second triangle
     glBindVertexArray(VAOs[1]);
     glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
     glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle,GL_STATIC_DRAW);
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
     glEnableVertexAttribArray(0);
     glBindVertexArray(0);


    while(!glfwWindowShouldClose(window))
    {

      glfwPollEvents();

        // Render
        // Clear the colorbuffer
      glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
      glClear(GL_COLOR_BUFFER_BIT);

        // Draw our first triangle
        // Activate shader (same shader for both triangles)
      glUseProgram(shaderProgram);
      // Draw first triangle using the data from the first VAO
      glBindVertexArray(VAOs[0]);
      glDrawArrays(GL_TRIANGLES, 0, 3);
      // Then we draw the second triangle using the data from the second VAO
      glBindVertexArray(VAOs[1]);
      glDrawArrays(GL_TRIANGLES, 0, 3);
      glBindVertexArray(0);

      glfwSwapBuffers(window);
    }

    // Properly de-allocate all resources once they've outlived their purpose
     glDeleteVertexArrays(2, VAOs);
     glDeleteBuffers(2, VBOs);

    glfwTerminate();
    return 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);
}

总体想法

将数据传入VBO,然后将VBO绑定到VAO中,在主循环中绑定VAO并进行绘画即可。

主要函数介绍

glBufferData is a function specifically targeted to copy user-defined data into the currently bound buffer. Its first argument is the type of the buffer we want to copy data into: the vertex buffer object currently bound to the GL_ARRAY_BUFFER target. The second argument specifies the size of the data (in bytes) we want to pass to the buffer; a simple sizeof of the vertex data suffices. The third parameter is the actual data we want to send.

The fourth parameter specifies how we want the graphics card to manage the given data. This can take 3 forms:

• GL_STATIC_DRAW: the data will most likely not change at all or very rarely.
• GL_DYNAMIC_DRAW: the data is likely to change a lot.
• GL_STREAM_DRAW: the data will change every time it is drawn.

 glBufferData函数的第一个参数是buffer的类型,第二个是数据的大小,第三个是数据,第四个是我们想如何让显卡处理这些数据。

The function glVertexAttribPointer has quite a few parameters so let’s carefully walk through them:

• The first parameter specifies which vertex attribute we want to configure. Remember that we specified the location of the position vertex attribute in the vertex shader with layout (location = 0).This sets the location of the vertex attribute to 0 and since we want to pass data to this vertex attribute, we pass in 0.
• The next argument specifies the size of the vertex attribute. The vertex attribute is a vec3 so it is composed of 3 values.
• The third argument specifies the type of the data which is GL_FLOAT (a vec* in GLSL consists of floating point values).
• The next argument specifies if we want the data to be normalized. If we set this to GL_TRUE all the data that has a value not between 0 (or -1 for signed data) and 1 will be mapped to those values. We leave this at GL_FALSE.
• The fifth argument is known as the stride and tells us the space between consecutive vertex attribute sets. Since the next set of position data is located exactly 3 times the size of a GLfloat away we specify that value as the stride. Note that since we know that the array is tightly packed (there is no space between the next vertex attribute value) we could’ve also specified the stride as 0 to let OpenGL determine the stride (this only works when values are tightly packed). Whenever we have more vertex attributes we have to carefully define the spacing between each vertex attribute but we’ll get to see more examples of that later on.
• The last parameter is of type GLvoid* and thus requires that weird cast. This is the offset of where the position data begins in the buffer. Since the position data is at the start of the data array this value is just 0. We will explore this parameter in more detail later on

函数glVertexAttribPointers的第一个参数表示vertex shader的layout, 第二个参数表示vertex的大小,第三个表示data的类型。第四个表示数据是否被正规化,第五个参数表示stride的长度,第六个表示buffer的开头位置,其余不是很懂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值