From 0ea68f5fe5d4d0091ac47a9ebd7d52f2a46f0f9e Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Sun, 20 Jun 2021 02:50:12 +0800 Subject: [PATCH] Move fixed stars generation from sky pass to loading state, fix bug related to loaded matrial property tweening --- src/game/states/loading.cpp | 160 ++++++++++++++++++++++-- src/game/states/nuptial-flight.cpp | 58 ++++++++- src/game/states/play.cpp | 2 +- src/renderer/passes/sky-pass.cpp | 189 +++++++++++------------------ src/renderer/passes/sky-pass.hpp | 23 ++-- src/resources/material-loader.cpp | 3 + 6 files changed, 291 insertions(+), 144 deletions(-) diff --git a/src/game/states/loading.cpp b/src/game/states/loading.cpp index 29cc9c0..3f1ce96 100644 --- a/src/game/states/loading.cpp +++ b/src/game/states/loading.cpp @@ -18,21 +18,34 @@ */ #include "game/states/loading.hpp" -#include "game/states/play.hpp" -#include "game/states/splash.hpp" +#include "application.hpp" +#include "astro/illuminance.hpp" +#include "color/color.hpp" +#include "entity/components/atmosphere.hpp" +#include "entity/components/blackbody.hpp" #include "entity/components/celestial-body.hpp" #include "entity/components/orbit.hpp" -#include "entity/components/blackbody.hpp" #include "entity/components/terrain.hpp" -#include "entity/components/atmosphere.hpp" #include "entity/components/transform.hpp" #include "entity/systems/astronomy.hpp" #include "entity/systems/orbit.hpp" -#include "scene/directional-light.hpp" -#include "scene/ambient-light.hpp" -#include "resources/resource-manager.hpp" -#include "application.hpp" +#include "game/states/nuptial-flight.hpp" +#include "game/states/play.hpp" +#include "game/states/splash.hpp" +#include "geom/spherical.hpp" +#include "gl/drawing-mode.hpp" +#include "gl/vertex-array.hpp" +#include "gl/vertex-attribute-type.hpp" +#include "gl/vertex-buffer.hpp" +#include "physics/light/photometry.hpp" +#include "physics/orbit/orbit.hpp" +#include "renderer/material.hpp" +#include "renderer/model.hpp" #include "renderer/passes/shadow-map-pass.hpp" +#include "renderer/vertex-attributes.hpp" +#include "resources/resource-manager.hpp" +#include "scene/ambient-light.hpp" +#include "scene/directional-light.hpp" namespace game { namespace state { @@ -50,6 +63,9 @@ static void planetogenesis(game::context* ctx); /// Creates a moon. static void selenogenesis(game::context* ctx); +/// Creates fixed stars. +static void extrasolar_heliogenesis(game::context* ctx); + void enter(game::context* ctx) { // Create universe @@ -69,9 +85,9 @@ void enter(game::context* ctx) application::state next_state; if (ctx->option_quick_start.has_value()) { - next_state.name = "play"; - next_state.enter = std::bind(game::state::play::enter, ctx); - next_state.exit = std::bind(game::state::play::exit, ctx); + next_state.name = "nuptial flight"; + next_state.enter = std::bind(game::state::nuptial_flight::enter, ctx); + next_state.exit = std::bind(game::state::nuptial_flight::exit, ctx); } else { @@ -132,6 +148,19 @@ void cosmogenesis(game::context* ctx) throw; } ctx->logger->pop_task(EXIT_SUCCESS); + + // Create fixed stars + ctx->logger->push_task("Creating fixed stars"); + try + { + extrasolar_heliogenesis(ctx); + } + catch (...) + { + ctx->logger->pop_task(EXIT_FAILURE); + throw; + } + ctx->logger->pop_task(EXIT_SUCCESS); } void heliogenesis(game::context* ctx) @@ -263,6 +292,115 @@ void selenogenesis(game::context* ctx) ctx->overworld_sky_pass->set_moon_model(ctx->resource_manager->load("moon.mdl")); } +void extrasolar_heliogenesis(game::context* ctx) +{ + // Load star catalog + string_table* star_catalog = ctx->resource_manager->load("stars.csv"); + + // Allocate star catalog vertex data + std::size_t star_count = 0; + if (star_catalog->size() > 0) + star_count = star_catalog->size() - 1; + std::size_t star_vertex_size = 6; + std::size_t star_vertex_stride = star_vertex_size * sizeof(float); + float* star_vertex_data = new float[star_count * star_vertex_size]; + float* star_vertex = star_vertex_data; + + // Build star catalog vertex data + for (std::size_t i = 1; i < star_catalog->size(); ++i) + { + const string_table_row& catalog_row = (*star_catalog)[i]; + + double ra = 0.0; + double dec = 0.0; + double vmag = 0.0; + double bv_color = 0.0; + + // Parse star catalog entry + try + { + ra = std::stod(catalog_row[1]); + dec = std::stod(catalog_row[2]); + vmag = std::stod(catalog_row[3]); + bv_color = std::stod(catalog_row[4]); + } + catch (const std::exception& e) + { + continue; + } + + // Convert right ascension and declination from degrees to radians + ra = math::wrap_radians(math::radians(ra)); + dec = math::wrap_radians(math::radians(dec)); + + // Transform spherical equatorial coordinates to rectangular equatorial coordinates + double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra}); + + // Transform coordinates from equatorial space to inertial space + physics::frame bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse(); + double3 position_inertial = bci_to_inertial * position_bci; + + // Convert color index to color temperature + double cct = color::index::bv_to_cct(bv_color); + + // Calculate XYZ color from color temperature + double3 color_xyz = color::cct::to_xyz(cct); + + // Transform XYZ color to ACEScg colorspace + double3 color_acescg = color::xyz::to_acescg(color_xyz); + + // Convert apparent magnitude to irradiance (W/m^2) + double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4)); + + // Convert irradiance to illuminance + double vmag_illuminance = vmag_irradiance * (683.0 * 0.14); + + // Scale color by illuminance + double3 scaled_color = color_acescg * vmag_illuminance; + + // Build vertex + *(star_vertex++) = static_cast(position_inertial.x); + *(star_vertex++) = static_cast(position_inertial.y); + *(star_vertex++) = static_cast(position_inertial.z); + *(star_vertex++) = static_cast(scaled_color.x); + *(star_vertex++) = static_cast(scaled_color.y); + *(star_vertex++) = static_cast(scaled_color.z); + } + + // Unload star catalog + ctx->resource_manager->unload("stars.csv"); + + // Allocate stars model + model* stars_model = new model(); + + // Resize model VBO and upload vertex data + gl::vertex_buffer* vbo = stars_model->get_vertex_buffer(); + vbo->resize(star_count * star_vertex_stride, star_vertex_data); + + // Free star catalog vertex data + delete[] star_vertex_data; + + // Bind vertex attributes to model VAO + gl::vertex_array* vao = stars_model->get_vertex_array(); + std::size_t vao_offset = 0; + vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, 0); + vao_offset += 3; + vao->bind_attribute(VERTEX_COLOR_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, sizeof(float) * vao_offset); + + // Load star material + material* star_material = ctx->resource_manager->load("fixed-star.mtl"); + + // Create model group + model_group* stars_model_group = stars_model->add_group("stars"); + stars_model_group->set_material(star_material); + stars_model_group->set_drawing_mode(gl::drawing_mode::points); + stars_model_group->set_start_index(0); + stars_model_group->set_index_count(star_count); + + // Pass stars model to sky pass + ctx->overworld_sky_pass->set_stars_model(stars_model); +} + } // namespace loading } // namespace state } // namespace game diff --git a/src/game/states/nuptial-flight.cpp b/src/game/states/nuptial-flight.cpp index 13c68da..f18f524 100644 --- a/src/game/states/nuptial-flight.cpp +++ b/src/game/states/nuptial-flight.cpp @@ -20,10 +20,17 @@ #include "game/states/nuptial-flight.hpp" #include "entity/systems/astronomy.hpp" #include "entity/systems/orbit.hpp" +#include "entity/systems/control.hpp" +#include "entity/systems/camera.hpp" +#include "entity/components/observer.hpp" +#include "entity/components/camera-follow.hpp" +#include "entity/components/transform.hpp" +#include "entity/components/terrain.hpp" #include "renderer/material-property.hpp" #include "animation/screen-transition.hpp" #include "animation/ease.hpp" #include "resources/config-file.hpp" +#include "resources/resource-manager.hpp" namespace game { namespace state { @@ -31,13 +38,62 @@ namespace nuptial_flight { void enter(game::context* ctx) { + // Find planet EID by name + entity::id planet_eid = entt::null; + if (auto it = ctx->named_entities.find("planet"); it != ctx->named_entities.end()) + { + planet_eid = it->second; + } + + // Replace planet terrain material with cloud material + entity::component::terrain planet_terrain = ctx->entity_registry->get(planet_eid); + planet_terrain.patch_material = ctx->resource_manager->load("cloud.mtl"); + ctx->entity_registry->replace(planet_eid, planet_terrain); + + // Create observer + auto observer_eid = ctx->entity_registry->create(); + { + entity::component::observer observer; + observer.reference_body_eid = planet_eid; + observer.elevation = 2000.0; + observer.latitude = 0.0; + observer.longitude = 0.0; + observer.camera = ctx->overworld_camera; + ctx->entity_registry->assign(observer_eid, observer); + + // Set reference location of astronomy system + ctx->astronomy_system->set_reference_body(planet_eid); + ctx->astronomy_system->set_observer_location(double3{observer.elevation, observer.latitude, observer.longitude}); + } + + // Create camera focal point + { + entity::component::transform focal_point_transform; + focal_point_transform.local = math::identity_transform; + focal_point_transform.warp = true; + ctx->entity_registry->assign_or_replace(ctx->focal_point_entity, focal_point_transform); + + entity::component::camera_follow focal_point_follow; + ctx->entity_registry->assign_or_replace(ctx->focal_point_entity, focal_point_follow); + } + + // Setup camera + ctx->overworld_camera->look_at({0, 0, 1}, {0, 0, 0}, {0, 1, 0}); + ctx->overworld_camera->set_exposure(-14.5f); + ctx->camera_system->set_camera(ctx->overworld_camera); + + entity::system::control* control_system = ctx->control_system; + control_system->update(0.0, 0.0); + + ctx->overworld_scene->update_tweens(); + // Pause motion of celestial objects ctx->astronomy_system->set_time_scale(0.0); ctx->orbit_system->set_time_scale(0.0); // Start fade in from white ctx->fade_transition_color->set_value({1, 1, 1}); - ctx->fade_transition->transition(1.0f, true, ease::in_quad); + ctx->fade_transition->transition(2.0f, true, ease::in_quad); } void exit(game::context* ctx) diff --git a/src/game/states/play.cpp b/src/game/states/play.cpp index e1bce7b..840d364 100644 --- a/src/game/states/play.cpp +++ b/src/game/states/play.cpp @@ -56,7 +56,7 @@ void enter(game::context* ctx) // Set reference location of astronomy system ctx->astronomy_system->set_reference_body(planet_eid); - ctx->astronomy_system->set_observer_location(double3{0.0, math::radians(0.0), math::radians(0.0)}); + ctx->astronomy_system->set_observer_location(double3{observer.elevation, observer.latitude, observer.longitude}); } // Create camera focal point diff --git a/src/renderer/passes/sky-pass.cpp b/src/renderer/passes/sky-pass.cpp index 7d4592a..b3b771f 100644 --- a/src/renderer/passes/sky-pass.cpp +++ b/src/renderer/passes/sky-pass.cpp @@ -57,114 +57,20 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe sky_model_vao(nullptr), sky_shader_program(nullptr), moon_model(nullptr), - moon_material(nullptr), moon_model_vao(nullptr), + moon_material(nullptr), moon_shader_program(nullptr), + stars_model(nullptr), + stars_model_vao(nullptr), + star_material(nullptr), + star_shader_program(nullptr), time_tween(nullptr), observer_altitude_tween(0.0f, math::lerp), sun_position_tween(float3{1.0f, 0.0f, 0.0f}, math::lerp), sun_color_tween(float3{1.0f, 1.0f, 1.0f}, math::lerp), topocentric_frame_translation({0, 0, 0}, math::lerp), topocentric_frame_rotation(math::quaternion::identity(), math::nlerp) -{ - // Load star catalog - string_table* star_catalog = resource_manager->load("stars.csv"); - - // Allocate star catalog vertex data - star_count = 0; - if (star_catalog->size() > 0) - star_count = star_catalog->size() - 1; - std::size_t star_vertex_size = 6; - std::size_t star_vertex_stride = star_vertex_size * sizeof(float); - float* star_vertex_data = new float[star_count * star_vertex_size]; - float* star_vertex = star_vertex_data; - - // Build star catalog vertex data - for (std::size_t i = 1; i < star_catalog->size(); ++i) - { - const string_table_row& catalog_row = (*star_catalog)[i]; - - double ra = 0.0; - double dec = 0.0; - double vmag = 0.0; - double bv_color = 0.0; - - // Parse star catalog entry - try - { - ra = std::stod(catalog_row[1]); - dec = std::stod(catalog_row[2]); - vmag = std::stod(catalog_row[3]); - bv_color = std::stod(catalog_row[4]); - } - catch (const std::exception& e) - { - continue; - } - - // Convert right ascension and declination from degrees to radians - ra = math::wrap_radians(math::radians(ra)); - dec = math::wrap_radians(math::radians(dec)); - - // Transform spherical equatorial coordinates to rectangular equatorial coordinates - double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra}); - - // Transform coordinates from equatorial space to inertial space - physics::frame bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse(); - double3 position_inertial = bci_to_inertial * position_bci; - - // Convert color index to color temperature - double cct = color::index::bv_to_cct(bv_color); - - // Calculate XYZ color from color temperature - double3 color_xyz = color::cct::to_xyz(cct); - - // Transform XYZ color to ACEScg colorspace - double3 color_acescg = color::xyz::to_acescg(color_xyz); - - // Convert apparent magnitude to irradiance (W/m^2) - double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4)); - - // Convert irradiance to illuminance - double vmag_illuminance = vmag_irradiance * (683.0 * 0.14); - - // Scale color by illuminance - double3 scaled_color = color_acescg * vmag_illuminance; - - // Build vertex - *(star_vertex++) = static_cast(position_inertial.x); - *(star_vertex++) = static_cast(position_inertial.y); - *(star_vertex++) = static_cast(position_inertial.z); - *(star_vertex++) = static_cast(scaled_color.x); - *(star_vertex++) = static_cast(scaled_color.y); - *(star_vertex++) = static_cast(scaled_color.z); - } - - // Unload star catalog - resource_manager->unload("stars.csv"); - - // Create star catalog VBO - star_catalog_vbo = new gl::vertex_buffer(star_count * star_vertex_stride, star_vertex_data); - - // Create star catalog VAO - star_catalog_vao = new gl::vertex_array(); - - // Bind star catalog vertex attributes - std::size_t vao_offset = 0; - star_catalog_vao->bind_attribute(VERTEX_POSITION_LOCATION, *star_catalog_vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, 0); - vao_offset += 3; - star_catalog_vao->bind_attribute(VERTEX_COLOR_LOCATION, *star_catalog_vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, sizeof(float) * vao_offset); - - // Free star catalog vertex data - delete[] star_vertex_data; - - // Load star shader - star_shader_program = resource_manager->load("star.glsl"); - star_model_view_input = star_shader_program->get_input("model_view"); - star_projection_input = star_shader_program->get_input("projection"); - star_distance_input = star_shader_program->get_input("star_distance"); - star_exposure_input = star_shader_program->get_input("camera.exposure"); -} +{} sky_pass::~sky_pass() {} @@ -258,6 +164,31 @@ void sky_pass::render(render_context* context) const //glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_ONE, GL_ONE); + // Draw stars + if (stars_model) + { + float star_distance = (clip_near + clip_far) * 0.5f; + + model = math::resize<4, 4>(math::matrix_cast(topocentric_frame.rotation)); + model = math::scale(model, {star_distance, star_distance, star_distance}); + + model_view = view * model; + + rasterizer->use_program(*star_shader_program); + if (star_model_view_input) + star_model_view_input->upload(model_view); + if (star_projection_input) + star_projection_input->upload(projection); + if (star_distance_input) + star_distance_input->upload(star_distance); + if (star_exposure_input) + star_exposure_input->upload(exposure); + + star_material->upload(context->alpha); + + rasterizer->draw_arrays(*stars_model_vao, stars_model_drawing_mode, stars_model_start_index, stars_model_index_count); + } + // Draw moon model /* float3 moon_position = {0, 0, 0}; @@ -292,27 +223,7 @@ void sky_pass::render(render_context* context) const } */ - // Draw stars - { - float star_distance = (clip_near + clip_far) * 0.5f; - - model = math::resize<4, 4>(math::matrix_cast(topocentric_frame.rotation)); - model = math::scale(model, {star_distance, star_distance, star_distance}); - - model_view = view * model; - - rasterizer->use_program(*star_shader_program); - if (star_model_view_input) - star_model_view_input->upload(model_view); - if (star_projection_input) - star_projection_input->upload(projection); - if (star_distance_input) - star_distance_input->upload(star_distance); - if (star_exposure_input) - star_exposure_input->upload(exposure); - - rasterizer->draw_arrays(*star_catalog_vao, gl::drawing_mode::points, 0, star_count); - } + } void sky_pass::set_sky_model(const model* model) @@ -398,6 +309,42 @@ void sky_pass::set_moon_model(const model* model) } } +void sky_pass::set_stars_model(const model* model) +{ + stars_model = model; + + if (stars_model) + { + stars_model_vao = model->get_vertex_array(); + + const std::vector& groups = *model->get_groups(); + for (model_group* group: groups) + { + star_material = group->get_material(); + stars_model_drawing_mode = group->get_drawing_mode(); + stars_model_start_index = group->get_start_index(); + stars_model_index_count = group->get_index_count(); + } + + if (star_material) + { + star_shader_program = star_material->get_shader_program(); + + if (star_shader_program) + { + star_model_view_input = star_shader_program->get_input("model_view"); + star_projection_input = star_shader_program->get_input("projection"); + star_distance_input = star_shader_program->get_input("star_distance"); + star_exposure_input = star_shader_program->get_input("camera.exposure"); + } + } + } + else + { + stars_model = nullptr; + } +} + void sky_pass::update_tweens() { observer_altitude_tween.update(); diff --git a/src/renderer/passes/sky-pass.hpp b/src/renderer/passes/sky-pass.hpp index cac2e63..34b80f9 100644 --- a/src/renderer/passes/sky-pass.hpp +++ b/src/renderer/passes/sky-pass.hpp @@ -55,6 +55,7 @@ public: void set_sky_model(const model* model); void set_time_tween(const tween* time); void set_moon_model(const model* model); + void set_stars_model(const model* model); void set_topocentric_frame(const physics::frame& frame); @@ -76,7 +77,6 @@ private: const gl::shader_input* resolution_input; const gl::shader_input* time_input; const gl::shader_input* exposure_input; - const gl::shader_input* observer_altitude_input; const gl::shader_input* sun_direction_input; const gl::shader_input* sun_color_input; @@ -93,15 +93,6 @@ private: const gl::shader_input* moon_moon_position_input; const gl::shader_input* moon_sun_position_input; - gl::vertex_buffer* star_catalog_vbo; - gl::vertex_array* star_catalog_vao; - gl::shader_program* star_shader_program; - const gl::shader_input* star_model_view_input; - const gl::shader_input* star_projection_input; - const gl::shader_input* star_exposure_input; - const gl::shader_input* star_distance_input; - std::size_t star_count; - const model* sky_model; const material* sky_material; const gl::vertex_array* sky_model_vao; @@ -115,6 +106,18 @@ private: gl::drawing_mode moon_model_drawing_mode; std::size_t moon_model_start_index; std::size_t moon_model_index_count; + + const model* stars_model; + const material* star_material; + const gl::vertex_array* stars_model_vao; + gl::drawing_mode stars_model_drawing_mode; + std::size_t stars_model_start_index; + std::size_t stars_model_index_count; + gl::shader_program* star_shader_program; + const gl::shader_input* star_model_view_input; + const gl::shader_input* star_projection_input; + const gl::shader_input* star_exposure_input; + const gl::shader_input* star_distance_input; const gl::texture_2d* blue_noise_map; const gl::texture_2d* sky_gradient; diff --git a/src/resources/material-loader.cpp b/src/resources/material-loader.cpp index a56b96b..444068b 100644 --- a/src/resources/material-loader.cpp +++ b/src/resources/material-loader.cpp @@ -400,5 +400,8 @@ material* resource_loader::load(resource_manager* resource_manager, PH } } + // Update material tweens + material->update_tweens(); + return material; }