15#define ANONYMOUS anonymous
21typedef bx::Vec3
Color;
24class dynamic_value_controller
26 using value_type =
Color;
27 using key_map = std::map<float, value_type>;
30 dynamic_value_controller(
const key_map& keymap) : key_map_(keymap)
34 value_type get_value(
float time)
const
36 auto itUpper = key_map_.upper_bound(time + 1e-6f);
37 auto itLower = itUpper;
40 if(itLower == key_map_.end())
42 return itUpper->second;
45 if(itUpper == key_map_.end())
47 return itLower->second;
50 float lowerTime = itLower->first;
51 const auto& lowerVal = itLower->second;
52 float upperTime = itUpper->first;
53 const auto& upperVal = itUpper->second;
55 if(lowerTime == upperTime)
60 return interpolate(lowerTime, lowerVal, upperTime, upperVal, time);
64 value_type interpolate(
float lowerTime,
65 const value_type& lowerVal,
67 const value_type& upperVal,
70 const float tt = (time - lowerTime) / (upperTime - lowerTime);
71 const auto result = bx::lerp(lowerVal, upperVal, tt);
75 const key_map& key_map_;
79static constexpr float M_XYZ2RGB[] = {
94 Color rgb(bx::InitNone);
95 rgb.x = M_XYZ2RGB[0] * xyz.x + M_XYZ2RGB[3] * xyz.y + M_XYZ2RGB[6] * xyz.z;
96 rgb.y = M_XYZ2RGB[1] * xyz.x + M_XYZ2RGB[4] * xyz.y + M_XYZ2RGB[7] * xyz.z;
97 rgb.z = M_XYZ2RGB[2] * xyz.x + M_XYZ2RGB[5] * xyz.y + M_XYZ2RGB[8] * xyz.z;
105static std::map<float, Color> sunLuminanceXYZTable = {
106 {5.0f, {0.000000f, 0.000000f, 0.000000f}},
107 {7.0f, {12.703322f, 12.989393f, 9.100411f}},
108 {8.0f, {13.202644f, 13.597814f, 11.524929f}},
109 {9.0f, {13.192974f, 13.597458f, 12.264488f}},
110 {10.0f, {13.132943f, 13.535914f, 12.560032f}},
111 {11.0f, {13.088722f, 13.489535f, 12.692996f}},
112 {12.0f, {13.067827f, 13.467483f, 12.745179f}},
113 {13.0f, {13.069653f, 13.469413f, 12.740822f}},
114 {14.0f, {13.094319f, 13.495428f, 12.678066f}},
115 {15.0f, {13.142133f, 13.545483f, 12.526785f}},
116 {16.0f, {13.201734f, 13.606017f, 12.188001f}},
117 {17.0f, {13.182774f, 13.572725f, 11.311157f}},
118 {18.0f, {12.448635f, 12.672520f, 8.267771f}},
119 {20.0f, {0.000000f, 0.000000f, 0.000000f}},
127static std::map<float, Color> skyLuminanceXYZTable = {
128 {0.0f, bx::mul({0.308f, 0.308f, 0.411f}, 0.0f)},
132 {4.0f, bx::mul({0.258f, 0.258f, 0.344f}, 0.05f)},
133 {5.0f, {0.258f, 0.258f, 0.344f}},
134 {7.0f, {0.962851f, 1.000000f, 1.747835f}},
135 {8.0f, {0.967787f, 1.000000f, 1.776762f}},
136 {9.0f, {0.970173f, 1.000000f, 1.788413f}},
137 {10.0f, {0.971431f, 1.000000f, 1.794102f}},
138 {11.0f, {0.972099f, 1.000000f, 1.797096f}},
139 {12.0f, {0.972385f, 1.000000f, 1.798389f}},
140 {13.0f, {0.972361f, 1.000000f, 1.798278f}},
141 {14.0f, {0.972020f, 1.000000f, 1.796740f}},
142 {15.0f, {0.971275f, 1.000000f, 1.793407f}},
143 {16.0f, {0.969885f, 1.000000f, 1.787078f}},
144 {17.0f, {0.967216f, 1.000000f, 1.773758f}},
145 {18.0f, {0.961668f, 1.000000f, 1.739891f}},
146 {20.0f, {0.264f, 0.264f, 0.352f}},
147 {21.0f, bx::mul({0.264f, 0.264f, 0.352f}, 0.05f)},
149 {23.0f, bx::mul({0.308f, 0.308f, 0.411f}, 0.0f)},
150 {24.0f, bx::mul({0.308f, 0.308f, 0.411f}, 0.0f)},
156static constexpr Color ABCDE[] = {
157 {-0.2592f, -0.2608f, -1.4630f},
158 {0.0008f, 0.0092f, 0.4275f},
159 {0.2125f, 0.2102f, 5.3251f},
160 {-0.8989f, -1.6537f, -2.5771f},
161 {0.0452f, 0.0529f, 0.3703f},
164static constexpr Color ABCDE_t[] = {
165 {-0.0193f, -0.0167f, 0.1787f},
166 {-0.0665f, -0.0950f, -0.3554f},
167 {-0.0004f, -0.0079f, -0.0227f},
168 {-0.0641f, -0.0441f, 0.1206f},
169 {-0.0033f, -0.0109f, -0.0670f},
172void compute_perez_coeff(
float _turbidity,
float* _outPerezCoeff)
174 const bx::Vec3 turbidity = {_turbidity, _turbidity, _turbidity};
175 for(uint32_t ii = 0; ii < 5; ++ii)
177 const bx::Vec3 tmp = bx::mad(ABCDE_t[ii], turbidity, ABCDE[ii]);
178 float* out = _outPerezCoeff + 4 * ii;
184float hour_of_day(math::vec3 sun_dir)
187 math::vec3
normal(0.0, -1.0, 0.0);
191 auto ref = math::vec3(-1.0f, 0.0f, 0.0f);
193 float angle = math::orientedAngle(v1, v2, ref);
194 angle = math::mod(angle, 2 * math::pi<float>());
195 angle = math::degrees(angle);
198 float hour_of_day = angle / 15;
216 auto fs_sky = am.get_asset<
gfx::shader>(
"engine:/data/shaders/atmospherics/fs_sky.sc");
217 auto fs_cloud = am.get_asset<
gfx::shader>(
"engine:/data/shaders/atmospherics/fs_cloud.sc");
219 atmospheric_program_.program = std::make_unique<gpu_program>(vs_sky, fs_sky);
220 atmospheric_program_.cache_uniforms();
222 cloud_program_.program = std::make_unique<gpu_program>(vs_sky, fs_cloud);
223 cloud_program_.cache_uniforms();
225 int vertical_count = 32;
226 int horizontal_count = 32;
227 std::vector<gfx::screen_pos_vertex> vertices(vertical_count * horizontal_count);
229 for(
int i = 0; i < vertical_count; i++)
231 for(
int j = 0; j < horizontal_count; j++)
234 v.
x = float(j) / (horizontal_count - 1) * 2.0f - 1.0f;
235 v.y = float(i) / (vertical_count - 1) * 2.0f - 1.0f;
239 std::vector<uint16_t>
indices((vertical_count - 1) * (horizontal_count - 1) * 6);
242 for(
int i = 0; i < vertical_count - 1; i++)
244 for(
int j = 0; j < horizontal_count - 1; j++)
246 indices[k++] = (uint16_t)(j + 0 + horizontal_count * (i + 0));
247 indices[k++] = (uint16_t)(j + 1 + horizontal_count * (i + 0));
248 indices[k++] = (uint16_t)(j + 0 + horizontal_count * (i + 1));
250 indices[k++] = (uint16_t)(j + 1 + horizontal_count * (i + 0));
251 indices[k++] = (uint16_t)(j + 1 + horizontal_count * (i + 1));
252 indices[k++] = (uint16_t)(j + 0 + horizontal_count * (i + 1));
256 vb_ = std::make_unique<gfx::vertex_buffer>(
259 ib_ = std::make_unique<gfx::index_buffer>(
gfx::copy(
indices.data(),
sizeof(uint16_t) * k));
275 const auto surface =
input.get();
276 const auto output_size = surface->get_size();
283 float exposition[4] = {0.02f, 3.0f, perez.
exposition, hour};
299 if(params.
cloud_mode == 2 && cloud_program_.program && cloud_program_.program->is_valid())
301 uint32_t half_w = output_size.width / 2;
302 uint32_t half_h = output_size.height / 2;
303 if(half_w < 1) half_w = 1;
304 if(half_h < 1) half_h = 1;
306 constexpr uint64_t cloud_tex_flags = BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP;
311 float prev_cloud_time{};
312 std::memcpy(&prev_cloud_time, &prev_cloud_time_bits,
sizeof(
float));
313 float cloud_time_delta = params.
cloud_time - prev_cloud_time;
314 uint32_t cur_time_bits{};
315 std::memcpy(&cur_time_bits, ¶ms.
cloud_time,
sizeof(
float));
316 prev_cloud_time_bits = cur_time_bits;
322 cloud_tex_a = std::make_shared<gfx::texture>(half_w, half_h,
false, 1,
323 gfx::texture_format::RGBA16F, cloud_tex_flags);
324 cloud_frame_count = 0;
331 cloud_tex_b = std::make_shared<gfx::texture>(half_w, half_h,
false, 1,
332 gfx::texture_format::RGBA16F, cloud_tex_flags);
333 cloud_frame_count = 0;
336 uint32_t cur = cloud_frame_count & 1;
337 auto& current_tex = (cur == 0) ? cloud_tex_a : cloud_tex_b;
338 auto& history_tex = (cur == 0) ? cloud_tex_b : cloud_tex_a;
344 cloud_fbo_a = std::make_shared<gfx::frame_buffer>();
345 cloud_fbo_a->populate({cloud_tex_a});
352 cloud_fbo_b = std::make_shared<gfx::frame_buffer>();
353 cloud_fbo_b->populate({cloud_tex_b});
356 auto& current_fbo = (cur == 0) ? cloud_fbo_a : cloud_fbo_b;
359 cloud_pass.
bind(current_fbo.get());
361 cloud_pass.
clear(BGFX_CLEAR_COLOR, 0x000000FF, 0.0f, 0);
363 cloud_program_.program->begin();
376 float cloud_frame[4] = {float(
gfx::get_render_frame()), float(cloud_frame_count), cloud_time_delta, 0.0f};
382 if(cloud_noise.base_noise)
384 gfx::set_texture(cloud_program_.s_cloudNoise, 0, cloud_noise.base_noise.get());
388 irect32_t cloud_rect(0, 0, half_w, half_h);
394 gfx::submit(cloud_pass.
id, cloud_program_.program->native_handle());
397 cloud_program_.program->end();
407 if(atmospheric_program_.program->is_valid())
409 atmospheric_program_.program->begin();
420 auto cloud_frame_count = rview.
data_get(
"CLOUD_FRAME_COUNT");
421 uint32_t prev = (cloud_frame_count - 1) & 1;
422 const auto& cloud_tex = rview.
tex_safe_get(prev == 0 ?
"CLOUD_PING" :
"CLOUD_PONG");
428 if(cloud_noise.flat_noise)
430 gfx::set_texture(atmospheric_program_.s_cloudNoise2D, 1, cloud_noise.flat_noise.get());
436 gfx::set_state(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_DEPTH_TEST_EQUAL);
439 gfx::submit(pass.
id, atmospheric_program_.program->native_handle());
442 atmospheric_program_.program->end();
449 math::vec3& out_sky_luminance_rgb,
450 math::vec3& out_sun_luminance_rgb)
452 auto hour = ANONYMOUS::hour_of_day(-light_direction);
453 ANONYMOUS::dynamic_value_controller sun_luminance_dc(ANONYMOUS::sunLuminanceXYZTable);
454 ANONYMOUS::dynamic_value_controller sky_luminance_dc(ANONYMOUS::skyLuminanceXYZTable);
455 auto sunLuminanceXYZ = sun_luminance_dc.get_value(hour);
456 auto sunLuminanceRGB = ANONYMOUS::xyzToRgb(sunLuminanceXYZ);
457 out_sun_luminance_rgb = math::vec3(sunLuminanceRGB.x, sunLuminanceRGB.y, sunLuminanceRGB.z);
458 auto skyLuminanceXYZ = sky_luminance_dc.get_value(hour);
459 auto skyLuminanceRGB = ANONYMOUS::xyzToRgb(skyLuminanceXYZ);
460 out_sky_luminance_rgb = math::vec3(skyLuminanceRGB.x, skyLuminanceRGB.y, skyLuminanceRGB.z);
467 math::vec3 sun_dir(-light_direction.x, -light_direction.y, -light_direction.z);
468 sun_dir = math::normalize(sun_dir);
470 auto hour = ANONYMOUS::hour_of_day(-light_direction);
471 ANONYMOUS::dynamic_value_controller sun_luminance_dc(ANONYMOUS::sunLuminanceXYZTable);
472 ANONYMOUS::dynamic_value_controller sky_luminance_dc(ANONYMOUS::skyLuminanceXYZTable);
473 auto sunLuminanceXYZ = sun_luminance_dc.get_value(hour);
474 auto sunLuminanceRGB = ANONYMOUS::xyzToRgb(sunLuminanceXYZ);
475 out.sun_luminance_rgb = math::vec3(sunLuminanceRGB.x, sunLuminanceRGB.y, sunLuminanceRGB.z);
477 auto skyLuminanceXYZ = sky_luminance_dc.get_value(hour);
478 out.sky_luminance_xyz =
479 math::vec3(skyLuminanceXYZ.x, skyLuminanceXYZ.y, skyLuminanceXYZ.z);
480 auto skyLuminanceRGB = ANONYMOUS::xyzToRgb(skyLuminanceXYZ);
481 out.sky_luminance_rgb = math::vec3(skyLuminanceRGB.x, skyLuminanceRGB.y, skyLuminanceRGB.z);
483 out.sun_direction = sun_dir;
485 float sun_altitude = sun_dir.y;
487 float altitude_factor = bx::lerp(0.6f, 1.0f, bx::clamp(bx::abs(sun_altitude), 0.0f, 1.0f));
488 out.exposition = 0.1f * altitude_factor;
490 ANONYMOUS::compute_perez_coeff(turbidity, &out.perez_coeff[0][0]);
std::shared_ptr< frame_buffer > ptr
auto data_get(const hpp::string_view &id, uint32_t default_val=0) const -> uint32_t
auto fbo_get_or_emplace(const hpp::string_view &id) -> frame_buffer::ptr &
auto tex_safe_get(const hpp::string_view &id) const -> const texture::ptr &
auto tex_get_or_emplace(const hpp::string_view &id) -> texture::ptr &
auto data_get_or_emplace(const hpp::string_view &id, uint32_t default_val=0) -> uint32_t &
Manages assets, including loading, unloading, and storage.
auto get_asset(const std::string &key, load_flags flags=load_flags::standard, load_mode mode=load_mode::immediate) -> asset_handle< T >
Gets an asset by its key.
auto init(rtti::context &ctx) -> bool
~atmospheric_pass_perez()
void run(gfx::frame_buffer::ptr input, const camera &camera, gfx::render_view &rview, delta_t dt, const run_params ¶ms)
Class representing a camera. Contains functionality for manipulating and updating a camera....
auto get_projection() const -> const math::transform &
Retrieves the current projection matrix.
auto get_prev_view_projection_relative() const -> math::transform
auto get_view_relative() const -> const math::transform &
static auto get() -> default_textures &
std::chrono::duration< float > delta_t
void submit(view_id _id, program_handle _handle, int32_t _depth, bool _preserveState)
uint16_t set_scissor(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
void set_state(uint64_t _state, uint32_t _rgba)
auto needs_recreate(const gfx::frame_buffer::ptr &fbo, const usize32_t &size) -> bool
void set_vertex_buffer(uint8_t _stream, vertex_buffer_handle _handle)
void discard(uint8_t _flags)
const memory_view * copy(const void *_data, uint32_t _size)
void set_uniform(uniform_handle _handle, const void *_value, uint16_t _num)
void set_index_buffer(index_buffer_handle _handle)
uint32_t get_render_frame()
void set_texture(uint8_t _stage, uniform_handle _sampler, texture_handle _handle, uint32_t _flags)
void compute_perez_luminance(const math::vec3 &light_direction, math::vec3 &out_sky_luminance_rgb, math::vec3 &out_sun_luminance_rgb)
Computes Perez sky and sun luminance from light direction (time-of-day). Uses the same tables as the ...
void compute_irradiance_perez_params(const math::vec3 &light_direction, float turbidity, irradiance_perez_params &out)
std::vector< uint32_t > indices
void set_view_proj(const float *v, const float *p)
void clear(uint16_t _flags, uint32_t _rgba=0x000000ff, float _depth=1.0f, uint8_t _stencil=0) const
void bind(const frame_buffer *fb=nullptr) const
static auto get_layout() -> const vertex_layout &
float cloud_vol_coarse_scale
float cloud_vol_edge_width
float cloud_vol_uv_scale
Volumetric cloud u_cloudParams3: uv scale, edge width, shape power, detail erode.
float cloud_density
Cloud density/opacity multiplier.
float cloud_absorption
Beer-Lambert extinction coefficient [0.01-0.5].
float cloud_vol_sun_intensity
float cloud_light_absorption
Light absorption / self-shadow strength [0.01-0.5].
float cloud_vol_macro_strength
Volumetric cloud u_cloudParams4: macro strength, coarse scale, base mix, sun intensity.
float cloud_vol_detail_erode
float cloud_top_altitude
Cloud top altitude in world units. Vol: slab top. Flat: ignored.
float cloud_coverage
Cloud coverage [0.0 = clear sky, 1.0 = overcast]. Controls the density threshold.
int cloud_mode
Cloud mode: 0=none, 1=flat, 2=volumetric.
math::vec3 light_direction
float cloud_time
Accumulated elapsed time (seconds) for cloud animation.
float sky_brightness
Sky brightness multiplier (1.0 = neutral). Affects visible sky and irradiance.
float cloud_base_altitude
Cloud base altitude in world units. Vol: slab bottom. Flat: projection height.
float cloud_vol_shape_power
Full Perez params for irradiance SH compute shader (mode 1).
math::vec3 sun_luminance_rgb
math::vec3 sky_luminance_rgb
math::vec3 sky_luminance_xyz