From cacc0641e5174d8b46e7a7086be6a45c87ab3642 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Sun, 12 Nov 2017 18:55:22 +0100 Subject: [PATCH] (slightly) better camera handling --- src/app/MasterState.hpp | 4 +- src/app/states.cpp | 36 +++++++-------- src/blobs.cpp | 31 +++++++++---- src/graphics/Camera.hpp | 31 ++++++++++--- src/graphics/viewport.cpp | 96 +++++++++++++++++++++++++++++++++++---- src/world/Simulation.hpp | 18 ++++++-- src/world/sim.cpp | 20 ++++++-- src/world/world.cpp | 3 ++ 8 files changed, 188 insertions(+), 51 deletions(-) diff --git a/src/app/MasterState.hpp b/src/app/MasterState.hpp index f62c773..d2072ee 100644 --- a/src/app/MasterState.hpp +++ b/src/app/MasterState.hpp @@ -28,7 +28,8 @@ public: MasterState &operator =(MasterState &&) = delete; public: - void SetReference(world::Body &r) { reference = &r; } + graphics::Camera &GetCamera() noexcept { return cam; } + const graphics::Camera &GetCamera() const noexcept { return cam; } private: void OnResize(int w, int h) override; @@ -44,7 +45,6 @@ private: private: Assets &assets; world::Simulation ∼ - world::Body *reference; graphics::Camera cam; diff --git a/src/app/states.cpp b/src/app/states.cpp index 67c073a..b9fc57a 100644 --- a/src/app/states.cpp +++ b/src/app/states.cpp @@ -1,7 +1,9 @@ #include "MasterState.hpp" #include "../world/Body.hpp" +#include "../world/Planet.hpp" #include "../world/Simulation.hpp" +#include "../world/Sun.hpp" #include @@ -13,17 +15,10 @@ MasterState::MasterState(Assets &assets, world::Simulation &sim) noexcept : State() , assets(assets) , sim(sim) -, reference(&sim.Root()) -, cam() +, cam(sim.Root()) , remain(0) , thirds(0) , paused(false) { - // sunset view: standing in the center of surface 0 (+Z), looking west (-X) - //cam.View(glm::lookAt(glm::vec3(0.0f, 0.0f, 5.6f), glm::vec3(-1.0f, 0.0f, 5.6f), glm::vec3(0.0f, 0.0f, 1.0f))); - // sunrise view: standing in the center of surface 0 (+Z), looking east (+X) - cam.View(glm::lookAt(glm::vec3(0.0f, 0.0f, 5.6f), glm::vec3(1.0f, 0.0f, 5.6f), glm::vec3(0.0f, 0.0f, 1.0f))); - // far out, looking at planet - //cam.View(glm::lookAt(glm::vec3(10.0f, 10.0f, 50.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f))); } MasterState::~MasterState() noexcept { @@ -61,22 +56,25 @@ void MasterState::OnKeyDown(const SDL_KeyboardEvent &e) { } void MasterState::OnRender(graphics::Viewport &viewport) { - glm::dmat4 ppos = reference->InverseTransform() * reference->ToParent(); + glm::dmat4 ppos = cam.Model(**sim.Suns().begin()); assets.shaders.planet_surface.Activate(); assets.shaders.planet_surface.SetTexture(assets.textures.tiles); + assets.shaders.planet_surface.SetLight(glm::vec3(cam.View() * ppos[3]), glm::vec3(1.0f, 1.0f, 1.0f), 1.0e6f); - assets.shaders.planet_surface.SetMVP(glm::mat4(1.0f), cam.View(), cam.Projection()); - assets.shaders.planet_surface.SetLight(glm::vec3(cam.View() * ppos[3]), glm::vec3(1.0f, 1.0f, 1.0f), 2.0e4f); - reference->Draw(assets, viewport); - - world::Body *child = reference->Children()[0]; - assets.shaders.planet_surface.SetMVP(reference->InverseTransform() * child->FromParent() * child->LocalTransform(), cam.View(), cam.Projection()); - child->Draw(assets, viewport); + for (auto planet : sim.Planets()) { + assets.shaders.planet_surface.SetMVP(cam.Model(*planet), cam.View(), cam.Projection()); + planet->Draw(assets, viewport); + } assets.shaders.sun_surface.Activate(); - assets.shaders.sun_surface.SetMVP(ppos * reference->Parent().LocalTransform(), cam.View(), cam.Projection()); - assets.shaders.sun_surface.SetLight(glm::vec3(1.0f, 1.0f, 1.0f), 2.0e4f); - assets.shaders.sun_surface.Draw(); + for (auto sun : sim.Suns()) { + double sun_radius = sun->Radius(); + assets.shaders.sun_surface.SetMVP( + cam.Model(*sun) * glm::scale(glm::vec3(sun_radius, sun_radius, sun_radius)), + cam.View(), cam.Projection()); + assets.shaders.sun_surface.SetLight(glm::vec3(1.0f, 1.0f, 1.0f), 1.0e6f); + assets.shaders.sun_surface.Draw(); + } } } diff --git a/src/blobs.cpp b/src/blobs.cpp index c302159..464273b 100644 --- a/src/blobs.cpp +++ b/src/blobs.cpp @@ -14,12 +14,12 @@ using namespace blobs; int main(int argc, char *argv[]) { - app::Init init; + app::Init init(true, 8); app::Assets assets; world::Sun sun; sun.Mass(1.0e12); - sun.Radius(1.0); + sun.Radius(10.0); sun.SurfaceTilt(glm::dvec2(PI * 0.25, PI * 0.25)); sun.AngularMomentum(1.0e9); @@ -27,28 +27,43 @@ int main(int argc, char *argv[]) { world::GenerateTest(planet); planet.SetParent(sun); planet.Mass(1.0e9); - planet.GetOrbit().SemiMajorAxis(100.0); + planet.GetOrbit().SemiMajorAxis(941.7); planet.SurfaceTilt(glm::dvec2(PI * 0.25, PI * 0.25)); planet.AxialTilt(glm::dvec2(PI * 0.127, 0.0)); - planet.AngularMomentum(3.0e9); + planet.AngularMomentum(1.25e9); world::Planet moon(3); world::GenerateTest(moon); moon.SetParent(planet); moon.Mass(1.0e6); moon.GetOrbit().SemiMajorAxis(25.0); - moon.AngularMomentum(1.0e5); + moon.Rotation(PI * 0.25); + moon.AngularMomentum(1.0e4); world::Simulation sim(sun); - sim.AddBody(planet); - sim.AddBody(moon); + sim.AddSun(sun); + sim.AddPlanet(planet); + sim.AddPlanet(moon); std::cout << "length of year: " << planet.OrbitalPeriod() << "s" << std::endl; std::cout << "length of moon cycle: " << moon.OrbitalPeriod() << "s" << std::endl; std::cout << "length of day: " << planet.RotationalPeriod() << "s" << std::endl; + std::cout << "days per year: " << (planet.OrbitalPeriod() / planet.RotationalPeriod()) << std::endl; + std::cout << "moon cycle in days: " << (moon.OrbitalPeriod() / planet.RotationalPeriod()) << std::endl; + std::cout << "moon cycles per year: " << (planet.OrbitalPeriod() / moon.OrbitalPeriod()) << std::endl; app::MasterState state(assets, sim); - state.SetReference(planet); + state.GetCamera() + .Reference(planet) + // sunrise + .FirstPerson(0, glm::vec3(0.0f, 0.0f, 0.1f), glm::vec3(1.0f, -0.75f, 0.1f)) + // sunset + //.FirstPerson(3, glm::vec3(0.0f, 0.0f, 0.1f), glm::vec3(1.0f, -0.75f, 0.1f)) + // from afar + //.MapView(0, glm::vec3(0.0f, 0.0f, 25.0f), 0.0f) + // system view + //.Orbital(glm::vec3(50.0f, 2500.0f, 50.0f)); + ; planet.BuildVAOs(); app::Application app(init.window, init.viewport); diff --git a/src/graphics/Camera.hpp b/src/graphics/Camera.hpp index 7cc141e..f4a98d5 100644 --- a/src/graphics/Camera.hpp +++ b/src/graphics/Camera.hpp @@ -5,12 +5,15 @@ namespace blobs { +namespace world { + class Body; +} namespace graphics { class Camera { public: - Camera() noexcept; + explicit Camera(const world::Body &) noexcept; ~Camera() noexcept; Camera(const Camera &) = delete; @@ -20,14 +23,25 @@ public: Camera &operator =(Camera &&) = delete; public: - void FOV(float f) noexcept; - void Aspect(float r) noexcept; - void Aspect(float w, float h) noexcept; - void Clip(float near, float far) noexcept; + Camera &FOV(float f) noexcept; + Camera &Aspect(float r) noexcept; + Camera &Aspect(float w, float h) noexcept; + Camera &Clip(float near, float far) noexcept; + + const world::Body &Reference() const noexcept { return *ref; } + Camera &Reference(const world::Body &) noexcept; + + /// standing on given surface, with pos.z being elevation over NN + /// looking at given coordinates + Camera &FirstPerson(int surface, const glm::vec3 &pos, const glm::vec3 &at) noexcept; + /// looking straight down at surface from above + Camera &MapView(int surface, const glm::vec3 &pos, float roll = 0.0f) noexcept; + /// look at center, position relative to orbital reference plane for children + Camera &Orbital(const glm::vec3 &pos) noexcept; const glm::mat4 &Projection() const noexcept { return projection; } const glm::mat4 &View() const noexcept { return view; } - void View(const glm::mat4 &v) noexcept; + glm::mat4 Model(const world::Body &) const noexcept; private: void UpdateProjection() noexcept; @@ -41,6 +55,11 @@ private: glm::mat4 projection; glm::mat4 view; + // reference frame + const world::Body *ref; + // track reference body's orientation + bool track_orient; + }; } diff --git a/src/graphics/viewport.cpp b/src/graphics/viewport.cpp index cb8d786..2d9b469 100644 --- a/src/graphics/viewport.cpp +++ b/src/graphics/viewport.cpp @@ -2,7 +2,9 @@ #include "Viewport.hpp" #include "../const.hpp" +#include "../world/Body.hpp" +#include #include #include @@ -10,41 +12,117 @@ namespace blobs { namespace graphics { -Camera::Camera() noexcept +Camera::Camera(const world::Body &r) noexcept : fov(PI_0p25) , aspect(1.0f) , near(0.1f) -, far(256.0f) +, far(12560.0f) , projection(glm::perspective(fov, aspect, near, far)) -, view(1.0f) { +, view(1.0f) +, ref(&r) +, track_orient(false) { } Camera::~Camera() noexcept { } -void Camera::FOV(float f) noexcept { +Camera &Camera::FOV(float f) noexcept { fov = f; UpdateProjection(); + return *this; } -void Camera::Aspect(float r) noexcept { +Camera &Camera::Aspect(float r) noexcept { aspect = r; UpdateProjection(); + return *this; } -void Camera::Aspect(float w, float h) noexcept { +Camera &Camera::Aspect(float w, float h) noexcept { Aspect(w / h); + return *this; } -void Camera::Clip(float n, float f) noexcept { +Camera &Camera::Clip(float n, float f) noexcept { near = n; far = f; UpdateProjection(); + return *this; } -void Camera::View(const glm::mat4 &v) noexcept { - view = v; +Camera &Camera::Reference(const world::Body &r) noexcept { + ref = &r; + return *this; +} + +Camera &Camera::FirstPerson(int srf, const glm::vec3 &pos, const glm::vec3 &at) noexcept { + track_orient = true; + + float dir = srf < 3 ? 1.0f : -1.0f; + + glm::vec3 position; + position[(srf + 0) % 3] = pos.x; + position[(srf + 1) % 3] = pos.y; + position[(srf + 2) % 3] = dir * (pos.z + Reference().Radius()); + + glm::vec3 up(0.0f); + up[(srf + 2) % 3] = dir; + + glm::vec3 target; + target[(srf + 0) % 3] = at.x; + target[(srf + 1) % 3] = at.y; + target[(srf + 2) % 3] = dir * (at.z + Reference().Radius()); + + view = glm::lookAt(position, target, up); + + return *this; +} + +Camera &Camera::MapView(int srf, const glm::vec3 &pos, float roll) noexcept { + track_orient = true; + + float dir = srf < 3 ? 1.0f : -1.0f; + + glm::vec3 position; + position[(srf + 0) % 3] = pos.x; + position[(srf + 1) % 3] = pos.y; + position[(srf + 2) % 3] = dir * (pos.z + Reference().Radius()); + + glm::vec3 up(0.0f); + up[(srf + 0) % 3] = std::cos(roll); + up[(srf + 1) % 3] = std::sin(roll); + up[(srf + 2) % 3] = 0.0f; + + glm::vec3 target = position; + target[(srf + 2) % 3] -= dir; + + view = glm::lookAt(position, target, up); + + return *this; +} + +Camera &Camera::Orbital(const glm::vec3 &pos) noexcept { + track_orient = false; + view = glm::lookAt(pos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); + return *this; +} + +glm::mat4 Camera::Model(const world::Body &b) const noexcept { + if (&b == ref) { + return track_orient ? glm::mat4(1.0f) : glm::mat4(ref->LocalTransform()); + } else if (b.HasParent() && &b.Parent() == ref) { + return track_orient + ? ref->InverseTransform() * b.FromParent() * b.LocalTransform() + : b.FromParent() * b.LocalTransform(); + } else if (ref->HasParent() && &ref->Parent() == &b) { + return track_orient + ? ref->InverseTransform() * ref->ToParent() * b.LocalTransform() + : ref->ToParent() * b.LocalTransform(); + } else { + // TODO: model matrices for path distances > 1 + return track_orient ? glm::mat4(1.0f) : glm::mat4(ref->LocalTransform()); + } } void Camera::UpdateProjection() noexcept { diff --git a/src/world/Simulation.hpp b/src/world/Simulation.hpp index 3025a74..ea81de5 100644 --- a/src/world/Simulation.hpp +++ b/src/world/Simulation.hpp @@ -1,13 +1,15 @@ #ifndef BLOBS_WORLD_SIMULATION_HPP_ #define BLOBS_WORLD_SIMULATION_HPP_ -#include +#include namespace blobs { namespace world { class Body; +class Planet; +class Sun; class Simulation { @@ -25,15 +27,23 @@ public: void Tick(); void AddBody(Body &); + void AddPlanet(Planet &); + void AddSun(Sun &); - Body &Root() { return root; } - const Body &Root() const { return root; } + Body &Root() noexcept { return root; } + const Body &Root() const noexcept { return root; } + + const std::set &Bodies() const noexcept { return bodies; } + const std::set &Planets() const noexcept { return planets; } + const std::set &Suns() const noexcept { return suns; } double Time() const noexcept { return time; } private: Body &root; - std::vector all_bodies; + std::set bodies; + std::set planets; + std::set suns; double time; }; diff --git a/src/world/sim.cpp b/src/world/sim.cpp index 46454fd..185046d 100644 --- a/src/world/sim.cpp +++ b/src/world/sim.cpp @@ -1,6 +1,8 @@ #include "Simulation.hpp" #include "Body.hpp" +#include "Planet.hpp" +#include "Sun.hpp" namespace blobs { @@ -8,7 +10,9 @@ namespace world { Simulation::Simulation(Body &r) : root(r) -, all_bodies() +, bodies() +, planets() +, suns() , time(0.0) { AddBody(r); } @@ -19,13 +23,23 @@ Simulation::~Simulation() { void Simulation::AddBody(Body &b) { b.SetSimulation(*this); - all_bodies.push_back(&b); + bodies.insert(&b); +} + +void Simulation::AddPlanet(Planet &p) { + AddBody(p); + planets.insert(&p); +} + +void Simulation::AddSun(Sun &s) { + AddBody(s); + suns.insert(&s); } void Simulation::Tick() { constexpr double dt = 0.01666666666666666666666666666666; time += dt; - for (auto body : all_bodies) { + for (auto body : bodies) { body->Rotation(body->Rotation() + dt * body->AngularMomentum() / body->Inertia()); } } diff --git a/src/world/world.cpp b/src/world/world.cpp index 0b1b22d..eb03490 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -254,6 +254,9 @@ void Planet::BuildVAOs() { auto attrib = vao.MapAttributes(GL_WRITE_ONLY); float offset = sidelength * 0.5f; + // srf 0 1 2 3 4 5 + // up +Z +X +Y -Z -X -Y + for (int index = 0, surface = 0; surface < 6; ++surface) { for (int y = 0; y < sidelength; ++y) { for (int x = 0; x < sidelength; ++x, ++index) { -- 2.39.2