diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-08-26 17:43:58 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 12:01:05 +0100 |
commit | 2d6a916835bd851b2ea03a2e887ba83f0065dae4 (patch) | |
tree | 25542172b4275da52396b40033d8e77f7e2ce64c /servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp | |
parent | f7aa7927e7268f7b9f99eed18e13dd04e25be8b2 (diff) |
Environment sky more or less working.
Diffstat (limited to 'servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp')
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp | 391 |
1 files changed, 390 insertions, 1 deletions
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index 26598b70a4..ab63cd9343 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -1,4 +1,366 @@ #include "rasterizer_scene_rd.h" +#include "core/project_settings.h" + +RID RasterizerSceneRD::sky_create() { + return sky_owner.make_rid(Sky()); +} + +void RasterizerSceneRD::_sky_invalidate(Sky *p_sky) { + if (!p_sky->dirty) { + p_sky->dirty = true; + p_sky->dirty_list = dirty_sky_list; + dirty_sky_list = p_sky; + } +} + +void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { + Sky *sky = sky_owner.getornull(p_sky); + ERR_FAIL_COND(!sky); + ERR_FAIL_COND(p_radiance_size < 32 || p_radiance_size > 2048); + if (sky->radiance_size == p_radiance_size) { + return; + } + sky->radiance_size = p_radiance_size; + _sky_invalidate(sky); + if (sky->radiance.is_valid()) { + //if size changes, everything must be cleared + RD::get_singleton()->free(sky->radiance); + //everything else gets dependency, erase, so just clean it up + sky->radiance = RID(); + sky->layers.clear(); + sky->radiance_base_cubemap = RID(); + } +} + +void RasterizerSceneRD::sky_set_mode(RID p_sky, VS::SkyMode p_mode) { + Sky *sky = sky_owner.getornull(p_sky); + ERR_FAIL_COND(!sky); + + if (sky->mode == p_mode) { + return; + } + + sky->mode = p_mode; + _sky_invalidate(sky); +} + +void RasterizerSceneRD::sky_set_texture(RID p_sky, RID p_panorama) { + + Sky *sky = sky_owner.getornull(p_sky); + ERR_FAIL_COND(!sky); + + if (sky->panorama.is_valid()) { + sky->panorama = RID(); + RD::get_singleton()->free(sky->radiance); + sky->radiance = RID(); + } + + sky->panorama = p_panorama; + + if (!sky->panorama.is_valid()) + return; //cleared + + _sky_invalidate(sky); +} +void RasterizerSceneRD::_update_dirty_skys() { + + Sky *sky = dirty_sky_list; + + while (sky) { + + //update sky configuration if texture is missing + + if (sky->radiance.is_null()) { + //recreate radiance and all data + int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; + if (sky->mode == VS::SKY_MODE_REALTIME) { + //use less mipmaps + mipmaps = MIN(8, mipmaps); + } + + uint32_t w = sky->radiance_size, h = sky->radiance_size; + + if (sky_use_cubemap_array) { + //array (higher quality, 6 times more memory) + RD::TextureFormat tf; + tf.array_layers = roughness_layers * 6; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.mipmaps = mipmaps; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + for (int i = 0; i < roughness_layers; i++) { + Sky::Layer layer; + uint32_t mmw = w; + uint32_t mmh = h; + layer.mipmaps.resize(mipmaps); + for (int j = 0; j < mipmaps; j++) { + Sky::Layer::Mipmap &mm = layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sky->radiance, i * 6 + k, j); + Vector<RID> fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + + mmw = MAX(1, mmw >> 1); + mmh = MAX(1, mmh >> 1); + } + + sky->layers.push_back(layer); + } + + } else { + //regular cubemap, lower quality (aliasing, less memory) + RD::TextureFormat tf; + tf.array_layers = 6; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE; + tf.mipmaps = roughness_layers; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Sky::Layer layer; + uint32_t mmw = w; + uint32_t mmh = h; + layer.mipmaps.resize(roughness_layers); + for (int j = 0; j < roughness_layers; j++) { + Sky::Layer::Mipmap &mm = layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sky->radiance, k, j); + Vector<RID> fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + + mmw = MAX(1, mmw >> 1); + mmh = MAX(1, mmh >> 1); + } + + sky->layers.push_back(layer); + } + + sky->radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sky->radiance, 0, 0, RD::TEXTURE_SLICE_CUBEMAP); + } + + RID panorama_texture = storage->texture_get_rd_texture(sky->panorama); + + if (panorama_texture.is_valid()) { + //is there a panorama texture? + + if (sky_use_cubemap_array) { + + if (sky->mode == VS::SKY_MODE_QUALITY) { + //render directly to the layers + for (int i = 0; i < sky->layers.size(); i++) { + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[i].mipmaps[0].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (sky->layers.size() - 1.0)); + } + } + } else if (sky->mode == VS::SKY_MODE_REALTIME) { + //render to first mipmap + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[0].framebuffers[j], j, sky_ggx_samples_realtime, 0.0); + } + //do the rest in other mipmaps and use cubemap itself as source + for (int i = 1; i < roughness_layers; i++) { + //render using a smaller mipmap, then copy to main layer + for (int j = 0; j < 6; j++) { + //storage->get_effects()->cubemap_roughness(sky->radiance_base_cubemap, false, sky->layers[0].mipmaps[i].framebuffers[0], j, sky_ggx_samples_realtime, float(i) / (sky->layers.size() - 1.0)); + storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[i].framebuffers[0], j, sky_ggx_samples_realtime, float(i) / (sky->layers.size() - 1.0)); + storage->get_effects()->copy(sky->layers[0].mipmaps[i].views[0], sky->layers[i].mipmaps[0].framebuffers[j], Rect2()); + } + } + } + + //generate mipmaps + + for (int i = 0; i < sky->layers.size(); i++) { + for (int j = 0; j < sky->layers[i].mipmaps.size() - 1; j++) { + for (int k = 0; k < 6; k++) { + RID view = sky->layers[i].mipmaps[j].views[k]; + RID fb = sky->layers[i].mipmaps[j + 1].framebuffers[k]; + Vector2 size = sky->layers[i].mipmaps[j].size; + size = Vector2(1.0 / size.x, 1.0 / size.y); + storage->get_effects()->make_mipmap(view, fb, size); + } + } + } + } else { + + if (sky->mode == VS::SKY_MODE_QUALITY) { + //render directly to the layers + for (int i = 0; i < sky->layers[0].mipmaps.size(); i++) { + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (sky->layers[0].mipmaps.size() - 1.0)); + } + } + } else { + + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[0].framebuffers[j], j, sky_ggx_samples_realtime, 0); + } + + for (int i = 1; i < sky->layers[0].mipmaps.size(); i++) { + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(sky->radiance_base_cubemap, false, sky->layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_realtime, float(i) / (sky->layers[0].mipmaps.size() - 1.0)); + } + } + } + } + } + + Sky *next = sky->dirty_list; + sky->dirty_list = nullptr; + sky->dirty = false; + sky = next; + } + + dirty_sky_list = nullptr; +} + +RID RasterizerSceneRD::sky_get_panorama_texture_rd(RID p_sky) const { + + Sky *sky = sky_owner.getornull(p_sky); + ERR_FAIL_COND_V(!sky, RID()); + if (sky->panorama.is_null()) { + return RID(); + } + + return storage->texture_get_rd_texture(sky->panorama, true); +} +RID RasterizerSceneRD::sky_get_radiance_texture_rd(RID p_sky) const { + Sky *sky = sky_owner.getornull(p_sky); + ERR_FAIL_COND_V(!sky, RID()); + + return sky->radiance; +} + +RID RasterizerSceneRD::environment_create() { + + return environment_owner.make_rid(Environent()); +} + +void RasterizerSceneRD::environment_set_background(RID p_env, VS::EnvironmentBG p_bg) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->background = p_bg; +} +void RasterizerSceneRD::environment_set_sky(RID p_env, RID p_sky) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->sky = p_sky; +} +void RasterizerSceneRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->sky_custom_fov = p_scale; +} +void RasterizerSceneRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->sky_orientation = p_orientation; +} +void RasterizerSceneRD::environment_set_bg_color(RID p_env, const Color &p_color) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->bg_color = p_color; +} +void RasterizerSceneRD::environment_set_bg_energy(RID p_env, float p_energy) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->bg_energy = p_energy; +} +void RasterizerSceneRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->canvas_max_layer = p_max_layer; +} +void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_color, VS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, VS::EnvironmentReflectionSource p_reflection_source) { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->ambient_light = p_color; + env->ambient_source = p_ambient; + env->ambient_light_energy = p_energy; + env->ambient_sky_contribution = p_sky_contribution; + env->reflection_source = p_reflection_source; +} + +VS::EnvironmentBG RasterizerSceneRD::environment_get_background(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, VS::ENV_BG_MAX); + return env->background; +} +RID RasterizerSceneRD::environment_get_sky(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, RID()); + return env->sky; +} +float RasterizerSceneRD::environment_get_sky_custom_fov(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, 0); + return env->sky_custom_fov; +} +Basis RasterizerSceneRD::environment_get_sky_orientation(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, Basis()); + return env->sky_orientation; +} +Color RasterizerSceneRD::environment_get_bg_color(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, Color()); + return env->bg_color; +} +float RasterizerSceneRD::environment_get_bg_energy(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, 0); + return env->bg_energy; +} +int RasterizerSceneRD::environment_get_canvas_max_layer(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, 0); + return env->canvas_max_layer; +} +Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, Color()); + return env->ambient_light; +} +VS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_light_ambient_source(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, VS::ENV_AMBIENT_SOURCE_BG); + return env->ambient_source; +} +float RasterizerSceneRD::environment_get_ambient_light_ambient_energy(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, 0); + return env->ambient_light_energy; +} +float RasterizerSceneRD::environment_get_ambient_sky_contribution(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, 0); + return env->ambient_sky_contribution; +} +VS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_source(RID p_env) const { + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, VS::ENV_REFLECTION_SOURCE_DISABLED); + return env->reflection_source; +} + +bool RasterizerSceneRD::is_environment(RID p_env) const { + return environment_owner.owns(p_env); +} RID RasterizerSceneRD::render_buffers_create() { RenderBuffers rb; @@ -16,6 +378,14 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren rb->data->configure(p_render_target, p_width, p_height, p_msaa); } +int RasterizerSceneRD::get_roughness_layers() const { + return roughness_layers; +} + +bool RasterizerSceneRD::is_using_radiance_cubemap_array() const { + return sky_use_cubemap_array; +} + void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -30,6 +400,14 @@ bool RasterizerSceneRD::free(RID p_rid) { RenderBuffers *rb = render_buffers_owner.getornull(p_rid); memdelete(rb->data); render_buffers_owner.free(p_rid); + } else if (environment_owner.owns(p_rid)) { + //not much to delete, just free it + environment_owner.free(p_rid); + } else if (sky_owner.owns(p_rid)) { + _update_dirty_skys(); + Sky *sky = sky_owner.getornull(p_rid); + RD::get_singleton()->free(sky->radiance); //free radiance, everything else gets dependency-erased + sky_owner.free(p_rid); } else { return false; } @@ -37,5 +415,16 @@ bool RasterizerSceneRD::free(RID p_rid) { return true; } -RasterizerSceneRD::RasterizerSceneRD() { +void RasterizerSceneRD::update() { + _update_dirty_skys(); +} + +RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { + storage = p_storage; + + roughness_layers = GLOBAL_GET("rendering/quality/reflections/roughness_layers"); + sky_ggx_samples_quality = GLOBAL_GET("rendering/quality/reflections/ggx_samples"); + sky_ggx_samples_realtime = GLOBAL_GET("rendering/quality/reflections/ggx_samples_realtime"); + sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); + sky_use_cubemap_array = false; } |