OpenGL笔记七之顶点数据绘制命令和绘制模式
—— 2024-07-07 杭州 下午
总结自bilibili赵新政老师的教程
文章目录
- OpenGL笔记七之顶点数据绘制命令和绘制模式
- 1.OpenGL版本号更改和编译更改
- 2.GL_TRIANGLES模式绘制一个三角形、支持NFC坐标随窗口缩放
- 2.1.三个点
- 2.2.四个点从0号点开始数3个点
- 2.3.四个点从1号点开始数3个点
- 2.4.四个点从2号点开始数3个点
- 2.5.六个点从0号点开始数6个点
- 2.6.六个点从0号点开始数5个点
- 3.GL_TRIANGLE_STRIP模式绘制三角形
- 4.GL_TRIANGLES_FAN模式绘制三角形
- 5.绘制直线:GL_LINES模式
- 6.绘制直线:GL_LINES_STRIP模式
- 7.其他代码文件
- 7.1.主CMakeLists.txt
- 7.2.application\CMakeLists.txt
- 7.3.application\Application.h
- 7.4.application\Application.cpp
- 7.5.wrapper\CMakeLists.txt
- 7.6.wrapper\checkError.h
- 7.7.wrapper\checkError.cpp
1.OpenGL版本号更改和编译更改
"#version 330 core\n"
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
2.GL_TRIANGLES模式绘制一个三角形、支持NFC坐标随窗口缩放
2.1.三个点
运行
关键代码
prepareInterleavedBuffer();
// prepareVAOForGLTriangles();
glDrawArrays(GL_TRIANGLES, 0, 3);
// glDrawArrays(GL_LINE_STRIP, 0, 6);
main.cpp
#include <iostream>
#define DEBUG
//注意:glad头文件必须在glfw引用之前引用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 学习glDrawArrays进行绘制命令
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
*│
*│ 1 采用GL_TRANGLES进行绘制
* ** 这里大家可以缩放窗体,实验NDC坐标的作用
*│ 2 prepareVAOForGLTriangles:构建四个顶点的vao
*│ 3 测试Triangle的三种mode:TRIANGLES TRIANGLE_STRIP TRIANGLE_FAN
*│ 4 测试Line的二种mode:LINES LINE_STRIP
*└────────────────────────────────────────────────┘
*/
GLuint vao, program;
void OnResize(int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
std::cout << "OnResize" << std::endl;
}
void OnKey(int key, int action, int mods) {
std::cout << key << std::endl;
}
void prepareSingleBuffer() {
//1 准备positions colors数据
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
//2 使用数据生成两个vbo posVbo, colorVbo
GLuint posVbo, colorVbo;
glGenBuffers(1, &posVbo);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
//3 生成vao并且绑定
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 分别将位置/颜色属性的描述信息加入vao当中
//4.1描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);//只有绑定了posVbo,下面的属性描述才会与此vbo相关
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//4.2 描述颜色属性
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareInterleavedBuffer() {
//1 准备好Interleaved数据(位置+颜色)
float vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
//2 创建唯一的vbo
GLuint vbo = 0;
GL_CALL(glGenBuffers(1, &vbo));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
//3 创建并绑定vao
GL_CALL(glGenVertexArrays(1, &vao));
GL_CALL(glBindVertexArray(vao));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
//4 为vao加入位置和颜色的描述信息
//4.1 位置描述信息
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0));
//4.2 颜色描述信息
GL_CALL(glEnableVertexAttribArray(1));
GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))));
//5 扫尾工作:解绑当前vao
glBindVertexArray(0);
}
void prepareVAOForGLTriangles() {
//1 准备positions
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.8f, 0.8f, 0.0f,
0.8f, 0.0f, 0.0f
};
//2 posVbo
GLuint posVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
//3 生成vao并且绑定
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
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(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
//1 绑定当前的program
glUseProgram(program);
//2 绑定当前的vao
glBindVertexArray(vao);
//3 发出绘制指令
glDrawArrays(GL_TRIANGLES, 0, 3);
// glDrawArrays(GL_LINE_STRIP, 0, 6);
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
prepareInterleavedBuffer();
// prepareVAOForGLTriangles();
while (app->update()) {
render();
}
app->destroy();
return 0;
}
2.2.四个点从0号点开始数3个点
运行
关键代码
// prepareInterleavedBuffer();
prepareVAOForGLTriangles();
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
// 0.8f, 0.8f, 0.0f,
// 0.8f, 0.0f, 0.0f
};
main.cpp
#include <iostream>
#define DEBUG
//注意:glad头文件必须在glfw引用之前引用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 学习glDrawArrays进行绘制命令
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
*│
*│ 1 采用GL_TRANGLES进行绘制
* ** 这里大家可以缩放窗体,实验NDC坐标的作用
*│ 2 prepareVAOForGLTriangles:构建四个顶点的vao
*│ 3 测试Triangle的三种mode:TRIANGLES TRIANGLE_STRIP TRIANGLE_FAN
*│ 4 测试Line的二种mode:LINES LINE_STRIP
*└────────────────────────────────────────────────┘
*/
GLuint vao, program;
void OnResize(int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
std::cout << "OnResize" << std::endl;
}
void OnKey(int key, int action, int mods) {
std::cout << key << std::endl;
}
void prepareSingleBuffer() {
//1 准备positions colors数据
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
//2 使用数据生成两个vbo posVbo, colorVbo
GLuint posVbo, colorVbo;
glGenBuffers(1, &posVbo);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
//3 生成vao并且绑定
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 分别将位置/颜色属性的描述信息加入vao当中
//4.1描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);//只有绑定了posVbo,下面的属性描述才会与此vbo相关
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//4.2 描述颜色属性
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareInterleavedBuffer() {
//1 准备好Interleaved数据(位置+颜色)
float vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
//2 创建唯一的vbo
GLuint vbo = 0;
GL_CALL(glGenBuffers(1, &vbo));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
//3 创建并绑定vao
GL_CALL(glGenVertexArrays(1, &vao));
GL_CALL(glBindVertexArray(vao));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
//4 为vao加入位置和颜色的描述信息
//4.1 位置描述信息
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0));
//4.2 颜色描述信息
GL_CALL(glEnableVertexAttribArray(1));
GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))));
//5 扫尾工作:解绑当前vao
glBindVertexArray(0);
}
void prepareVAOForGLTriangles() {
//1 准备positions
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
// 0.8f, 0.8f, 0.0f,
// 0.8f, 0.0f, 0.0f
};
//2 posVbo
GLuint posVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
//3 生成vao并且绑定
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
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(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
//1 绑定当前的program
glUseProgram(program);
//2 绑定当前的vao
glBindVertexArray(vao);
//3 发出绘制指令
glDrawArrays(GL_TRIANGLES, 0, 3);
// glDrawArrays(GL_LINE_STRIP, 0, 6);
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
// prepareInterleavedBuffer();
prepareVAOForGLTriangles();
while (app->update()) {
render();
}
app->destroy();
return 0;
}
2.3.四个点从1号点开始数3个点
运行
关键代码
glDrawArrays(GL_TRIANGLES, 1, 3);
2.4.四个点从2号点开始数3个点
运行
关键代码
glDrawArrays(GL_TRIANGLES, 2, 3);
2.5.六个点从0号点开始数6个点
运行
关键代码
glDrawArrays(GL_TRIANGLES, 0, 6);
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.8f, 0.8f, 0.0f,
0.8f, 0.0f, 0.0f
};
2.6.六个点从0号点开始数5个点
运行
关键代码
glDrawArrays(GL_TRIANGLES, 0, 5);
3.GL_TRIANGLE_STRIP模式绘制三角形
运行
关键代码
glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
main.cpp
#include <iostream>
#define DEBUG
//注意:glad头文件必须在glfw引用之前引用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 学习glDrawArrays进行绘制命令
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
*│
*│ 1 采用GL_TRANGLES进行绘制
* ** 这里大家可以缩放窗体,实验NDC坐标的作用
*│ 2 prepareVAOForGLTriangles:构建四个顶点的vao
*│ 3 测试Triangle的三种mode:TRIANGLES TRIANGLE_STRIP TRIANGLE_FAN
*│ 4 测试Line的二种mode:LINES LINE_STRIP
*└────────────────────────────────────────────────┘
*/
GLuint vao, program;
void OnResize(int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
std::cout << "OnResize" << std::endl;
}
void OnKey(int key, int action, int mods) {
std::cout << key << std::endl;
}
void prepareSingleBuffer() {
//1 准备positions colors数据
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
//2 使用数据生成两个vbo posVbo, colorVbo
GLuint posVbo, colorVbo;
glGenBuffers(1, &posVbo);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
//3 生成vao并且绑定
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 分别将位置/颜色属性的描述信息加入vao当中
//4.1描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);//只有绑定了posVbo,下面的属性描述才会与此vbo相关
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//4.2 描述颜色属性
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareInterleavedBuffer() {
//1 准备好Interleaved数据(位置+颜色)
float vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
//2 创建唯一的vbo
GLuint vbo = 0;
GL_CALL(glGenBuffers(1, &vbo));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
//3 创建并绑定vao
GL_CALL(glGenVertexArrays(1, &vao));
GL_CALL(glBindVertexArray(vao));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
//4 为vao加入位置和颜色的描述信息
//4.1 位置描述信息
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0));
//4.2 颜色描述信息
GL_CALL(glEnableVertexAttribArray(1));
GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))));
//5 扫尾工作:解绑当前vao
glBindVertexArray(0);
}
void prepareVAOForGLTriangles() {
//1 准备positions
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.8f, 0.8f, 0.0f,
0.8f, 0.0f, 0.0f
};
//2 posVbo
GLuint posVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
//3 生成vao并且绑定
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
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(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
//1 绑定当前的program
glUseProgram(program);
//2 绑定当前的vao
glBindVertexArray(vao);
//3 发出绘制指令
glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
// glDrawArrays(GL_TRIANGLES, 0, 6);
// glDrawArrays(GL_LINE_STRIP, 0, 6);
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
// prepareInterleavedBuffer();
prepareVAOForGLTriangles();
while (app->update()) {
render();
}
app->destroy();
return 0;
}
4.GL_TRIANGLES_FAN模式绘制三角形
运行
关键代码
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
main.cpp
#include <iostream>
#define DEBUG
//注意:glad头文件必须在glfw引用之前引用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 学习glDrawArrays进行绘制命令
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
*│
*│ 1 采用GL_TRANGLES进行绘制
* ** 这里大家可以缩放窗体,实验NDC坐标的作用
*│ 2 prepareVAOForGLTriangles:构建四个顶点的vao
*│ 3 测试Triangle的三种mode:TRIANGLES TRIANGLE_STRIP TRIANGLE_FAN
*│ 4 测试Line的二种mode:LINES LINE_STRIP
*└────────────────────────────────────────────────┘
*/
GLuint vao, program;
void OnResize(int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
std::cout << "OnResize" << std::endl;
}
void OnKey(int key, int action, int mods) {
std::cout << key << std::endl;
}
void prepareSingleBuffer() {
//1 准备positions colors数据
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
//2 使用数据生成两个vbo posVbo, colorVbo
GLuint posVbo, colorVbo;
glGenBuffers(1, &posVbo);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
//3 生成vao并且绑定
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 分别将位置/颜色属性的描述信息加入vao当中
//4.1描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);//只有绑定了posVbo,下面的属性描述才会与此vbo相关
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//4.2 描述颜色属性
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareInterleavedBuffer() {
//1 准备好Interleaved数据(位置+颜色)
float vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
//2 创建唯一的vbo
GLuint vbo = 0;
GL_CALL(glGenBuffers(1, &vbo));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
//3 创建并绑定vao
GL_CALL(glGenVertexArrays(1, &vao));
GL_CALL(glBindVertexArray(vao));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
//4 为vao加入位置和颜色的描述信息
//4.1 位置描述信息
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0));
//4.2 颜色描述信息
GL_CALL(glEnableVertexAttribArray(1));
GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))));
//5 扫尾工作:解绑当前vao
glBindVertexArray(0);
}
void prepareVAOForGLTriangles() {
//1 准备positions
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.8f, 0.8f, 0.0f,
0.8f, 0.0f, 0.0f
};
//2 posVbo
GLuint posVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
//3 生成vao并且绑定
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
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(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
//1 绑定当前的program
glUseProgram(program);
//2 绑定当前的vao
glBindVertexArray(vao);
//3 发出绘制指令
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
// glDrawArrays(GL_TRIANGLES, 0, 6);
// glDrawArrays(GL_LINE_STRIP, 0, 6);
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
// prepareInterleavedBuffer();
prepareVAOForGLTriangles();
while (app->update()) {
render();
}
app->destroy();
return 0;
}
5.绘制直线:GL_LINES模式
运行
关键代码
glDrawArrays(GL_LINES, 0, 6);
6.绘制直线:GL_LINES_STRIP模式
运行
关键代码
glDrawArrays(GL_LINE_STRIP, 0, 6);
main.cpp
#include <iostream>
#define DEBUG
//注意:glad头文件必须在glfw引用之前引用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 学习glDrawArrays进行绘制命令
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
*│
*│ 1 采用GL_TRANGLES进行绘制
* ** 这里大家可以缩放窗体,实验NDC坐标的作用
*│ 2 prepareVAOForGLTriangles:构建四个顶点的vao
*│ 3 测试Triangle的三种mode:TRIANGLES TRIANGLE_STRIP TRIANGLE_FAN
*│ 4 测试Line的二种mode:LINES LINE_STRIP
*└────────────────────────────────────────────────┘
*/
GLuint vao, program;
void OnResize(int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
std::cout << "OnResize" << std::endl;
}
void OnKey(int key, int action, int mods) {
std::cout << key << std::endl;
}
void prepareSingleBuffer() {
//1 准备positions colors数据
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
//2 使用数据生成两个vbo posVbo, colorVbo
GLuint posVbo, colorVbo;
glGenBuffers(1, &posVbo);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
//3 生成vao并且绑定
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 分别将位置/颜色属性的描述信息加入vao当中
//4.1描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);//只有绑定了posVbo,下面的属性描述才会与此vbo相关
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//4.2 描述颜色属性
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareInterleavedBuffer() {
//1 准备好Interleaved数据(位置+颜色)
float vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
//2 创建唯一的vbo
GLuint vbo = 0;
GL_CALL(glGenBuffers(1, &vbo));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
//3 创建并绑定vao
GL_CALL(glGenVertexArrays(1, &vao));
GL_CALL(glBindVertexArray(vao));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
//4 为vao加入位置和颜色的描述信息
//4.1 位置描述信息
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0));
//4.2 颜色描述信息
GL_CALL(glEnableVertexAttribArray(1));
GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))));
//5 扫尾工作:解绑当前vao
glBindVertexArray(0);
}
void prepareVAOForGLTriangles() {
//1 准备positions
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.8f, 0.8f, 0.0f,
0.8f, 0.0f, 0.0f
};
//2 posVbo
GLuint posVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
//3 生成vao并且绑定
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//4 描述位置属性
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
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(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
//1 绑定当前的program
glUseProgram(program);
//2 绑定当前的vao
glBindVertexArray(vao);
//3 发出绘制指令
glDrawArrays(GL_LINE_STRIP, 0, 6);
// glDrawArrays(GL_TRIANGLES, 0, 6);
// glDrawArrays(GL_LINE_STRIP, 0, 6);
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
// prepareInterleavedBuffer();
prepareVAOForGLTriangles();
while (app->update()) {
render();
}
app->destroy();
return 0;
}
7.其他代码文件
7.1.主CMakeLists.txt
# 指定 CMake 最低版本
cmake_minimum_required(VERSION 3.12)
# 项目名称
project(OpenGL_Lecture)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
# 包含头文件目录
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/thirdParty/include
/usr/include
)
# 包含库文件目录
link_directories(
${CMAKE_CURRENT_SOURCE_DIR}/thirdParty/lib
/usr/lib/x86_64-linux-gnu
)
# 设置 CMAKE_PREFIX_PATH 以找到 GLFW
set(CMAKE_PREFIX_PATH "/usr/local/lib/cmake/glfw3")
set(GLFW_DIR "/usr/local/lib/cmake/glfw3")
# 查找 GLFW3 库
find_package(glfw3 REQUIRED CONFIG)
add_subdirectory(wrapper)
add_subdirectory(application)
# 添加可执行文件
add_executable(openglStudy "main.cpp" "glad.c")
# 链接库
target_link_libraries(openglStudy glfw wrapper app)
7.2.application\CMakeLists.txt
#递归将本文件夹下所有cpp放到FUNCS中
file(GLOB_RECURSE APP ./ *.cpp)
#将FUNCS中所有cpp编译为funcs这个lib库
add_library(app ${APP} )
target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(app PRIVATE glfw)
7.3.application\Application.h
#pragma once
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 封装Application(表示了当前应用程序本身)
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
*│
*│ 1 单例类(全局唯一实例)
*│ 2 成员变量 + 成员函数
* 2.1 成员函数-init(初始化)
* 2.2 成员函数-update(每一帧执行)
* 2.3 成员函数-destroy(结尾执行)
*│ 3 响应回调函数(Resize)
* 3.1 声明一个函数指针ResizeCallback
* 3.2 声明一个ResizeCallback类型的成员变量
* 3.3 声明一个SetResizeCallback的函数 ,设置窗体变化响应回调函数
* 3.4 声明一个static的静态函数,用于响应glfw窗体变化
* 3.5 将静态函数设置到glfw的监听Resize监听当中
* 3.6 * 学会使用glfw的UserPointer
*│ 4 响应键盘消息函数(KeyBoard)
* 3.1 声明一个static的静态函数,用于响应glfw的键盘事件
* 3.2 将静态函数设置到glfw的监听KeyCallback监听当中
* 3.3 声明一个函数指针KeyBoardCallback
* 3.4 声明一个KeyBoardCallback类型的成员变量
* 3.5 声明一个SetKeyBoardCallback的函数 ,设置键盘响应回调函数
* 3.6 * 学会使用glfw的UserPointer
*└────────────────────────────────────────────────┘
*/
#include <iostream>
#define app Application::getInstance()
class GLFWwindow;
using ResizeCallback = void(*)(int width, int height);
using KeyBoardCallback = void(*)(int key, int action, int mods);
class Application {
public:
~Application();
//用于访问实例的静态函数
static Application* getInstance();
bool init(const int& width = 800, const int& height = 600);
bool update();
void destroy();
uint32_t getWidth()const { return mWidth; }
uint32_t getHeight()const { return mHeight; }
void setResizeCallback(ResizeCallback callback) { mResizeCallback = callback; }
void setKeyBoardCallback(KeyBoardCallback callback) { mKeyBoardCallback = callback; }
private:
//C++类内函数指针
static void frameBufferSizeCallback(GLFWwindow* window, int width, int height);
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
private:
//全局唯一的静态变量实例
static Application* mInstance;
uint32_t mWidth{ 0 };
uint32_t mHeight{ 0 };
GLFWwindow* mWindow{ nullptr };
ResizeCallback mResizeCallback{ nullptr };
KeyBoardCallback mKeyBoardCallback{ nullptr };
Application();
};
7.4.application\Application.cpp
#include "Application.h"
#include<glad/glad.h>
#include<GLFW/glfw3.h>
//初始化Application的静态变量
Application* Application::mInstance = nullptr;
Application* Application::getInstance() {
//如果mInstance已经实例化了(new出来了),就直接返回
//否则需要先new出来,再返回
if (mInstance == nullptr) {
mInstance = new Application();
}
return mInstance;
}
Application::Application() {
}
Application::~Application() {
}
bool Application::init(const int& width, const int& height) {
mWidth = width;
mHeight = height;
//1 初始化GLFW基本环境
glfwInit();
//1.1 设置OpenGL主版本号、次版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//1.2 设置OpenGL启用核心模式(非立即渲染模式)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//2 创建窗体对象
mWindow = glfwCreateWindow(mWidth, mHeight, "OpenGLStudy", NULL, NULL);
if (mWindow == NULL) {
return false;
}
//**设置当前窗体对象为OpenGL的绘制舞台
glfwMakeContextCurrent(mWindow);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return false;
}
glfwSetFramebufferSizeCallback(mWindow, frameBufferSizeCallback);
//this就是当前全局唯一的Application对象
glfwSetWindowUserPointer(mWindow, this);
//键盘响应
glfwSetKeyCallback(mWindow, keyCallback);
return true;
}
bool Application::update() {
if (glfwWindowShouldClose(mWindow)) {
return false;
}
//接收并分发窗体消息
//检查消息队列是否有需要处理的鼠标、键盘等消息
//如果有的话就将消息批量处理,清空队列
glfwPollEvents();
//切换双缓存
glfwSwapBuffers(mWindow);
return true;
}
void Application::destroy() {
//退出程序前做相关清理
glfwTerminate();
}
void Application::frameBufferSizeCallback(GLFWwindow* window, int width, int height) {
std::cout << "Resize" << std::endl;
Application* self = (Application*)glfwGetWindowUserPointer(window);
if (self->mResizeCallback != nullptr) {
self->mResizeCallback(width, height);
}
//if (Application::getInstance()->mResizeCallback != nullptr) {
// Application::getInstance()->mResizeCallback(width, height);
//}
}
void Application::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
Application* self = (Application*)glfwGetWindowUserPointer(window);
if (self->mKeyBoardCallback != nullptr) {
self->mKeyBoardCallback(key, action, mods);
}
}
7.5.wrapper\CMakeLists.txt
#递归将本文件夹下所有cpp放到FUNCS中
file(GLOB_RECURSE WRAPPER ./ *.cpp)
#将FUNCS中所有cpp编译为funcs这个lib库
add_library(wrapper ${WRAPPER} )
target_include_directories(wrapper PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(wrapper PRIVATE glfw)
7.6.wrapper\checkError.h
#pragma once
//预编译宏
#ifdef DEBUG
#define GL_CALL(func) func;checkError();
#else
#define GL_CALL(func)
#endif
void checkError();
7.7.wrapper\checkError.cpp
#include "checkError.h"
#include <glad/glad.h>
#include <string>
#include <iostream>
#include <assert.h>
void checkError() {
GLenum errorCode = glGetError();
std::string error = "";
if (errorCode != GL_NO_ERROR) {
switch (errorCode)
{
case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
case GL_OUT_OF_MEMORY: error = "OUT OF MEMORY"; break;
default:
error = "UNKNOWN";
break;
}
std::cout << error << std::endl;
//assert会根据传入的bool值,来决定程序是否停止
//true:程序顺利运行
//false:程序会断死
assert(false);
}
}