summaryrefslogtreecommitdiff
path: root/servers/visual/rasterizer_rd
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2019-10-10 23:14:56 -0300
committerJuan Linietsky <reduzio@gmail.com>2020-02-11 12:03:52 +0100
commit561b431d85314000fe70d42e39713e5da394c3b5 (patch)
treea8260a08943abb9ed38e855a337d770d4d414cdb /servers/visual/rasterizer_rd
parenta95fb114baf6c8deb79073810ad8ea33efd4deb9 (diff)
Dynamic object support for GI Probes (a bit buggy still)
Diffstat (limited to 'servers/visual/rasterizer_rd')
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp74
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h7
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp692
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.h50
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp333
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.h9
-rw-r--r--servers/visual/rasterizer_rd/shaders/SCsub2
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe.glsl425
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl50
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl194
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward.glsl40
11 files changed, 1538 insertions, 338 deletions
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
index 55974846f2..867120db04 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
@@ -308,9 +308,11 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
if (depth_draw == DEPTH_DRAW_OPAQUE) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
}
- } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS)) {
+ } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
//none, blend state contains nothing
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
} else {
blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
}
@@ -326,6 +328,9 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
//none, leave empty
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+
} else {
//specular write
blend_state = blend_state_opaque_specular;
@@ -601,7 +606,7 @@ bool RasterizerSceneForwardRD::free(RID p_rid) {
return false;
}
-void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count) {
+void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth) {
for (int i = 0; i < p_element_count; i++) {
@@ -637,6 +642,10 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements,
}
}
+ if (p_for_depth) {
+ id.gi_offset = 0xFFFFFFFF;
+ continue;
+ }
//forward
uint32_t reflection_count = 0;
@@ -850,6 +859,9 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
} break;
+ case PASS_MODE_DEPTH_MATERIAL: {
+ shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ } break;
}
RenderPipelineVertexFormatCacheRD *pipeline = nullptr;
@@ -939,12 +951,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
}
}
-void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) {
+void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y) {
//CameraMatrix projection = p_cam_projection;
//projection.flip_y(); // Vulkan and modern APIs use Y-Down
CameraMatrix correction;
- correction.set_depth_correction(!p_reflection_probe.is_valid());
+ correction.set_depth_correction(p_flip_y);
CameraMatrix projection = correction * p_cam_projection;
//store camera into ubo
@@ -1236,7 +1248,7 @@ void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_insta
return;
}
- if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+ if (p_pass_mode != PASS_MODE_DEPTH_MATERIAL && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
//shader does not use discard and does not write a vertex position, use generic material
if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) {
p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
@@ -1837,7 +1849,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
_setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
- _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas);
+ _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid());
render_list.clear();
_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
@@ -1896,7 +1908,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
render_list.sort_by_key(false);
- _fill_instances(render_list.elements, render_list.element_count);
+ _fill_instances(render_list.elements, render_list.element_count, false);
bool can_continue = true; //unless the middle buffers are needed
bool debug_giprobes = debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
@@ -1952,7 +1964,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
render_list.sort_by_reverse_depth_and_priority(true);
- _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count);
+ _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false);
{
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
@@ -2087,7 +2099,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
scene_state.ubo.z_far = p_zfar;
scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
- _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID());
+ _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true);
render_list.clear();
@@ -2101,7 +2113,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
render_list.sort_by_key(false);
- _fill_instances(render_list.elements, render_list.element_count);
+ _fill_instances(render_list.elements, render_list.element_count, true);
{
//regular forward for now
@@ -2111,6 +2123,47 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
}
}
+void RasterizerSceneForwardRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering Shadow");
+
+ _update_render_base_uniform_set();
+
+ render_pass++;
+
+ scene_state.ubo.shadow_z_offset = 0;
+ scene_state.ubo.shadow_z_slope_scale = 0;
+ scene_state.ubo.z_far = 0;
+ scene_state.ubo.dual_paraboloid_side = 0;
+
+ _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false);
+
+ render_list.clear();
+
+ PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+ _fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
+
+ _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
+
+ RENDER_TIMESTAMP("Render Material");
+
+ render_list.sort_by_key(false);
+
+ _fill_instances(render_list.elements, render_list.element_count, true);
+
+ {
+ //regular forward for now
+ Vector<Color> clear;
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true);
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
void RasterizerSceneForwardRD::_update_render_base_uniform_set() {
if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || gi_probe_slots_are_dirty()) {
@@ -2425,6 +2478,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_BUFFER\n");
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_ROUGHNESS_BUFFER\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
shader_versions.push_back("");
shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n");
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
index 2d057b5840..6e88a04e6d 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
@@ -45,6 +45,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
SHADER_VERSION_DEPTH_PASS_DP,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_COLOR_PASS,
SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
SHADER_VERSION_VCT_COLOR_PASS,
@@ -519,14 +520,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
PASS_MODE_DEPTH,
PASS_MODE_DEPTH_NORMAL,
PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
+ PASS_MODE_DEPTH_MATERIAL,
};
- void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas);
+ void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y);
void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
void _setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform);
- void _fill_instances(RenderList::Element **p_elements, int p_element_count);
+ void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth);
void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi);
_FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index);
_FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index);
@@ -540,6 +542,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
protected:
virtual void _render_scene(RenderBufferData *p_buffer_data, 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_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip);
+ virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
public:
virtual void set_time(double p_time);
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
index f039bae766..5633a8e2ef 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -1245,7 +1245,7 @@ bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const {
return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
}
-void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances) {
+void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) {
GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
ERR_FAIL_COND(!gi_probe);
@@ -1266,6 +1266,13 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
gi_probe->mipmaps.clear();
}
+ for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
+ RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
+ }
+
+ gi_probe->dynamic_maps.clear();
+
Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
if (octree_size != Vector3i()) {
@@ -1355,6 +1362,21 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
uniforms.push_back(u);
}
{
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
Vector<RD::Uniform> copy_uniforms = uniforms;
if (i == 0) {
{
@@ -1376,13 +1398,6 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
u.ids.push_back(gi_probe->texture);
copy_uniforms.push_back(u);
}
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- copy_uniforms.push_back(u);
- }
if (gi_probe_use_anisotropy) {
{
@@ -1436,138 +1451,579 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
gi_probe->mipmaps.push_back(mipmap);
}
+
+ {
+ uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+ uint32_t oversample = nearest_power_of_2_templated(4);
+ int mipmap_index = 0;
+
+ while (mipmap_index < gi_probe->mipmaps.size()) {
+ GIProbeInstance::DynamicMap dmap;
+
+ if (oversample > 0) {
+ dmap.size = dynamic_map_size * (1 << oversample);
+ dmap.mipmap = -1;
+ oversample--;
+ } else {
+ dmap.size = dynamic_map_size >> mipmap_index;
+ dmap.mipmap = mipmap_index;
+ mipmap_index++;
+ }
+
+ RD::TextureFormat dtf;
+ dtf.width = dmap.size;
+ dtf.height = dmap.size;
+ dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ if (gi_probe->dynamic_maps.size() == 0) {
+ dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+ dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ if (gi_probe->dynamic_maps.size() == 0) {
+ //render depth for first one
+ dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
+ dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ }
+
+ //just use depth as-is
+ dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ if (gi_probe->dynamic_maps.size() == 0) {
+
+ dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ Vector<RID> fb;
+ fb.push_back(dmap.albedo);
+ fb.push_back(dmap.normal);
+ fb.push_back(dmap.orm);
+ fb.push_back(dmap.texture); //emission
+ fb.push_back(dmap.depth);
+ fb.push_back(dmap.fb_depth);
+
+ dmap.fb = RD::get_singleton()->framebuffer_create(fb);
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(gi_probe_lights_uniform);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(dmap.albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(dmap.normal);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.orm);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 8;
+ u.ids.push_back(dmap.fb_depth);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
+ }
+ } else {
+ bool plot = dmap.mipmap >= 0;
+ bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1);
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth);
+ uniforms.push_back(u);
+ }
+
+ if (write) {
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ if (plot) {
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
+ uniforms.push_back(u);
+ }
+ if (gi_probe_is_anisotropic()) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 13;
+ u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[1]);
+ uniforms.push_back(u);
+ }
+ }
+ }
+
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT], 0);
+ }
+
+ gi_probe->dynamic_maps.push_back(dmap);
+ }
+ }
}
gi_probe->last_probe_data_version = data_version;
gi_probe_slots_dirty = true;
+ p_update_light_instances = true; //just in case
}
// UDPDATE TIME
- uint32_t light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
- {
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
- Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
- //update lights
+ if (gi_probe->has_dynamic_object_data) {
+ //if it has dynamic object data, it needs to be cleared
+ RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
+ }
- for (uint32_t i = 0; i < light_count; i++) {
- GIProbeLight &l = gi_probe_lights[i];
- RID light_instance = p_light_instances[i];
- RID light = light_instance_get_base_light(light_instance);
+ uint32_t light_count = 0;
- l.type = storage->light_get_type(light);
- l.attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_ATTENUATION);
- l.energy = storage->light_get_param(light, VS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, VS::LIGHT_PARAM_RANGE), 0, 0)).length();
- Color color = storage->light_get_color(light).to_linear();
- l.color[0] = color.r;
- l.color[1] = color.g;
- l.color[2] = color.b;
+ if (p_update_light_instances || p_dynamic_object_count > 0) {
- l.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ANGLE));
- l.spot_attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ATTENUATION);
+ light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
- Transform xform = light_instance_get_base_transform(light_instance);
+ {
+ Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
+ Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
+ //update lights
- Vector3 pos = to_probe_xform.xform(xform.origin);
- Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
+ for (uint32_t i = 0; i < light_count; i++) {
+ GIProbeLight &l = gi_probe_lights[i];
+ RID light_instance = p_light_instances[i];
+ RID light = light_instance_get_base_light(light_instance);
- l.position[0] = pos.x;
- l.position[1] = pos.y;
- l.position[2] = pos.z;
+ l.type = storage->light_get_type(light);
+ l.attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_ATTENUATION);
+ l.energy = storage->light_get_param(light, VS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, VS::LIGHT_PARAM_INDIRECT_ENERGY);
+ l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, VS::LIGHT_PARAM_RANGE), 0, 0)).length();
+ Color color = storage->light_get_color(light).to_linear();
+ l.color[0] = color.r;
+ l.color[1] = color.g;
+ l.color[2] = color.b;
- l.direction[0] = dir.x;
- l.direction[1] = dir.y;
- l.direction[2] = dir.z;
+ l.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ANGLE));
+ l.spot_attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ATTENUATION);
- l.has_shadow = storage->light_has_shadow(light);
- }
+ Transform xform = light_instance_get_base_transform(light_instance);
+
+ Vector3 pos = to_probe_xform.xform(xform.origin);
+ Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
- RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights, true);
+ l.position[0] = pos.x;
+ l.position[1] = pos.y;
+ l.position[2] = pos.z;
+
+ l.direction[0] = dir.x;
+ l.direction[1] = dir.y;
+ l.direction[2] = dir.z;
+
+ l.has_shadow = storage->light_has_shadow(light);
+ }
+
+ RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights, true);
+ }
}
- // PROCESS MIPMAPS
- if (gi_probe->mipmaps.size()) {
- //can update mipmaps
-
- Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- GIProbePushConstant push_constant;
-
- push_constant.limits[0] = probe_size.x;
- push_constant.limits[1] = probe_size.y;
- push_constant.limits[2] = probe_size.z;
- push_constant.stack_size = gi_probe->mipmaps.size();
- push_constant.emission_scale = 1.0;
- push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.light_count = light_count;
- push_constant.aniso_strength = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
-
- /* print_line("probe update to version " + itos(gi_probe->last_probe_version));
- print_line("propagation " + rtos(push_constant.propagation));
- print_line("dynrange " + rtos(push_constant.dynamic_range));
-*/
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- int passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
- int wg_size = 64;
- int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
-
- for (int pass = 0; pass < passes; pass++) {
-
- for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
- if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
- } else if (i == 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
- }
+ if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) {
+ // PROCESS MIPMAPS
+ if (gi_probe->mipmaps.size()) {
+ //can update mipmaps
+
+ Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
+
+ GIProbePushConstant push_constant;
+
+ push_constant.limits[0] = probe_size.x;
+ push_constant.limits[1] = probe_size.y;
+ push_constant.limits[2] = probe_size.z;
+ push_constant.stack_size = gi_probe->mipmaps.size();
+ push_constant.emission_scale = 1.0;
+ push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
+ push_constant.light_count = light_count;
+ push_constant.aniso_strength = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
+
+ /* print_line("probe update to version " + itos(gi_probe->last_probe_version));
+ print_line("propagation " + rtos(push_constant.propagation));
+ print_line("dynrange " + rtos(push_constant.dynamic_range));
+ */
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ int passes;
+ if (p_update_light_instances) {
+ passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
+ } else {
+ passes = 1; //only re-blitting is necessary
+ }
+ int wg_size = 64;
+ int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
+
+ for (int pass = 0; pass < passes; pass++) {
+
+ if (p_update_light_instances) {
+
+ for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
+ if (i == 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
+ } else if (i == 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
+ }
+
+ if (pass == 1 || i > 0) {
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+ }
+ if (pass == 0 || i > 0) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
+ }
+
+ push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
+ push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+
+ int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
+ while (wg_todo) {
+ int wg_count = MIN(wg_todo, wg_limit_x);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+ wg_todo -= wg_count;
+ push_constant.cell_offset += wg_count * wg_size;
+ }
+ }
- if (pass == 1 || i > 0) {
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
}
- if (pass == 0 || i > 0) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
- } else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+
+ for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
+
+ push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
+ push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+
+ int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
+ while (wg_todo) {
+ int wg_count = MIN(wg_todo, wg_limit_x);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+ wg_todo -= wg_count;
+ push_constant.cell_offset += wg_count * wg_size;
+ }
}
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+ }
- push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
- push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+ gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again
- int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
- while (wg_todo) {
- int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
- wg_todo -= wg_count;
- push_constant.cell_offset += wg_count * wg_size;
+ if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) {
+
+ Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
+ int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+
+ Transform oversample_scale;
+ oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
+
+ Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe);
+ Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse();
+ Transform to_probe_xform = to_world_xform.affine_inverse();
+
+ AABB probe_aabb(Vector3(), octree_size);
+
+ //this could probably be better parallelized in compute..
+ for (int i = 0; i < p_dynamic_object_count; i++) {
+
+ InstanceBase *instance = p_dynamic_objects[i];
+ //not used, so clear
+ instance->depth_layer = 0;
+ instance->depth = 0;
+
+ //transform aabb to giprobe
+ AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb);
+
+ //this needs to wrap to grid resolution to avoid jitter
+ //also extend margin a bit just in case
+ Vector3i begin = aabb.position - Vector3i(1, 1, 1);
+ Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
+
+ for (int j = 0; j < 3; j++) {
+ if ((end[j] - begin[j]) & 1) {
+ end[j]++; //for half extents split, it needs to be even
}
+ begin[j] = MAX(begin[j], 0);
+ end[j] = MIN(end[j], octree_size[j] * multiplier);
}
- RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+ //aabb = aabb.intersection(probe_aabb); //intersect
+ aabb.position = begin;
+ aabb.size = end - begin;
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+ //print_line("aabb: " + aabb);
- for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
+ for (int j = 0; j < 6; j++) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
+ //if (j != 0 && j != 3) {
+ // continue;
+ //}
+ static const Vector3 render_z[6] = {
+ Vector3(1, 0, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(-1, 0, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, -1),
+ };
+ static const Vector3 render_up[6] = {
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ };
+
+ Vector3 render_dir = render_z[j];
+ Vector3 up_dir = render_up[j];
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ Transform xform;
+ xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
+
+ Vector3 x_dir = xform.basis.get_axis(0).abs();
+ int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
+ Vector3 y_dir = xform.basis.get_axis(1).abs();
+ int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
+ Vector3 z_dir = -xform.basis.get_axis(2);
+ int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
+
+ Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
+ bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
+ bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
+ bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
+
+ CameraMatrix cm;
+ cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
+
+ _render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
+
+ GIProbeDynamicPushConstant push_constant;
+ zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant));
+ push_constant.limits[0] = octree_size.x;
+ push_constant.limits[1] = octree_size.y;
+ push_constant.limits[2] = octree_size.z;
+ push_constant.light_count = p_light_instances.size();
+ push_constant.x_dir[0] = x_dir[0];
+ push_constant.x_dir[1] = x_dir[1];
+ push_constant.x_dir[2] = x_dir[2];
+ push_constant.y_dir[0] = y_dir[0];
+ push_constant.y_dir[1] = y_dir[1];
+ push_constant.y_dir[2] = y_dir[2];
+ push_constant.z_dir[0] = z_dir[0];
+ push_constant.z_dir[1] = z_dir[1];
+ push_constant.z_dir[2] = z_dir[2];
+ push_constant.z_base = xform.origin[z_axis];
+ push_constant.z_sign = (z_flip ? -1.0 : 1.0);
+ push_constant.pos_multiplier = float(1.0) / multiplier;
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
+ push_constant.flip_x = x_flip;
+ push_constant.flip_y = y_flip;
+ push_constant.rect_pos[0] = rect.position[0];
+ push_constant.rect_pos[1] = rect.position[1];
+ push_constant.rect_size[0] = rect.size[0];
+ push_constant.rect_size[1] = rect.size[1];
+ push_constant.prev_rect_ofs[0] = 0;
+ push_constant.prev_rect_ofs[1] = 0;
+ push_constant.prev_rect_size[0] = 0;
+ push_constant.prev_rect_size[1] = 0;
+ push_constant.keep_downsample_color = true;
+
+ //process lighting
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
+ //print_line("rect: " + itos(i) + ": " + rect);
+
+ for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) {
+
+ // enlarge the rect if needed so all pixels fit when downscaled,
+ // this ensures downsampling is smooth and optimal because no pixels are left behind
+
+ //x
+ if (rect.position.x & 1) {
+ rect.size.x++;
+ push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
+ } else {
+ push_constant.prev_rect_ofs[0] = 0;
+ }
+ if (rect.size.x & 1) {
+ rect.size.x++;
+ }
- push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
- push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+ rect.position.x >>= 1;
+ rect.size.x = MAX(1, rect.size.x >> 1);
+
+ //y
+ if (rect.position.y & 1) {
+ rect.size.y++;
+ push_constant.prev_rect_ofs[1] = 1;
+ } else {
+ push_constant.prev_rect_ofs[1] = 0;
+ }
+ if (rect.size.y & 1) {
+ rect.size.y++;
+ }
+
+ rect.position.y >>= 1;
+ rect.size.y = MAX(1, rect.size.y >> 1);
+
+ //shrink limits to ensure plot does not go outside map
+ if (gi_probe->dynamic_maps[i].mipmap > 0) {
+ for (int l = 0; l < 3; l++) {
+ push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
+ }
+ }
- int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
- while (wg_todo) {
- int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
- wg_todo -= wg_count;
- push_constant.cell_offset += wg_count * wg_size;
+ //print_line("rect: " + itos(i) + ": " + rect);
+ push_constant.rect_pos[0] = rect.position[0];
+ push_constant.rect_pos[1] = rect.position[1];
+ push_constant.prev_rect_size[0] = push_constant.rect_size[0];
+ push_constant.prev_rect_size[1] = push_constant.rect_size[1];
+ push_constant.rect_size[0] = rect.size[0];
+ push_constant.rect_size[1] = rect.size[1];
+ push_constant.keep_downsample_color = gi_probe->dynamic_maps[i].mipmap <= 0;
+ ;
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (gi_probe->dynamic_maps[k].mipmap < 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
+ } else if (k < gi_probe->dynamic_maps.size() - 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
+ } else {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
}
+
+ RD::get_singleton()->compute_list_end();
}
}
- RD::get_singleton()->compute_list_end();
+ gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again
}
gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
@@ -1584,6 +2040,7 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse());
int level = 0;
+ Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
GIProbeDebugPushConstant push_constant;
push_constant.alpha = p_alpha;
@@ -1591,7 +2048,10 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
push_constant.level = level;
- int cell_count = gi_probe->mipmaps[level].cell_count;
+ push_constant.bounds[0] = octree_size.x >> level;
+ push_constant.bounds[1] = octree_size.y >> level;
+ push_constant.bounds[2] = octree_size.z >> level;
+ push_constant.pad = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
@@ -1643,8 +2103,15 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
}
}
+ int cell_count;
+ if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) {
+ cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
+ } else {
+ cell_count = gi_probe->mipmaps[level].cell_count;
+ }
+
giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? GI_PROBE_DEBUG_LIGHT : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0);
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
@@ -1875,6 +2342,11 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas
}
}
+void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
+
+ _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region);
+}
+
bool RasterizerSceneRD::free(RID p_rid) {
if (render_buffers_owner.owns(p_rid)) {
@@ -1903,6 +2375,11 @@ bool RasterizerSceneRD::free(RID p_rid) {
RD::get_singleton()->free(gi_probe->anisotropy[1]);
}
+ for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
+ RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
+ }
+
gi_probe_slots.write[gi_probe->slot] = RID();
gi_probe_instance_owner.free(p_rid);
@@ -2002,6 +2479,10 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
giprobe_shader.initialize(versions, defines);
giprobe_lighting_shader_version = giprobe_shader.version_create();
@@ -2021,6 +2502,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
versions.push_back("\n#define MODE_DEBUG_COLOR\n");
versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
+ versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
giprobe_debug_shader.initialize(versions, defines);
giprobe_debug_shader_version = giprobe_debug_shader.version_create();
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
index d05c9a9328..4712ad92c9 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
@@ -26,6 +26,7 @@ protected:
virtual void _render_scene(RenderBufferData *p_buffer_data, 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_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip) = 0;
+ virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
@@ -155,6 +156,26 @@ private:
uint32_t pad;
};
+ struct GIProbeDynamicPushConstant {
+
+ int32_t limits[3];
+ uint32_t light_count;
+ int32_t x_dir[3];
+ float z_base;
+ int32_t y_dir[3];
+ float z_sign;
+ int32_t z_dir[3];
+ float pos_multiplier;
+ uint32_t rect_pos[2];
+ uint32_t rect_size[2];
+ uint32_t prev_rect_ofs[2];
+ uint32_t prev_rect_size[2];
+ uint32_t flip_x;
+ uint32_t flip_y;
+ float dynamic_range;
+ uint32_t keep_downsample_color;
+ };
+
struct GIProbeInstance {
RID probe;
@@ -174,6 +195,21 @@ private:
};
Vector<Mipmap> mipmaps;
+ struct DynamicMap {
+ RID texture; //color normally, or emission on first pass
+ RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
+ RID depth; //actual depth buffer for the first pass, float depth for later passes
+ RID normal; //normal buffer for the first pass
+ RID albedo; //emission buffer for the first pass
+ RID orm; //orm buffer for the first pass
+ RID fb; //used for rendering, only valid on first map
+ RID uniform_set;
+ uint32_t size;
+ int mipmap; // mipmap to write to, -1 if no mipmap assigned
+ };
+
+ Vector<DynamicMap> dynamic_maps;
+
int slot = -1;
uint32_t last_probe_version = 0;
uint32_t last_probe_data_version = 0;
@@ -181,6 +217,8 @@ private:
uint64_t last_pass = 0;
uint32_t render_index = 0;
+ bool has_dynamic_object_data = false;
+
Transform transform;
};
@@ -198,6 +236,10 @@ private:
GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
GI_PROBE_SHADER_VERSION_MAX
};
GiprobeShaderRD giprobe_shader;
@@ -211,6 +253,7 @@ private:
GI_PROBE_DEBUG_COLOR,
GI_PROBE_DEBUG_LIGHT,
GI_PROBE_DEBUG_EMISSION,
+ GI_PROBE_DEBUG_LIGHT_FULL,
GI_PROBE_DEBUG_MAX
};
@@ -220,6 +263,8 @@ private:
float dynamic_range;
float alpha;
uint32_t level;
+ int32_t bounds[3];
+ uint32_t pad;
};
GiprobeDebugShaderRD giprobe_debug_shader;
@@ -662,7 +707,8 @@ public:
RID gi_probe_instance_create(RID p_base);
void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
bool gi_probe_needs_update(RID p_probe) const;
- void gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances);
+ void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects);
+
_FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) {
GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
return gi_probe->slot;
@@ -726,6 +772,8 @@ public:
void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
+ void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
+
virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; }
_FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; }
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
index 28ecda081d..4c5b9b94fb 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -3558,41 +3558,19 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
bool data_version_changed = false;
- if (gi_probe->octree_buffer_size != p_octree_cells.size() || gi_probe->data_buffer_size != p_data_cells.size()) {
- //buffer size changed, clear if needed
- if (gi_probe->octree_buffer.is_valid()) {
- RD::get_singleton()->free(gi_probe->octree_buffer);
- RD::get_singleton()->free(gi_probe->data_buffer);
-
- gi_probe->octree_buffer = RID();
- gi_probe->data_buffer = RID();
- gi_probe->octree_buffer_size = 0;
- gi_probe->data_buffer_size = 0;
- gi_probe->cell_count = 0;
+ if (gi_probe->octree_buffer.is_valid()) {
+ RD::get_singleton()->free(gi_probe->octree_buffer);
+ RD::get_singleton()->free(gi_probe->data_buffer);
+ if (gi_probe->sdf_texture.is_valid()) {
+ RD::get_singleton()->free(gi_probe->sdf_texture);
}
- data_version_changed = true;
-
- } else if (gi_probe->octree_buffer_size) {
- //they are the same and size did not change..
- //update
-
- PoolVector<uint8_t>::Read rc = p_octree_cells.read();
- PoolVector<uint8_t>::Read rd = p_data_cells.read();
-
- RD::get_singleton()->buffer_update(gi_probe->octree_buffer, 0, gi_probe->octree_buffer_size, rc.ptr());
- RD::get_singleton()->buffer_update(gi_probe->data_buffer, 0, gi_probe->data_buffer_size, rd.ptr());
- }
-
- if (gi_probe->level_counts.size() != p_level_counts.size()) {
- data_version_changed = true;
- } else {
- for (int i = 0; i < p_level_counts.size(); i++) {
- if (gi_probe->level_counts[i] != p_level_counts[i]) {
- data_version_changed = true;
- break;
- }
- }
+ gi_probe->sdf_texture = RID();
+ gi_probe->octree_buffer = RID();
+ gi_probe->data_buffer = RID();
+ gi_probe->octree_buffer_size = 0;
+ gi_probe->data_buffer_size = 0;
+ gi_probe->cell_count = 0;
}
gi_probe->to_cell_xform = p_to_cell_xform;
@@ -3600,7 +3578,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
gi_probe->octree_size = p_octree_size;
gi_probe->level_counts = p_level_counts;
- if (p_octree_cells.size() && gi_probe->octree_buffer.is_null()) {
+ if (p_octree_cells.size()) {
ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32
uint32_t cell_count = p_octree_cells.size() / 32;
@@ -3612,13 +3590,80 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
gi_probe->octree_buffer_size = p_octree_cells.size();
gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
gi_probe->data_buffer_size = p_data_cells.size();
- data_version_changed = true;
+
+ {
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = gi_probe->octree_size.x;
+ tf.height = gi_probe->octree_size.y;
+ tf.depth = gi_probe->octree_size.z;
+ tf.type = RD::TEXTURE_TYPE_3D;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
+ gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+ RID shared_tex;
+ {
+
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R8_UINT;
+ shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture);
+ }
+ //update SDF texture
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(gi_probe->octree_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(gi_probe->data_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(shared_tex);
+ uniforms.push_back(u);
+ }
+
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
+
+ {
+ uint32_t push_constant[4] = { 0, 0, 0, 0 };
+
+ for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) {
+ push_constant[0] += gi_probe->level_counts[i];
+ }
+ push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
+
+ print_line("offset: " + itos(push_constant[0]));
+ print_line("size: " + itos(push_constant[1]));
+ //create SDF
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4);
+ RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4);
+ RD::get_singleton()->compute_list_end();
+ }
+
+ RD::get_singleton()->free(uniform_set);
+ RD::get_singleton()->free(shared_tex);
+ }
}
gi_probe->version++;
- if (data_version_changed) {
- gi_probe->data_version++;
- }
+ gi_probe->data_version++;
+
gi_probe->instance_dependency.instance_notify_changed(true, false);
}
@@ -3794,6 +3839,13 @@ RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
return gi_probe->data_buffer;
}
+RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+
+ return gi_probe->sdf_texture;
+}
+
/* RENDER TARGET API */
void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
@@ -4583,110 +4635,121 @@ RasterizerStorageRD::RasterizerStorageRD() {
{
{ //vertex
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 3);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
- { //normal
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 3);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 1.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 3);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
- { //tangent
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 4);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 1.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- fptr[3] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
+{ //normal
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 3);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 1.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
- { //color
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 4);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 1.0;
- fptr[1] = 1.0;
- fptr[2] = 1.0;
- fptr[3] = 1.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
+{ //tangent
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 4);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 1.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ fptr[3] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
- { //tex uv 1
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 2);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
- { //tex uv 2
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 2);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
+{ //color
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 4);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 1.0;
+ fptr[1] = 1.0;
+ fptr[2] = 1.0;
+ fptr[3] = 1.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
- { //bones
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(uint32_t) * 4);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- uint32_t *fptr = (uint32_t *)w.ptr();
- fptr[0] = 0;
- fptr[1] = 0;
- fptr[2] = 0;
- fptr[3] = 0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
+{ //tex uv 1
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 2);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+{ //tex uv 2
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 2);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
- { //weights
- PoolVector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 4);
- {
- PoolVector<uint8_t>::Write w = buffer.write();
- float *fptr = (float *)w.ptr();
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- fptr[3] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
- }
+{ //bones
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(uint32_t) * 4);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ uint32_t *fptr = (uint32_t *)w.ptr();
+ fptr[0] = 0;
+ fptr[1] = 0;
+ fptr[2] = 0;
+ fptr[3] = 0;
}
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //weights
+ PoolVector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 4);
+ {
+ PoolVector<uint8_t>::Write w = buffer.write();
+ float *fptr = (float *)w.ptr();
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ fptr[3] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+}
+
+{
+ Vector<String> sdf_versions;
+ sdf_versions.push_back(""); //one only
+ giprobe_sdf_shader.initialize(sdf_versions);
+ giprobe_sdf_shader_version = giprobe_sdf_shader.version_create();
+ giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector<String>());
+ giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0);
+ giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader);
+}
}
RasterizerStorageRD::~RasterizerStorageRD() {
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
index 289a2ae5a8..63713c6add 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
@@ -35,6 +35,7 @@
#include "servers/visual/rasterizer.h"
#include "servers/visual/rasterizer_rd/rasterizer_effects_rd.h"
#include "servers/visual/rasterizer_rd/shader_compiler_rd.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
#include "servers/visual/rendering_device.h"
class RasterizerStorageRD : public RasterizerStorage {
@@ -407,6 +408,7 @@ private:
RID octree_buffer;
RID data_buffer;
+ RID sdf_texture;
uint32_t octree_buffer_size = 0;
uint32_t data_buffer_size = 0;
@@ -435,6 +437,11 @@ private:
RasterizerScene::InstanceDependency instance_dependency;
};
+ GiprobeSdfShaderRD giprobe_sdf_shader;
+ RID giprobe_sdf_shader_version;
+ RID giprobe_sdf_shader_version_shader;
+ RID giprobe_sdf_shader_pipeline;
+
mutable RID_Owner<GIProbe> gi_probe_owner;
/* RENDER TARGET */
@@ -999,6 +1006,8 @@ public:
RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
RID gi_probe_get_data_buffer(RID p_gi_probe) const;
+ RID gi_probe_get_sdf_texture(RID p_gi_probe);
+
/* LIGHTMAP CAPTURE */
void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub
index bce700f7b0..ff83b46a9b 100644
--- a/servers/visual/rasterizer_rd/shaders/SCsub
+++ b/servers/visual/rasterizer_rd/shaders/SCsub
@@ -13,4 +13,6 @@ if 'RD_GLSL' in env['BUILDERS']:
env.RD_GLSL('copy.glsl');
env.RD_GLSL('giprobe.glsl');
env.RD_GLSL('giprobe_debug.glsl');
+ env.RD_GLSL('giprobe_sdf.glsl');
+
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe.glsl b/servers/visual/rasterizer_rd/shaders/giprobe.glsl
index a723490e8b..d756058356 100644
--- a/servers/visual/rasterizer_rd/shaders/giprobe.glsl
+++ b/servers/visual/rasterizer_rd/shaders/giprobe.glsl
@@ -4,8 +4,18 @@
VERSION_DEFINES
+#ifdef MODE_DYNAMIC
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+#else
+
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+#endif
+
+#ifndef MODE_DYNAMIC
+
#define NO_CHILDREN 0xFFFFFFFF
#define GREY_VEC vec3(0.33333,0.33333,0.33333)
@@ -28,11 +38,14 @@ layout(set=0,binding=2,std430) buffer CellDataBuffer {
CellData data[];
} cell_data;
+
+#endif // MODE DYNAMIC
+
#define LIGHT_TYPE_DIRECTIONAL 0
#define LIGHT_TYPE_OMNI 1
#define LIGHT_TYPE_SPOT 2
-#ifdef MODE_COMPUTE_LIGHT
+#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING)
struct Light {
@@ -64,7 +77,6 @@ layout(set=0,binding=3,std140) uniform Lights {
#ifdef MODE_SECOND_BOUNCE
layout (set=0,binding=5) uniform texture3D color_texture;
-layout (set=0,binding=6) uniform sampler texture_sampler;
#ifdef MODE_ANISOTROPIC
layout (set=0,binding=7) uniform texture3D aniso_pos_texture;
@@ -73,6 +85,7 @@ layout (set=0,binding=8) uniform texture3D aniso_neg_texture;
#endif // MODE_SECOND_BOUNCE
+#ifndef MODE_DYNAMIC
layout(push_constant, binding = 0, std430) uniform Params {
@@ -96,6 +109,11 @@ layout(set=0,binding=4,std430) buffer Outputs {
vec4 data[];
} outputs;
+#endif // MODE DYNAMIC
+
+layout (set=0,binding=9) uniform texture3D texture_sdf;
+layout (set=0,binding=10) uniform sampler texture_sampler;
+
#ifdef MODE_WRITE_TEXTURE
layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
@@ -111,63 +129,97 @@ layout (r16ui,set=0,binding=7) uniform restrict writeonly uimage3D aniso_neg_tex
#endif
-#ifdef MODE_COMPUTE_LIGHT
+#ifdef MODE_DYNAMIC
-uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+layout(push_constant, binding = 0, std430) uniform Params {
- uint result = NO_CHILDREN;
+ ivec3 limits;
+ uint light_count;
+ ivec3 x_dir;
+ float z_base;
+ ivec3 y_dir;
+ float z_sign;
+ ivec3 z_dir;
+ float pos_multiplier;
+ ivec2 rect_pos;
+ ivec2 rect_size;
+ ivec2 prev_rect_ofs;
+ ivec2 prev_rect_size;
+ bool flip_x;
+ bool flip_y;
+ float dynamic_range;
+ bool keep_downsample_color;
- ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
+} params;
- while (distance > -distance_adv) { //use this to avoid precision errors
+#ifdef MODE_DYNAMIC_LIGHTING
- uint cell = 0;
+layout (rgba8,set=0,binding=5) uniform restrict readonly image2D source_albedo;
+layout (rgba8,set=0,binding=6) uniform restrict readonly image2D source_normal;
+layout (rgba8,set=0,binding=7) uniform restrict readonly image2D source_orm;
+//layout (set=0,binding=8) uniform texture2D source_depth;
+layout (rgba16f,set=0,binding=11) uniform restrict image2D emission;
+layout (r32f,set=0,binding=12) uniform restrict image2D depth;
- ivec3 pos = ivec3(from);
+#endif
- if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
+#ifdef MODE_DYNAMIC_SHRINK
- ivec3 ofs = ivec3(0);
- ivec3 half_size = size / 2;
+layout (rgba16f,set=0,binding=5) uniform restrict readonly image2D source_light;
+layout (r32f,set=0,binding=6) uniform restrict readonly image2D source_depth;
- for (int i = 0; i < params.stack_size - 1; i++) {
+#ifdef MODE_DYNAMIC_SHRINK_WRITE
- bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+layout (rgba16f,set=0,binding=7) uniform restrict writeonly image2D light;
+layout (r32f,set=0,binding=8) uniform restrict writeonly image2D depth;
- ofs += mix(ivec3(0),half_size,greater);
+#endif // MODE_DYNAMIC_SHRINK_WRITE
- uint child = 0; //wonder if this can be done faster
- if (greater.x) {
- child|=1;
- }
- if (greater.y) {
- child|=2;
- }
- if (greater.z) {
- child|=4;
- }
+#ifdef MODE_DYNAMIC_SHRINK_PLOT
- cell = cell_children.data[cell].children[child];
- if (cell == NO_CHILDREN)
- break;
+layout (rgba8,set=0,binding=11) uniform restrict image3D color_texture;
- half_size >>= ivec3(1);
- }
+#ifdef MODE_ANISOTROPIC
+
+layout (r16ui,set=0,binding=12) uniform restrict writeonly uimage3D aniso_pos_texture;
+layout (r16ui,set=0,binding=13) uniform restrict writeonly uimage3D aniso_neg_texture;
+
+#endif // MODE ANISOTROPIC
+
+#endif //MODE_DYNAMIC_SHRINK_PLOT
+
+#endif // MODE_DYNAMIC_SHRINK
+
+//layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
+
+
+#endif // MODE DYNAMIC
+
+#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING)
+
+float raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
- if ( cell != NO_CHILDREN) {
- return cell; //found cell!
- }
+
+ vec3 cell_size = 1.0 / vec3(params.limits);
+
+ while (distance > 0.0) { //use this to avoid precision errors
+ float advance = texture(sampler3D(texture_sdf,texture_sampler),from * cell_size).r * 255.0 - 1.0;
+ if (advance<0.0) {
+ break;
}
- from += direction * distance_adv;
- distance -= distance_adv;
+ advance = max(distance_adv, advance - mod(advance, distance_adv)); //should always advance in multiples of distance_adv
+
+ from += direction * advance;
+ distance -= advance;
}
- return NO_CHILDREN;
+ return max(0.0,distance);
+
}
-bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+bool compute_light_vector(uint light, vec3 pos,out float attenuation, out vec3 light_pos) {
if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
@@ -226,13 +278,84 @@ float get_normal_advance(vec3 p_normal) {
return 1.0 / dot(normal,unorm);
}
-#endif
+void clip_segment(vec4 plane, vec3 begin, inout vec3 end) {
+
+ vec3 segment = begin - end;
+ float den = dot(plane.xyz,segment);
+
+ //printf("den is %i\n",den);
+ if (den < 0.0001) {
+ return;
+ }
+
+ float dist = (dot(plane.xyz,begin) - plane.w) / den;
+
+ if (dist < 0.0001 || dist > 1.0001) {
+ return;
+ }
+
+ end = begin + segment * -dist;
+}
+
+bool compute_light_at_pos(uint index, vec3 pos, vec3 normal, inout vec3 light, inout vec3 light_dir) {
+ float attenuation;
+ vec3 light_pos;
+
+ if (!compute_light_vector(index,pos,attenuation,light_pos)) {
+ return false;
+ }
+
+ light_dir = normalize(pos - light_pos);
+
+ if (attenuation < 0.01 || (length(normal) > 0.2 && dot(normal,light_dir)>=0)) {
+ return false; //not facing the light, or attenuation is near zero
+ }
+
+ if (lights.data[index].has_shadow) {
+
+ float distance_adv = get_normal_advance(light_dir);
+
+
+ vec3 to = pos;
+ to-= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
+
+ //clip
+ clip_segment(mix(vec4(-1.0,0.0,0.0,0.0),vec4(1.0,0.0,0.0,float(params.limits.x-1)),bvec4(light_dir.x < 0.0)),to,light_pos);
+ clip_segment(mix(vec4(0.0,-1.0,0.0,0.0),vec4(0.0,1.0,0.0,float(params.limits.y-1)),bvec4(light_dir.y < 0.0)),to,light_pos);
+ clip_segment(mix(vec4(0.0,0.0,-1.0,0.0),vec4(0.0,0.0,1.0,float(params.limits.z-1)),bvec4(light_dir.z < 0.0)),to,light_pos);
+
+
+ float distance = length(to-light_pos);
+ if (distance < 0.1) {
+ return false; // hit
+ }
+
+ distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
+ light_pos = to - light_dir * distance;
+
+ //from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
+ float dist = raymarch(distance,distance_adv,light_pos,light_dir);
+
+ if (dist > distance_adv) {
+ return false;
+ }
+
+
+ }
+
+ light = lights.data[index].color * attenuation * lights.data[index].energy;
+ return true;
+}
+
+#endif // MODE COMPUTE LIGHT
void main() {
+#ifndef MODE_DYNAMIC
+
uint cell_index = gl_GlobalInvocationID.x;;
if (cell_index >= params.cell_count) {
return;
@@ -242,6 +365,8 @@ void main() {
uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21);
vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
+#endif
+
/////////////////COMPUTE LIGHT///////////////////////////////
#ifdef MODE_COMPUTE_LIGHT
@@ -249,7 +374,7 @@ void main() {
vec3 pos = vec3(posu) + vec3(0.5);
vec3 emission = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
- vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+ vec3 normal = unpackSnorm4x8(cell_data.data[cell_index].normal).xyz;
#ifdef MODE_ANISOTROPIC
vec3 accum[6]=vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
@@ -260,41 +385,13 @@ void main() {
for(uint i=0;i<params.light_count;i++) {
- float attenuation;
- vec3 light_pos;
-
- if (!compute_light_vector(i,cell_index,pos,attenuation,light_pos)) {
+ vec3 light;
+ vec3 light_dir;
+ if (!compute_light_at_pos(i,pos,normal.xyz,light,light_dir)) {
continue;
}
- vec3 light_dir = pos - light_pos;
- float distance = length(light_dir);
- light_dir=normalize(light_dir);
-
- if (attenuation < 0.01 || (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0)) {
- continue; //not facing the light, or attenuation is near zero
- }
-
- if (lights.data[i].has_shadow) {
-
- float distance_adv = get_normal_advance(light_dir);
-
-
- distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
-
- vec3 from = pos - light_dir * distance; //approximate
- from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
-
-
-
- uint result = raymarch(distance,distance_adv,from,light_dir);
-
- if (result != cell_index) {
- continue; //was occluded
- }
- }
-
- vec3 light = lights.data[i].color * albedo.rgb * attenuation * lights.data[i].energy;
+ light*= albedo.rgb;
#ifdef MODE_ANISOTROPIC
for(uint j=0;j<6;j++) {
@@ -302,11 +399,11 @@ void main() {
accum[j]+=max(0.0,dot(accum_dirs[j],-light_dir))*light;
}
#else
- if (length(normal.xyz) > 0.2) {
- accum+=max(0.0,dot(normal.xyz,-light_dir))*light;
+ if (length(normal) > 0.2) {
+ accum+=max(0.0,dot(normal,-light_dir))*light;
} else {
//all directions
- accum+=light+emission;
+ accum+=light;
}
#endif
}
@@ -314,12 +411,17 @@ void main() {
#ifdef MODE_ANISOTROPIC
- outputs.data[cell_index*6+0]=vec4(accum[0] + emission,0.0);
- outputs.data[cell_index*6+1]=vec4(accum[1] + emission,0.0);
- outputs.data[cell_index*6+2]=vec4(accum[2] + emission,0.0);
- outputs.data[cell_index*6+3]=vec4(accum[3] + emission,0.0);
- outputs.data[cell_index*6+4]=vec4(accum[4] + emission,0.0);
- outputs.data[cell_index*6+5]=vec4(accum[5] + emission,0.0);
+ for(uint i=0;i<6;i++) {
+ vec3 light = accum[i];
+ if (length(normal) > 0.2) {
+ light += max(0.0,dot(accum_dirs[i],-normal)) * emission;
+ } else {
+ light += emission;
+ }
+
+ outputs.data[cell_index*6+i] = vec4(light,0.0);
+ }
+
#else
outputs.data[cell_index]=vec4(accum + emission,0.0);
@@ -540,4 +642,167 @@ void main() {
}
#endif
+
+///////////////////DYNAMIC LIGHTING/////////////////////////////
+
+#ifdef MODE_DYNAMIC
+
+ ivec2 pos_xy = ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThanEqual(pos_xy,params.rect_size))) {
+ return; //out of bounds
+ }
+
+ ivec2 uv_xy = pos_xy;
+ if (params.flip_x) {
+ uv_xy.x = params.rect_size.x - pos_xy.x - 1;
+ }
+ if (params.flip_y) {
+ uv_xy.y = params.rect_size.y - pos_xy.y - 1;
+ }
+
+
+#ifdef MODE_DYNAMIC_LIGHTING
+
+
+ {
+
+
+ float z = params.z_base + imageLoad(depth,uv_xy).x * params.z_sign;
+
+ ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(z);
+
+ vec3 normal = imageLoad(source_normal,uv_xy).xyz * 2.0 - 1.0;
+ normal = vec3(params.x_dir) * normal.x * mix(1.0,-1.0,params.flip_x) + vec3(params.y_dir) * normal.y * mix(1.0,-1.0,params.flip_y) - vec3(params.z_dir) * normal.z;
+
+
+
+
+ vec4 albedo = imageLoad(source_albedo,uv_xy);
+
+ //determine the position in space
+
+ vec3 accum = vec3(0.0);
+ for(uint i=0;i<params.light_count;i++) {
+
+ vec3 light;
+ vec3 light_dir;
+ if (!compute_light_at_pos(i,vec3(pos) * params.pos_multiplier,normal,light,light_dir)) {
+ continue;
+ }
+
+ light*= albedo.rgb;
+
+ accum+=max(0.0,dot(normal,-light_dir))*light;
+
+ }
+
+ accum+=imageLoad(emission,uv_xy).xyz;
+
+ imageStore(emission,uv_xy,vec4(accum,albedo.a));
+ imageStore(depth,uv_xy,vec4(z));
+
+ }
+
+#endif // MODE DYNAMIC LIGHTING
+
+#ifdef MODE_DYNAMIC_SHRINK
+
+ {
+ vec4 accum = vec4(0.0);
+ float accum_z = 0.0;
+ float count = 0.0;
+
+ for(int i=0;i<4;i++) {
+ ivec2 ofs = pos_xy*2 + ivec2(i&1,i>>1) - params.prev_rect_ofs;
+ if (any(lessThan(ofs,ivec2(0))) || any(greaterThanEqual(ofs,params.prev_rect_size))) {
+ continue;
+ }
+ if (params.flip_x) {
+ ofs.x = params.prev_rect_size.x - ofs.x - 1;
+ }
+ if (params.flip_y) {
+ ofs.y = params.prev_rect_size.y - ofs.y - 1;
+ }
+
+ vec4 light = imageLoad(source_light,ofs);
+ if (light.a==0.0) { //ignore empty
+ continue;
+ }
+ accum += light;
+ float z = imageLoad(source_depth,ofs).x;
+ accum_z += z*0.5; //shrink half too
+ count+=1.0;
+ }
+
+
+ accum/=4.0;
+
+ if (count==0.0) {
+ accum_z=0.0; //avoid nan
+ } else {
+ accum_z/=count;
+ }
+
+#ifdef MODE_DYNAMIC_SHRINK_WRITE
+
+ imageStore(light,uv_xy,accum);
+ imageStore(depth,uv_xy,vec4(accum_z));
+#endif
+
+#ifdef MODE_DYNAMIC_SHRINK_PLOT
+
+
+ if (accum.a<0.001) {
+ return; //do not blit if alpha is too low
+ }
+
+ ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(accum_z);
+
+ float z_frac = fract(accum_z);
+
+ for(int i = 0; i< 2; i++) {
+ ivec3 pos3d = pos + abs(params.z_dir) * i;
+ if (any(lessThan(pos3d,ivec3(0))) || any(greaterThanEqual(pos3d,params.limits))) {
+ //skip if offlimits
+ continue;
+ }
+ vec4 color_blit = accum * (i==0 ? 1.0 - z_frac : z_frac );
+ vec4 color = imageLoad(color_texture,pos3d);
+ color.rgb *=params.dynamic_range;
+
+#if 0
+ color.rgb = mix(color.rgb,color_blit.rgb,color_blit.a);
+ color.a+=color_blit.a;
+#else
+
+
+ float sa = 1.0 - color_blit.a;
+ vec4 result;
+ result.a = color.a * sa + color_blit.a;
+ if (result.a==0.0) {
+ result = vec4(0.0);
+ } else {
+ result.rgb = (color.rgb * color.a * sa + color_blit.rgb * color_blit.a) / result.a;
+ color = result;
+ }
+
+#endif
+ color.rgb /= params.dynamic_range;
+ imageStore(color_texture,pos3d,color);
+ //imageStore(color_texture,pos3d,vec4(1,1,1,1));
+
+#ifdef MODE_ANISOTROPIC
+ //do not care about anisotropy for dynamic objects, just store full lit in all directions
+ imageStore(aniso_pos_texture,pos3d,uvec4(0xFFFF));
+ imageStore(aniso_neg_texture,pos3d,uvec4(0xFFFF));
+
+#endif // ANISOTROPIC
+ }
+#endif // MODE_DYNAMIC_SHRINK_PLOT
+
+
+ }
+#endif
+
+#endif // MODE DYNAMIC
}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
index 71ecaffde7..7218d2da3a 100644
--- a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
+++ b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
@@ -32,6 +32,8 @@ layout(push_constant, binding = 0, std430) uniform Params {
float dynamic_range;
float alpha;
uint level;
+ ivec3 bounds;
+ uint pad;
} params;
@@ -80,10 +82,13 @@ void main() {
vec3 vertex = cube_triangles[gl_VertexIndex] * 0.5 + 0.5;
-
+#ifdef MODE_DEBUG_LIGHT_FULL
+ uvec3 posu = uvec3( gl_InstanceIndex % params.bounds.x, (gl_InstanceIndex / params.bounds.x) % params.bounds.y,gl_InstanceIndex / (params.bounds.y * params.bounds.x) );
+#else
uint cell_index = gl_InstanceIndex + params.cell_offset;
uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21);
+#endif
#ifdef MODE_DEBUG_EMISSION
color_interp.xyz = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
@@ -138,16 +143,24 @@ void main() {
color_interp.xyz *= strength;
#else
- color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).xyz * params.dynamic_range;
+ color_interp = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level));
+ color_interp.xyz * params.dynamic_range;
#endif
#endif
float scale = (1<<params.level);
- color_interp.a = params.alpha;
gl_Position = params.projection * vec4((vec3(posu)+vertex)*scale,1.0);
+#ifdef MODE_DEBUG_LIGHT_FULL
+ if (color_interp.a == 0.0) {
+ gl_Position = vec4(0.0); //force clip and not draw
+ }
+#else
+ color_interp.a = params.alpha;
+#endif
+
}
[fragment]
@@ -162,4 +175,35 @@ layout(location=0) out vec4 frag_color;
void main() {
frag_color = color_interp;
+
+#ifdef MODE_DEBUG_LIGHT_FULL
+
+ //there really is no alpha, so use dither
+
+ int x = int(gl_FragCoord.x) % 4;
+ int y = int(gl_FragCoord.y) % 4;
+ int index = x + y * 4;
+ float limit = 0.0;
+ if (x < 8) {
+ if (index == 0) limit = 0.0625;
+ if (index == 1) limit = 0.5625;
+ if (index == 2) limit = 0.1875;
+ if (index == 3) limit = 0.6875;
+ if (index == 4) limit = 0.8125;
+ if (index == 5) limit = 0.3125;
+ if (index == 6) limit = 0.9375;
+ if (index == 7) limit = 0.4375;
+ if (index == 8) limit = 0.25;
+ if (index == 9) limit = 0.75;
+ if (index == 10) limit = 0.125;
+ if (index == 11) limit = 0.625;
+ if (index == 12) limit = 1.0;
+ if (index == 13) limit = 0.5;
+ if (index == 14) limit = 0.875;
+ if (index == 15) limit = 0.375;
+ }
+ if (frag_color.a < limit) {
+ discard;
+ }
+#endif
}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl
new file mode 100644
index 0000000000..02f0f67a15
--- /dev/null
+++ b/servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl
@@ -0,0 +1,194 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
+
+#define MAX_DISTANCE 100000
+
+#define NO_CHILDREN 0xFFFFFFFF
+#define GREY_VEC vec3(0.33333,0.33333,0.33333)
+
+struct CellChildren {
+ uint children[8];
+};
+
+layout(set=0,binding=1,std430) buffer CellChildrenBuffer {
+ CellChildren data[];
+} cell_children;
+
+
+struct CellData {
+ uint position; // xyz 10 bits
+ uint albedo; //rgb albedo
+ uint emission; //rgb normalized with e as multiplier
+ uint normal; //RGB normal encoded
+};
+
+layout(set=0,binding=2,std430) buffer CellDataBuffer {
+ CellData data[];
+} cell_data;
+
+layout (r8ui,set=0,binding=3) uniform restrict writeonly uimage3D sdf_tex;
+
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+ uint offset;
+ uint end;
+ uint pad0;
+ uint pad1;
+} params;
+
+void main() {
+
+ vec3 pos = vec3(gl_GlobalInvocationID);
+ float closest_dist = 100000.0;
+
+ for(uint i=params.offset;i<params.end;i++) {
+ vec3 posu = vec3(uvec3(cell_data.data[i].position&0x7FF,(cell_data.data[i].position>>11)&0x3FF,cell_data.data[i].position>>21));
+ float dist = length(pos-posu);
+ if (dist < closest_dist) {
+ closest_dist = dist;
+ }
+ }
+
+ uint dist_8;
+
+ if (closest_dist<0.0001) { // same cell
+ dist_8=0; //equals to -1
+ } else {
+ dist_8 = clamp(uint(closest_dist),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid
+ }
+
+ imageStore(sdf_tex,ivec3(gl_GlobalInvocationID),uvec4(dist_8));
+ //imageStore(sdf_tex,pos,uvec4(pos*2,0));
+}
+
+
+#if 0
+layout(push_constant, binding = 0, std430) uniform Params {
+
+ ivec3 limits;
+ uint stack_size;
+} params;
+
+
+float distance_to_aabb(ivec3 pos, ivec3 aabb_pos, ivec3 aabb_size) {
+
+ vec3 delta = vec3(max(ivec3(0),max(aabb_pos - pos, pos - (aabb_pos + aabb_size - ivec3(1)))));
+ return length(delta);
+}
+
+void main() {
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID);
+
+ uint stack[10]=uint[](0,0,0,0,0,0,0,0,0,0);
+ uint stack_indices[10]=uint[](0,0,0,0,0,0,0,0,0,0);
+ ivec3 stack_positions[10]=ivec3[](ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0));
+
+ const uint cell_orders[8]=uint[](
+ 0x11f58d1,
+ 0xe2e70a,
+ 0xd47463,
+ 0xbb829c,
+ 0x8d11f5,
+ 0x70ae2e,
+ 0x463d47,
+ 0x29cbb8
+ );
+
+ bool cell_found = false;
+ bool cell_found_exact = false;
+ ivec3 closest_cell_pos;
+ float closest_distance = MAX_DISTANCE;
+ int stack_pos = 0;
+
+ while(true) {
+
+ uint index = stack_indices[stack_pos]>>24;
+
+ if (index == 8) {
+ //go up
+ if (stack_pos==0) {
+ break; //done going through octree
+ }
+ stack_pos--;
+ continue;
+ }
+
+ stack_indices[stack_pos] = (stack_indices[stack_pos]&((1<<24)-1))|((index + 1)<<24);
+
+
+ uint cell_index = (stack_indices[stack_pos]>>(index*3))&0x7;
+ uint child_cell = cell_children.data[stack[stack_pos]].children[cell_index];
+
+ if (child_cell == NO_CHILDREN) {
+ continue;
+ }
+
+ ivec3 child_cell_size = params.limits >> (stack_pos+1);
+ ivec3 child_cell_pos = stack_positions[stack_pos];
+
+ child_cell_pos+=mix(ivec3(0),child_cell_size,bvec3(uvec3(index&1,index&2,index&4)!=uvec3(0)));
+
+ bool is_leaf = stack_pos == (params.stack_size-2);
+
+ if (child_cell_pos==pos && is_leaf) {
+ //we may actually end up in the exact cell.
+ //if this happens, just abort
+ cell_found_exact=true;
+ break;
+ }
+
+ if (cell_found) {
+ //discard by distance
+ float distance = distance_to_aabb(pos,child_cell_pos,child_cell_size);
+ if (distance >= closest_distance) {
+ continue; //pointless, just test next child
+ } else if (is_leaf) {
+ //closer than what we have AND end of stack, save and continue
+ closest_cell_pos = child_cell_pos;
+ closest_distance = distance;
+ continue;
+ }
+ } else if (is_leaf) {
+ //first solid cell we find, save and continue
+ closest_distance = distance_to_aabb(pos,child_cell_pos,child_cell_size);
+ closest_cell_pos = child_cell_pos;
+ cell_found=true;
+ continue;
+ }
+
+
+
+
+ bvec3 direction = greaterThan(( pos - ( child_cell_pos + (child_cell_size >>1) ) ) , ivec3(0) );
+ uint cell_order = 0;
+ cell_order|=mix(0,1,direction.x);
+ cell_order|=mix(0,2,direction.y);
+ cell_order|=mix(0,4,direction.z);
+
+ stack[stack_pos+1]=child_cell;
+ stack_indices[stack_pos+1]=cell_orders[cell_order]; //start counting
+ stack_positions[stack_pos+1]=child_cell_pos;
+ stack_pos++; //go up stack
+
+ }
+
+ uint dist_8;
+
+ if (cell_found_exact) {
+ dist_8=0; //equals to -1
+ } else {
+ float closest_distance = length(vec3(pos-closest_cell_pos));
+ dist_8 = clamp(uint(closest_distance),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid
+ }
+
+ imageStore(sdf_tex,pos,uvec4(dist_8));
+
+}
+#endif
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
index a54a84536a..1ffccdc4ee 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
+++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
@@ -344,17 +344,30 @@ FRAGMENT_SHADER_GLOBALS
/* clang-format on */
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+layout(location = 0) out vec4 albedo_output_buffer;
+layout(location = 1) out vec4 normal_output_buffer;
+layout(location = 2) out vec4 orm_output_buffer;
+layout(location = 3) out vec4 emission_output_buffer;
+layout(location = 4) out float depth_output_buffer;
+
+#endif
+
+#else // RENDER DEPTH
+
#ifdef MODE_MULTIPLE_RENDER_TARGETS
layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
#else
-#ifndef MODE_RENDER_DEPTH
layout(location = 0) out vec4 frag_color;
#endif
-#endif
+#endif // RENDER DEPTH
@@ -1668,6 +1681,29 @@ FRAGMENT_SHADER_CODE
#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+ albedo_output_buffer.rgb = albedo;
+ albedo_output_buffer.a = alpha;
+
+ normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.a = 0.0;
+ depth_output_buffer.r = -vertex.z;
+
+#if defined(AO_USED)
+ orm_output_buffer.r = ao;
+#else
+ orm_output_buffer.r = 0.0;
+#endif
+ orm_output_buffer.g = roughness;
+ orm_output_buffer.b = metallic;
+ orm_output_buffer.a = sss_strength;
+
+ emission_output_buffer.rgb = emission;
+ emission_output_buffer.a = 0.0;
+#endif
+
//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
#else