OpenGL学习——绘制第一个三角形
终于把三角形绘制出来了,首先一些关键概念、操作。
Vertex Data 顶点数据
VBO Vertex Buffer Objects 顶点缓冲对象
VAO Vertex Array Objects 顶点数组对象
Vertex Attribute Pointer 顶点属性指针
NDC Normalized Device Coordinates 标准化设备坐标
Vertex Shader Objects 顶点着色器对象
GLSL OpenGL Shading Language 着色器语言
顶点数组位置声明
顶点着色器 in 关键字声明输入
预定义关键字 gl_Position 顶点着色器输出
Fragment Shader Objects 片段着色器对象
片段着色器 out 关键字声明输出
Shader Program 着色器程序
着色器程序链接顶点着色器与片段着色器
在绘制循环里使用着色器程序、绑定顶点数组对象、告知绘制图元类型、解绑顶点数组对象。
Graphics Pipeline:
Vertex Data => Vertex Shader => Primitive Assembly => Geometry Shader
⇩
Alpha Test And Blending <= Fragment Shader <= Rasterization
就这些吧,上图、上源码:
主函数 main.cpp
// GLEW #define GLEW_STATIC #include <GL/glew.h> // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "Triangles.h" int main(){ // glfw init 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); //create a glfw window GLFWwindow *window = glfwCreateWindow(640, 360, "opengl-triangles", nullptr, nullptr); if (window == nullptr){ std::cout << "create glfw window failed..." << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window);//set current window // glew init glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK){ std::cout << "glew init failed..." << std::endl; return -1; } //get width and height from glfw window int width, height; glfwGetFramebufferSize(window, &width, &height); //define the glViewport glViewport(0, 0, width, height); Triangles triangles; triangles.init(); //add the game loop while (!glfwWindowShouldClose(window)){ //check event glfwPollEvents(); //now clear window glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);//the gl color buffer bit //your OpenGL code logical triangles.draw(); //swap buffer glfwSwapBuffers(window); } //the end, glfw window has been closed glfwTerminate(); return 0; }
头文件Triangles.h:
// GLEW #define GLEW_STATIC #include <GL/glew.h> // GLFW #include <GLFW/glfw3.h> #include <iostream> #include <sstream> class Triangles{ public: Triangles(); ~Triangles(); public: void init(); void draw(); private: //create vertex shader void createVertexShader(); //create fragment shader void createFragmentShader(); //create shader program void createShaderProgram(); //get vertex shader source code std::string getVertexShaderSrc(); //get fragment shader source code std::string getFragmentShaderSrc(); private: GLuint VAO; //define VAO, vertex array object GLuint vertexShader; GLuint fragmentShader; GLuint shaderProgram; };
实现类Triangles.cpp:
#include "Triangles.h" Triangles::Triangles(){ } Triangles::~Triangles(){ } void Triangles::init(){ // x,y,z opengl coordinates, the vertex data, three 3d point in normalized device coordinates GLfloat vertexs[] = { -0.4f, -0.5f, 0.0f, 0.4f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, }; //define VAO, vertex array object //GLuint VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // bind vertex array object //define VBO, vertex buffer object GLuint VBO; glGenBuffers(1, &VBO); // gen buffer object glBindBuffer(GL_ARRAY_BUFFER, VBO); // bind buffer to the target glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW); // copy vertex data to VBO //set vertex attribute point glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); glBindVertexArray(0);//unbind vertex array object //create shader program this->createShaderProgram(); } void Triangles::draw(){ //use shader programs glUseProgram(shaderProgram); //draw the triangles glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); } void Triangles::createVertexShader(){ //compile vertex shader source std::string vertexShaderStr = this->getVertexShaderSrc(); const char *vertexShaderSrc = vertexShaderStr.c_str(); std::cout << "vertexShaderSrc:\n" << vertexShaderSrc; //GLuint vertexShader; // shader object vertexShader = glCreateShader(GL_VERTEX_SHADER); // create vertex shader object glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // shader source attach to shader object glCompileShader(vertexShader); // compile shader //compile result check GLint success; GLchar infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success){ glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "vertex shader source compile failed...\n" << infoLog << std::endl; std::cout << vertexShaderSrc; } } void Triangles::createFragmentShader(){ //compile fragment shader source std::string fragmentShaderStr = this->getFragmentShaderSrc(); const char *fragmentShaderSrc = fragmentShaderStr.c_str(); std::cout << "\n\nfragmentShaderSrc:\n" << fragmentShaderSrc; //GLuint fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL); glCompileShader(fragmentShader); } void Triangles::createShaderProgram(){ this->createVertexShader(); this->createFragmentShader(); if (vertexShader == NULL || fragmentShader == NULL){ return; } //shader program, link vertex shader object and fragment shader object //GLuint shaderProgram; shaderProgram = glCreateProgram(); // create shader program glAttachShader(shaderProgram, vertexShader); // attach vertex shader glAttachShader(shaderProgram, fragmentShader); // attach fragment shader glLinkProgram(shaderProgram); // linking //check link result GLint success; GLchar infoLog[512]; glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success){ glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); std::cout << "shader program linking failed...\n"<< infoLog << std::endl; return; } //delete vertex shader object and fragment shader object glDeleteShader(vertexShader); glDeleteShader(fragmentShader); //return shaderProgram; } std::string Triangles::getVertexShaderSrc(){ std::stringstream ss; ss << "#version 330 core \n"; ss << "layout (location = 0) in vec3 position;"; ss << "void main()"; ss << "{"; ss << " gl_Position = vec4(position.x, position.y, position.z, 1.0);"; ss << "}"; //return ss.str(); std::string vertexShaderStr = "#version 330 core\n" "layout (location = 0) in vec3 pos; " "void main () {" " gl_Position = vec4(pos, 1.0);" "}"; return vertexShaderStr; } std::string Triangles::getFragmentShaderSrc(){ std::stringstream ss; ss << " #version 330 core \n"; ss << " out vec4 color; \n"; ss << " void main(){ \n"; ss << " color = vec4(1.0f, 0.1f, 0.1f, 1.0f); \n"; ss << " } \n"; //return ss.str(); std::string fragmentShaderStr = "#version 330 core\n" "out vec4 color; " "void main () {" " color = vec4(1.0f, 0.1f, 0.1f, 1.0f);" "}"; return fragmentShaderStr; }
运行结果:
参照:https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/04%20Hello%20Triangle/