OpenGL 行星asteroids系统的实例
发布时间
阅读量:
阅读量
这是一个基于OpenGL的行星类asteroids和地球类planet的3D图形展示程序。代码主要包括以下主要内容:
窗口创建与初始化:
- 使用GLFW创建窗口,并设置分辨率(800x600)。
- 初始化GLAD加载器和启用深度测试。
资源加载与着色器配置:- 加载所需的几何体(rock和planet)模型。
- 编译并使用自定义顶点和片元着色器Shader文件。
模型数据处理:- 生成10万个随机分布的 asteroid 模型。
- 设置每个 model 的缩放和平移变换矩阵。
- 将这些矩阵存储在数组中供后续渲染使用。
渲染循环:- 使用标准的 OpenGL 渲染流程进行绘制。
- 绘制 asteroid 和 planet 模型,并应用相应的变换矩阵进行显示。
- 实时更新视图矩阵以实现 camera 的移动与旋转效果。
用户输入处理:- 处理键盘按键(W, S, A, D)控制 camera 的移动方向。
- 处理鼠标移动与缩放事件以调整视角。
其他功能:- 设置视口大小回调函数以确保正确显示视口内容。
- 清除屏幕背景颜色并显示红色背景。
OpenGL 行星asteroids系统
- 先上图,再解答。
- 完整主要的源代码
- 源代码剖析
先上图,再解答。

完整主要的源代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <learnopengl/filesystem.h>
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
Camera camera(glm::vec3(0.0f, 0.0f, 155.0f));
float lastX = (float)SCR_WIDTH / 2.0;
float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true;
float deltaTime = 0.0f;
float lastFrame = 0.0f;
int main()
{
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
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "it_xiangqiang", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glEnable(GL_DEPTH_TEST);
Shader asteroidShader("10.3.asteroids.vs", "10.3.asteroids.fs");
Shader planetShader("10.3.planet.vs", "10.3.planet.fs");
Model rock(FileSystem::getPath("resources/objects/rock/rock.obj"));
Model planet(FileSystem::getPath("resources/objects/planet/planet.obj"));
unsigned int amount = 100000;
glm::mat4* modelMatrices;
modelMatrices = new glm::mat4[amount];
srand(glfwGetTime());
float radius = 150.0;
float offset = 25.0f;
for (unsigned int i = 0; i < amount; i++)
{
glm::mat4 model = glm::mat4(1.0f);
float angle = (float)i / (float)amount * 360.0f;
float displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;
float x = sin(angle) * radius + displacement;
displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;
float y = displacement * 0.4f;
displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;
float z = cos(angle) * radius + displacement;
model = glm::translate(model, glm::vec3(x, y, z));
float scale = (rand() % 20) / 100.0f + 0.05;
model = glm::scale(model, glm::vec3(scale));
float rotAngle = (rand() % 360);
model = glm::rotate(model, rotAngle, glm::vec3(0.4f, 0.6f, 0.8f));
modelMatrices[i] = model;
}
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW);
for (unsigned int i = 0; i < rock.meshes.size(); i++)
{
unsigned int VAO = rock.meshes[i].VAO;
glBindVertexArray(VAO);
// set attribute pointers for matrix (4 times vec4)
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glVertexAttribDivisor(6, 1);
glBindVertexArray(0);
}
while (!glfwWindowShouldClose(window))
{
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
glClearColor(1.f, 0.f, 0.f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 1000.0f);
glm::mat4 view = camera.GetViewMatrix();
asteroidShader.use();
asteroidShader.setMat4("projection", projection);
asteroidShader.setMat4("view", view);
planetShader.use();
planetShader.setMat4("projection", projection);
planetShader.setMat4("view", view);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, -3.0f, 0.0f));
model = glm::scale(model, glm::vec3(4.0f, 4.0f, 4.0f));
planetShader.setMat4("model", model);
planet.Draw(planetShader);
asteroidShader.use();
asteroidShader.setInt("texture_diffuse1", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rock.textures_loaded[0].id); // note: we also made the textures_loaded vector public (instead of private) from the model class.
for (unsigned int i = 0; i < rock.meshes.size(); i++)
{
glBindVertexArray(rock.meshes[i].VAO);
glDrawElementsInstanced(GL_TRIANGLES, rock.meshes[i].indices.size(), GL_UNSIGNED_INT, 0, amount);
glBindVertexArray(0);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(yoffset);
}
源代码剖析
当窗口尺寸发生变动(通常由系统自动调整或手动设置)时,该回调函数会被触发。
函数processInput(Window *window)//检查在当前帧期间是否按下了或释放了相关按钮,并以相应的动作作出回应
glfwInit();//初始化和配置
glfw窗口句柄 window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "it_xiangqiang", NULL); // 创建指定大小的 GLFW窗口
gltfLoader((GLADloadproc)glfwGetProcAddress)
glEnable(GL_DEPTH_TEST);//配置全局opengl状态
while (!glfwWindowShouldClose(window)){}//渲染循环
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); //渲染RBG红色
glfwTerminate();//终止,清除所有先前分配的GLFW资源
调用glViewport函数设置为当前窗口的宽度和高度;请注意以确保视口与目标新窗口保持一致,宽度和高度将显著超过在视网膜显示器上的指定值。
全部评论 (0)
还没有任何评论哟~
