#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 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 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; } void RasterizerSceneRD::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->tone_mapper = p_tone_mapper; env->auto_exposure = p_auto_exposure; env->white = p_white; env->min_luminance = p_min_luminance; env->max_luminance = p_max_luminance; env->auto_exp_speed = p_auto_exp_speed; env->auto_exp_scale = p_auto_exp_scale; } VS::EnvironmentToneMapper RasterizerSceneRD::environment_get_tonemapper(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, VS::ENV_TONE_MAPPER_LINEAR); return env->tone_mapper; } float RasterizerSceneRD::environment_get_exposure(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->exposure; } float RasterizerSceneRD::environment_get_white(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->white; } bool RasterizerSceneRD::environment_get_auto_exposure(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->auto_exposure; } float RasterizerSceneRD::environment_get_min_luminance(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->min_luminance; } float RasterizerSceneRD::environment_get_max_luminance(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->max_luminance; } float RasterizerSceneRD::environment_get_auto_exposure_scale(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->auto_exp_scale; } float RasterizerSceneRD::environment_get_auto_exposure_speed(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->auto_exp_speed; } bool RasterizerSceneRD::is_environment(RID p_env) const { return environment_owner.owns(p_env); } RID RasterizerSceneRD::render_buffers_create() { RenderBuffers rb; rb.data = _create_render_buffer_data(); return render_buffers_owner.make_rid(rb); } void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; rb->render_target = p_render_target; rb->msaa = p_msaa; 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); ERR_FAIL_COND(!rb && p_render_buffers.is_valid()); _render_scene(rb->data, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass); } bool RasterizerSceneRD::free(RID p_rid) { if (render_buffers_owner.owns(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; } return true; } 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; }