Browse Source

Add weather system

master
C. J. Howard 1 year ago
parent
commit
7222deeb56
14 changed files with 314 additions and 40 deletions
  1. +1
    -0
      CMakeLists.txt
  2. +46
    -1
      src/game/bootloader.cpp
  3. +2
    -0
      src/game/game-context.hpp
  4. +4
    -3
      src/game/states/play-state.cpp
  5. +2
    -0
      src/game/systems/control-system.cpp
  6. +14
    -0
      src/game/systems/control-system.hpp
  7. +124
    -0
      src/game/systems/weather-system.cpp
  8. +64
    -0
      src/game/systems/weather-system.hpp
  9. +10
    -1
      src/renderer/passes/material-pass.cpp
  10. +4
    -0
      src/renderer/passes/material-pass.hpp
  11. +13
    -23
      src/renderer/passes/shadow-map-pass.cpp
  12. +4
    -0
      src/renderer/passes/shadow-map-pass.hpp
  13. +19
    -12
      src/renderer/passes/sky-pass.cpp
  14. +7
    -0
      src/renderer/passes/sky-pass.hpp

+ 1
- 0
CMakeLists.txt View File

@ -14,6 +14,7 @@ find_package(SDL2 REQUIRED COMPONENTS SDL2::SDL2-static SDL2::SDL2main CONFIG)
find_package(OpenAL REQUIRED CONFIG)
find_library(physfs REQUIRED NAMES physfs-static PATHS "${CMAKE_PREFIX_PATH}/lib")
# Determine dependencies
set(STATIC_LIBS
dr_wav

+ 46
- 1
src/game/bootloader.cpp View File

@ -78,6 +78,7 @@
#include "game/systems/spatial-system.hpp"
#include "game/systems/tracking-system.hpp"
#include "game/systems/painting-system.hpp"
#include "game/systems/weather-system.hpp"
#include "game/components/marker-component.hpp"
#include "game/entity-commands.hpp"
#include "utility/paths.hpp"
@ -753,6 +754,7 @@ void setup_animation(game_context* ctx)
ctx->focal_point_tween->set_interpolator(math::lerp<float3, float>);
// Set material pass tweens
ctx->overworld_sky_pass->set_time_tween(ctx->time_tween);
ctx->overworld_material_pass->set_time_tween(ctx->time_tween);
ctx->overworld_material_pass->set_focal_point_tween(ctx->focal_point_tween);
ctx->underworld_material_pass->set_time_tween(ctx->time_tween);
@ -855,6 +857,18 @@ void setup_systems(game_context* ctx)
ctx->painting_system = new painting_system(*ctx->ecs_registry, event_dispatcher, ctx->resource_manager);
ctx->painting_system->set_scene(ctx->overworld_scene);
// Setup weather system
ctx->weather_system = new weather_system(*ctx->ecs_registry);
ctx->weather_system->set_ambient_light(ctx->sun_indirect);
ctx->weather_system->set_sun_light(ctx->sun_direct);
ctx->weather_system->set_sky_pass(ctx->overworld_sky_pass);
ctx->weather_system->set_shadow_map_pass(ctx->overworld_shadow_map_pass);
ctx->weather_system->set_material_pass(ctx->overworld_material_pass);
if (ctx->config->has("time_scale"))
{
ctx->weather_system->set_time_scale(ctx->config->get<float>("time_scale"));
}
// Setup render system
ctx->render_system = new ::render_system(*ctx->ecs_registry);
ctx->render_system->add_layer(ctx->overworld_scene);
@ -1030,6 +1044,8 @@ void setup_controls(game_context* ctx)
ctx->input_event_router->add_mapping(game_controller_axis_mapping(ctx->control_system->get_zoom_in_control(), nullptr, game_controller_axis::trigger_right, false));
ctx->input_event_router->add_mapping(key_mapping(ctx->control_system->get_rotate_ccw_control(), nullptr, scancode::q));
ctx->input_event_router->add_mapping(key_mapping(ctx->control_system->get_rotate_cw_control(), nullptr, scancode::e));
ctx->input_event_router->add_mapping(key_mapping(ctx->control_system->get_fast_forward_control(), nullptr, scancode::dot));
ctx->input_event_router->add_mapping(key_mapping(ctx->control_system->get_rewind_control(), nullptr, scancode::comma));
ctx->input_event_router->add_mapping(key_mapping(ctx->control_system->get_equip_brush_control(), nullptr, scancode::one));
@ -1143,8 +1159,36 @@ void setup_controls(game_context* ctx)
}
);
float time_scale = ctx->config->get<float>("time_scale");
ctx->control_system->get_fast_forward_control()->set_activated_callback
(
[ctx, time_scale]()
{
ctx->weather_system->set_time_scale(time_scale * 100.0f);
}
);
ctx->control_system->get_fast_forward_control()->set_deactivated_callback
(
[ctx, time_scale]()
{
ctx->weather_system->set_time_scale(time_scale);
}
);
ctx->control_system->get_rewind_control()->set_activated_callback
(
[ctx, time_scale]()
{
ctx->weather_system->set_time_scale(time_scale * -100.0f);
}
);
ctx->control_system->get_rewind_control()->set_deactivated_callback
(
[ctx, time_scale]()
{
ctx->weather_system->set_time_scale(time_scale);
}
);
// Make lens tool's model instance unculled, so its shadow is always visible.
model_instance* lens_model_instance = ctx->render_system->get_model_instance(ctx->lens_entity);
@ -1201,6 +1245,7 @@ void setup_callbacks(game_context* ctx)
ctx->constraint_system->update(t, dt);
ctx->tracking_system->update(t, dt);
ctx->painting_system->update(t, dt);
ctx->weather_system->update(t, dt);
//(*ctx->focal_point_tween)[1] = ctx->orbit_cam->get_focal_point();

+ 2
- 0
src/game/game-context.hpp View File

@ -86,6 +86,7 @@ class cli;
class outline_pass;
class tracking_system;
class painting_system;
class weather_system;
struct biome;
template <typename T> class animation;
template <typename T> class material_property;
@ -241,6 +242,7 @@ struct game_context
spatial_system* spatial_system;
tracking_system* tracking_system;
painting_system* painting_system;
weather_system* weather_system;
// Game
biome* biome;

+ 4
- 3
src/game/states/play-state.cpp View File

@ -54,6 +54,7 @@
#include "game/systems/camera-system.hpp"
#include "game/systems/render-system.hpp"
#include "game/systems/tool-system.hpp"
#include "game/systems/weather-system.hpp"
#include "game/biome.hpp"
#include "utility/fundamental-types.hpp"
#include "utility/gamma.hpp"
@ -93,11 +94,11 @@ void play_state_enter(game_context* ctx)
sky_pass->set_zenith_color(ctx->biome->zenith_color);
texture_2d* sky_palette = ctx->resource_manager->load<texture_2d>("sky-palette.png");
sky_palette->set_wrapping(texture_wrapping::repeat, texture_wrapping::clamp);
sky_palette->set_filters(texture_min_filter::linear, texture_mag_filter::linear);
sky_palette->set_wrapping(texture_wrapping::clamp, texture_wrapping::clamp);
sky_palette->set_filters(texture_min_filter::nearest, texture_mag_filter::nearest);
sky_pass->set_sky_palette(sky_palette);
ctx->tool_system->set_sun_direction(ctx->sun_direct->get_direction());
ctx->weather_system->set_time_of_day(6.0f * 60.0f * 60.0f);
resource_manager* resource_manager = ctx->resource_manager;
entt::registry& ecs_registry = *ctx->ecs_registry;

+ 2
- 0
src/game/systems/control-system.cpp View File

@ -60,6 +60,8 @@ control_system::control_system(entt::registry& registry):
control_set.add_control(&next_marker_control);
control_set.add_control(&previous_marker_control);
control_set.add_control(&use_tool_control);
control_set.add_control(&fast_forward_control);
control_set.add_control(&rewind_control);
// Set deadzone at 15% for all controls
const std::list<control*>* controls = control_set.get_controls();

+ 14
- 0
src/game/systems/control-system.hpp View File

@ -80,6 +80,8 @@ public:
control* get_next_marker_control();
control* get_previous_marker_control();
control* get_use_tool_control();
control* get_fast_forward_control();
control* get_rewind_control();
private:
virtual void handle_event(const mouse_moved_event& event);
@ -110,6 +112,8 @@ private:
control next_marker_control;
control previous_marker_control;
control use_tool_control;
control fast_forward_control;
control rewind_control;
float zoom_speed;
float min_elevation;
@ -269,5 +273,15 @@ inline control* control_system::get_use_tool_control()
return &use_tool_control;
}
inline control* control_system::get_fast_forward_control()
{
return &fast_forward_control;
}
inline control* control_system::get_rewind_control()
{
return &rewind_control;
}
#endif // ANTKEEPER_CONTROL_SYSTEM_HPP

+ 124
- 0
src/game/systems/weather-system.cpp View File

@ -0,0 +1,124 @@
/*
* Copyright (C) 2020 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/systems/weather-system.hpp"
#include "scene/directional-light.hpp"
#include "renderer/passes/sky-pass.hpp"
#include "renderer/passes/shadow-map-pass.hpp"
#include "renderer/passes/material-pass.hpp"
#include <cmath>
weather_system::weather_system(entt::registry& registry):
entity_system(registry),
ambient_light(nullptr),
sun_light(nullptr),
moon_light(nullptr),
shadow_light(nullptr),
sky_pass(nullptr),
shadow_map_pass(nullptr),
material_pass(nullptr),
time_of_day(0.0f),
time_scale(1.0f),
sun_direction{0.0f, -1.0f, 0.0f}
{}
void weather_system::update(double t, double dt)
{
set_time_of_day(time_of_day + dt * time_scale);
}
void weather_system::set_ambient_light(::ambient_light* light)
{
this->ambient_light = light;
}
void weather_system::set_sun_light(directional_light* light)
{
sun_light = light;
if (sky_pass)
{
sky_pass->set_sun_light(sun_light);
}
}
void weather_system::set_moon_light(directional_light* light)
{
moon_light = light;
}
void weather_system::set_sky_pass(::sky_pass* pass)
{
sky_pass = pass;
if (sky_pass)
{
sky_pass->set_sun_light(sun_light);
}
}
void weather_system::set_shadow_map_pass(::shadow_map_pass* pass)
{
shadow_map_pass = pass;
if (shadow_map_pass)
{
shadow_map_pass->set_light(shadow_light);
}
}
void weather_system::set_material_pass(::material_pass* pass)
{
material_pass = pass;
if (material_pass)
{
material_pass->set_shadow_strength(0.75f);
}
}
void weather_system::set_time_of_day(float t)
{
static constexpr float seconds_per_day = 24.0f * 60.0f * 60.0f;
time_of_day = std::fmod(t, seconds_per_day);
sun_azimuth = 0.0f;
sun_elevation = (time_of_day / seconds_per_day) * math::two_pi<float> - math::half_pi<float>;
math::quaternion<float> sun_azimuth_rotation = math::angle_axis(sun_azimuth, float3{0, 1, 0});
math::quaternion<float> sun_elevation_rotation = math::angle_axis(sun_elevation, float3{-1, 0, 0});
math::quaternion<float> sun_rotation = math::normalize(sun_azimuth_rotation * sun_elevation_rotation);
sun_direction = math::normalize(sun_rotation * float3{0, 0, -1});
if (sun_light)
{
sun_light->set_rotation(sun_rotation);
}
shadow_light = sun_light;
if (shadow_map_pass)
{
shadow_map_pass->set_light(shadow_light);
}
}
void weather_system::set_time_scale(float scale)
{
time_scale = scale;
}

+ 64
- 0
src/game/systems/weather-system.hpp View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2020 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_WEATHER_SYSTEM_HPP
#define ANTKEEPER_WEATHER_SYSTEM_HPP
#include "entity-system.hpp"
#include "utility/fundamental-types.hpp"
class sky_pass;
class shadow_map_pass;
class material_pass;
class ambient_light;
class directional_light;
class weather_system:
public entity_system
{
public:
weather_system(entt::registry& registry);
virtual void update(double t, double dt);
void set_ambient_light(ambient_light* light);
void set_sun_light(directional_light* light);
void set_moon_light(directional_light* light);
void set_sky_pass(::sky_pass* pass);
void set_shadow_map_pass(::shadow_map_pass* pass);
void set_material_pass(::material_pass* pass);
void set_time_of_day(float t);
void set_time_scale(float scale);
private:
float time_of_day;
float time_scale;
float sun_azimuth;
float sun_elevation;
float3 sun_direction;
ambient_light* ambient_light;
directional_light* sun_light;
directional_light* moon_light;
directional_light* shadow_light;
sky_pass* sky_pass;
shadow_map_pass* shadow_map_pass;
material_pass* material_pass;
};
#endif // ANTKEEPER_WEATHER_SYSTEM_HPP

+ 10
- 1
src/renderer/passes/material-pass.cpp View File

@ -60,7 +60,8 @@ material_pass::material_pass(::rasterizer* rasterizer, const ::framebuffer* fram
mouse_position({0.0f, 0.0f}),
focal_point_tween(nullptr),
shadow_map_pass(nullptr),
shadow_map(nullptr)
shadow_map(nullptr),
shadow_strength(1.0f)
{
soft_shadows_texture = resource_manager->load<texture_2d>("tree-shadow.png");
soft_shadows_texture->set_wrapping(texture_wrapping::clamp, texture_wrapping::clamp);
@ -464,6 +465,8 @@ void material_pass::render(render_context* context) const
parameters->shadow_map_split_distances->upload(shadow_map_split_distances);
if (parameters->shadow_map && shadow_map)
parameters->shadow_map->upload(shadow_map);
if (parameters->shadow_strength)
parameters->shadow_strength->upload(shadow_strength);
}
// Upload material properties to shader
@ -504,6 +507,11 @@ void material_pass::set_time_tween(const tween* time)
this->time_tween = time;
}
void material_pass::set_shadow_strength(float strength)
{
this->shadow_strength = strength;
}
void material_pass::set_focal_point_tween(const tween<float3>* focal_point)
{
this->focal_point_tween = focal_point;
@ -545,6 +553,7 @@ const material_pass::parameter_set* material_pass::load_parameter_set(const shad
parameters->shadow_map_matrices = program->get_input("shadow_map_matrices");
parameters->shadow_map_split_distances = program->get_input("shadow_map_split_distances");
parameters->shadow_map = program->get_input("shadow_map");
parameters->shadow_strength = program->get_input("shadow_strength");
// Add parameter set to map of parameter sets
parameter_sets[program] = parameters;

+ 4
- 0
src/renderer/passes/material-pass.hpp View File

@ -52,6 +52,8 @@ public:
/// Sets the time tween, which is interpolated between updates
void set_time_tween(const tween<double>* time);
void set_shadow_strength(float strength);
void set_focal_point_tween(const tween<float3>* focal_point);
const ::shadow_map_pass* shadow_map_pass;
@ -98,6 +100,7 @@ private:
const shader_input* shadow_map_matrices;
const shader_input* shadow_map_split_distances;
const shader_input* shadow_map;
const shader_input* shadow_strength;
};
const parameter_set* load_parameter_set(const shader_program* program) const;
@ -108,6 +111,7 @@ private:
float2 mouse_position;
const tween<float3>* focal_point_tween;
texture_2d* soft_shadows_texture;
float shadow_strength;
int max_ambient_light_count;
int max_point_light_count;

+ 13
- 23
src/renderer/passes/shadow-map-pass.cpp View File

@ -60,7 +60,8 @@ void shadow_map_pass::distribute_frustum_splits(float* split_distances, std::siz
shadow_map_pass::shadow_map_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, resource_manager* resource_manager):
render_pass(rasterizer, framebuffer),
split_scheme_weight(0.5f)
split_scheme_weight(0.5f),
light(nullptr)
{
// Load skinned shader program
unskinned_shader_program = resource_manager->load<::shader_program>("depth-unskinned.glsl");
@ -87,6 +88,12 @@ shadow_map_pass::~shadow_map_pass()
void shadow_map_pass::render(render_context* context) const
{
// Abort if no directional light was set
if (!light)
{
return;
}
rasterizer->use_framebuffer(*framebuffer);
// Disable blending
@ -103,28 +110,6 @@ void shadow_map_pass::render(render_context* context) const
// Get camera
const ::camera& camera = *context->camera;
// Find the first active directional light
const std::list<scene_object_base*>* lights = context->scene->get_objects(light::object_type_id);
const ::directional_light* light = nullptr;
for (const scene_object_base* object: *lights)
{
// Skip inactive lights
if (!object->is_active())
continue;
if (static_cast<const ::light*>(object)->get_light_type() == light_type::directional)
{
light = static_cast<const ::directional_light*>(object);
break;
}
}
// Abort if no directional light was found
if (!light)
{
return;
}
// Calculate distances to the depth clipping planes of each frustum split
float clip_near = camera.get_clip_near_tween().interpolate(context->alpha);
float clip_far = camera.get_clip_far_tween().interpolate(context->alpha);
@ -266,6 +251,11 @@ void shadow_map_pass::set_split_scheme_weight(float weight)
split_scheme_weight = weight;
}
void shadow_map_pass::set_light(const directional_light* light)
{
this->light = light;
}
bool operation_compare(const render_operation& a, const render_operation& b)
{
// Determine transparency

+ 4
- 0
src/renderer/passes/shadow-map-pass.hpp View File

@ -27,6 +27,7 @@ class shader_program;
class shader_input;
class camera;
class resource_manager;
class directional_light;
/**
*
@ -45,6 +46,8 @@ public:
*/
void set_split_scheme_weight(float weight);
void set_light(const directional_light* light);
const float4x4* get_shadow_matrices() const;
const float* get_split_distances() const;
@ -70,6 +73,7 @@ private:
mutable float4x4 shadow_matrices[4];
float4x4 bias_tile_matrices[4];
float split_scheme_weight;
const directional_light* light;
};
inline const float4x4* shadow_map_pass::get_shadow_matrices() const

+ 19
- 12
src/renderer/passes/sky-pass.cpp View File

@ -44,7 +44,8 @@
sky_pass::sky_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, resource_manager* resource_manager):
render_pass(rasterizer, framebuffer),
sky_palette(nullptr),
mouse_position({0.0f, 0.0f})
mouse_position({0.0f, 0.0f}),
sun_light(nullptr)
{
shader_program = resource_manager->load<::shader_program>("sky.glsl");
matrix_input = shader_program->get_input("matrix");
@ -57,6 +58,7 @@ sky_pass::sky_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, r
sky_palette_input = shader_program->get_input("sky_palette");
mouse_input = shader_program->get_input("mouse");
resolution_input = shader_program->get_input("resolution");
time_input = shader_program->get_input("time");
const float vertex_data[] =
{
@ -95,20 +97,13 @@ void sky_pass::render(render_context* context) const
auto viewport = framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
float time = (time_tween) ? time_tween->interpolate(context->alpha) : 0.0f;
float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
float3 sun_direction = {0, -1, 0};
// Find sun direction
float3 sun_direction = {0, 0, -1};
const std::list<scene_object_base*>* lights = context->scene->get_objects(light::object_type_id);
for (const scene_object_base* object: *lights)
if (sun_light)
{
const ::light* light = static_cast<const ::light*>(object);
if (light->get_light_type() == light_type::directional)
{
sun_direction = static_cast<const directional_light*>(light)->get_direction_tween().interpolate(context->alpha);
break;
}
sun_direction = sun_light->get_direction_tween().interpolate(context->alpha);
}
// Calculate matrix
@ -138,6 +133,8 @@ void sky_pass::render(render_context* context) const
mouse_input->upload(mouse_position);
if (resolution_input)
resolution_input->upload(resolution);
if (time_input)
time_input->upload(time);
// Draw quad
rasterizer->draw_arrays(*quad_vao, drawing_mode::triangles, 0, 6);
@ -163,11 +160,21 @@ void sky_pass::set_zenith_color(const float3& color)
zenith_color = color;
}
void sky_pass::set_sun_light(const directional_light* light)
{
sun_light = light;
}
void sky_pass::set_sky_palette(const texture_2d* texture)
{
sky_palette = texture;
}
void sky_pass::set_time_tween(const tween<double>* time)
{
this->time_tween = time;
}
void sky_pass::handle_event(const mouse_moved_event& event)
{
mouse_position = {static_cast<float>(event.x), static_cast<float>(event.y)};

+ 7
- 0
src/renderer/passes/sky-pass.hpp View File

@ -24,6 +24,7 @@
#include "utility/fundamental-types.hpp"
#include "event/event-handler.hpp"
#include "event/input-events.hpp"
#include "animation/tween.hpp"
class shader_program;
class shader_input;
@ -31,6 +32,7 @@ class vertex_buffer;
class vertex_array;
class texture_2d;
class resource_manager;
class directional_light;
/**
*
@ -47,7 +49,9 @@ public:
void set_sun_color(const float3& color);
void set_horizon_color(const float3& color);
void set_zenith_color(const float3& color);
void set_sun_light(const directional_light* direction);
void set_sky_palette(const texture_2d* texture);
void set_time_tween(const tween<double>* time);
private:
virtual void handle_event(const mouse_moved_event& event);
@ -62,6 +66,7 @@ private:
const shader_input* sky_palette_input;
const shader_input* mouse_input;
const shader_input* resolution_input;
const shader_input* time_input;
vertex_buffer* quad_vbo;
vertex_array* quad_vao;
@ -70,8 +75,10 @@ private:
float3 sun_color;
float3 horizon_color;
float3 zenith_color;
const directional_light* sun_light;
const texture_2d* sky_palette;
float2 mouse_position;
const tween<double>* time_tween;
};
#endif // ANTKEEPER_SKY_PASS_HPP

Loading…
Cancel
Save