一、項(xiàng)目簡(jiǎn)介
使用OpenGL(glfw, glad)模擬太陽(yáng)系(地球、月球、太陽(yáng))系統(tǒng),涉及三維圖形變換、坐標(biāo)系統(tǒng),光照模型(待添加)、鍵盤鼠標(biāo)事件處理等內(nèi)容,在main函數(shù)中封裝了絕大部分的OpenGL接口,極大的減少了代碼量,操作簡(jiǎn)便。
二、代碼特點(diǎn)
Shader.h Camera.h與Texture.h封裝著色器、攝像機(jī)與紋理類,其中紋理類實(shí)例化即完成生成紋理與綁定、設(shè)置紋理環(huán)繞方式與過(guò)濾等工作,減少大量代碼量。
VertexArray,VertexBuffer與IndexBuffer封裝VAO, VBO, EBO,類實(shí)例化時(shí)即自動(dòng)生成頂點(diǎn)數(shù)組對(duì)象、頂點(diǎn)緩沖對(duì)象、元素緩沖對(duì)象,并提供綁定與解綁等接口。VertexBufferLayout類可自由設(shè)置頂點(diǎn)屬性。
Sphere類獲得繪制球體所需的所有頂點(diǎn)坐標(biāo)以及索引緩沖數(shù)組,用于實(shí)例化VBO和EBO對(duì)象,可手動(dòng)調(diào)節(jié)設(shè)置球體繪制的精細(xì)程度。
通過(guò)Renderer類的Draw方法實(shí)現(xiàn)球體繪制。
三、源碼實(shí)現(xiàn)及詳細(xì)說(shuō)明
GitHub源碼地址:wonderful2643/SolarSystem (github.com)
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "Shader.h"
#include "Sphere.h"
#include "Config.h"
#include "Camera.h"
#include "Renderer.h"
#include "Texture.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "VertexBufferLayout.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
// camera
Camera camera(glm::vec3(0.0f, 5.0f, 35.0f));
float lastX = WindowWidth / 2.0f;
float lastY = WindowHeight / 2.0f;
bool firstMouse = true;
// timing
float deltaTime = 0.0f; // time between current frame and last frame
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);
GLFWwindow* window = glfwCreateWindow(WindowWidth, WindowHeight, "Solar System", nullptr, nullptr);
if (!window)
{
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);
//注釋該行,調(diào)試出bug鍵盤鼠標(biāo)不會(huì)卡死
//glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSwapInterval(1);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
std::cout << glGetString(GL_VERSION) << std::endl;
//獲得球體所有頂點(diǎn)坐標(biāo)以及EBO數(shù)組
Sphere mySphere(40);
std::vector<float> sphereVertices = mySphere.getVertices();
std::vector<unsigned int> sphereIndices = mySphere.getIndices();
{
//VAO
VertexArray va;
//VBO
VertexBuffer vb(&sphereVertices[0], sphereVertices.size() * sizeof(float));
VertexBufferLayout layout;
//頂點(diǎn)屬性布局:前三位為球體上點(diǎn)的x, y, z坐標(biāo),后兩位為2D紋理坐標(biāo)
layout.Push<float>(3);
layout.Push<float>(2);
va.AddBuffer(layout);
IndexBuffer ib(&sphereIndices[0], sphereIndices.size());//放在最后
glEnable(GL_DEPTH_TEST);
Shader shader("res/shader/task3.vs", "res/shader/task3.fs");
shader.Bind();
shader.setInt("u_Texture", 0);
Texture textureSun("res/textures/sun.jpg");
Texture textureEarth("res/textures/earth.jpg");
Texture textureMoon("res/textures/moon.jpg");
vb.Unbind();
va.Unbind();
ib.Unbind();
shader.Unbind();
Renderer render;
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 proj = glm::perspective(glm::radians(camera.Zoom), (float)WindowWidth / (float)WindowHeight, 0.1f, 100.0f);
// 渲染循環(huán)
while (!glfwWindowShouldClose(window))
{
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
va.Bind();
{
// Sun
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(glm::mat4(1.0f), -(float)glfwGetTime() / 5, glm::vec3(0.0f, 1.0f, 0.0f));
model = scale(model, glm::vec3(sunScale, sunScale, sunScale));
glm::mat4 mvp = proj * view * model;
textureSun.Bind();
shader.Bind();
shader.setMat4("u_MVP", mvp);
render.Draw(mySphere.getNumIndices());
}
{
// Earth
glm::mat4 model = glm::mat4(1.0f);
// 公轉(zhuǎn)
model = glm::rotate(model, (float)glfwGetTime() / 1.5f, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::translate(model, glm::vec3(SunEarthDistance, .0f, .0f));
// 抵消公轉(zhuǎn)對(duì)自身傾斜方向的影響,保證公轉(zhuǎn)后 仍然向右傾斜
model = glm::rotate(model, -(float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, -glm::radians(ErothAxialAngle), glm::vec3(0.0, 0.0, 1.0));
// 自轉(zhuǎn)
model = glm::rotate(model, -(float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 mvp = proj * view * model;
textureEarth.Bind();
shader.Bind();
shader.setMat4("u_MVP", mvp);
render.Draw(mySphere.getNumIndices());
}
{
// Moon
glm::mat4 model = glm::mat4(1.0f);
// 地日公轉(zhuǎn)
model = glm::rotate(model, (float)glfwGetTime() / 1.5f, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::translate(model, glm::vec3(SunEarthDistance, .0f, .0f));
// 月球公轉(zhuǎn)
model = glm::rotate(model, (float)glfwGetTime() * 2.0f, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::translate(model, glm::vec3(MoonEarthDistance, 0.0, 0.0));
// 月球自轉(zhuǎn)
model = glm::rotate(model, -(float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));
model = scale(model, glm::vec3(moonScale, moonScale, moonScale));
glm::mat4 mvp = proj * view * model;
textureMoon.Bind();
shader.Bind();
shader.setMat4("u_MVP", mvp);
render.Draw(mySphere.getNumIndices());
}
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 xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
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);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
四、效果展示及項(xiàng)目框架

參考鏈接
C++ 實(shí)現(xiàn)太陽(yáng)系行星系統(tǒng)(OpenGL)
OpenGL畫球面(6) - 邗影 - 博客園 (cnblogs.com)
openGL編程學(xué)習(xí)(3):太陽(yáng)、地球、月亮(含自轉(zhuǎn)和公轉(zhuǎn))和航天飛機(jī)_LynnJute的博客-CSDN博客_glfw實(shí)現(xiàn)日地月
OpenGL入門三——變換進(jìn)階
LearnOpenGL CN文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-763990.html
【【譯】TheCherno-OpenGL系列教程】文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-763990.html
到了這里,關(guān)于OpenGL太陽(yáng)系行星系統(tǒng)簡(jiǎn)單實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!