, cam()
, remain(0)
, thirds(0) {
- cam.View(glm::translate(glm::vec3(-3.0f, -2.0f, -10.0f)));
+ cam.View(glm::lookAt(glm::vec3(2.0f, 3.0f, 10.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)));
}
MasterState::~MasterState() noexcept {
void MasterState::OnRender(graphics::Viewport &viewport) {
+ glm::mat4 ppos = reference->ToParent();
assets.shaders.planet_surface.Activate();
assets.shaders.planet_surface.SetMVP(glm::mat4(1.0f), cam.View(), cam.Projection());
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), 100.0f);
reference->Draw(assets, viewport);
}
+#include "const.hpp"
#include "app/Application.hpp"
#include "app/Assets.hpp"
#include "app/init.hpp"
app::Assets assets;
world::Sun sun;
+ sun.Mass(1.0e13);
world::Simulation sim(sun);
world::Planet planet(3);
+ planet.Mass(1.0e7);
+ planet.Inclination(PI * 0.25);
world::GenerateTest(planet);
planet.SetParent(sun);
+ planet.SemiMajorAxis(10.0);
app::MasterState state(assets, sim);
state.SetReference(planet);
--- /dev/null
+#ifndef BLOBS_CONST_HPP_
+#define BLOBS_CONST_HPP_
+
+
+namespace blobs {
+
+constexpr double PI = 3.141592653589793238462643383279502884;
+constexpr double PI_0p25 = PI * 0.25;
+constexpr double PI_0p5 = PI * 0.5;
+constexpr double PI_1p5 = PI * 1.5;
+constexpr double PI_2p0 = PI * 2.0;
+
+constexpr double PI_inv = 1.0 / PI;
+constexpr double PI_0p5_inv = 1.0 / PI_0p5;
+
+constexpr double G = 6.674e-11; // m³kg¯¹s¯²
+
+}
+
+#endif
#include "Program.hpp"
+#include "glm.hpp"
+
namespace blobs {
namespace graphics {
void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetNormal(const glm::vec3 &) noexcept;
void SetTexture(ArrayTexture &) noexcept;
+ void SetLight(const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept;
+
+ const glm::mat4 &M() const noexcept { return m; }
+ const glm::mat4 &V() const noexcept { return v; }
+ const glm::mat4 &P() const noexcept { return p; }
+ const glm::mat4 &MV() const noexcept { return mv; }
+ const glm::mat4 &MVP() const noexcept { return mvp; }
private:
Program prog;
+ glm::mat4 m;
+ glm::mat4 v;
+ glm::mat4 p;
+ glm::mat4 mv;
+ glm::mat4 mvp;
+
GLuint m_handle;
GLuint mv_handle;
GLuint mvp_handle;
GLuint sampler_handle;
GLuint normal_handle;
+ GLuint light_position_handle;
+ GLuint light_color_handle;
+ GLuint light_strength_handle;
+
};
}
+++ /dev/null
-#ifndef BLOBS_GRAPHICS_CONST_HPP_
-#define BLOBS_GRAPHICS_CONST_HPP_
-
-
-namespace blobs {
-namespace graphics {
-
-constexpr double PI = 3.141592653589793238462643383279502884;
-constexpr double PI_0p25 = PI * 0.25;
-constexpr double PI_0p5 = PI * 0.5;
-constexpr double PI_1p5 = PI * 1.5;
-constexpr double PI_2p0 = PI * 2.0;
-
-constexpr double PI_inv = 1.0 / PI;
-constexpr double PI_0p5_inv = 1.0 / PI_0p5;
-
-}
-}
-
-#endif
GL_FRAGMENT_SHADER,
"#version 330 core\n"
+ "struct LightSource {\n"
+ "vec3 position;\n"
+ "vec3 color;\n"
+ "float strength;\n"
+ "};\n"
+
"in vec3 vtx_viewspace;\n"
"in vec3 frag_tex_uv;\n"
"uniform sampler2DArray tex_sampler;\n"
"uniform vec3 normal;\n"
+ "uniform LightSource light;\n"
"out vec3 color;\n"
"void main() {\n"
"vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
- // TODO: lighting
- "color = tex_color;\n"
+ "vec3 to_light = light.position - vtx_viewspace;\n"
+ "float distance = length(to_light);\n"
+ "vec3 light_dir = normalize(to_light);\n"
+ "float attenuation = light.strength / (distance * distance);\n"
+ "vec3 ambient = tex_color * vec3(0.01, 0.01, 0.01);\n"
+ "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light.color * tex_color;\n"
+ "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
+ "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
+ "if (dot(normal, light_dir) >= 0.0) {\n"
+ "attenuation * light.color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
+ "}\n"
+ "color = ambient + diffuse + specular;\n"
"}\n"
);
prog.Link();
mvp_handle = prog.UniformLocation("MVP");
sampler_handle = prog.UniformLocation("tex_sampler");
normal_handle = prog.UniformLocation("normal");
+ light_position_handle = prog.UniformLocation("light.position");
+ light_color_handle = prog.UniformLocation("light.color");
+ light_strength_handle = prog.UniformLocation("light.strength");
}
PlanetSurface::~PlanetSurface() {
prog.Use();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
- glDisable(GL_CULL_FACE);
+ glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
}
-void PlanetSurface::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept {
+void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ m = mm;
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
prog.Uniform(m_handle, m);
- glm::mat4 mv(v * m);
prog.Uniform(mv_handle, mv);
- prog.Uniform(mvp_handle, p * mv);
+ prog.Uniform(mvp_handle, mvp);
}
void PlanetSurface::SetNormal(const glm::vec3 &n) noexcept {
prog.Uniform(sampler_handle, GLint(0));
}
+void PlanetSurface::SetLight(const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
+ prog.Uniform(light_position_handle, pos);
+ prog.Uniform(light_color_handle, color);
+ prog.Uniform(light_strength_handle, strength);
+}
+
}
}
#include "Camera.hpp"
#include "Viewport.hpp"
-#include "const.hpp"
+#include "../const.hpp"
#include <GL/glew.h>
#include <glm/gtx/transform.hpp>
#ifndef BLOBS_WORLD_BODY_HPP_
#define BLOBS_WORLD_BODY_HPP_
+#include "../graphics/glm.hpp"
+
#include <vector>
}
namespace world {
+class Simulation;
+
class Body {
public:
Body &operator =(Body &&) = delete;
public:
+ bool HasSimulation() const noexcept { return sim; }
+ const Simulation &GetSimulation() const noexcept { return *sim; }
+ void SetSimulation(Simulation &) noexcept;
+
bool HasParent() const { return parent; }
Body &Parent() { return *parent; }
const Body &Parent() const { return *parent; }
void SetParent(Body &);
void UnsetParent();
+ double Mass() const noexcept;
+ void Mass(double) noexcept;
+
+ double Radius() const noexcept;
+ void Radius(double) noexcept;
+
+ double SemiMajorAxis() const noexcept;
+ void SemiMajorAxis(double) noexcept;
+
+ double Eccentricity() const noexcept;
+ void Eccentricity(double) noexcept;
+
+ double Inclination() const noexcept;
+ void Inclination(double) noexcept;
+
+ double LongitudeAscending() const noexcept;
+ void LongitudeAscending(double) noexcept;
+
+ double ArgumentPeriapsis() const noexcept;
+ void ArgumentPeriapsis(double) noexcept;
+
+ double MeanAnomaly() const noexcept;
+ void MeanAnomaly(double) noexcept;
+
+ double GravitationalParameter() const noexcept;
+ double OrbitalPeriod() const noexcept;
+
+ glm::mat4 ToParent() const noexcept;
+ glm::mat4 FromParent() const noexcept;
+
virtual void Draw(app::Assets &, graphics::Viewport &) { }
private:
void RemoveChild(Body &);
private:
+ Simulation *sim;
Body *parent;
std::vector<Body *> children;
double mass;
double radius;
+ // Orbit
+ double sma; // semi-major axis
+ double ecc; // eccentricity
+ double inc; // inclination
+ double asc; // longitude of ascending node
+ double arg; // argument of periapsis
+ double mna; // mean anomaly (at t=0)
+
};
}
Body &Root() { return root; }
const Body &Root() const { return root; }
+ double Time() const noexcept { return time; }
+
private:
Body &root;
+ double time;
};
#include "Simulation.hpp"
+#include "Body.hpp"
+
namespace blobs {
namespace world {
Simulation::Simulation(Body &r)
: root(r) {
+ r.SetSimulation(*this);
}
Simulation::~Simulation() {
void Simulation::Tick() {
+ time += 0.01666666666666666666666666666666;
}
}
#include "Body.hpp"
#include "Planet.hpp"
+#include "Simulation.hpp"
#include "Sun.hpp"
#include "Tile.hpp"
+#include "../const.hpp"
#include "../app/Assets.hpp"
#include "../graphics/Viewport.hpp"
#include <algorithm>
+#include <cmath>
+#include <glm/gtx/transform.hpp>
+
+using blobs::G;
+using blobs::PI_2p0;
+
+using std::sin;
+using std::cos;
+using std::pow;
+using std::sqrt;
namespace blobs {
namespace world {
Body::Body()
-: parent(nullptr)
+: sim(nullptr)
+, parent(nullptr)
, children()
, mass(1.0)
-, radius(1.0) {
+, radius(1.0)
+, sma(1.0)
+, ecc(0.0)
+, inc(0.0)
+, asc(0.0)
+, arg(0.0)
+, mna(0.0) {
}
Body::~Body() {
}
+void Body::SetSimulation(Simulation &s) noexcept {
+ sim = &s;
+ for (auto child : children) {
+ child->SetSimulation(s);
+ }
+}
+
void Body::SetParent(Body &p) {
if (HasParent()) {
UnsetParent();
void Body::AddChild(Body &c) {
children.push_back(&c);
+ c.SetSimulation(*sim);
}
void Body::RemoveChild(Body &c) {
}
}
+double Body::Mass() const noexcept {
+ return mass;
+}
+
+void Body::Mass(double m) noexcept {
+ mass = m;
+}
+
+double Body::Radius() const noexcept {
+ return radius;
+}
+
+void Body::Radius(double r) noexcept {
+ radius = r;
+}
+
+double Body::SemiMajorAxis() const noexcept {
+ return sma;
+}
+
+void Body::SemiMajorAxis(double s) noexcept {
+ sma = s;
+}
+
+double Body::Eccentricity() const noexcept {
+ return ecc;
+}
+
+void Body::Eccentricity(double e) noexcept {
+ ecc = e;
+}
+
+double Body::Inclination() const noexcept {
+ return inc;
+}
+
+void Body::Inclination(double i) noexcept {
+ inc = i;
+}
+
+double Body::LongitudeAscending() const noexcept {
+ return asc;
+}
+
+void Body::LongitudeAscending(double l) noexcept {
+ asc = l;
+}
+
+double Body::ArgumentPeriapsis() const noexcept {
+ return arg;
+}
+
+void Body::ArgumentPeriapsis(double a) noexcept {
+ arg = a;
+}
+
+double Body::MeanAnomaly() const noexcept {
+ return mna;
+}
+
+void Body::MeanAnomaly(double m) noexcept {
+ mna = m;
+}
+
+double Body::GravitationalParameter() const noexcept {
+ return G * Mass();
+}
+
+double Body::OrbitalPeriod() const noexcept {
+ if (parent) {
+ return PI_2p0 * sqrt((sma * sma * sma) / (G * (parent->Mass() + Mass())));
+ } else {
+ return 0.0;
+ }
+}
+
+glm::mat4 Body::ToParent() const noexcept {
+ if (!parent) {
+ return glm::mat4(1.0f);
+ }
+
+ double T = OrbitalPeriod();
+
+ double M = mna + PI_2p0 * (GetSimulation().Time() / T); // + time
+
+ double E = M; // eccentric anomaly, solve M = E - e sin E
+ while (true) {
+ double dE = (E - ecc * sin(E) - M) / (1 - ecc * cos(E));
+ E -= dE;
+ if (abs(dE) < 1.0e-6) break;
+ }
+
+ // coordinates in orbital plane
+ double P = sma * (cos(E) - ecc);
+ double Q = sma * sin(E) * sqrt(1 - (ecc * ecc));
+
+ // tile by argument of periapsis, …
+ double x = cos(arg) * P - sin(arg) * Q;
+ double y = sin(arg) * P + cos(arg) * Q;
+ // …inclination, …
+ double z = sin(inc) * x;
+ x = cos(inc) * x;
+ // …and longitude of ascending node
+ glm::vec3 pos(
+ cos(asc) * x - sin(asc) * y,
+ sin(asc) * x + cos(asc) * y,
+ z);
+
+ // TODO: calculate complete matrix
+ return glm::translate(-pos);
+}
+
+glm::mat4 Body::FromParent() const noexcept {
+ if (!parent) {
+ return glm::mat4(1.0f);
+ }
+ // TODO: calculate real position
+ return glm::translate(glm::vec3(-sma, 0.0f, 0.0f));
+}
+
Planet::Planet(int sidelength)
: Body()
vao.ReserveElements(TilesTotal() * 6, GL_STATIC_DRAW);
{
auto element = vao.MapElements(GL_WRITE_ONLY);
- for (int index = 0, surface = 0; surface < 6; ++surface) {
+ int index = 0;
+ for (int surface = 0; surface < 3; ++surface) {
+ for (int y = 0; y < sidelength; ++y) {
+ for (int x = 0; x < sidelength; ++x, ++index) {
+ element[6 * index + 0] = 4 * index + 0;
+ element[6 * index + 1] = 4 * index + 2;
+ element[6 * index + 2] = 4 * index + 1;
+ element[6 * index + 3] = 4 * index + 1;
+ element[6 * index + 4] = 4 * index + 2;
+ element[6 * index + 5] = 4 * index + 3;
+ }
+ }
+ }
+ for (int surface = 3; surface < 6; ++surface) {
for (int y = 0; y < sidelength; ++y) {
for (int x = 0; x < sidelength; ++x, ++index) {
element[6 * index + 0] = 4 * index + 0;
void Planet::Draw(app::Assets &assets, graphics::Viewport &viewport) {
vao.Bind();
- // TODO: premultiply normal with model matrix (i.e. just take it from M)
- assets.shaders.planet_surface.SetNormal(glm::vec3(0.0f, 0.0f, 1.0f));
- vao.DrawTriangles(TilesTotal() * 4, TilesTotal() * 4 * 0);
- assets.shaders.planet_surface.SetNormal(glm::vec3(1.0f, 0.0f, 0.0f));
- vao.DrawTriangles(TilesTotal() * 4, TilesTotal() * 4 * 1);
- assets.shaders.planet_surface.SetNormal(glm::vec3(0.0f, 1.0f, 0.0f));
- vao.DrawTriangles(TilesTotal() * 4, TilesTotal() * 4 * 2);
- assets.shaders.planet_surface.SetNormal(glm::vec3(0.0f, 0.0f, -1.0f));
- vao.DrawTriangles(TilesTotal() * 4, TilesTotal() * 4 * 3);
- assets.shaders.planet_surface.SetNormal(glm::vec3(-1.0f, 0.0f, 0.0f));
- vao.DrawTriangles(TilesTotal() * 4, TilesTotal() * 4 * 4);
- assets.shaders.planet_surface.SetNormal(glm::vec3(0.0f, -1.0f, 0.0f));
- vao.DrawTriangles(TilesTotal() * 4, TilesTotal() * 4 * 5);
+ const glm::mat4 &MV = assets.shaders.planet_surface.MV();
+ assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)));
+ vao.DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 0);
+ assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)));
+ vao.DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 1);
+ assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)));
+ vao.DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 2);
+ assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)));
+ vao.DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 3);
+ assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(-1.0f, 0.0f, 0.0f, 0.0f)));
+ vao.DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 4);
+ assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, -1.0f, 0.0f, 0.0f)));
+ vao.DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 5);
}