From da3a917896de6853683934d6ee4647ffaf413f1e Mon Sep 17 00:00:00 2001 From: Cat Flynn Date: Sat, 24 Aug 2024 13:18:08 +0100 Subject: [PATCH] feat: render nested orbits --- lib/skein/include/skein/particlemap.h | 1 + lib/skein/src/particlemap.cpp | 36 +++++++++++++++++---- src/main.cpp | 45 +++++++++++++++++---------- src/orbitvisualizer.cpp | 18 +++++++---- src/orbitvisualizer.hpp | 9 +++--- 5 files changed, 77 insertions(+), 32 deletions(-) diff --git a/lib/skein/include/skein/particlemap.h b/lib/skein/include/skein/particlemap.h index 17bb2ff..d25fab5 100644 --- a/lib/skein/include/skein/particlemap.h +++ b/lib/skein/include/skein/particlemap.h @@ -14,6 +14,7 @@ class ParticleMap // providing these as two methods keeps things unambiguous - manipulating particles // is just done for setup const Particle& getParticle(const std::string& id) const; + const Particle& getParent(const std::string& id) const; glm::dvec3 getParticlePosition(const std::string& id, double time) const; const Orbit& getOrbit(const std::string& id) const; diff --git a/lib/skein/src/particlemap.cpp b/lib/skein/src/particlemap.cpp index 55e12de..477b013 100644 --- a/lib/skein/src/particlemap.cpp +++ b/lib/skein/src/particlemap.cpp @@ -6,6 +6,12 @@ const Particle& ParticleMap::getParticle(const std::string& id) const return _particles.at(id); } +const Particle& ParticleMap::getParent(const std::string& childId) const +{ + const std::string parentId = _relationships.at(childId); + return _particles.at(parentId); +} + const Orbit& ParticleMap::getOrbit(const std::string& id) const { return _orbits.at(id); @@ -16,13 +22,31 @@ glm::dvec3 ParticleMap::getParticlePosition(const std::string& id, double time) if (_orbits.find(id) == _orbits.end()) return {0,0,0}; - const std::string& parentId = _relationships.at(id); - const Particle& parent = _particles.at(parentId); - const double gravitationalParameter = parent.getGravitationalParameter(); + const Particle* particle = &(_particles.at(id)); + glm::dvec3 pos(0,0,0); - // TODO: actually nest stuff so position is determined from all parents - const Orbit& orbit = _orbits.at(id); - return orbit.getPosition(gravitationalParameter, time); + do + { + const std::string& id = particle->getId(); + const std::string& parentId = _relationships.at(id); + const Particle& parent = _particles.at(parentId); + const double gravitationalParameter = parent.getGravitationalParameter(); + const Orbit& orbit = _orbits.at(id); + + pos += orbit.getPosition(gravitationalParameter, time); + + auto it = _relationships.find(parentId); + if (it != _relationships.end()) + { + particle = &parent; + } + else + { + particle = nullptr; + } + } while (particle != nullptr); + + return pos; } void ParticleMap::setParticle(const Particle& particle) diff --git a/src/main.cpp b/src/main.cpp index 0a89382..4307cad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,24 +66,35 @@ int main() GLuint unlitProgram = compileShaderProgram("./frag_unlit.glsl"); // set parameters of moon's orbit around earth - Orbit orbit; - double semiMajorAxis = 3.84748e8; - orbit.setSemiMajorAxis(semiMajorAxis); // metres - orbit.setEccentricity(0.055); - orbit.setInclination(glm::radians(5.15)); // radians - orbit.setArgumentOfPeriapsis(318.15); // in the case of the moon these last two values are - orbit.setLongitudeOfAscendingNode(60.0); // pretty much constantly changing so use whatever + Orbit moonOrbit; + double moonOrbitSemiMajorAxis = 3.84748e8; + moonOrbit.setSemiMajorAxis(moonOrbitSemiMajorAxis); // metres + moonOrbit.setEccentricity(0.055); + moonOrbit.setInclination(glm::radians(5.15)); // radians + moonOrbit.setArgumentOfPeriapsis(318.15); // in the case of the moon these last two values are + moonOrbit.setLongitudeOfAscendingNode(60.0); // pretty much constantly changing so use whatever + + // set parameters of satellite orbit around moon + Orbit stationOrbit; + stationOrbit.setSemiMajorAxis(5e7); + stationOrbit.setEccentricity(0.6); + stationOrbit.setInclination(glm::radians(89.0)); + stationOrbit.setArgumentOfPeriapsis(43.2); + stationOrbit.setLongitudeOfAscendingNode(239.7); - // TODO: add something in a nice eccentric orbit around the moon - // make the earth-moon system ParticleMap map; map.setParticle({"earth", 5.9e24}); map.setParticle({"moon", 7.3e22}); - map.setRelationship("earth", "moon", orbit); - float scale = semiMajorAxis * 1.1; - ParticleVisualizer earthVis(map, "earth", 0.2, litProgram, unlitProgram, scale); - ParticleVisualizer moonVis(map, "moon", 0.1, litProgram, unlitProgram, scale); - OrbitVisualizer orbitVis(orbit, unlitProgram, scale); + map.setParticle({"station", 1e6}); + map.setRelationship("earth", "moon", moonOrbit); + map.setRelationship("moon", "station", stationOrbit); + + float scale = moonOrbitSemiMajorAxis * 1.1; + ParticleVisualizer earthVis(map, "earth", 0.1, litProgram, unlitProgram, scale); + ParticleVisualizer moonVis(map, "moon", 0.02, litProgram, unlitProgram, scale); + ParticleVisualizer stationVis(map, "station", 0.01, litProgram, unlitProgram, scale); + OrbitVisualizer moonOrbitVis(map, "moon", unlitProgram, scale); + OrbitVisualizer stationOrbitVis(map, "station", unlitProgram, scale); // register input glfwSetKeyCallback(window, keyCallback); @@ -125,7 +136,7 @@ int main() else { double e = .25 + .2 * sin(getTime()); - orbit.setEccentricity(e); + moonOrbit.setEccentricity(e); } // rendering @@ -134,7 +145,9 @@ int main() earthVis.render(time); moonVis.render(time); - orbitVis.render(time); + stationVis.render(time); + moonOrbitVis.render(time); + stationOrbitVis.render(time); glfwSwapBuffers(window); } diff --git a/src/orbitvisualizer.cpp b/src/orbitvisualizer.cpp index 5f52a96..44a39b7 100644 --- a/src/orbitvisualizer.cpp +++ b/src/orbitvisualizer.cpp @@ -1,8 +1,8 @@ #include "orbitvisualizer.hpp" #include "gfx.hpp" -OrbitVisualizer::OrbitVisualizer(const Orbit& orbit, const GLuint shaderProgram, float scale) - : _orbit(orbit), _shaderProgram(shaderProgram), _scale(scale) +OrbitVisualizer::OrbitVisualizer(const ParticleMap& map, const std::string& particleId, const GLuint shaderProgram, float scale) + : _map(map), _particleId(particleId), _shaderProgram(shaderProgram), _scale(scale) { glGenVertexArrays(1, &_vao); glGenBuffers(1, &_vbo); @@ -10,7 +10,11 @@ OrbitVisualizer::OrbitVisualizer(const Orbit& orbit, const GLuint shaderProgram, void OrbitVisualizer::render(const float time) { - regenerateVertices(); + // Orbit needs to be drawn relative to its parent + const Particle& parent = _map.getParent(_particleId); + const glm::vec3 parentPos = _map.getParticlePosition(parent.getId(), time); + + regenerateVertices(parentPos); glUseProgram(_shaderProgram); updateModelViewProjectionMatrix(_shaderProgram, time); @@ -21,17 +25,19 @@ void OrbitVisualizer::render(const float time) glDrawArrays(GL_LINE_LOOP, 0, _vertices.size() / 3); } -void OrbitVisualizer::regenerateVertices() +void OrbitVisualizer::regenerateVertices(const glm::vec3& basePos) { - _vertices.clear(); + const Orbit& orbit = _map.getOrbit(_particleId); + _vertices.clear(); for (int i = 0; i < _vertexCount; i++) { // TODO: this method of getting ellipse vertices is a huge hack. it would be // better to actually create a first-class ellipse object and use that to generate // a nice continuous mesh, instead of using orbital positions. float t = (float)i / (float)_vertexCount * 2.0 * _pi; - glm::vec3 pos = _orbit.getPositionFromMeanAnomaly(t); + glm::vec3 pos = orbit.getPositionFromMeanAnomaly(t); + pos += basePos; // Vertices come out of the library with X and Y being in the 'flat' plane. Re-order them // here such that Z is up. diff --git a/src/orbitvisualizer.hpp b/src/orbitvisualizer.hpp index db9be6a..9b9783a 100644 --- a/src/orbitvisualizer.hpp +++ b/src/orbitvisualizer.hpp @@ -2,12 +2,12 @@ #include #include -#include +#include class OrbitVisualizer { public: - OrbitVisualizer(const Orbit& orbit, const GLuint shaderProgram, float scale); + OrbitVisualizer(const ParticleMap& map, const std::string& particleId, const GLuint shaderProgram, float scale); ~OrbitVisualizer(); void render(const float time); @@ -17,12 +17,13 @@ class OrbitVisualizer const int _vertexCount = 100; const GLuint _shaderProgram; - const Orbit& _orbit; + const ParticleMap& _map; + const std::string _particleId; const float _scale; GLuint _vbo; GLuint _vao; std::vector _vertices; - void regenerateVertices(); + void regenerateVertices(const glm::vec3& basePos); };