OpenGL笔记二十一之几何类设计
—— 2024-09-16 下午
bilibili赵新政老师的教程看后笔记
code review!
文章目录
- OpenGL笔记二十一之几何类设计
- 1.运行
- 1.1.立方体运行
- 1.2.球体运行
- 2.几何类搭建
- 1.立方体分析
- 2.球体分析
- 3.图片资源文件
- 4.关键实现
- 4.1.geometry.h
- 4.2.geometry.cpp
- 4.3.vertex.glsl
- 4.4.fragment.glsl
- 4.5.main.cpp
1.运行
1.1.立方体运行
1.2.球体运行
2.几何类搭建
1.立方体分析
将0.5替换成halfSize就可以了。
2.球体分析
3.图片资源文件
goku.jpg
earth.png
4.关键实现
4.1.geometry.h
代码
#pragma once
#include "core.h"
class Geometry {
public:
Geometry();
~Geometry();
static Geometry* createBox(float size);
static Geometry* createSphere(float radius);
GLuint getVao()const { return mVao; }
uint32_t getIndicesCount()const { return mIndicesCount; }
private:
GLuint mVao{ 0 };
GLuint mPosVbo{ 0 };
GLuint mUvVbo{ 0 };
GLuint mEbo{ 0 };
uint32_t mIndicesCount{ 0 };
};
4.2.geometry.cpp
代码
#include "geometry.h"
#include <vector>
Geometry::Geometry() {
}
Geometry::~Geometry() {
if (mVao != 0) {
glDeleteVertexArrays(1, &mVao);
}
if (mPosVbo != 0) {
glDeleteBuffers(1, &mPosVbo);
}
if (mUvVbo != 0) {
glDeleteBuffers(1, &mUvVbo);
}
if (mEbo != 0) {
glDeleteBuffers(1, &mEbo);
}
}
Geometry* Geometry::createBox(float size) {
Geometry* geometry = new Geometry();
geometry->mIndicesCount = 36;
float halfSize = size / 2.0f;
float positions[] = {
// Front face
-halfSize, -halfSize, halfSize, halfSize, -halfSize, halfSize, halfSize, halfSize, halfSize, -halfSize, halfSize, halfSize,
// Back face
-halfSize, -halfSize, -halfSize, -halfSize, halfSize, -halfSize, halfSize, halfSize, -halfSize, halfSize, -halfSize, -halfSize,
// Top face
-halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, -halfSize, -halfSize, halfSize, -halfSize,
// Bottom face
-halfSize, -halfSize, -halfSize, halfSize, -halfSize, -halfSize, halfSize, -halfSize, halfSize, -halfSize, -halfSize, halfSize,
// Right face
halfSize, -halfSize, halfSize, halfSize, -halfSize, -halfSize, halfSize, halfSize, -halfSize, halfSize, halfSize, halfSize,
// Left face
-halfSize, -halfSize, -halfSize, -halfSize, -halfSize, halfSize, -halfSize, halfSize, halfSize, -halfSize, halfSize, -halfSize
};
float uvs[] = {
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
};
unsigned int indices[] = {
0, 1, 2, 2, 3, 0, // Front face
4, 5, 6, 6, 7, 4, // Back face
8, 9, 10, 10, 11, 8, // Top face
12, 13, 14, 14, 15, 12, // Bottom face
16, 17, 18, 18, 19, 16, // Right face
20, 21, 22, 22, 23, 20 // Left face
};
//2 VBO创建
GLuint& posVbo = geometry->mPosVbo, uvVbo = geometry->mUvVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);
//3 EBO创建
glGenBuffers(1, &geometry->mEbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->mEbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//4 VAO创建
glGenVertexArrays(1, &geometry->mVao);
glBindVertexArray(geometry->mVao);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)0);
//5.4 加入ebo到当前的vao
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->mEbo);
glBindVertexArray(0);
return geometry;
}
Geometry* Geometry::createSphere(float radius) {
Geometry* geometry = new Geometry();
//目标:1 位置 2 uv 3 索引
//1 主要变量声明
std::vector<GLfloat> positions{};
std::vector<GLfloat> uvs{};
std::vector<GLuint> indices{};
//声明纬线与经线的数量
int numLatLines = 60;//纬线
int numLongLines = 60;//经线
//2 通过两层循环(纬线在外,经线在内)->位置、uv
for (int i = 0; i <= numLatLines; i++) {
for (int j = 0; j <= numLongLines; j++) {
float phi = i * glm::pi<float>() / numLatLines;
float theta = j * 2 * glm::pi<float>() / numLongLines;
float y = radius * cos(phi);
float x = radius * sin(phi) * cos(theta);
float z = radius * sin(phi) * sin(theta);
positions.push_back(x);
positions.push_back(y);
positions.push_back(z);
float u = 1.0 - (float)j / (float)numLongLines;
float v = 1.0 - (float)i / (float)numLatLines;
uvs.push_back(u);
uvs.push_back(v);
}
}
//3 通过两层循环(这里没有=号)->顶点索引
for (int i = 0; i < numLatLines; i++) {
for (int j = 0; j < numLongLines; j++) {
int p1 = i * (numLongLines + 1) + j;
int p2 = p1 + numLongLines + 1;
int p3 = p1 + 1;
int p4 = p2 + 1;
indices.push_back(p1);
indices.push_back(p2);
indices.push_back(p3);
indices.push_back(p3);
indices.push_back(p2);
indices.push_back(p4);
}
}
//4 生成vbo与vao
GLuint& posVbo = geometry->mPosVbo, uvVbo = geometry->mUvVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(float), positions.data(), GL_STATIC_DRAW);
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(float), uvs.data(), GL_STATIC_DRAW);
glGenBuffers(1, &geometry->mEbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->mEbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);
glGenVertexArrays(1, &geometry->mVao);
glBindVertexArray(geometry->mVao);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->mEbo);
glBindVertexArray(0);
geometry->mIndicesCount = indices.size();
return geometry;
}
4.3.vertex.glsl
代码
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aUV;
out vec2 uv;
uniform mat4 transform;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
//aPos作为attribute(属性)传入shader
//不允许更改的
void main()
{
vec4 position = vec4(aPos, 1.0);
position = projectionMatrix * viewMatrix * transform * position;
gl_Position = position;
uv = aUV;
}
4.4.fragment.glsl
代码
#version 460 core
out vec4 FragColor;
in vec2 uv;
uniform sampler2D sampler;
void main()
{
FragColor = texture(sampler, uv);
}
4.5.main.cpp
代码
#include <iostream>
#include "glframework/core.h"
#include "glframework/shader.h"
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
#include "glframework/texture.h"
//引入相机+控制器
#include "application/camera/perspectiveCamera.h"
#include "application/camera/orthographicCamera.h"
#include "application/camera/trackBallCameraControl.h"
#include "application/camera/gameCameraControl.h"
#include "glframework/geometry.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 设计并实现Geometry系统,用于学习方便
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
* 搭建Geometry类框架
*└────────────────────────────────────────────────┘
*/
Geometry* geometry = nullptr;
Shader* shader = nullptr;
Texture* texture = nullptr;
glm::mat4 transform(1.0f);
PerspectiveCamera* camera = nullptr;
TrackBallCameraControl* cameraControl = nullptr;
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) {
cameraControl->onKey(key, action, mods);
}
//鼠标按下/抬起
void OnMouse(int button, int action, int mods) {
double x, y;
app->getCursorPosition(&x, &y);
cameraControl->onMouse(button, action, x, y);
}
//鼠标移动
void OnCursor(double xpos, double ypos) {
cameraControl->onCursor(xpos, ypos);
}
//鼠标滚轮
void OnScroll(double offset) {
cameraControl->onScroll(offset);
}
void prepareVAO() {
geometry = Geometry::createBox(3.0f);
// geometry = Geometry::createSphere(3.0f);
}
void prepareShader() {
shader = new Shader("assets/shaders/vertex.glsl","assets/shaders/fragment.glsl");
}
void prepareTexture() {
texture = new Texture("assets/textures/goku.jpg", 0);
// texture = new Texture("assets/textures/earth.png", 0);
}
void prepareCamera() {
float size = 6.0f;
//camera = new OrthographicCamera(-size, size, size, -size, size, -size);
camera = new PerspectiveCamera(
60.0f,
(float)app->getWidth() / (float)app->getHeight(),
0.1f,
1000.0f
);
cameraControl = new TrackBallCameraControl();
cameraControl->setCamera(camera);
cameraControl->setSensitivity(0.4f);
}
void prepareState() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
//绑定当前的program
shader->begin();
shader->setInt("sampler", 0);
shader->setMatrix4x4("transform", transform);
shader->setMatrix4x4("viewMatrix", camera->getViewMatrix());
shader->setMatrix4x4("projectionMatrix", camera->getProjectionMatrix());
//绑定当前的vao
GL_CALL(glBindVertexArray(geometry->getVao()));
//发出绘制指令
GL_CALL(glDrawElements(GL_TRIANGLES, geometry->getIndicesCount(), GL_UNSIGNED_INT, 0));
GL_CALL(glBindVertexArray(0));
shader->end();
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
app->setMouseCallback(OnMouse);
app->setCursorCallback(OnCursor);
app->setScrollCallback(OnScroll);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
prepareVAO();
prepareTexture();
prepareCamera();
prepareState();
while (app->update()) {
cameraControl->update();
render();
}
app->destroy();
return 0;
}