From: Daniel Karbach Date: Tue, 28 Nov 2017 20:39:09 +0000 (+0100) Subject: creature skin overhaul X-Git-Url: http://git.localhorst.tv/?p=blobs.git;a=commitdiff_plain;h=2ab70a92ae39cebc6166ef15545ebcbd31a31c38 creature skin overhaul --- diff --git a/assets b/assets index 51cf5cf..3c715b3 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 51cf5cf9b1bda806e44dd77fb31041f90d06ce2b +Subproject commit 3c715b39e3aece21fc1f0fd6042611e79bfbeb44 diff --git a/src/app/app.cpp b/src/app/app.cpp index f2d0e59..a732ca6 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -216,15 +216,12 @@ Assets::Assets() textures.skins.Bind(); textures.skins.Reserve(256, 256, 9, format); - LoadSkinTexture("1", textures.skins, 0); - LoadSkinTexture("2", textures.skins, 1); - LoadSkinTexture("3", textures.skins, 2); - LoadSkinTexture("4", textures.skins, 3); - LoadSkinTexture("5", textures.skins, 4); - LoadSkinTexture("6", textures.skins, 5); - LoadSkinTexture("7", textures.skins, 6); - LoadSkinTexture("8", textures.skins, 7); - LoadSkinTexture("9", textures.skins, 8); + LoadSkinTexture("plain", textures.skins, 0); + LoadSkinTexture("stripes", textures.skins, 1); + LoadSkinTexture("dots", textures.skins, 2); + LoadSkinTexture("lines", textures.skins, 3); + LoadSkinTexture("spots", textures.skins, 4); + LoadSkinTexture("circles", textures.skins, 5); textures.skins.FilterTrilinear(); } diff --git a/src/app/states.cpp b/src/app/states.cpp index d1e092e..b1a20db 100644 --- a/src/app/states.cpp +++ b/src/app/states.cpp @@ -135,6 +135,8 @@ void MasterState::OnRender(graphics::Viewport &viewport) { // TODO: extend to nearby bodies as well for (auto c : cam.Reference().Creatures()) { assets.shaders.creature_skin.SetM(cam.Model(cam.Reference()) * glm::mat4(c->LocalTransform())); + assets.shaders.creature_skin.SetBaseColor(c->BaseColor()); + assets.shaders.creature_skin.SetHighlightColor(c->HighlightColor()); c->Draw(viewport); } diff --git a/src/creature/Creature.hpp b/src/creature/Creature.hpp index f443e48..f36a2db 100644 --- a/src/creature/Creature.hpp +++ b/src/creature/Creature.hpp @@ -57,6 +57,15 @@ public: Genome::Properties &GetProperties() noexcept { return properties; } const Genome::Properties &GetProperties() const noexcept { return properties; } + const Genome::PropertySet &CurProps() const noexcept { return properties.props[cur_prop]; } + const Genome::PropertySet &NextProps() const noexcept { return properties.props[cur_prop + 1]; } + + void BaseColor(const glm::dvec3 &c) noexcept { base_color = c; } + const glm::dvec3 &BaseColor() const noexcept { return base_color; } + + void HighlightColor(const glm::dvec3 &c) noexcept { highlight_color = c; } + glm::dvec4 HighlightColor() const noexcept; + void Mass(double m) noexcept { mass = m; size = std::cbrt(mass / density); } double Mass() const noexcept { return mass; } void Grow(double amount) noexcept; @@ -66,6 +75,7 @@ public: double Size() const noexcept; double Age() const noexcept; + double AgeLerp(double from, double to) const noexcept; // change of giving birth per tick double Fertility() const noexcept; @@ -110,6 +120,9 @@ private: Genome::Properties properties; int cur_prop; + glm::dvec3 base_color; + glm::dvec3 highlight_color; + double mass; double density; double size; diff --git a/src/creature/Genome.hpp b/src/creature/Genome.hpp index a7be0e1..b14efc1 100644 --- a/src/creature/Genome.hpp +++ b/src/creature/Genome.hpp @@ -3,6 +3,7 @@ #include "../math/Distribution.hpp" #include "../math/GaloisLFSR.hpp" +#include "../math/glm.hpp" #include @@ -22,6 +23,7 @@ struct Genome { T age; T mass; T fertility; + T highlight; }; template struct Properties { @@ -70,7 +72,8 @@ struct Genome { return { p.age.FakeNormal(rand.SNorm()), p.mass.FakeNormal(rand.SNorm()), - p.fertility.FakeNormal(rand.SNorm()) + p.fertility.FakeNormal(rand.SNorm()), + glm::clamp(p.highlight.FakeNormal(rand.SNorm()), 0.0, 1.0) }; } diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index 1196a3c..92fa367 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -33,6 +33,8 @@ Creature::Creature(world::Simulation &sim) , genome() , properties() , cur_prop(0) +, base_color(1.0) +, highlight_color(0.0) , mass(1.0) , density(1.0) , size(1.0) @@ -51,8 +53,13 @@ Creature::Creature(world::Simulation &sim) Creature::~Creature() { } +glm::dvec4 Creature::HighlightColor() const noexcept { + return glm::dvec4(highlight_color, AgeLerp(CurProps().highlight, NextProps().highlight)); +} + void Creature::Grow(double amount) noexcept { - Mass(std::min(properties.props[cur_prop].mass, mass + amount)); + const double max_mass = AgeLerp(CurProps().mass, NextProps().mass); + Mass(std::min(max_mass, mass + amount)); } void Creature::Hurt(double dt) noexcept { @@ -82,9 +89,12 @@ double Creature::Age() const noexcept { return sim.Time() - birth; } +double Creature::AgeLerp(double from, double to) const noexcept { + return glm::mix(from, to, glm::smoothstep(CurProps().age, NextProps().age, Age())); +} + double Creature::Fertility() const noexcept { - // TODO: lerp based on age? - return properties.props[cur_prop].fertility / 3600.0; + return AgeLerp(CurProps().fertility, NextProps().fertility) / 3600.0; } void Creature::AddGoal(std::unique_ptr &&g) { @@ -103,11 +113,12 @@ bool GoalCompare(const std::unique_ptr &a, const std::unique_ptr &b) void Creature::Tick(double dt) { if (cur_prop < 5 && Age() > properties.props[cur_prop + 1].age) { - ++cur_prop; - if (cur_prop == 5) { + if (cur_prop == 4) { std::cout << "[" << int(sim.Time()) << "s] " << name << " died of old age" << std::endl; Die(); + } else { + ++cur_prop; } } @@ -301,26 +312,32 @@ void Spawn(Creature &c, world::Planet &p) { genome.properties.Birth().age = { 0.0, 0.0 }; genome.properties.Birth().mass = { 0.5, 0.05 }; genome.properties.Birth().fertility = { 0.0, 0.0 }; + genome.properties.Birth().highlight = { 0.0, 0.0 }; genome.properties.Child().age = { 30.0, 1.0 }; genome.properties.Child().mass = { 0.7, 0.05 }; genome.properties.Child().fertility = { 0.0, 0.0 }; + genome.properties.Child().highlight = { 0.2, 0.05 }; genome.properties.Youth().age = { 60.0, 5.0 }; genome.properties.Youth().mass = { 0.9, 0.1 }; genome.properties.Youth().fertility = { 0.5, 0.03 }; + genome.properties.Youth().highlight = { 0.9, 0.1 }; genome.properties.Adult().age = { 120.0, 10.0 }; genome.properties.Adult().mass = { 1.2, 0.1 }; genome.properties.Adult().fertility = { 0.4, 0.01 }; + genome.properties.Adult().highlight = { 0.7, 0.1 }; genome.properties.Elder().age = { 360.0, 30.0 }; genome.properties.Elder().mass = { 1.0, 0.05 }; genome.properties.Elder().fertility = { 0.1, 0.01 }; + genome.properties.Elder().highlight = { 0.6, 0.1 }; genome.properties.Death().age = { 480.0, 60.0 }; genome.properties.Death().mass = { 0.9, 0.05 }; genome.properties.Death().fertility = { 0.0, 0.0 }; + genome.properties.Death().highlight = { 0.5, 0.1 }; glm::dvec3 color_avg(0.0); double color_divisor = 0.0; @@ -333,7 +350,7 @@ void Spawn(Creature &c, world::Planet &p) { { 0.1, 0.0005 }, // penalty { 0.0, 0.0 }, // growth }); - color_avg += c.GetSimulation().Resources()[p.Atmosphere()].base_color; + color_avg += c.GetSimulation().Resources()[p.Atmosphere()].base_color * 0.1; color_divisor += 0.1; } if (liquid > -1) { @@ -344,7 +361,7 @@ void Spawn(Creature &c, world::Planet &p) { { 0.01, 0.002 }, // penalty { 0.1, 0.0 }, // growth }); - color_avg += c.GetSimulation().Resources()[liquid].base_color; + color_avg += c.GetSimulation().Resources()[liquid].base_color * 0.5; color_divisor += 0.5; } if (solid > -1) { @@ -405,6 +422,19 @@ void Genome::Configure(Creature &c) const { c.AddNeed(std::move(need)); } + glm::dvec3 base_color( + std::fmod(base_hue.FakeNormal(random.SNorm()) + 1.0, 1.0), + glm::clamp(base_saturation.FakeNormal(random.SNorm()), 0.0, 1.0), + glm::clamp(base_lightness.FakeNormal(random.SNorm()), 0.0, 1.0) + ); + glm::dvec3 highlight_color( + std::fmod(base_color.x + 0.5, 1.0), + 1.0 - base_color.y, + 1.0 - base_color.z + ); + c.BaseColor(hsl2rgb(base_color)); + c.HighlightColor(hsl2rgb(highlight_color)); + c.Mass(c.GetProperties().props[0].mass); c.Density(mass / volume); c.GetSteering().MaxAcceleration(1.4); @@ -416,7 +446,6 @@ void Genome::Configure(Creature &c) const { void Split(Creature &c) { Creature *a = new Creature(c.GetSimulation()); const Situation &s = c.GetSituation(); - // TODO: generate names a->Name(c.GetSimulation().Assets().name.Sequential()); // TODO: mutate c.GetGenome().Configure(*a); diff --git a/src/graphics/CreatureSkin.hpp b/src/graphics/CreatureSkin.hpp index c24a746..b61c108 100644 --- a/src/graphics/CreatureSkin.hpp +++ b/src/graphics/CreatureSkin.hpp @@ -31,6 +31,8 @@ public: void SetV(const glm::mat4 &v) noexcept; void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept; void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept; + void SetBaseColor(const glm::vec3 &) noexcept; + void SetHighlightColor(const glm::vec4 &) noexcept; void SetTexture(ArrayTexture &) noexcept; void SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept; void SetNumLights(int n) noexcept; @@ -55,8 +57,10 @@ private: GLuint m_handle; GLuint mv_handle; GLuint mvp_handle; - GLuint sampler_handle; + GLuint base_color_handle; + GLuint highlight_color_handle; + GLuint sampler_handle; GLuint num_lights_handle; GLuint light_handle[MAX_LIGHTS * 3]; diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index 6a08bb5..0890dfd 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -546,6 +546,8 @@ CreatureSkin::CreatureSkin() "in vec3 frag_tex_uv;\n" "in vec3 normal;\n" + "uniform vec3 base_color;\n" + "uniform vec4 highlight_color;\n" "uniform sampler2DArray tex_sampler;\n" "uniform int num_lights;\n" "uniform LightSource light[8];\n" @@ -553,14 +555,15 @@ CreatureSkin::CreatureSkin() "out vec3 color;\n" "void main() {\n" - "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n" - "vec3 total_light = tex_color * vec3(0.1, 0.1, 0.1);\n" + "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n" + "vec3 mat_color = mix(base_color, highlight_color.rgb, tex_color.r * tex_color.a * highlight_color.a);\n" + "vec3 total_light = mat_color * vec3(0.1, 0.1, 0.1);\n" "for (int i = 0; i < num_lights; ++i) {\n" "vec3 to_light = light[i].position - vtx_viewspace;\n" "float distance = length(to_light) + length(vtx_viewspace);\n" "vec3 light_dir = normalize(to_light);\n" "float attenuation = light[i].strength / (distance * distance);\n" - "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n" + "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * mat_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" @@ -579,6 +582,8 @@ CreatureSkin::CreatureSkin() m_handle = prog.UniformLocation("M"); mv_handle = prog.UniformLocation("MV"); mvp_handle = prog.UniformLocation("MVP"); + base_color_handle = prog.UniformLocation("base_color"); + highlight_color_handle = prog.UniformLocation("highlight_color"); sampler_handle = prog.UniformLocation("tex_sampler"); num_lights_handle = prog.UniformLocation("num_lights"); for (int i = 0; i < MAX_LIGHTS; ++i) { @@ -636,6 +641,14 @@ void CreatureSkin::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::m prog.Uniform(mvp_handle, mvp); } +void CreatureSkin::SetBaseColor(const glm::vec3 &c) noexcept { + prog.Uniform(base_color_handle, c); +} + +void CreatureSkin::SetHighlightColor(const glm::vec4 &c) noexcept { + prog.Uniform(highlight_color_handle, c); +} + void CreatureSkin::SetTexture(ArrayTexture &tex) noexcept { glActiveTexture(GL_TEXTURE0); tex.Bind(); diff --git a/src/math/glm.hpp b/src/math/glm.hpp index 46843db..80126aa 100644 --- a/src/math/glm.hpp +++ b/src/math/glm.hpp @@ -55,8 +55,8 @@ template inline T hsl2rgb(const T &hsl) { using Vec3 = glm::tvec3; using Vec4 = glm::tvec4; - const Vec4 K(0.0, -1.0/3.0, 2.0/3.0, -1.0); - const Vec3 p(glm::abs(glm::fract(Vec3(hsl.h) + Vec3(K)) * 6.0 - Vec3(K.w))); + const Vec4 K(1.0, 2.0/3.0, 1.0/3.0, 3.0); + const Vec3 p(glm::abs(glm::fract(Vec3(hsl.x) + Vec3(K)) * 6.0 - Vec3(K.w))); T rgb = hsl.z * glm::mix(Vec3(K.x), glm::clamp(p - Vec3(K.x), 0.0, 1.0), hsl.y); return rgb; } diff --git a/src/world/world.cpp b/src/world/world.cpp index eee1283..dd7d28d 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -347,34 +347,34 @@ void Planet::BuildVAO(const Set &ts) { for (int y = 0; y < sidelength; ++y) { for (int x = 0; x < sidelength; ++x, ++index) { float tex = ts[TileAt(surface, x, y).type].texture; - const float tex_u_begin = surface < 3 ? 1.0f : 0.0f; - const float tex_u_end = surface < 3 ? 0.0f : 1.0f; + const float tex_v_begin = surface < 3 ? 1.0f : 0.0f; + const float tex_v_end = surface < 3 ? 0.0f : 1.0f; attrib[4 * index + 0].position[(surface + 0) % 3] = x + 0 - offset; attrib[4 * index + 0].position[(surface + 1) % 3] = y + 0 - offset; attrib[4 * index + 0].position[(surface + 2) % 3] = surface < 3 ? offset : -offset; - attrib[4 * index + 0].tex_coord[0] = tex_u_begin; - attrib[4 * index + 0].tex_coord[1] = 1.0f; + attrib[4 * index + 0].tex_coord[0] = 0.0f; + attrib[4 * index + 0].tex_coord[1] = tex_v_begin; attrib[4 * index + 0].tex_coord[2] = tex; attrib[4 * index + 1].position[(surface + 0) % 3] = x + 0 - offset; attrib[4 * index + 1].position[(surface + 1) % 3] = y + 1 - offset; attrib[4 * index + 1].position[(surface + 2) % 3] = surface < 3 ? offset : -offset; - attrib[4 * index + 1].tex_coord[0] = tex_u_end; - attrib[4 * index + 1].tex_coord[1] = 1.0f; + attrib[4 * index + 1].tex_coord[0] = 0.0f; + attrib[4 * index + 1].tex_coord[1] = tex_v_end; attrib[4 * index + 1].tex_coord[2] = tex; attrib[4 * index + 2].position[(surface + 0) % 3] = x + 1 - offset; attrib[4 * index + 2].position[(surface + 1) % 3] = y + 0 - offset; attrib[4 * index + 2].position[(surface + 2) % 3] = surface < 3 ? offset : -offset; - attrib[4 * index + 2].tex_coord[0] = tex_u_begin; - attrib[4 * index + 2].tex_coord[1] = 0.0f; + attrib[4 * index + 2].tex_coord[0] = 1.0f; + attrib[4 * index + 2].tex_coord[1] = tex_v_begin; attrib[4 * index + 2].tex_coord[2] = tex; attrib[4 * index + 3].position[(surface + 0) % 3] = x + 1 - offset; attrib[4 * index + 3].position[(surface + 1) % 3] = y + 1 - offset; attrib[4 * index + 3].position[(surface + 2) % 3] = surface < 3 ? offset : -offset; - attrib[4 * index + 3].tex_coord[0] = tex_u_end; - attrib[4 * index + 3].tex_coord[1] = 0.0f; + attrib[4 * index + 3].tex_coord[0] = 1.0f; + attrib[4 * index + 3].tex_coord[1] = tex_v_end; attrib[4 * index + 3].tex_coord[2] = tex; } }