From 441a0748d1188dcdf67f805413f852415271f322 Mon Sep 17 00:00:00 2001 From: ktyl Date: Mon, 26 Feb 2024 20:00:59 +0000 Subject: [PATCH] refactor: extract Orbiter class split render logic across objects move rendering code from main loop to Orbiter make objects responsible for setting up their own render contexts --- CMakeLists.txt | 1 + src/icosphere.cpp | 5 +++- src/icosphere.hpp | 2 +- src/main.cpp | 41 +++++------------------------ src/orbit.cpp | 39 ++++++++++++++++++++++++--- src/orbit.hpp | 7 +++-- src/orbiter.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++ src/orbiter.hpp | 29 ++++++++++++++++++++ src/widget.cpp | 35 +++++++------------------ src/widget.hpp | 19 ++++++-------- 10 files changed, 166 insertions(+), 79 deletions(-) create mode 100644 src/orbiter.cpp create mode 100644 src/orbiter.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d56de93..8ab0968 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(${PROJECT_NAME} src/icosphere.cpp src/gfx.cpp src/orbit.cpp + src/orbiter.cpp src/widget.cpp ) diff --git a/src/icosphere.cpp b/src/icosphere.cpp index db404b8..94ee370 100644 --- a/src/icosphere.cpp +++ b/src/icosphere.cpp @@ -146,8 +146,11 @@ void Icosphere::updateModelMatrix() glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &model[0][0]); } -void Icosphere::render() +void Icosphere::render(const float time) { + glUseProgram(_shaderProgram); + updateModelViewProjectionMatrix(_shaderProgram, time); + updateModelMatrix(); glBindVertexArray(_vao); diff --git a/src/icosphere.hpp b/src/icosphere.hpp index 856802b..ff2edd6 100644 --- a/src/icosphere.hpp +++ b/src/icosphere.hpp @@ -11,7 +11,7 @@ class Icosphere { public: Icosphere(float radius, int subdivisions, GLuint shaderProgram); - void render(); + void render(const float time); void setPosition(glm::vec3 position); diff --git a/src/main.cpp b/src/main.cpp index 0828e25..ef99cec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,6 +42,7 @@ #include "gfx.hpp" #include "icosphere.hpp" #include "orbit.hpp" +#include "orbiter.hpp" #include "widget.hpp" int main() @@ -54,7 +55,7 @@ int main() GLuint unlitProgram = compileShaderProgram("./frag_unlit.glsl"); Icosphere planet(0.2, 3, litProgram); - Icosphere orbiter(0.07, 2, litProgram); + std::vector keplerianElements(6); keplerianElements[astro::semiMajorAxisIndex] = .75; @@ -62,9 +63,10 @@ int main() keplerianElements[astro::inclinationIndex] = 3.142 / 2.0 + 1; keplerianElements[astro::argumentOfPeriapsisIndex] = 2.0; keplerianElements[astro::longitudeOfAscendingNodeIndex] = 0; - Orbit orbit(keplerianElements); + Orbit orbit(keplerianElements, unlitProgram); - Widget widget(orbit, unlitProgram); + Icosphere orbiterSphere(0.07, 2, litProgram); + Orbiter orbiter(orbiterSphere, orbit, unlitProgram); // Main loop while (!glfwWindowShouldClose(window)) @@ -73,39 +75,8 @@ int main() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); float time = glfwGetTime(); - const float orbitalPeriod = 6.284; - const int ANIM_ORBITING = 0; - const int ANIM_ECCENTRICITY = 1; - int animation = (int)(time / orbitalPeriod) % 2 == 1; - - glm::vec3 pos; - if (animation == ANIM_ORBITING) - { - pos = orbit.getPosition(time); - } - else if (animation == ANIM_ECCENTRICITY) - { - float e = .25 + .2 * sin(time); - keplerianElements[astro::eccentricityIndex] = e; - orbit.setElements(keplerianElements); - - pos = orbit.getPosition(0); - } - orbiter.setPosition(pos); - - // Render lit objects - glUseProgram(litProgram); - updateModelViewProjectionMatrix(litProgram, time); - - planet.render(); - orbiter.render(); - - // Render unlit objects - glUseProgram(unlitProgram); - updateModelViewProjectionMatrix(unlitProgram, time); - orbit.render(); - widget.render(); + orbiter.render(time); glfwSwapBuffers(window); glfwPollEvents(); diff --git a/src/orbit.cpp b/src/orbit.cpp index 2df3dec..ff6d5ee 100644 --- a/src/orbit.cpp +++ b/src/orbit.cpp @@ -1,10 +1,14 @@ +#include "gfx.hpp" #include "orbit.hpp" #include "astro/stateVectorIndices.hpp" #include "astro/orbitalElementConversions.hpp" -Orbit::Orbit(Vector6 keplerianElements) : - _keplerianElements(keplerianElements) +#include + +Orbit::Orbit(Vector6 keplerianElements, GLuint shaderProgram) : + _keplerianElements(keplerianElements), + _shaderProgram(shaderProgram) { glGenVertexArrays(1, &_vao); glGenBuffers(1, &_vbo); @@ -45,6 +49,32 @@ void Orbit::setElements(Vector6 keplerianElements) regenerateVertices(); } +void Orbit::getElements(Vector6& keplerianElements) const +{ + keplerianElements = _keplerianElements; +} + +glm::mat4 Orbit::getLookAlongMatrix(const float meanAnomaly) +{ + glm::vec3 position = getPosition(meanAnomaly); + + // get the tangent of the orbital ellipse + glm::vec3 tan = getTangent(meanAnomaly); + // we want to point along the orbit + glm::vec3 target = position + tan; + // TODO: this is not 'up' with respect to the orbited body! + // 'up' is just the normalized position vector because the orbit is centred at the origin + glm::vec3 up = glm::normalize(position); + // easy peasy lookAt matrix + glm::mat4 look = glm::lookAt(position, target, up); + + // invert the lookat matrix because it's meant for cameras, cameras work backwards and + // we are not a camera + glm::mat4 lookAlong = glm::inverse(look); + + return lookAlong; +} + float Orbit::getEccentricAnomaly(const float meanAnomaly) { const float eccentricity = _keplerianElements[astro::eccentricityIndex]; @@ -92,8 +122,11 @@ glm::vec3 Orbit::getTangent(const float meanAnomaly) return glm::normalize(ahead - behind); } -void Orbit::render() +void Orbit::render(const float time) { + glUseProgram(_shaderProgram); + updateModelViewProjectionMatrix(_shaderProgram, time); + glBindVertexArray(_vao); glBindBuffer(GL_ARRAY_BUFFER, _vbo); diff --git a/src/orbit.hpp b/src/orbit.hpp index 1dd36ef..96c9ffd 100644 --- a/src/orbit.hpp +++ b/src/orbit.hpp @@ -10,15 +10,17 @@ typedef std::vector Vector6; class Orbit { public: - Orbit(Vector6 keplerianElements); - void render(); + Orbit(Vector6 keplerianElements, GLuint shaderProgram); + void render(const float time); // TODO: meanAnomaly in all these arguments actually means eccentricMeanAnomaly, // will have to change that when adding non-ellipctical orbits - don't get confused! glm::vec3 getPosition(const float meanAnomaly); glm::vec3 getTangent(const float meanAnomaly); + glm::mat4 getLookAlongMatrix(const float meanAnomaly); void setElements(Vector6 keplerianElements); + void getElements(Vector6& keplerianElements) const; ~Orbit(); private: @@ -27,6 +29,7 @@ private: GLuint _vbo; GLuint _vao; + GLuint _shaderProgram; std::vector _vertices; Vector6 _keplerianElements; diff --git a/src/orbiter.cpp b/src/orbiter.cpp new file mode 100644 index 0000000..ed53b31 --- /dev/null +++ b/src/orbiter.cpp @@ -0,0 +1,67 @@ +#include "orbiter.hpp" + +#include +#include +#include + +Orbiter::Orbiter(Icosphere& sphere, Orbit& orbit, GLuint unlitShaderProgram) : + _sphere(sphere), + _orbit(orbit), + _widget(unlitShaderProgram) +{ +} + +float Orbiter::getMeanAnomaly() +{ + float time = glfwGetTime(); + return time; +} + +glm::vec3 Orbiter::getPosition(const float time) +{ + std::vector keplerianElements(6); + _orbit.getElements(keplerianElements); + + int animation = (int)(time/ORBITAL_PERIOD) % 2 == 1; + + if (animation == ANIM_ORBITING) + return _orbit.getPosition(time); + + // TODO: i want to modify the eccentricity of the orbit with a control, + // not an automatic animation + if (animation == ANIM_ECCENTRICITY) + { + // TODO: what are these magic numbers + float e = .25 + .2 * sin(time); + keplerianElements[astro::eccentricityIndex] = e; + // TODO: extract set from getter + _orbit.setElements(keplerianElements); + + return _orbit.getPosition(0); + } + + std::cerr << "unknown animation " << animation << std::endl; + throw 1; +} + +void Orbiter::render(const float time) +{ + const float meanAnomaly = time; + glm::vec3 pos = getPosition(meanAnomaly); + + // render orbit + _orbit.render(time); + + // render widget + glm::mat4 widgetMatrix = _orbit.getLookAlongMatrix(time); + _widget.setModelMatrix(widgetMatrix); + _widget.render(time); + + // render sphere + _sphere.setPosition(pos); + _sphere.render(time); +} + +Orbiter::~Orbiter() +{ +} diff --git a/src/orbiter.hpp b/src/orbiter.hpp new file mode 100644 index 0000000..afb7fda --- /dev/null +++ b/src/orbiter.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "icosphere.hpp" +#include "orbit.hpp" +#include "widget.hpp" + +class Orbiter +{ +public: + Orbiter(Icosphere& sphere, Orbit& orbit, GLuint unlitShaderProgram); + ~Orbiter(); + + void render(const float time); + +private: + void updateModelMatrix(); + float getMeanAnomaly(); + glm::vec3 getPosition(const float time); + void getOrbitalElements(const float time, Vector6& keplerianElements); + + Icosphere& _sphere; + Orbit& _orbit; + Widget _widget; + + const float ORBITAL_PERIOD = 6.284; + + const int ANIM_ORBITING = 0; + const int ANIM_ECCENTRICITY = 1; +}; diff --git a/src/widget.cpp b/src/widget.cpp index 92f9d31..e11ca55 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1,10 +1,7 @@ #include "widget.hpp" #include "gfx.hpp" -#include -#include -Widget::Widget(Orbit& orbit, GLuint shaderProgram) : - _orbit(orbit), +Widget::Widget(GLuint shaderProgram) : _shaderProgram(shaderProgram) { const float lineLength = 0.1; @@ -30,36 +27,22 @@ Widget::Widget(Orbit& orbit, GLuint shaderProgram) : glBindVertexArray(0); } -void Widget::render() +void Widget::render(const float time) { - updateModelMatrix(); + glUseProgram(_shaderProgram); + updateModelViewProjectionMatrix(_shaderProgram, time); + + GLint modelLocation = getShaderUniformLocation(_shaderProgram, "_Model"); + glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &_modelMatrix[0][0]); glBindVertexArray(_vao); glBindBuffer(GL_ARRAY_BUFFER, _vbo); glDrawArrays(GL_LINES, 0, 6); } -void Widget::updateModelMatrix() +void Widget::setModelMatrix(const glm::mat4 matrix) { - float p = glfwGetTime(); - - _position = _orbit.getPosition(p); - - // get the tangent of the orbital ellipse - glm::vec3 tan = _orbit.getTangent(p); - // we want to point along the orbit - glm::vec3 target = _position + tan; - // 'up' is just the normalized position vector because the orbit is centred at the origin - glm::vec3 up = glm::normalize(_position); - // easy peasy lookAt matrix - glm::mat4 look = glm::lookAt(_position, target, up); - - // invert the lookat matrix because it's meant for cameras, cameras work backwards and - // we are not a camera - glm::mat4 model = glm::inverse(look); - - GLint modelLocation = getShaderUniformLocation(_shaderProgram, "_Model"); - glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &model[0][0]); + _modelMatrix = matrix; } Widget::~Widget() diff --git a/src/widget.hpp b/src/widget.hpp index 7b203ef..ebbeabf 100644 --- a/src/widget.hpp +++ b/src/widget.hpp @@ -1,28 +1,25 @@ #pragma once -#include "orbit.hpp" -#include +#include +#include "glm/glm.hpp" class Widget { public: - // A widget is renderer at a point on the orbit. + // A widget is 3D cross. // It consists of 3 orthagonally intersecting lines. - Widget(Orbit& orbit, GLuint shaderProgram); - void render(); + Widget(GLuint shaderProgram); + void render(const float time); + + void setModelMatrix(const glm::mat4 matrix); - void setPosition(glm::vec3 position); ~Widget(); private: - Orbit& _orbit; - glm::vec3 _position; - GLuint _vao; GLuint _vbo; GLuint _shaderProgram; - - void updateModelMatrix(); + glm::mat4 _modelMatrix; float _lineLength = 0.2; float _vertices[3*6] =