LearnOpenGL 完整画一个三角形or正方形

2020-09-15  本文已影响0人  li_礼光

实现流程
1.创建一个基本的窗口.
2.利用用C++封装的Program和Shader
3.简单创建自己需要的顶点数据和索引数据
4.调用对应的绘制方法. glDrawArrays 或者 glDrawElements

#include "MyOpenglWindow.hpp"
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include "MyShader.hpp"
#include "MyProgram.hpp"

#define STRINGIZE(x) #x
#define SHADER(shader) STRINGIZE(shader)


// 模拟顶点数据
//三角形
GLfloat triangleVertices[] = {
    -0.5f, -0.5f, 0.0f,  //左下
     0.5f, -0.5f, 0.0f,  //右下
     0.0f,  0.5f, 0.0f,   //中上
};
  

//正方形
GLfloat squareVertices[] = {
    -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  squareIndices[] = { // 注意索引从0开始!
    0, 1, 2, // 第一个三角形
    0, 3, 2  // 第二个三角形
};


//顶点着色器程序
char *vertexShaderStr = SHADER(
    \#version 330 core\n
                               layout (location = 0) in vec3 position;
                               void main()
                               {
    gl_Position = vec4(position.x, position.y, position.z, 1.0);
    }
);

//片元着色器程序
char *fragmentShaderSrc = SHADER(
            \#version 330 core\n
                                 out vec4 color;
                                 void main()
                                 {
    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    }
);



bool showTriangle = false;


int runMyOpenGlWindow() {
        
    int result = glfwInit();
    if (result == GL_FALSE) {
        printf("glfwInit 初始化失败");
        return -1;
    }
    
    //这里的宏不好提示出来, 根据LearnOpenGL的文档提示, 用这三个
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //Mac平台需要加入
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

    //创建一个Window
    GLFWwindow *window = glfwCreateWindow(600, 400, "My Opengl Window", NULL, NULL);
    if(!window) {
        printf("window 创建失败");

    }
    
    //opengl运行模式 -- 单线程, 理解为跟当前的Window做一次绑定操作.
    glfwMakeContextCurrent(window);
    
    //任何的OpenGL接口调用都必须在初始化GLAD库后才可以正常访问。如果成功的话,该接口将返回GL_TRUE,否则就会返回GL_FALSE。
    gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
    
    
    
    
     //----------------------------------------------------------------------
    //先创建我们的Program对象, 加载顶点着色器程序和片元着色器程序
    MyProgram myProgram = MyProgram(vertexShaderStr, fragmentShaderSrc);

    GLuint VBO , VAO , EBO;
    unsigned int squareIndicesCount = 0;
    showTriangle = false;
    if (showTriangle) {
        //创建VBO
        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW);

       
       //创建VAO
        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(0);
        //解绑VAO
        glBindVertexArray(0);
        
        
    } else {
        //创建VBO
        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertices), squareVertices, GL_STATIC_DRAW);

        
        //创建VAO
        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(0);
        
        //创建EBO, 这里的EBO相当于索引的作用
        glGenBuffers(1, &EBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(squareIndices), squareIndices, GL_STATIC_DRAW);

        //解绑VAO
        glBindVertexArray(0);
        //计算索引个数
        squareIndicesCount = sizeof(squareIndices)/sizeof(squareIndices[0]);
        
    }
    
   
    
    
    //在glUseProgram函数调用之后,每个着色器调用和渲染调用都会使用这个程序对象(也就是之前写的着色器)了。
    glUseProgram(myProgram.program);
    //线框模式
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //----------------------------------------------------------------------
 


    
    //进行绘制
    while(!glfwWindowShouldClose(window)){
       //检查事件
        glfwPollEvents();
        
        //渲染指令
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //这里VAO也行, VBO也行
        glBindVertexArray(VAO);
        
        if (showTriangle) {
            glDrawArrays(GL_TRIANGLES, 0, 3);
            
        } else {
            //使用EBO
            glDrawElements(GL_TRIANGLES, squareIndicesCount, GL_UNSIGNED_INT, 0);
            
            //不使用EBO
//            glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
            /*
            v参数1:有三种取值
            1.GL_TRIANGLES:每三个顶之间绘制三角形,之间不连接
            2.GL_TRIANGLE_FAN:以V0V1V2,V0V2V3,V0V3V4,……的形式绘制三角形
            3.GL_TRIANGLE_STRIP:顺序在每三个顶点之间均绘制三角形。
             这个方法可以保证从相同的方向上所有三角形均被绘制。以V0V1V2,V1V2V3,V2V3V4……的形式绘制三角形
            */
        }
        
        //解绑VAO
        glBindVertexArray(0);
        
        //交换缓冲
        glfwSwapBuffers(window);
    }
    //程序销毁
    glfwTerminate();
    
    return 1;
}

在main.cpp中执行

int main(int argc, const char * argv[]) {
    return runMyOpenGlWindow();
}



注意点 :
1.创建了一个SHADER宏 , 里面写的内容直接会转为字符串.

  1. 顶点着色器程序vertexShaderStr 和片元着色器程序fragmentShaderSrc暂时不用管它是什么一回事, 假装默认就是这样. 还需要研究Shader编程.

3.理解绘制的流程, 绘制的方法.

4.理解VAO,VBO,EBO的buffer绑定方式,怎么(调用什么函数)把数据拷贝到缓冲区中

5.整个流程理解了, 开始研究Shader, 着色器语言.

6.后续实现 : 通过研究Shader,实现一个渐变的正方形




效果图 :


正方形
上一篇下一篇

猜你喜欢

热点阅读