GL-PipeLine
·467 words·3 mins
课程
OpenGL
计算机图形学
本文介绍用cpp和OpenGL绘制一个简单的三角形。
GLAD #
OpenGL是图形标准,而不是具体实现,它定义了一套接口规范,但是每个操作系统的实现都不一样,所以我们需要一个库来帮助我们加载OpenGL的函数指针,这个库就是GLAD。
GLAD能帮我们找到函数的具体实现,这样我们才能调用各种OpenGL的函数。
创建窗口 #
创建窗口需要使用GLFW库,GLFW能够在不同操作系统上创建窗口,接收用户输入,处理用户输入,以及与系统交互。如果不用这个库, 就需要自己找操作系统的API,这样就会很麻烦。
我们有三个地方要用GLFW的库,分别是初始化,循环,和终止。由于整体框架完全一致,我们可以封装一下窗口的类,初始化就放在构造函数里,终止放在析构函数里。
循环部分比较特殊,需要接收OpenGL真正画图的部分,我们要提供一个接口,让外部的函数能传进来,这样就可以在循环里调用了。
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <functional>
class GLFWWindowFactory
{
public:
GLFWWindowFactory(int width, int height, const char *title)
{
// Same window initialization logic here
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
this->window = glfwCreateWindow(width, height, title, NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
exit(-1);
}
glfwMakeContextCurrent(this->window);
glfwSetFramebufferSizeCallback(this->window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
}
}
void processInput()
{
if (glfwGetKey(this->window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(this->window, true);
}
GLFWwindow *getWindow()
{
return this->window;
}
void run(std::function<void()> updateFunc)
{
while (!glfwWindowShouldClose(this->window))
{
// Input
processInput();
// Custom update function
updateFunc();
// Swap buffers and poll events
glfwSwapBuffers(this->window);
glfwPollEvents();
}
glfwTerminate();
}
static void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
private:
GLFWwindow *window;
};
有了这个类,在主函数里我们就能很方便的创建窗口了。
#include "./utils/windowFactory.cpp"
//#include "models/Model.h"
int main()
{
GLFWWindowFactory myWindow(800, 600, "LearnOpenGL");
myWindow.run([&]()
{
// Custom model updates and rendering logic here.
// For example:
// model->update();
// renderer->draw(model);
});
return 0;
}
画一个三角形 #
要画一个东西我们要定义它的顶点:
float vertices[] = {
0.0f, 0.5f, 0.0f, // 顶部顶点
-0.5f, -0.5f, 0.0f, // 左下角顶点
0.5f, -0.5f, 0.0f // 右下角顶点
};
然后初始化一个顶点缓冲对象(VBO)和一个顶点数组对象(VAO)来存储这些数据,并把它们传给OpenGL。
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// 绑定和设置顶点缓冲
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 配置顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
然后我们就可以在循环里画出来了。
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
以上代码都能封装模型类里,Triangle.h:
#pragma once
#include <glad/glad.h>
class TriangleModel
{
public:
TriangleModel();
~TriangleModel();
void draw();
private:
unsigned int VAO;
unsigned int VBO;
unsigned int shaderProgram;
void compileShaders();
void setupBuffers();
};
Triangle.cpp:
#include "TriangleModel.h"
#include <iostream>
const int VERTEX_ATTR_POSITION = 0;
const int NUM_COMPONENTS_PER_VERTEX = 3;
TriangleModel::TriangleModel()
{
compileShaders();
setupBuffers();
}
TriangleModel::~TriangleModel()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
}
void TriangleModel::draw()
{
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void TriangleModel::compileShaders()
{
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void TriangleModel::setupBuffers()
{
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
1.0f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.25f, 0.0f, 0.0f
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(VERTEX_ATTR_POSITION, NUM_COMPONENTS_PER_VERTEX, GL_FLOAT, GL_FALSE, NUM_COMPONENTS_PER_VERTEX * sizeof(float), (void *)0);
glEnableVertexAttribArray(VERTEX_ATTR_POSITION);
}
更新我们的主函数:
#include "./utils/windowFactory.cpp"
#include "models/Triangle.h"
int main()
{
GLFWWindowFactory myWindow(800, 600, "LearnOpenGL");
TriangleModel triangle;
myWindow.run([&]()
{
triangle.draw();
});
return 0;
}
Related
vscode学opengl
·264 words·2 mins
课程
OpenGL
vscode
BST Traversal
·133 words·1 min
刷题
二叉树
Attention Implementation
·118 words·1 min
Paper Reading
Neuron Network
attention mechanism