| 
 
 | 
 
 
发表于 2023-2-21 22:05:09
|
查看: 280 |
回复: 0  
 
 
一、项目简介 
 
使用OpenGL(glfw, glad)模拟太阳系(地球、月球、太阳)系统,涉及三维图形变换、坐标系统,光照模型(待添加)、键盘鼠标事件处理等内容,在main函数中封装了绝大部分的OpenGL接口,极大的减少了代码量,操作简便。 
二、代码特点 
 
Shader.h Camera.h与Texture.h封装着色器、摄像机与纹理类,其中纹理类实例化即完成生成纹理与绑定、设置纹理环绕方式与过滤等工作。 
VertexArray,VertexBuffer与IndexBuffer封装VAO, VBO, EBO,类实例化时即自动生成顶点数组对象、顶点缓冲对象、元素缓冲对象,并提供绑定与解绑等接口。VertexBufferLayout类可自由设置顶点属性。 
Sphere类获得绘制球体所需的所有顶点坐标以及索引缓冲数组,用于实例化VBO和EBO对象,可手动调节设置球体绘制的精细程度。 
通过Renderer类的Draw方法实现球体绘制功能。 
三、源码实现及详细说明 
 
GitHub源码地址:wonderful2643/SolarSystem (github.com) 
#include <glad/glad.h> 
#include <GLFW/glfw3.h> 
 
#include <iostream> 
 
#include &#34;Shader.h&#34; 
#include &#34;Sphere.h&#34; 
#include &#34;Config.h&#34; 
#include &#34;Camera.h&#34; 
#include &#34;Renderer.h&#34; 
#include &#34;Texture.h&#34; 
 
#include &#34;VertexArray.h&#34; 
#include &#34;VertexBuffer.h&#34; 
#include &#34;IndexBuffer.h&#34; 
#include &#34;VertexBufferLayout.h&#34; 
 
#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, &#34;Solar System&#34;, nullptr, nullptr); 
 
  if (!window) 
  { 
    std::cout << &#34;Failed to create GLFW window&#34; << std::endl; 
    glfwTerminate(); 
    return -1; 
  } 
 
  glfwMakeContextCurrent(window); 
  glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 
  glfwSetCursorPosCallback(window, mouse_callback); 
  glfwSetScrollCallback(window, scroll_callback); 
 
  //注释该行,调试出bug键盘鼠标不会卡死 
  //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 
  glfwSwapInterval(1); 
 
  if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 
  { 
    std::cout << &#34;Failed to initialize GLAD&#34; << std::endl; 
    return -1; 
  } 
 
  std::cout << glGetString(GL_VERSION) << std::endl; 
   
  //获得球体所有顶点坐标以及EBO数组 
  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; 
    //顶点属性布局:前三位为球体上点的x, y, z坐标,后两位为2D纹理坐标 
    layout.Push<float>(3); 
    layout.Push<float>(2); 
    va.AddBuffer(layout); 
 
    IndexBuffer ib(&sphereIndices[0], sphereIndices.size());//放在最后 
 
    glEnable(GL_DEPTH_TEST); 
 
    Shader shader(&#34;res/shader/task3.vs&#34;, &#34;res/shader/task3.fs&#34;); 
    shader.Bind(); 
    shader.setInt(&#34;u_Texture&#34;, 0); 
 
    Texture textureSun(&#34;res/textures/sun.jpg&#34;); 
    Texture textureEarth(&#34;res/textures/earth.jpg&#34;); 
    Texture textureMoon(&#34;res/textures/moon.jpg&#34;); 
 
    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); 
 
    // 渲染循环 
    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(&#34;u_MVP&#34;, mvp); 
 
        render.Draw(mySphere.getNumIndices()); 
      } 
       
      { 
        // Earth 
        glm::mat4 model = glm::mat4(1.0f); 
        // 公转 
        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)); 
        // 抵消公转对自身倾斜方向的影响,保证公转后 仍然向右倾斜 
        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)); 
        // 自转 
        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(&#34;u_MVP&#34;, mvp); 
 
        render.Draw(mySphere.getNumIndices()); 
      } 
 
      { 
        // Moon 
        glm::mat4 model = glm::mat4(1.0f); 
        // 地日公转 
        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)); 
        // 月球公转 
        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)); 
        // 月球自转 
        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(&#34;u_MVP&#34;, 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)); 
} 
四、效果展示及项目框架 
 
 
 
 
 
参考链接 
 
C++ 实现太阳系行星系统(OpenGL) 
OpenGL画球面(6) - 邗影 - 博客园 (cnblogs.com) 
openGL编程学习(3):太阳、地球、月亮(含自转和公转)和航天飞机_LynnJute的博客-CSDN博客_glfw实现日地月 
OpenGL入门三——变换进阶 
LearnOpenGL CN 
【【译】TheCherno-OpenGL系列教程】 |   
 
  
 |