summaryrefslogtreecommitdiff
path: root/servers/visual
diff options
context:
space:
mode:
Diffstat (limited to 'servers/visual')
-rw-r--r--servers/visual/rasterizer.h65
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp4
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp16
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp826
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h31
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp563
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.h179
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp265
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.h95
-rw-r--r--servers/visual/rasterizer_rd/shaders/SCsub3
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe.glsl543
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl160
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl241
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_write.glsl353
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward.glsl302
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl123
-rw-r--r--servers/visual/rendering_device.h19
-rw-r--r--servers/visual/visual_server_raster.h30
-rw-r--r--servers/visual/visual_server_scene.cpp1122
-rw-r--r--servers/visual/visual_server_scene.h120
-rw-r--r--servers/visual/visual_server_wrap_mt.h30
21 files changed, 3046 insertions, 2044 deletions
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 02d44c5c5d..85e2b8aadc 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -230,12 +230,13 @@ public:
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
- virtual RID gi_probe_instance_create() = 0;
- virtual void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) = 0;
+ virtual RID gi_probe_instance_create(RID p_gi_probe) = 0;
virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;
- virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) = 0;
+ virtual bool gi_probe_needs_update(RID p_probe) const = 0;
+ virtual void gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances) = 0;
+
+ virtual void 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_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_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) = 0;
virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0;
virtual void set_scene_pass(uint64_t p_pass) = 0;
@@ -481,51 +482,41 @@ public:
virtual RID gi_probe_create() = 0;
- virtual void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) = 0;
- virtual AABB gi_probe_get_bounds(RID p_probe) const = 0;
-
- virtual void gi_probe_set_cell_size(RID p_probe, float p_range) = 0;
- virtual float gi_probe_get_cell_size(RID p_probe) const = 0;
+ virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) = 0;
- virtual void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) = 0;
- virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const = 0;
+ virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
+ virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
+ virtual PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
+ virtual PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
+ virtual PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
+ virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data) = 0;
- virtual PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const = 0;
+ virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_dynamic_range(RID p_probe, int p_range) = 0;
- virtual int gi_probe_get_dynamic_range(RID p_probe) const = 0;
+ virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_energy(RID p_probe, float p_range) = 0;
- virtual float gi_probe_get_energy(RID p_probe) const = 0;
+ virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
+ virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_bias(RID p_probe, float p_range) = 0;
- virtual float gi_probe_get_bias(RID p_probe) const = 0;
+ virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
+ virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_normal_bias(RID p_probe, float p_range) = 0;
- virtual float gi_probe_get_normal_bias(RID p_probe) const = 0;
+ virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_propagation(RID p_probe, float p_range) = 0;
- virtual float gi_probe_get_propagation(RID p_probe) const = 0;
+ virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
+ virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_interior(RID p_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_interior(RID p_probe) const = 0;
+ virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
+ virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
- virtual void gi_probe_set_compress(RID p_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_compressed(RID p_probe) const = 0;
+ virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
+ virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
- enum GIProbeCompression {
- GI_PROBE_UNCOMPRESSED,
- GI_PROBE_S3TC,
- GI_PROBE_ETC2
- };
-
- virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const = 0;
- virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) = 0;
- virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) = 0;
-
/* LIGHTMAP CAPTURE */
struct LightmapCaptureOctree {
diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
index 0da86f23a7..b6228bf165 100644
--- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
@@ -1331,7 +1331,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
if (p_screen_uniform_set.is_valid()) {
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 3);
@@ -1637,7 +1637,7 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_lig
Vector<Color> cc;
cc.push_back(Color(p_far, p_far, p_far, 1.0));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, cc, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1));
CameraMatrix projection;
{
diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
index 1e32594118..3d3298d0c1 100644
--- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -46,7 +46,7 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_frame
blur.push_constant.flags |= BLUR_FLAG_FLIP_Y;
}
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, Vector<Color>(), p_rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -67,7 +67,7 @@ void RasterizerEffectsRD::region_copy(RID p_source_rd_texture, RID p_dest_frameb
blur.push_constant.section[3] = p_region.size.height;
}
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -93,7 +93,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuff
blur.push_constant.pixel_size[1] = p_pixel_size.y;
//HORIZONTAL
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -105,7 +105,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuff
RD::get_singleton()->draw_list_end();
//VERTICAL
- draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+ draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -127,7 +127,7 @@ void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_sour
roughness.push_constant.use_direct_write = p_roughness == 0.0;
//RUN
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
@@ -171,7 +171,7 @@ void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_frameb
blur.push_constant.pixel_size[0] = p_pixel_size.x;
blur.push_constant.pixel_size[1] = p_pixel_size.y;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_MIPMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -188,7 +188,7 @@ void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest
push_constant.z_near = p_z_near;
push_constant.z_flip = p_dp_flip;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, Vector<Color>(), p_rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy.pipelines[COPY_MODE_CUBE_TO_DP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -222,7 +222,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer,
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1);
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
index e44955d666..3fda64c536 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
@@ -267,7 +267,7 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
@@ -500,7 +500,7 @@ void RasterizerSceneForwardRD::MaterialData::update_parameters(const Map<StringN
}
}
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), 2);
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), 3);
}
RasterizerSceneForwardRD::MaterialData::~MaterialData() {
if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
@@ -576,7 +576,12 @@ void RasterizerSceneForwardRD::RenderBufferDataForward::configure(RID p_render_t
color_fb = RD::get_singleton()->framebuffer_create(fb);
}
+ {
+ Vector<RID> fb;
+ fb.push_back(depth);
+ depth_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
{
Vector<RID> fb;
fb.push_back(color);
@@ -697,6 +702,39 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements,
id.flags |= omni_count << 3;
id.flags |= spot_count << 6;
id.flags |= decal_count << 9;
+
+ if (!e->instance->gi_probe_instances.empty()) {
+ uint32_t written = 0;
+ for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) {
+ RID probe = e->instance->gi_probe_instances[j];
+ int slot = gi_probe_instance_get_slot(probe);
+ if (slot < 0) {
+ continue; //unallocated, dont render
+ }
+
+ if (render_pass != gi_probe_instance_get_render_pass(probe)) {
+ continue; //not rendered in this frame
+ }
+
+ uint32_t index = gi_probe_instance_get_render_index(probe);
+
+ if (written == 0) {
+ id.gi_offset = index;
+ written = 1;
+ } else {
+ id.gi_offset = index << 16;
+ written = 2;
+ break;
+ }
+ }
+ if (written == 0) {
+ id.gi_offset = 0xFFFFFFFF;
+ } else if (written == 1) {
+ id.gi_offset |= 0xFFFF0000;
+ }
+ } else {
+ id.gi_offset = 0xFFFFFFFF;
+ }
}
RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true);
@@ -711,7 +749,8 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
//global scope bindings
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, 0);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_pass_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, 2);
MaterialData *prev_material = nullptr;
// ShaderData *prev_shader = nullptr;
@@ -752,7 +791,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
case VS::INSTANCE_MESH: {
primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index);
if (e->instance->skeleton.is_valid()) {
- xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, 1);
+ xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, 2);
}
} break;
case VS::INSTANCE_MULTIMESH: {
@@ -760,7 +799,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
ERR_CONTINUE(!mesh.is_valid()); //should be a bug
primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index);
- xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, 1);
+ xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, 2);
} break;
case VS::INSTANCE_IMMEDIATE: {
@@ -863,14 +902,14 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
}
if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, 2);
prev_xforms_uniform_set = xforms_uniform_set;
}
if (material != prev_material) {
//update uniform set
if (material->uniform_set.is_valid()) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, 3);
}
prev_material = material;
@@ -1449,6 +1488,59 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r
}
}
+void RasterizerSceneForwardRD::_setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform) {
+
+ int index = 0;
+
+ for (int i = 0; i < p_gi_probe_probe_cull_count; i++) {
+
+ RID rpi = p_gi_probe_probe_cull_result[i];
+
+ if (index >= (int)scene_state.max_gi_probes) {
+ continue;
+ }
+
+ int slot = gi_probe_instance_get_slot(rpi);
+ if (slot < 0) {
+ continue; //not usable
+ }
+
+ RID base_probe = gi_probe_instance_get_base_probe(rpi);
+
+ GIProbeData &gi_probe_ubo = scene_state.gi_probes[index];
+
+ Transform to_cell = gi_probe_instance_get_transform_to_cell(rpi) * p_camera_transform;
+
+ store_transform(to_cell, gi_probe_ubo.xform);
+
+ Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+
+ gi_probe_ubo.bounds[0] = bounds.x;
+ gi_probe_ubo.bounds[1] = bounds.y;
+ gi_probe_ubo.bounds[2] = bounds.z;
+
+ gi_probe_ubo.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
+ gi_probe_ubo.bias = storage->gi_probe_get_bias(base_probe);
+ gi_probe_ubo.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
+ gi_probe_ubo.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gi_probe_ubo.texture_slot = gi_probe_instance_get_slot(rpi);
+ gi_probe_ubo.anisotropy_strength = storage->gi_probe_get_anisotropy_strength(base_probe);
+
+ if (gi_probe_is_anisotropic()) {
+ gi_probe_ubo.texture_slot *= 3;
+ }
+
+ gi_probe_instance_set_render_index(rpi, index);
+ gi_probe_instance_set_render_pass(rpi, render_pass);
+
+ index++;
+ }
+
+ if (index) {
+ RD::get_singleton()->buffer_update(scene_state.gi_probe_buffer, 0, index * sizeof(GIProbeData), scene_state.gi_probes, true);
+ }
+}
+
void RasterizerSceneForwardRD::_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) {
uint32_t light_count = 0;
@@ -1632,7 +1724,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
}
}
-void RasterizerSceneForwardRD::_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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RasterizerSceneForwardRD::_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) {
RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)p_buffer_data;
@@ -1664,6 +1756,8 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
RENDER_TIMESTAMP("Setup 3D Scene");
+ _update_render_base_uniform_set();
+
bool using_shadows = true;
if (p_reflection_probe.is_valid()) {
@@ -1687,6 +1781,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
RID render_target;
Size2 screen_pixel_size;
RID opaque_framebuffer;
+ RID depth_framebuffer;
RID alpha_framebuffer;
if (render_buffer) {
@@ -1695,6 +1790,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
render_target = render_buffer->render_target;
opaque_framebuffer = render_buffer->color_fb;
+ depth_framebuffer = render_buffer->depth_fb;
alpha_framebuffer = opaque_framebuffer;
} else if (p_reflection_probe.is_valid()) {
@@ -1703,6 +1799,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
screen_pixel_size.height = 1.0 / resolution;
opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass);
+ depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_reflection_probe, p_reflection_probe_pass);
alpha_framebuffer = opaque_framebuffer;
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
@@ -1715,337 +1812,11 @@ 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);
-#if 0
- for (int i = 0; i < p_light_cull_count; i++) {
-
- ERR_BREAK(i >= RenderList::MAX_LIGHTS);
-
- LightInstance *li = light_instance_owner.getornull(p_light_cull_result[i]);
- if (li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] > CMP_EPSILON) {
- state.used_contact_shadows = true;
- }
- }
-#endif
-#if 0
- // Do depth prepass if it's explicitly enabled
- bool use_depth_prepass = storage->config.use_depth_prepass;
-
- // If contact shadows are used then we need to do depth prepass even if it's otherwise disabled
- use_depth_prepass = use_depth_prepass || state.used_contact_shadows;
-
- // Never do depth prepass if effects are disabled or if we render overdraws
- use_depth_prepass = use_depth_prepass && storage->frame.current_rt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS];
- use_depth_prepass = use_depth_prepass && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
-
- if (use_depth_prepass) {
- //pre z pass
-
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- glDrawBuffers(0, NULL);
-
- glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
-
- glColorMask(0, 0, 0, 0);
- glClearDepth(1.0f);
- glClear(GL_DEPTH_BUFFER_BIT);
-
- render_list.clear();
- _fill_render_list(p_cull_result, p_cull_count, true, false);
- render_list.sort_by_key(false);
- state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, true);
- _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, 0, false, false, true, false, false);
- state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false);
-
- glColorMask(1, 1, 1, 1);
-
- if (state.used_contact_shadows) {
-
- _prepare_depth_texture();
- _bind_depth_texture();
- }
-
- fb_cleared = true;
- render_pass++;
- state.used_depth_prepass = true;
- } else {
- state.used_depth_prepass = false;
- }
-
- _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas);
- _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_reflection_atlas, env);
-
- bool use_mrt = false;
-#endif
-
render_list.clear();
_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
-#if 0
- //
-
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
-
- //rendering to a probe cubemap side
- ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe);
- GLuint current_fbo;
-
- if (probe) {
-
- ReflectionAtlas *ref_atlas = reflection_atlas_owner.getornull(probe->atlas);
- ERR_FAIL_COND(!ref_atlas);
-
- int target_size = ref_atlas->size / ref_atlas->subdiv;
-
- int cubemap_index = reflection_cubemaps.size() - 1;
-
- for (int i = reflection_cubemaps.size() - 1; i >= 0; i--) {
- //find appropriate cubemap to render to
- if (reflection_cubemaps[i].size > target_size * 2)
- break;
-
- cubemap_index = i;
- }
-
- current_fbo = reflection_cubemaps[cubemap_index].fbo_id[p_reflection_probe_pass];
- use_mrt = false;
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false);
-
- glViewport(0, 0, reflection_cubemaps[cubemap_index].size, reflection_cubemaps[cubemap_index].size);
- glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
-
- } else {
-
- use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); //only enable MRT rendering if any of these is enabled
- //effects disabled and transparency also prevent using MRTs
- use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT];
- use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS];
- use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
- use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS);
-
- glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
-
- if (use_mrt) {
-
- current_fbo = storage->frame.current_rt->buffers.fbo;
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, true);
-
- Vector<GLenum> draw_buffers;
- draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
- draw_buffers.push_back(GL_COLOR_ATTACHMENT1);
- draw_buffers.push_back(GL_COLOR_ATTACHMENT2);
- if (state.used_sss) {
- draw_buffers.push_back(GL_COLOR_ATTACHMENT3);
- }
- glDrawBuffers(draw_buffers.size(), draw_buffers.ptr());
-
- Color black(0, 0, 0, 0);
- glClearBufferfv(GL_COLOR, 1, black.components); // specular
- glClearBufferfv(GL_COLOR, 2, black.components); // normal metal rough
- if (state.used_sss) {
- glClearBufferfv(GL_COLOR, 3, black.components); // normal metal rough
- }
-
- } else {
-
- if (storage->frame.current_rt->buffers.active) {
- current_fbo = storage->frame.current_rt->buffers.fbo;
- } else {
- current_fbo = storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo;
- }
-
- glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false);
-
- Vector<GLenum> draw_buffers;
- draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
- glDrawBuffers(draw_buffers.size(), draw_buffers.ptr());
- }
- }
-
- if (!fb_cleared) {
- glClearDepth(1.0f);
- glClear(GL_DEPTH_BUFFER_BIT);
- }
-
- Color clear_color(0, 0, 0, 0);
-
- RasterizerStorageGLES3::Sky *sky = NULL;
- Ref<CameraFeed> feed;
- GLuint env_radiance_tex = 0;
-
- if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
- clear_color = Color(0, 0, 0, 0);
- storage->frame.clear_request = false;
- } else if (!probe && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- clear_color = Color(0, 0, 0, 0);
- storage->frame.clear_request = false;
-
- } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR) {
-
- if (storage->frame.clear_request) {
-
- clear_color = storage->frame.clear_request_color.to_linear();
- storage->frame.clear_request = false;
- }
-
- } else if (env->bg_mode == VS::ENV_BG_CANVAS) {
-
- clear_color = env->bg_color.to_linear();
- storage->frame.clear_request = false;
- } else if (env->bg_mode == VS::ENV_BG_COLOR) {
-
- clear_color = env->bg_color.to_linear();
- storage->frame.clear_request = false;
- } else if (env->bg_mode == VS::ENV_BG_SKY) {
-
- storage->frame.clear_request = false;
-
- } else if (env->bg_mode == VS::ENV_BG_COLOR_SKY) {
-
- clear_color = env->bg_color.to_linear();
- storage->frame.clear_request = false;
-
- } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) {
- feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id);
- storage->frame.clear_request = false;
- } else {
- storage->frame.clear_request = false;
- }
-
- if (!env || env->bg_mode != VS::ENV_BG_KEEP) {
- glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular
- }
-
- VS::EnvironmentBG bg_mode = (!env || (probe && env->bg_mode == VS::ENV_BG_CANVAS)) ? VS::ENV_BG_CLEAR_COLOR : env->bg_mode; //if no environment, or canvas while rendering a probe (invalid use case), use color.
-
- if (env) {
- switch (bg_mode) {
- case VS::ENV_BG_COLOR_SKY:
- case VS::ENV_BG_SKY:
-
- sky = storage->sky_owner.getornull(env->sky);
-
- if (sky) {
- env_radiance_tex = sky->radiance;
- }
- break;
- case VS::ENV_BG_CANVAS:
- //copy canvas to 3d buffer and convert it to linear
-
- glDisable(GL_BLEND);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true);
-
- storage->shaders.copy.bind();
-
- _copy_screen(true, true);
-
- //turn off everything used
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false);
-
- //restore
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- break;
- case VS::ENV_BG_CAMERA_FEED:
- if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) {
- // copy our camera feed to our background
-
- glDisable(GL_BLEND);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, true);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true);
-
- if (feed->get_datatype() == CameraFeed::FEED_RGB) {
- RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE);
-
- VS::get_singleton()->texture_bind(camera_RGBA, 0);
- } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) {
- RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE);
-
- VS::get_singleton()->texture_bind(camera_YCbCr, 0);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true);
-
- } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) {
- RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE);
- RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE);
-
- VS::get_singleton()->texture_bind(camera_Y, 0);
- VS::get_singleton()->texture_bind(camera_CbCr, 1);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, true);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true);
- };
-
- storage->shaders.copy.bind();
- storage->shaders.copy.set_uniform(CopyShaderGLES3::DISPLAY_TRANSFORM, feed->get_transform());
-
- _copy_screen(true, true);
-
- //turn off everything used
- storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, false);
-
- //restore
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- } else {
- // don't have a feed, just show greenscreen :)
- clear_color = Color(0.0, 1.0, 0.0, 1.0);
- }
- break;
- default: {
- }
- }
- }
-
- if (probe && probe->probe_ptr->interior) {
- env_radiance_tex = 0; //for rendering probe interiors, radiance must not be used.
- }
-
- state.texscreen_copied = false;
-
- glBlendEquation(GL_FUNC_ADD);
-
- if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- } else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
- }
-#endif
RID radiance_cubemap;
bool draw_sky = false;
@@ -2097,27 +1868,50 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
RENDER_TIMESTAMP("Render Opaque Pass");
- _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, p_reflection_atlas);
+ _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, p_reflection_atlas);
render_list.sort_by_key(false);
_fill_instances(render_list.elements, render_list.element_count);
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;
bool using_separate_specular = false;
+ bool depth_pre_pass = depth_framebuffer.is_valid();
+ if (depth_pre_pass) { //depth pre pass
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_DEPTH, render_buffer == nullptr);
+ RD::get_singleton()->draw_list_end();
+ }
+
{
+ bool will_continue = (can_continue || draw_sky || debug_giprobes);
//regular forward for now
Vector<Color> c;
c.push_back(clear_color.to_linear());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP_COLOR : RD::INITIAL_ACTION_CLEAR, (can_continue || draw_sky) ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH, c);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, render_buffer == nullptr);
RD::get_singleton()->draw_list_end();
}
+ if (debug_giprobes) {
+ //debug giprobes
+ bool will_continue = (can_continue || draw_sky);
+ CameraMatrix dc;
+ dc.set_depth_correction(true);
+ CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ for (int i = 0; i < p_gi_probe_cull_count; i++) {
+ _debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, 1.0);
+ }
+ RD::get_singleton()->draw_list_end();
+ }
+
if (draw_sky) {
RENDER_TIMESTAMP("Render Sky");
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
_draw_sky(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), p_environment, p_cam_projection, p_cam_transform, 1.0);
RD::get_singleton()->draw_list_end();
@@ -2128,93 +1922,6 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
}
}
- //_render_list
-#if 0
- if (state.directional_light_count == 0) {
- directional_light = NULL;
- _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, false, shadow_atlas != NULL);
- } else {
- for (int i = 0; i < state.directional_light_count; i++) {
- directional_light = directional_lights[i];
- if (i > 0) {
- glEnable(GL_BLEND);
- }
- _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
- _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, i > 0, shadow_atlas != NULL);
- }
- }
-
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false);
-
- if (use_mrt) {
- GLenum gldb = GL_COLOR_ATTACHMENT0;
- glDrawBuffers(1, &gldb);
- }
-
- if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || (!storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW))) {
-
- /*
- if (use_mrt) {
- glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters
- */
-
- if (sky && sky->panorama.is_valid())
- _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation);
- }
-
- //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true);
- //glColorMask(1,1,1,1);
-
- //state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false);
-
- if (use_mrt) {
-
- _render_mrts(env, p_cam_projection);
- } else {
- // Here we have to do the blits/resolves that otherwise are done in the MRT rendering, in particular
- // - prepare screen texture for any geometry that uses a shader with screen texture
- // - prepare depth texture for any geometry that uses a shader with depth texture
-
- bool framebuffer_dirty = false;
-
- if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_screen_texture) {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- glReadBuffer(GL_COLOR_ATTACHMENT0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo);
- glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- _blur_effect_buffer();
- framebuffer_dirty = true;
- }
-
- if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_depth_texture) {
- _prepare_depth_texture();
- framebuffer_dirty = true;
- }
-
- if (framebuffer_dirty) {
- // Restore framebuffer
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
- }
- }
-
- if (storage->frame.current_rt && state.used_depth_texture && storage->frame.current_rt->buffers.active) {
- _bind_depth_texture();
- }
-
- if (storage->frame.current_rt && state.used_screen_texture && storage->frame.current_rt->buffers.active) {
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color);
- }
-
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
-#endif
-
RENDER_TIMESTAMP("Render Transparent Pass");
render_list.sort_by_reverse_depth_and_priority(true);
@@ -2222,7 +1929,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
_fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count);
{
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP_COLOR_AND_DEPTH, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH);
+ 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);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr);
RD::get_singleton()->draw_list_end();
}
@@ -2266,7 +1973,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
storage->render_target_disable_clear_request(render_buffer->render_target);
- if (false) {
+ if (render_buffer && debug_draw == VS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
if (p_shadow_atlas.is_valid()) {
RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
Size2 rtsize = storage->render_target_get_size(render_buffer->render_target);
@@ -2275,7 +1982,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
}
}
- if (false) {
+ if (render_buffer && debug_draw == VS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) {
if (directional_shadow_get_texture().is_valid()) {
RID shadow_atlas_texture = directional_shadow_get_texture();
Size2 rtsize = storage->render_target_get_size(render_buffer->render_target);
@@ -2345,6 +2052,8 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
RENDER_TIMESTAMP("Setup Rendering Shadow");
+ _update_render_base_uniform_set();
+
render_pass++;
scene_state.ubo.shadow_z_offset = p_bias;
@@ -2360,7 +2069,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
_fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
- _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
+ _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
RENDER_TIMESTAMP("Render Shadow");
@@ -2370,16 +2079,142 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
{
//regular forward for now
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH);
+ 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);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true);
RD::get_singleton()->draw_list_end();
}
}
-void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas) {
+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()) {
+
+ if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.light_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.reflection_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.gi_probe_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ int slot_count = gi_probe_get_slots().size();
+ if (gi_probe_is_anisotropic()) {
+ u.ids.resize(slot_count * 3);
+ } else {
+ u.ids.resize(slot_count);
+ }
+ for (int i = 0; i < slot_count; i++) {
+
+ RID probe = gi_probe_get_slots()[i];
+
+ if (gi_probe_is_anisotropic()) {
+ if (probe.is_null()) {
+ RID empty_tex = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.write[i * 3 + 0] = empty_tex;
+ u.ids.write[i * 3 + 1] = empty_tex;
+ u.ids.write[i * 3 + 2] = empty_tex;
+ } else {
+ u.ids.write[i * 3 + 0] = gi_probe_instance_get_texture(probe);
+ u.ids.write[i * 3 + 1] = gi_probe_instance_get_aniso_texture(probe, 0);
+ u.ids.write[i * 3 + 2] = gi_probe_instance_get_aniso_texture(probe, 1);
+ }
+ } else {
+ if (probe.is_null()) {
+ u.ids.write[i] = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ } else {
+ u.ids.write[i] = gi_probe_instance_get_texture(probe);
+ }
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 0);
+
+ gi_probe_slots_make_not_dirty();
+ }
+}
+
+void RasterizerSceneForwardRD::_setup_render_pass_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas) {
- if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
- RD::get_singleton()->free(render_base_uniform_set);
+ if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) {
+ RD::get_singleton()->free(render_pass_uniform_set);
}
//default render buffer and scene state uniform set
@@ -2387,7 +2222,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
- u.binding = 1;
+ u.binding = 0;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_depth_buffer.is_valid() ? p_depth_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
u.ids.push_back(texture);
@@ -2395,7 +2230,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
}
{
RD::Uniform u;
- u.binding = 2;
+ u.binding = 1;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_color_buffer.is_valid() ? p_color_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
@@ -2403,7 +2238,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
}
{
RD::Uniform u;
- u.binding = 3;
+ u.binding = 2;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_normal_buffer.is_valid() ? p_normal_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
u.ids.push_back(texture);
@@ -2412,7 +2247,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 3;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_roughness_limit_buffer.is_valid() ? p_roughness_limit_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
@@ -2421,7 +2256,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 4;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_radiance_cubemap.is_valid() ? p_radiance_cubemap : storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
u.ids.push_back(texture);
@@ -2429,62 +2264,10 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
}
{
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.resize(12);
- RID *ids_ptr = u.ids.ptrw();
- ids_ptr[0] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 7;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(shadow_sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 8;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.uniform_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(scene_state.instance_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 10;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.reflection_buffer);
- uniforms.push_back(u);
- }
-
- {
RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
RD::Uniform u;
- u.binding = 11;
+ u.binding = 5;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (ref_texture.is_valid()) {
u.ids.push_back(ref_texture);
@@ -2496,15 +2279,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 12;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.light_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 13;
+ u.binding = 6;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (p_shadow_atlas.is_valid()) {
u.ids.push_back(shadow_atlas_get_texture(p_shadow_atlas));
@@ -2516,15 +2291,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 14;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.directional_light_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 15;
+ u.binding = 7;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (directional_shadow_get_texture().is_valid()) {
u.ids.push_back(directional_shadow_get_texture());
@@ -2534,7 +2301,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
uniforms.push_back(u);
}
- render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 0);
+ render_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 1);
}
RasterizerSceneForwardRD *RasterizerSceneForwardRD::singleton = NULL;
@@ -2543,6 +2310,10 @@ void RasterizerSceneForwardRD::set_time(double p_time) {
time = p_time;
}
+void RasterizerSceneForwardRD::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {
+ debug_draw = p_debug_draw;
+}
+
RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storage) :
RasterizerSceneRD(p_storage) {
singleton = this;
@@ -2577,7 +2348,6 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
{ //lights
scene_state.max_lights = MIN(65536, uniform_max_size) / sizeof(LightData);
uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData);
- print_line("ID: " + itos(sizeof(InstanceData)));
scene_state.lights = memnew_arr(LightData, scene_state.max_lights);
scene_state.light_buffer = RD::get_singleton()->uniform_buffer_create(light_buffer_size);
defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n";
@@ -2589,6 +2359,32 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(scene_state.max_directional_lights) + "\n";
}
+ { //giprobes
+ int slot_count = gi_probe_get_slots().size();
+ if (gi_probe_is_anisotropic()) {
+ slot_count *= 3;
+ defines += "\n#define GI_PROBE_USE_ANISOTROPY\n";
+ }
+ if (gi_probe_is_high_quality()) {
+ defines += "\n#define GI_PROBE_HIGH_QUALITY\n";
+ }
+ defines += "\n#define MAX_GI_PROBE_TEXTURES " + itos(slot_count) + "\n";
+
+ uint32_t giprobe_buffer_size;
+ if (uniform_max_size < 65536) {
+ //Yes, you guessed right, ARM again
+ giprobe_buffer_size = uniform_max_size;
+ } else {
+ giprobe_buffer_size = 65536;
+ }
+
+ giprobe_buffer_size = MIN(sizeof(GIProbeData) * gi_probe_get_slots().size(), giprobe_buffer_size);
+ scene_state.max_gi_probes = giprobe_buffer_size / sizeof(GIProbeData);
+ scene_state.gi_probes = memnew_arr(GIProbeData, scene_state.max_gi_probes);
+ scene_state.gi_probe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * scene_state.max_gi_probes);
+ defines += "\n#define MAX_GI_PROBES " + itos(scene_state.max_gi_probes) + "\n";
+ }
+
Vector<String> shader_versions;
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
@@ -2733,7 +2529,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
- actions.texture_layout_set = 2;
+ actions.texture_layout_set = 3;
actions.base_uniform_string = "material.";
actions.base_varying_index = 10;
@@ -2777,7 +2573,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
u.binding = 0;
uniforms.push_back(u);
- default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 1);
+ default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 2);
}
{
@@ -2792,8 +2588,8 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
RasterizerSceneForwardRD::~RasterizerSceneForwardRD() {
//clear base uniform set if still valid
- if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
- RD::get_singleton()->free(render_base_uniform_set);
+ if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) {
+ RD::get_singleton()->free(render_pass_uniform_set);
}
{
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
index 73d48c5fe8..f62fe11de7 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
@@ -188,6 +188,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
//for rendering, may be MSAAd
RID color;
RID depth;
+ RID depth_fb;
RID color_fb;
RID color_only_fb;
int width, height;
@@ -204,7 +205,9 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
RID shadow_sampler;
RID render_base_uniform_set;
- void _setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas);
+ RID render_pass_uniform_set;
+ void _update_render_base_uniform_set();
+ void _setup_render_pass_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas);
/* Scene State UBO */
@@ -247,6 +250,20 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
float shadow_matrices[4][16];
};
+ struct GIProbeData {
+ float xform[16];
+ float bounds[3];
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ uint32_t blend_ambient;
+ uint32_t texture_slot;
+
+ float anisotropy_strength;
+ uint32_t pad[3];
+ };
+
enum {
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
@@ -315,6 +332,11 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
RID reflection_buffer;
uint32_t max_reflection_probes_per_instance;
+ GIProbeData *gi_probes;
+ uint32_t max_gi_probes;
+ RID gi_probe_buffer;
+ uint32_t max_gi_probe_probes_per_instance;
+
LightData *lights;
uint32_t max_lights;
RID light_buffer;
@@ -498,6 +520,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
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_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 _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);
@@ -508,13 +531,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
void _draw_sky(RD::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha);
+ VS::ViewportDebugDraw debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED;
+
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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+ 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);
public:
virtual void set_time(double p_time);
- virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {}
+ virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw);
virtual bool free(RID p_rid);
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
index 888568e21a..e292f9c69b 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -619,6 +619,10 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R
atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
}
}
+
+ Vector<RID> fb;
+ fb.push_back(atlas->depth_buffer);
+ atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
}
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
@@ -700,6 +704,16 @@ RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance,
return atlas->reflections[rpi->atlas_index].fbs[p_index];
}
+RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_INDEX_V(p_index, 6, RID());
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->depth_fb;
+}
+
///////////////////////////////////////////////////////////
RID RasterizerSceneRD::shadow_atlas_create() {
@@ -1192,6 +1206,454 @@ RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p
return &shadow_maps[p_size];
}
+/////////////////////////////////
+
+RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) {
+ //find a free slot
+ int index = -1;
+ for (int i = 0; i < gi_probe_slots.size(); i++) {
+ if (gi_probe_slots[i] == RID()) {
+ index = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND_V(index == -1, RID());
+
+ GIProbeInstance gi_probe;
+ gi_probe.slot = index;
+ gi_probe.probe = p_base;
+ RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+ gi_probe_slots.write[index] = rid;
+
+ return rid;
+}
+
+void RasterizerSceneRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
+
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->transform = p_xform;
+}
+
+bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gi_probe, false);
+
+ //return true;
+ 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) {
+
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe);
+
+ // (RE)CREATE IF NEEDED
+
+ if (gi_probe->last_probe_data_version != data_version) {
+ //need to re-create everything
+ if (gi_probe->texture.is_valid()) {
+ RD::get_singleton()->free(gi_probe->texture);
+ if (gi_probe_use_anisotropy) {
+ RD::get_singleton()->free(gi_probe->anisotropy[0]);
+ RD::get_singleton()->free(gi_probe->anisotropy[1]);
+ }
+ RD::get_singleton()->free(gi_probe->write_buffer);
+ gi_probe->mipmaps.clear();
+ }
+
+ Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
+
+ if (octree_size != Vector3i()) {
+ //can create a 3D texture
+ PoolVector<int> levels = storage->gi_probe_get_level_counts(gi_probe->probe);
+
+ for (int i = 0; i < levels.size(); i++) {
+ print_line("level " + itos(i) + ": " + itos(levels[i]));
+ }
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tf.width = octree_size.x;
+ tf.height = octree_size.y;
+ tf.depth = octree_size.z;
+ tf.type = RD::TEXTURE_TYPE_3D;
+ tf.mipmaps = levels.size();
+
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+ gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+
+ if (gi_probe_use_anisotropy) {
+ tf.format = RD::DATA_FORMAT_R5G6B5_UNORM_PACK16;
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R5G6B5_UNORM_PACK16);
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
+
+ gi_probe->anisotropy[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ gi_probe->anisotropy[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ RD::get_singleton()->texture_clear(gi_probe->anisotropy[0], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+ RD::get_singleton()->texture_clear(gi_probe->anisotropy[1], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+ }
+
+ {
+ int total_elements = 0;
+ for (int i = 0; i < levels.size(); i++) {
+ total_elements += levels[i];
+ }
+
+ if (gi_probe_use_anisotropy) {
+ total_elements *= 6;
+ }
+
+ gi_probe->write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16);
+ }
+
+ for (int i = 0; i < levels.size(); i++) {
+ GIProbeInstance::Mipmap mipmap;
+ mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), gi_probe->texture, 0, i, RD::TEXTURE_SLICE_3D);
+ if (gi_probe_use_anisotropy) {
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R16_UINT;
+ mipmap.anisotropy[0] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[0], 0, i, RD::TEXTURE_SLICE_3D);
+ mipmap.anisotropy[1] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[1], 0, i, RD::TEXTURE_SLICE_3D);
+ }
+
+ mipmap.level = levels.size() - i - 1;
+ mipmap.cell_offset = 0;
+ for (uint32_t j = 0; j < mipmap.level; j++) {
+ mipmap.cell_offset += levels[j];
+ }
+ mipmap.cell_count = levels[mipmap.level];
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 4;
+ u.ids.push_back(gi_probe->write_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ Vector<RD::Uniform> copy_uniforms = uniforms;
+ if (i == 0) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(gi_probe_lights_uniform);
+ copy_uniforms.push_back(u);
+ }
+
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
+
+ copy_uniforms = uniforms; //restore
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ 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) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 7;
+ u.ids.push_back(gi_probe->anisotropy[0]);
+ copy_uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 8;
+ u.ids.push_back(gi_probe->anisotropy[1]);
+ copy_uniforms.push_back(u);
+ }
+ }
+
+ mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
+ } else {
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(mipmap.texture);
+ uniforms.push_back(u);
+ }
+
+ if (gi_probe_use_anisotropy) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(mipmap.anisotropy[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(mipmap.anisotropy[1]);
+ uniforms.push_back(u);
+ }
+ }
+
+ mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
+
+ gi_probe->mipmaps.push_back(mipmap);
+ }
+ }
+
+ gi_probe->last_probe_data_version = data_version;
+ }
+
+ // 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
+
+ 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.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.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);
+
+ 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();
+
+ 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;
+
+ 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 (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;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, (gi_probe->mipmaps[i].cell_count - 1) / 64 + 1, 1, 1);
+ }
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+
+ 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;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, (gi_probe->mipmaps[i].cell_count - 1) / 64 + 1, 1, 1);
+ }
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+
+ gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
+ print_line("update GI");
+}
+
+void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, float p_alpha) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ if (gi_probe->mipmaps.size() == 0) {
+ return;
+ }
+
+ 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;
+
+ GIProbeDebugPushConstant push_constant;
+ push_constant.alpha = p_alpha;
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
+ push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
+ push_constant.level = level;
+
+ int cell_count = gi_probe->mipmaps[level].cell_count;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+
+ push_constant.projection[i * 4 + j] = transform.matrix[i][j];
+ }
+ }
+
+ if (giprobe_debug_uniform_set.is_valid()) {
+ RD::get_singleton()->free(giprobe_debug_uniform_set);
+ }
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(gi_probe->texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 3;
+ u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ if (gi_probe_use_anisotropy) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 4;
+ u.ids.push_back(gi_probe->anisotropy[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ u.ids.push_back(gi_probe->anisotropy[1]);
+ uniforms.push_back(u);
+ }
+ }
+
+ 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_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_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);
+}
+
+const Vector<RID> &RasterizerSceneRD::gi_probe_get_slots() const {
+
+ return gi_probe_slots;
+}
+
+bool RasterizerSceneRD::gi_probe_slots_are_dirty() const {
+ return gi_probe_slots_dirty;
+}
+
+void RasterizerSceneRD::gi_probe_slots_make_not_dirty() {
+ gi_probe_slots_dirty = false;
+}
+
+bool RasterizerSceneRD::gi_probe_is_high_quality() const {
+ return gi_probe_use_6_cones;
+}
////////////////////////////////
RID RasterizerSceneRD::render_buffers_create() {
@@ -1218,12 +1680,12 @@ 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) {
+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_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) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb && p_render_buffers.is_valid());
- _render_scene(rb ? rb->data : (RenderBufferData *)NULL, 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);
+ _render_scene(rb ? rb->data : (RenderBufferData *)NULL, 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_gi_probe_cull_result, p_gi_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
}
void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
@@ -1418,6 +1880,20 @@ bool RasterizerSceneRD::free(RID p_rid) {
//ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
reflection_probe_release_atlas_index(p_rid);
reflection_probe_instance_owner.free(p_rid);
+ } else if (gi_probe_instance_owner.owns(p_rid)) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid);
+ if (gi_probe->texture.is_valid()) {
+ RD::get_singleton()->free(gi_probe->texture);
+ RD::get_singleton()->free(gi_probe->write_buffer);
+ }
+ if (gi_probe->anisotropy[0].is_valid()) {
+ RD::get_singleton()->free(gi_probe->anisotropy[0]);
+ RD::get_singleton()->free(gi_probe->anisotropy[1]);
+ }
+
+ gi_probe_slots.write[gi_probe->slot] = RID();
+
+ gi_probe_instance_owner.free(p_rid);
} else if (sky_owner.owns(p_rid)) {
_update_dirty_skys();
Sky *sky = sky_owner.getornull(p_rid);
@@ -1470,13 +1946,83 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections");
// sky_use_cubemap_array = false;
+ uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
+
{
- String defines = "";
+
+ //kinda complicated to compute the amount of slots, we try to use as many as we can
+
+ gi_probe_max_lights = 32;
+
+ gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
+ gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
+
+ gi_probe_use_anisotropy = GLOBAL_GET("rendering/quality/gi_probes/anisotropic");
+ gi_probe_use_6_cones = GLOBAL_GET("rendering/quality/gi_probes/high_quality");
+
+ if (textures_per_stage <= 16) {
+ gi_probe_slots.resize(2); //thats all you can get
+ gi_probe_use_anisotropy = false;
+ } else if (textures_per_stage <= 31) {
+ gi_probe_slots.resize(4); //thats all you can get, iOS
+ gi_probe_use_anisotropy = false;
+ } else if (textures_per_stage <= 128) {
+ gi_probe_slots.resize(32); //old intel
+ gi_probe_use_anisotropy = false;
+ } else if (textures_per_stage <= 256) {
+ gi_probe_slots.resize(64); //old intel too
+ gi_probe_use_anisotropy = false;
+ } else {
+ if (gi_probe_use_anisotropy) {
+ gi_probe_slots.resize(1024 / 3); //needs 3 textures
+ } else {
+ gi_probe_slots.resize(1024); //modern intel, nvidia, 8192 or greater
+ }
+ }
+
+ String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+ if (gi_probe_use_anisotropy) {
+ defines += "\n#define MODE_ANISOTROPIC\n";
+ }
+
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
+ 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");
+
+ giprobe_shader.initialize(versions, defines);
+ giprobe_lighting_shader_version = giprobe_shader.version_create();
+ for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
+ giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
+ giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
+ }
+ }
+
+ {
+
+ String defines;
+ if (gi_probe_use_anisotropy) {
+ defines += "\n#define USE_ANISOTROPY\n";
+ }
Vector<String> versions;
- versions.push_back("");
- giprobe_lighting_shader.initialize(versions, defines);
- giprobe_lighting_shader_version = giprobe_lighting_shader.version_create();
- giprobe_lighting_shader_version_shader = giprobe_lighting_shader.version_get_shader(giprobe_lighting_shader_version, 0);
+ versions.push_back("\n#define MODE_DEBUG_COLOR\n");
+ versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
+
+ giprobe_debug_shader.initialize(versions, defines);
+ giprobe_debug_shader_version = giprobe_debug_shader.version_create();
+ for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
+ giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
+
+ RD::PipelineRasterizationState rs;
+ rs.cull_mode = RD::POLYGON_CULL_FRONT;
+ RD::PipelineDepthStencilState ds;
+ ds.enable_depth_test = true;
+ ds.enable_depth_write = true;
+ ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+
+ giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
}
}
@@ -1489,4 +2035,7 @@ RasterizerSceneRD::~RasterizerSceneRD() {
for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) {
RD::get_singleton()->free(E->get().cubemap);
}
+
+ RD::get_singleton()->free(gi_probe_lights_uniform);
+ memdelete_arr(gi_probe_lights);
}
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
index 97e1d08d90..cb32880e13 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
@@ -4,7 +4,8 @@
#include "core/rid_owner.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl.gen.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe.glsl.gen.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl.gen.h"
#include "servers/visual/rendering_device.h"
class RasterizerSceneRD : public RasterizerScene {
@@ -16,9 +17,11 @@ protected:
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
- 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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
+ 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 _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, float p_alpha);
+
private:
int roughness_layers;
@@ -76,6 +79,7 @@ private:
RID reflection;
RID depth_buffer;
+ RID depth_fb;
struct Reflection {
RID owner;
@@ -111,9 +115,110 @@ private:
/* GIPROBE INSTANCE */
- GiprobeLightingShaderRD giprobe_lighting_shader;
+ struct GIProbeLight {
+
+ uint32_t type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ float color[3];
+ float spot_angle_radians;
+
+ float position[3];
+ float spot_attenuation;
+
+ float direction[3];
+ uint32_t has_shadow;
+ };
+
+ struct GIProbePushConstant {
+
+ int32_t limits[3];
+ uint32_t stack_size;
+
+ float emission_scale;
+ float propagation;
+ float dynamic_range;
+ uint32_t light_count;
+
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ float aniso_strength;
+ uint32_t pad;
+ };
+
+ struct GIProbeInstance {
+
+ RID probe;
+ RID texture;
+ RID anisotropy[2]; //only if anisotropy is used
+ RID write_buffer;
+
+ struct Mipmap {
+ RID texture;
+ RID anisotropy[2]; //only if anisotropy is used
+ RID uniform_set;
+ RID second_bounce_uniform_set;
+ RID write_uniform_set;
+ uint32_t level;
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ };
+ Vector<Mipmap> mipmaps;
+
+ int slot = -1;
+ uint32_t last_probe_version = 0;
+ uint32_t last_probe_data_version = 0;
+
+ uint64_t last_pass = 0;
+ uint32_t render_index = 0;
+
+ Transform transform;
+ };
+
+ GIProbeLight *gi_probe_lights;
+ uint32_t gi_probe_max_lights;
+ RID gi_probe_lights_uniform;
+
+ bool gi_probe_use_anisotropy = false;
+ bool gi_probe_use_6_cones = false;
+ bool gi_probe_slots_dirty = true;
+ Vector<RID> gi_probe_slots;
+
+ enum {
+ GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
+ GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
+ GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
+ GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
+ GI_PROBE_SHADER_VERSION_MAX
+ };
+ GiprobeShaderRD giprobe_shader;
RID giprobe_lighting_shader_version;
- RID giprobe_lighting_shader_version_shader;
+ RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
+ RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
+
+ mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+
+ enum {
+ GI_PROBE_DEBUG_COLOR,
+ GI_PROBE_DEBUG_LIGHT,
+ GI_PROBE_DEBUG_MAX
+ };
+
+ struct GIProbeDebugPushConstant {
+ float projection[16];
+ uint32_t cell_offset;
+ float dynamic_range;
+ float alpha;
+ uint32_t level;
+ };
+
+ GiprobeDebugShaderRD giprobe_debug_shader;
+ RID giprobe_debug_shader_version;
+ RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
+ RenderPipelineVertexFormatCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
+ RID giprobe_debug_uniform_set;
/* SHADOW ATLAS */
@@ -497,6 +602,7 @@ public:
uint32_t reflection_probe_instance_get_resolution(RID p_instance);
RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
+ RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
@@ -545,15 +651,70 @@ public:
return rpi->atlas_index;
}
- RID gi_probe_instance_create() { return RID(); }
- void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {}
- void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {}
- void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) {}
+ 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);
+ _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;
+ }
+ _FORCE_INLINE_ RID gi_probe_instance_get_base_probe(RID p_probe) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ return gi_probe->probe;
+ }
+ _FORCE_INLINE_ Transform gi_probe_instance_get_transform_to_cell(RID p_probe) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ return storage->gi_probe_get_to_cell_xform(gi_probe->probe) * gi_probe->transform.affine_inverse();
+ }
+
+ _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ return gi_probe->texture;
+ }
+ _FORCE_INLINE_ RID gi_probe_instance_get_aniso_texture(RID p_probe, int p_index) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ return gi_probe->anisotropy[p_index];
+ }
+
+ _FORCE_INLINE_ void gi_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!gi_probe);
+ gi_probe->render_index = p_render_index;
+ }
+
+ _FORCE_INLINE_ uint32_t gi_probe_instance_get_render_index(RID p_instance) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+
+ return gi_probe->render_index;
+ }
+
+ _FORCE_INLINE_ void gi_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
+ GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!g_probe);
+ g_probe->last_pass = p_render_pass;
+ }
+
+ _FORCE_INLINE_ uint32_t gi_probe_instance_get_render_pass(RID p_instance) {
+ GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!g_probe, 0);
+
+ return g_probe->last_pass;
+ }
+
+ const Vector<RID> &gi_probe_get_slots() const;
+ bool gi_probe_slots_are_dirty() const;
+ void gi_probe_slots_make_not_dirty();
+ _FORCE_INLINE_ bool gi_probe_is_anisotropic() const {
+ return gi_probe_use_anisotropy;
+ }
+ bool gi_probe_is_high_quality() const;
RID render_buffers_create();
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa);
- void 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);
+ void 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_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);
void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
index cd2f48b328..28ecda081d 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -987,6 +987,7 @@ void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_t
/* COMMON MATERIAL API */
RID RasterizerStorageRD::material_create() {
+
Material material;
material.data = NULL;
material.shader = NULL;
@@ -1924,7 +1925,7 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_
mesh->aabb.merge_with(p_surface.aabb);
}
- s->material = p_mesh;
+ s->material = p_surface.material;
mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
mesh->surfaces[mesh->surface_count] = s;
@@ -1995,6 +1996,8 @@ VS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface)
sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
sd.vertex_count = s.vertex_count;
sd.index_count = s.index_count;
+ sd.primitive = s.primitive;
+
if (sd.index_count) {
sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
}
@@ -3544,6 +3547,253 @@ float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribut
return reflection_probe->interior_ambient_probe_contrib;
}
+RID RasterizerStorageRD::gi_probe_create() {
+
+ return gi_probe_owner.make_rid(GIProbe());
+}
+
+void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ 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;
+ }
+
+ 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->to_cell_xform = p_to_cell_xform;
+ gi_probe->bounds = p_aabb;
+ 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()) {
+ 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;
+
+ ERR_FAIL_COND(p_data_cells.size() != cell_count * 16); //see that data size matches
+
+ gi_probe->cell_count = cell_count;
+ gi_probe->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
+ 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;
+ }
+
+ gi_probe->version++;
+ if (data_version_changed) {
+ gi_probe->data_version++;
+ }
+ gi_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
+AABB RasterizerStorageRD::gi_probe_get_bounds(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, AABB());
+
+ return gi_probe->bounds;
+}
+
+Vector3i RasterizerStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Vector3i());
+ return gi_probe->octree_size;
+}
+PoolVector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, PoolVector<uint8_t>());
+
+ if (gi_probe->octree_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer);
+ }
+ return PoolVector<uint8_t>();
+}
+PoolVector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, PoolVector<uint8_t>());
+
+ if (gi_probe->data_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer);
+ }
+ return PoolVector<uint8_t>();
+}
+PoolVector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, PoolVector<int>());
+
+ return gi_probe->level_counts;
+}
+Transform RasterizerStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Transform());
+
+ return gi_probe->to_cell_xform;
+}
+
+void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->dynamic_range = p_range;
+ gi_probe->version++;
+}
+float RasterizerStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+
+ return gi_probe->dynamic_range;
+}
+
+void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->propagation = p_range;
+ gi_probe->version++;
+}
+float RasterizerStorageRD::gi_probe_get_propagation(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->propagation;
+}
+
+void RasterizerStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->energy = p_energy;
+}
+float RasterizerStorageRD::gi_probe_get_energy(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->energy;
+}
+
+void RasterizerStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->bias = p_bias;
+}
+float RasterizerStorageRD::gi_probe_get_bias(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->bias;
+}
+
+void RasterizerStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->normal_bias = p_normal_bias;
+}
+float RasterizerStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->normal_bias;
+}
+
+void RasterizerStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->anisotropy_strength = p_strength;
+}
+
+float RasterizerStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->anisotropy_strength;
+}
+
+void RasterizerStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->interior = p_enable;
+}
+
+void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->use_two_bounces = p_enable;
+ gi_probe->version++;
+}
+
+bool RasterizerStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, false);
+ return gi_probe->use_two_bounces;
+}
+
+bool RasterizerStorageRD::gi_probe_is_interior(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->interior;
+}
+
+uint32_t RasterizerStorageRD::gi_probe_get_version(RID p_gi_probe) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->version;
+}
+
+uint32_t RasterizerStorageRD::gi_probe_get_data_version(RID p_gi_probe) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->data_version;
+}
+
+RID RasterizerStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+ return gi_probe->octree_buffer;
+}
+RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+ return gi_probe->data_buffer;
+}
+
/* RENDER TARGET API */
void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
@@ -3821,7 +4071,7 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
}
Vector<Color> clear_colors;
clear_colors.push_back(rt->clear_color);
- RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
+ RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
RD::get_singleton()->draw_list_end();
rt->clear_requested = false;
}
@@ -3899,6 +4149,9 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In
} else if (reflection_probe_owner.owns(p_base)) {
ReflectionProbe *rp = reflection_probe_owner.getornull(p_base);
p_instance->update_dependency(&rp->instance_dependency);
+ } else if (gi_probe_owner.owns(p_base)) {
+ GIProbe *gip = gi_probe_owner.getornull(p_base);
+ p_instance->update_dependency(&gip->instance_dependency);
} else if (light_owner.owns(p_base)) {
Light *l = light_owner.getornull(p_base);
p_instance->update_dependency(&l->instance_dependency);
@@ -3924,6 +4177,9 @@ VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
if (reflection_probe_owner.owns(p_rid)) {
return VS::INSTANCE_REFLECTION_PROBE;
}
+ if (gi_probe_owner.owns(p_rid)) {
+ return VS::INSTANCE_GI_PROBE;
+ }
if (light_owner.owns(p_rid)) {
return VS::INSTANCE_LIGHT;
}
@@ -4032,6 +4288,11 @@ bool RasterizerStorageRD::free(RID p_rid) {
ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid);
reflection_probe->instance_dependency.instance_notify_deleted(p_rid);
reflection_probe_owner.free(p_rid);
+ } else if (gi_probe_owner.owns(p_rid)) {
+ gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), PoolVector<uint8_t>(), PoolVector<uint8_t>(), PoolVector<int>()); //deallocate
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
+ gi_probe->instance_dependency.instance_notify_deleted(p_rid);
+ gi_probe_owner.free(p_rid);
} else if (light_owner.owns(p_rid)) {
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
index 6cdc21c2f0..289a2ae5a8 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
@@ -401,6 +401,42 @@ private:
mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
+ /* GI PROBE */
+
+ struct GIProbe {
+
+ RID octree_buffer;
+ RID data_buffer;
+
+ uint32_t octree_buffer_size = 0;
+ uint32_t data_buffer_size = 0;
+
+ PoolVector<int> level_counts;
+
+ int cell_count = 0;
+
+ Transform to_cell_xform;
+ AABB bounds;
+ Vector3i octree_size;
+
+ float dynamic_range = 4.0;
+ float energy = 1.0;
+ float bias = 1.4;
+ float normal_bias = 0.0;
+ float propagation = 0.7;
+ bool interior = false;
+ bool use_two_bounces = false;
+
+ float anisotropy_strength = 0.5;
+
+ uint32_t version = 1;
+ uint32_t data_version = 1;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<GIProbe> gi_probe_owner;
+
/* RENDER TARGET */
struct RenderTarget {
@@ -922,49 +958,46 @@ public:
/* GI PROBE API */
- RID gi_probe_create() { return RID(); }
+ RID gi_probe_create();
- void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) {}
- AABB gi_probe_get_bounds(RID p_probe) const { return AABB(); }
+ void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts);
- void gi_probe_set_cell_size(RID p_probe, float p_range) {}
- float gi_probe_get_cell_size(RID p_probe) const { return 0.0; }
+ AABB gi_probe_get_bounds(RID p_gi_probe) const;
+ Vector3i gi_probe_get_octree_size(RID p_gi_probe) const;
+ PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const;
+ PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const;
+ PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const;
+ Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const;
- void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) {}
- Transform gi_probe_get_to_cell_xform(RID p_probe) const { return Transform(); }
-
- void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data) {}
- PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const {
- PoolVector<int> p;
- return p;
- }
+ void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range);
+ float gi_probe_get_dynamic_range(RID p_gi_probe) const;
- void gi_probe_set_dynamic_range(RID p_probe, int p_range) {}
- int gi_probe_get_dynamic_range(RID p_probe) const { return 0; }
+ void gi_probe_set_propagation(RID p_gi_probe, float p_range);
+ float gi_probe_get_propagation(RID p_gi_probe) const;
- void gi_probe_set_energy(RID p_probe, float p_range) {}
- float gi_probe_get_energy(RID p_probe) const { return 0.0; }
+ void gi_probe_set_energy(RID p_gi_probe, float p_energy);
+ float gi_probe_get_energy(RID p_gi_probe) const;
- void gi_probe_set_bias(RID p_probe, float p_range) {}
- float gi_probe_get_bias(RID p_probe) const { return 0.0; }
+ void gi_probe_set_bias(RID p_gi_probe, float p_bias);
+ float gi_probe_get_bias(RID p_gi_probe) const;
- void gi_probe_set_normal_bias(RID p_probe, float p_range) {}
- float gi_probe_get_normal_bias(RID p_probe) const { return 0.0; }
+ void gi_probe_set_normal_bias(RID p_gi_probe, float p_range);
+ float gi_probe_get_normal_bias(RID p_gi_probe) const;
- void gi_probe_set_propagation(RID p_probe, float p_range) {}
- float gi_probe_get_propagation(RID p_probe) const { return 0.0; }
+ void gi_probe_set_interior(RID p_gi_probe, bool p_enable);
+ bool gi_probe_is_interior(RID p_gi_probe) const;
- void gi_probe_set_interior(RID p_probe, bool p_enable) {}
- bool gi_probe_is_interior(RID p_probe) const { return false; }
+ void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable);
+ bool gi_probe_is_using_two_bounces(RID p_gi_probe) const;
- void gi_probe_set_compress(RID p_probe, bool p_enable) {}
- bool gi_probe_is_compressed(RID p_probe) const { return false; }
+ void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength);
+ float gi_probe_get_anisotropy_strength(RID p_gi_probe) const;
- uint32_t gi_probe_get_version(RID p_probe) { return 0; }
+ uint32_t gi_probe_get_version(RID p_probe);
+ uint32_t gi_probe_get_data_version(RID p_probe);
- GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const { return GI_PROBE_UNCOMPRESSED; }
- RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) { return RID(); }
- void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {}
+ RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
+ RID gi_probe_get_data_buffer(RID p_gi_probe) const;
/* LIGHTMAP CAPTURE */
diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub
index 660523e29f..bce700f7b0 100644
--- a/servers/visual/rasterizer_rd/shaders/SCsub
+++ b/servers/visual/rasterizer_rd/shaders/SCsub
@@ -11,5 +11,6 @@ if 'RD_GLSL' in env['BUILDERS']:
env.RD_GLSL('sky.glsl');
env.RD_GLSL('tonemap.glsl');
env.RD_GLSL('copy.glsl');
- env.RD_GLSL('giprobe_lighting.glsl');
+ env.RD_GLSL('giprobe.glsl');
+ env.RD_GLSL('giprobe_debug.glsl');
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe.glsl b/servers/visual/rasterizer_rd/shaders/giprobe.glsl
new file mode 100644
index 0000000000..35b8d6ba6b
--- /dev/null
+++ b/servers/visual/rasterizer_rd/shaders/giprobe.glsl
@@ -0,0 +1,543 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+#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;
+
+#define LIGHT_TYPE_DIRECTIONAL 0
+#define LIGHT_TYPE_OMNI 1
+#define LIGHT_TYPE_SPOT 2
+
+#ifdef MODE_COMPUTE_LIGHT
+
+struct Light {
+
+ uint type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ vec3 color;
+ float spot_angle_radians;
+
+ vec3 position;
+ float spot_attenuation;
+
+ vec3 direction;
+ bool has_shadow;
+};
+
+
+layout(set=0,binding=3,std140) uniform Lights {
+ Light data[MAX_LIGHTS];
+} lights;
+
+
+
+#endif // MODE COMPUTE LIGHT
+
+
+#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;
+layout (set=0,binding=8) uniform texture3D aniso_neg_texture;
+#endif // MODE ANISOTROPIC
+
+#endif // MODE_SECOND_BOUNCE
+
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+ ivec3 limits;
+ uint stack_size;
+
+ float emission_scale;
+ float propagation;
+ float dynamic_range;
+
+ uint light_count;
+ uint cell_offset;
+ uint cell_count;
+ float aniso_strength;
+ uint pad;
+
+} params;
+
+
+layout(set=0,binding=4,std430) buffer Outputs {
+ vec4 data[];
+} outputs;
+
+#ifdef MODE_WRITE_TEXTURE
+
+layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
+
+#ifdef MODE_ANISOTROPIC
+
+layout (r16ui,set=0,binding=6) uniform restrict writeonly uimage3D aniso_pos_tex;
+layout (r16ui,set=0,binding=7) uniform restrict writeonly uimage3D aniso_neg_tex;
+
+#endif
+
+
+#endif
+
+
+#ifdef MODE_COMPUTE_LIGHT
+
+uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+
+ uint result = NO_CHILDREN;
+
+ ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
+
+ while (distance > -distance_adv) { //use this to avoid precision errors
+
+ uint cell = 0;
+
+ ivec3 pos = ivec3(from);
+
+ if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
+
+ ivec3 ofs = ivec3(0);
+ ivec3 half_size = size / 2;
+
+ for (int i = 0; i < params.stack_size - 1; i++) {
+
+ bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+
+ ofs += mix(ivec3(0),half_size,greater);
+
+ 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;
+ }
+
+ cell = cell_children.data[cell].children[child];
+ if (cell == NO_CHILDREN)
+ break;
+
+ half_size >>= ivec3(1);
+ }
+
+ if ( cell != NO_CHILDREN) {
+ return cell; //found cell!
+ }
+
+ }
+
+ from += direction * distance_adv;
+ distance -= distance_adv;
+ }
+
+ return NO_CHILDREN;
+}
+
+bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+
+
+ if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
+
+ light_pos = pos - lights.data[light].direction * length(vec3(params.limits));
+ attenuation = 1.0;
+
+ } else {
+
+ light_pos = lights.data[light].position;
+ float distance = length(pos - light_pos);
+ if (distance >= lights.data[light].radius) {
+ return false;
+ }
+
+
+ attenuation = pow( clamp( 1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation );
+
+
+ if (lights.data[light].type==LIGHT_TYPE_SPOT) {
+
+ vec3 rel = normalize(pos - light_pos);
+ float angle = acos(dot(rel,lights.data[light].direction));
+ if (angle > lights.data[light].spot_angle_radians) {
+ return false;
+ }
+
+ float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
+ attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+ }
+ }
+
+ return true;
+}
+
+float get_normal_advance(vec3 p_normal) {
+
+ vec3 normal = p_normal;
+ vec3 unorm = abs(normal);
+
+ if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+ } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+ } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
+ } else {
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3(1.0, 0.0, 0.0);
+ }
+
+ return 1.0 / dot(normal,unorm);
+}
+
+#endif
+
+
+
+
+void main() {
+
+ uint cell_index = gl_GlobalInvocationID.x;;
+ if (cell_index >= params.cell_count) {
+ return;
+ }
+ cell_index += 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);
+ vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
+
+/////////////////COMPUTE LIGHT///////////////////////////////
+
+#ifdef MODE_COMPUTE_LIGHT
+
+ vec3 pos = vec3(posu) + vec3(0.5);
+
+ vec3 emission = vec3(ivec3(cell_data.data[cell_index].emission&0x3FF,(cell_data.data[cell_index].emission>>10)&0x7FF,cell_data.data[cell_index].emission>>21)) * params.emission_scale;
+ vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+
+#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));
+ const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+#else
+ vec3 accum = vec3(0.0);
+#endif
+
+ 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)) {
+ continue;
+ }
+
+ vec3 light_dir = pos - light_pos;
+ float distance = length(light_dir);
+ light_dir=normalize(light_dir);
+
+ if (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0) {
+ continue; //not facing the light
+ }
+
+ 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;
+
+#ifdef MODE_ANISOTROPIC
+ for(uint j=0;j<6;j++) {
+
+ accum[j]+=max(0.0,dot(accum_dirs[j],-light_dir))*light+emission;
+ }
+#else
+ if (length(normal.xyz) > 0.2) {
+ accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
+ } else {
+ //all directions
+ accum+=light+emission;
+ }
+#endif
+ }
+
+
+#ifdef MODE_ANISOTROPIC
+
+ outputs.data[cell_index*6+0]=vec4(accum[0],0.0);
+ outputs.data[cell_index*6+1]=vec4(accum[1],0.0);
+ outputs.data[cell_index*6+2]=vec4(accum[2],0.0);
+ outputs.data[cell_index*6+3]=vec4(accum[3],0.0);
+ outputs.data[cell_index*6+4]=vec4(accum[4],0.0);
+ outputs.data[cell_index*6+5]=vec4(accum[5],0.0);
+#else
+ outputs.data[cell_index]=vec4(accum,0.0);
+
+#endif
+
+
+
+#endif //MODE_COMPUTE_LIGHT
+
+/////////////////SECOND BOUNCE///////////////////////////////
+#ifdef MODE_SECOND_BOUNCE
+ vec3 pos = vec3(posu) + vec3(0.5);
+ ivec3 ipos = ivec3(posu);
+ vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+
+
+#ifdef MODE_ANISOTROPIC
+ vec3 accum[6];
+ const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+
+ /*vec3 src_color = texelFetch(sampler3D(color_texture,texture_sampler),ipos,0).rgb * params.dynamic_range;
+ vec3 src_aniso_pos = texelFetch(sampler3D(aniso_pos_texture,texture_sampler),ipos,0).rgb;
+ vec3 src_anisp_neg = texelFetch(sampler3D(anisp_neg_texture,texture_sampler),ipos,0).rgb;
+ accum[0]=src_col * src_aniso_pos.x;
+ accum[1]=src_col * src_aniso_neg.x;
+ accum[2]=src_col * src_aniso_pos.y;
+ accum[3]=src_col * src_aniso_neg.y;
+ accum[4]=src_col * src_aniso_pos.z;
+ accum[5]=src_col * src_aniso_neg.z;*/
+
+ accum[0] = outputs.data[cell_index*6+0].rgb;
+ accum[1] = outputs.data[cell_index*6+1].rgb;
+ accum[2] = outputs.data[cell_index*6+2].rgb;
+ accum[3] = outputs.data[cell_index*6+3].rgb;
+ accum[4] = outputs.data[cell_index*6+4].rgb;
+ accum[5] = outputs.data[cell_index*6+5].rgb;
+
+#else
+ vec3 accum = outputs.data[cell_index].rgb;
+
+#endif
+
+ if (length(normal.xyz) > 0.2) {
+
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, normal.xyz));
+ vec3 bitangent = normalize(cross(tangent, normal.xyz));
+ mat3 normal_mat = mat3(tangent, bitangent, normal.xyz);
+
+#define MAX_CONE_DIRS 6
+
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.0, 0.0, 1.0),
+ vec3(0.866025, 0.0, 0.5),
+ vec3(0.267617, 0.823639, 0.5),
+ vec3(-0.700629, 0.509037, 0.5),
+ vec3(-0.700629, -0.509037, 0.5),
+ vec3(0.267617, -0.823639, 0.5));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+ float tan_half_angle = 0.577;
+
+ for (int i = 0; i < MAX_CONE_DIRS; i++) {
+
+ vec3 direction = normal_mat * cone_dirs[i];
+ vec4 color = vec4(0.0);
+ {
+
+ float dist = 1.5;
+ float max_distance = length(vec3(params.limits));
+ vec3 cell_size = 1.0 / vec3(params.limits);
+
+#ifdef MODE_ANISOTROPIC
+ vec3 aniso_normal = mix(direction,normal.xyz,params.aniso_strength);
+#endif
+ while (dist < max_distance && color.a < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ float half_diameter = diameter * 0.5;
+ //check if outside, then break
+ //if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+ // break;
+ //}
+
+ float log2_diameter = log2(diameter);
+ vec4 scolor = textureLod(sampler3D(color_texture,texture_sampler), uvw_pos, log2_diameter);
+#ifdef MODE_ANISOTROPIC
+
+ vec3 aniso_neg = textureLod(sampler3D(aniso_neg_texture,texture_sampler), uvw_pos, log2_diameter).rgb;
+ vec3 aniso_pos = textureLod(sampler3D(aniso_pos_texture,texture_sampler), uvw_pos, log2_diameter).rgb;
+
+ scolor.rgb*=dot(max(vec3(0.0),(aniso_normal * aniso_pos)),vec3(1.0)) + dot(max(vec3(0.0),(-aniso_normal * aniso_neg)),vec3(1.0));
+#endif
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += half_diameter;
+
+ }
+
+ }
+ color *= cone_weights[i] * params.dynamic_range; //restore range
+#ifdef MODE_ANISOTROPIC
+ for(uint j=0;j<6;j++) {
+
+ accum[j]+=max(0.0,dot(accum_dirs[j],direction))*color.rgb;
+ }
+#else
+ accum+=color.rgb;
+#endif
+ }
+ }
+
+#ifdef MODE_ANISOTROPIC
+
+ outputs.data[cell_index*6+0]=vec4(accum[0],0.0);
+ outputs.data[cell_index*6+1]=vec4(accum[1],0.0);
+ outputs.data[cell_index*6+2]=vec4(accum[2],0.0);
+ outputs.data[cell_index*6+3]=vec4(accum[3],0.0);
+ outputs.data[cell_index*6+4]=vec4(accum[4],0.0);
+ outputs.data[cell_index*6+5]=vec4(accum[5],0.0);
+#else
+ outputs.data[cell_index]=vec4(accum,0.0);
+
+#endif
+
+#endif // MODE_SECOND_BOUNCE
+/////////////////UPDATE MIPMAPS///////////////////////////////
+
+#ifdef MODE_UPDATE_MIPMAPS
+
+ {
+#ifdef MODE_ANISOTROPIC
+ vec3 light_accum[6] = vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
+#else
+ vec3 light_accum = vec3(0.0);
+#endif
+ float count = 0.0;
+ for(uint i=0;i<8;i++) {
+ uint child_index = cell_children.data[cell_index].children[i];
+ if (child_index==NO_CHILDREN) {
+ continue;
+ }
+#ifdef MODE_ANISOTROPIC
+ light_accum[0] += outputs.data[child_index*6+0].rgb;
+ light_accum[1] += outputs.data[child_index*6+1].rgb;
+ light_accum[2] += outputs.data[child_index*6+2].rgb;
+ light_accum[3] += outputs.data[child_index*6+3].rgb;
+ light_accum[4] += outputs.data[child_index*6+4].rgb;
+ light_accum[5] += outputs.data[child_index*6+5].rgb;
+
+#else
+ light_accum += outputs.data[child_index].rgb;
+
+#endif
+
+ count+=1.0;
+ }
+
+ float divisor = mix(8.0,count,params.propagation);
+#ifdef MODE_ANISOTROPIC
+ outputs.data[cell_index*6+0]=vec4(light_accum[0] / divisor,0.0);
+ outputs.data[cell_index*6+1]=vec4(light_accum[1] / divisor,0.0);
+ outputs.data[cell_index*6+2]=vec4(light_accum[2] / divisor,0.0);
+ outputs.data[cell_index*6+3]=vec4(light_accum[3] / divisor,0.0);
+ outputs.data[cell_index*6+4]=vec4(light_accum[4] / divisor,0.0);
+ outputs.data[cell_index*6+5]=vec4(light_accum[5] / divisor,0.0);
+
+#else
+ outputs.data[cell_index]=vec4(light_accum / divisor,0.0);
+#endif
+
+
+
+ }
+#endif
+
+///////////////////WRITE TEXTURE/////////////////////////////
+
+#ifdef MODE_WRITE_TEXTURE
+ {
+
+#ifdef MODE_ANISOTROPIC
+ vec3 accum_total = vec3(0.0);
+ accum_total += outputs.data[cell_index*6+0].rgb;
+ accum_total += outputs.data[cell_index*6+1].rgb;
+ accum_total += outputs.data[cell_index*6+2].rgb;
+ accum_total += outputs.data[cell_index*6+3].rgb;
+ accum_total += outputs.data[cell_index*6+4].rgb;
+ accum_total += outputs.data[cell_index*6+5].rgb;
+
+ float accum_total_energy = max(dot(accum_total,GREY_VEC),0.00001);
+ vec3 iso_positive = vec3(dot(outputs.data[cell_index*6+0].rgb,GREY_VEC),dot(outputs.data[cell_index*6+2].rgb,GREY_VEC),dot(outputs.data[cell_index*6+4].rgb,GREY_VEC))/vec3(accum_total_energy);
+ vec3 iso_negative = vec3(dot(outputs.data[cell_index*6+1].rgb,GREY_VEC),dot(outputs.data[cell_index*6+3].rgb,GREY_VEC),dot(outputs.data[cell_index*6+5].rgb,GREY_VEC))/vec3(accum_total_energy);
+
+
+ {
+ uint aniso_pos = uint(clamp(iso_positive.b * 31.0,0.0,31.0));
+ aniso_pos |= uint(clamp(iso_positive.g * 63.0,0.0,63.0))<<5;
+ aniso_pos |= uint(clamp(iso_positive.r * 31.0,0.0,31.0))<<11;
+ imageStore(aniso_pos_tex,ivec3(posu),uvec4(aniso_pos));
+ }
+
+ {
+ uint aniso_neg = uint(clamp(iso_negative.b * 31.0,0.0,31.0));
+ aniso_neg |= uint(clamp(iso_negative.g * 63.0,0.0,63.0))<<5;
+ aniso_neg |= uint(clamp(iso_negative.r * 31.0,0.0,31.0))<<11;
+ imageStore(aniso_neg_tex,ivec3(posu),uvec4(aniso_neg));
+ }
+
+ imageStore(color_tex,ivec3(posu),vec4(accum_total / params.dynamic_range ,albedo.a));
+
+#else
+
+ imageStore(color_tex,ivec3(posu),vec4(outputs.data[cell_index].rgb / params.dynamic_range,albedo.a));
+
+#endif
+
+
+ }
+#endif
+}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
new file mode 100644
index 0000000000..deaeb771b9
--- /dev/null
+++ b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
@@ -0,0 +1,160 @@
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+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=1,std140) buffer CellDataBuffer {
+ CellData data[];
+} cell_data;
+
+layout (set=0,binding=2) uniform texture3D color_tex;
+
+layout (set=0,binding=3) uniform sampler tex_sampler;
+
+#ifdef USE_ANISOTROPY
+layout (set=0,binding=4) uniform texture3D aniso_pos_tex;
+layout (set=0,binding=5) uniform texture3D aniso_neg_tex;
+#endif
+
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+ mat4 projection;
+ uint cell_offset;
+ float dynamic_range;
+ float alpha;
+ uint level;
+
+} params;
+
+layout(location=0) out vec4 color_interp;
+
+void main() {
+
+ const vec3 cube_triangles[36] = vec3[](
+ vec3(-1.0f,-1.0f,-1.0f),
+ vec3(-1.0f,-1.0f, 1.0f),
+ vec3(-1.0f, 1.0f, 1.0f),
+ vec3(1.0f, 1.0f,-1.0f),
+ vec3(-1.0f,-1.0f,-1.0f),
+ vec3(-1.0f, 1.0f,-1.0f),
+ vec3(1.0f,-1.0f, 1.0f),
+ vec3(-1.0f,-1.0f,-1.0f),
+ vec3(1.0f,-1.0f,-1.0f),
+ vec3(1.0f, 1.0f,-1.0f),
+ vec3(1.0f,-1.0f,-1.0f),
+ vec3(-1.0f,-1.0f,-1.0f),
+ vec3(-1.0f,-1.0f,-1.0f),
+ vec3(-1.0f, 1.0f, 1.0f),
+ vec3(-1.0f, 1.0f,-1.0f),
+ vec3(1.0f,-1.0f, 1.0f),
+ vec3(-1.0f,-1.0f, 1.0f),
+ vec3(-1.0f,-1.0f,-1.0f),
+ vec3(-1.0f, 1.0f, 1.0f),
+ vec3(-1.0f,-1.0f, 1.0f),
+ vec3(1.0f,-1.0f, 1.0f),
+ vec3(1.0f, 1.0f, 1.0f),
+ vec3(1.0f,-1.0f,-1.0f),
+ vec3(1.0f, 1.0f,-1.0f),
+ vec3(1.0f,-1.0f,-1.0f),
+ vec3(1.0f, 1.0f, 1.0f),
+ vec3(1.0f,-1.0f, 1.0f),
+ vec3(1.0f, 1.0f, 1.0f),
+ vec3(1.0f, 1.0f,-1.0f),
+ vec3(-1.0f, 1.0f,-1.0f),
+ vec3(1.0f, 1.0f, 1.0f),
+ vec3(-1.0f, 1.0f,-1.0f),
+ vec3(-1.0f, 1.0f, 1.0f),
+ vec3(1.0f, 1.0f, 1.0f),
+ vec3(-1.0f, 1.0f, 1.0f),
+ vec3(1.0f,-1.0f, 1.0f)
+ );
+
+
+ vec3 vertex = cube_triangles[gl_VertexIndex] * 0.5 + 0.5;
+
+ 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);
+
+#ifdef MODE_DEBUG_COLOR
+ color_interp.xyz = unpackUnorm4x8(cell_data.data[cell_index].albedo).xyz;
+#endif
+#ifdef MODE_DEBUG_LIGHT
+
+#ifdef USE_ANISOTROPY
+
+#define POS_X 0
+#define POS_Y 1
+#define POS_Z 2
+#define NEG_X 3
+#define NEG_Y 4
+#define NEG_Z 5
+
+ const uint triangle_aniso[12] = uint[](
+ NEG_X,
+ NEG_Z,
+ NEG_Y,
+ NEG_Z,
+ NEG_X,
+ NEG_Y,
+ POS_Z,
+ POS_X,
+ POS_X,
+ POS_Y,
+ POS_Y,
+ POS_Z
+ );
+
+ color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).xyz * params.dynamic_range;
+ vec3 aniso_pos = texelFetch(sampler3D(aniso_pos_tex,tex_sampler),ivec3(posu),int(params.level)).xyz;
+ vec3 aniso_neg = texelFetch(sampler3D(aniso_neg_tex,tex_sampler),ivec3(posu),int(params.level)).xyz;
+ uint side = triangle_aniso[gl_VertexIndex/3];
+
+ float strength = 0.0;
+ switch(side) {
+ case POS_X: strength = aniso_pos.x; break;
+ case POS_Y: strength = aniso_pos.y; break;
+ case POS_Z: strength = aniso_pos.z; break;
+ case NEG_X: strength = aniso_neg.x; break;
+ case NEG_Y: strength = aniso_neg.y; break;
+ case NEG_Z: strength = aniso_neg.z; break;
+
+ }
+
+ color_interp.xyz *= strength;
+
+#else
+ color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).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);
+
+}
+
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location=0) in vec4 color_interp;
+layout(location=0) out vec4 frag_color;
+
+void main() {
+
+ frag_color = color_interp;
+}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
deleted file mode 100644
index cec25f86f9..0000000000
--- a/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
+++ /dev/null
@@ -1,241 +0,0 @@
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
-
-#define NO_CHILDREN 0xFFFFFFFF
-#define GREY_VEC vec3(0.33333,0.33333,0.33333)
-
-struct CellPosition {
- uint children[8];
-};
-
-
-layout(set=0,binding=1,std140) buffer CellPositions {
- CellPosition data[];
-} cell_positions;
-
-struct CellMaterial {
- 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,std140) buffer CellMaterials {
- CellMaterial data[];
-} cell_materials;
-
-#define LIGHT_TYPE_DIRECTIONAL 0
-#define LIGHT_TYPE_OMNI 1
-#define LIGHT_TYPE_SPOT 2
-
-struct Light {
-
- uint type;
- float energy;
- float radius;
- float attenuation;
-
- vec3 color;
- float spot_angle_radians;
-
- float advance;
- float max_length;
- uint pad0;
- uint pad2;
-
- vec3 position;
- float spot_attenuation;
-
-
- vec3 direction;
- bool visible;
-
- vec4 clip_planes[3];
-};
-
-layout(set=0,binding=3,std140) buffer Lights {
- Light data[];
-} lights;
-
-
-layout(set=0,binding=4,std140) uniform Params {
- vec3 limits;
- float max_length;
- uint size;
- uint stack_size;
- uint light_count;
- float emission_scale;
-} params;
-
-
-layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
-
-
-uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
-
- uint result = NO_CHILDREN;
-
- while (distance > -distance_adv) { //use this to avoid precision errors
-
- uint cell = 0;
-
- ivec3 pos = ivec3(from);
- ivec3 ofs = ivec3(0);
- ivec3 half_size = ivec3(params.size) / 2;
- if (any(lessThan(pos,ivec3(0))) || any(greaterThanEqual(pos,ivec3(params.size)))) {
- return NO_CHILDREN; //outside range
- }
-
- for (int i = 0; i < params.stack_size - 1; i++) {
-
- bvec3 greater = greaterThanEqual(pos,ofs+half_size);
-
- ofs += mix(ivec3(0),half_size,greater);
-
- 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;
- }
-
- cell = cell_positions.data[cell].children[child];
- if (cell == NO_CHILDREN)
- break;
-
- half_size >>= ivec3(1);
- }
-
- if ( cell != NO_CHILDREN) {
- return cell; //found cell!
- }
-
- from += direction * distance_adv;
- distance -= distance_adv;
- }
-
- return NO_CHILDREN;
-}
-
-bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
-
- if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
-
- light_pos = pos - lights.data[light].direction * params.max_length;
- attenuation = 1.0;
-
- } else {
-
- light_pos = lights.data[light].position;
- float distance = length(pos - light_pos);
- if (distance >= lights.data[light].radius) {
- return false;
- }
-
- attenuation = pow( distance / lights.data[light].radius + 0.0001, lights.data[light].attenuation );
-
-
- if (lights.data[light].type==LIGHT_TYPE_SPOT) {
-
- vec3 rel = normalize(pos - light_pos);
- float angle = acos(dot(rel,lights.data[light].direction));
- if (angle > lights.data[light].spot_angle_radians) {
- return false;
- }
-
- float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
- attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
- }
- }
-
- return true;
-}
-
-void main() {
-
- uint cell_index = gl_GlobalInvocationID.x;
-
- uvec3 posu = uvec3(cell_materials.data[cell_index].position&0x3FF,(cell_materials.data[cell_index].position>>10)&0x3FF,cell_materials.data[cell_index].position>>20);
- vec3 pos = vec3(posu);
-
- vec3 emission = vec3(ivec3(cell_materials.data[cell_index].emission&0x3FF,(cell_materials.data[cell_index].emission>>10)&0x7FF,cell_materials.data[cell_index].emission>>21)) * params.emission_scale;
- vec4 albedo = unpackUnorm4x8(cell_materials.data[cell_index].albedo);
- vec4 normal = unpackSnorm4x8(cell_materials.data[cell_index].normal); //w >0.5 means, all directions
-
-#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));
- const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
-#else
- vec3 accum = vec3(0);
-#endif
-
- 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)) {
- continue;
- }
-
- float distance_adv = lights.data[i].advance;
-
- vec3 light_dir = pos - light_pos;
- float distance = length(light_dir);
-
- light_dir=normalize(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
-
- if (normal.w < 0.5 && dot(normal.xyz,light_dir)>=0) {
- continue; //not facing the light
- }
-
- uint result = raymarch(distance,distance_adv,from,lights.data[i].direction);
-
- if (result != cell_index) {
- continue; //was occluded
- }
-
- vec3 light = lights.data[i].color * albedo.rgb * attenuation;
-
-#ifdef MODE_ANISOTROPIC
- for(uint j=0;j<6;j++) {
- accum[j]+=max(0.0,dot(accum_dir,-light_dir))*light+emission;
- }
-#else
- if (normal.w < 0.5) {
- accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
- } else {
- //all directions
- accum+=light+emission;
- }
-#endif
-
- }
-
-#ifdef MODE_ANISOTROPIC
-
- vec3 accum_total = accum[0]+accum[1]+accum[2]+accum[3]+accum[4]+accum[5];
- float accum_total_energy = max(dot(accum_total,GREY_VEC),0.00001);
- vec3 iso_positive = vec3(dot(aniso[0],GREY_VEC),dot(aniso[2],GREY_VEC),dot(aniso[4],GREY_VEC))/vec3(accum_total_energy);
- vec3 iso_negative = vec3(dot(aniso[1],GREY_VEC),dot(aniso[3],GREY_VEC),dot(aniso[5],GREY_VEC))/vec3(accum_total_energy);
-
- //store in 3D textures, total color, and isotropic magnitudes
-#else
- //store in 3D texture pos, accum
- imageStore(color_tex,ivec3(posu),vec4(accum,albedo.a));
-#endif
-
-}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl
new file mode 100644
index 0000000000..01d33c28de
--- /dev/null
+++ b/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl
@@ -0,0 +1,353 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+#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;
+
+#define LIGHT_TYPE_DIRECTIONAL 0
+#define LIGHT_TYPE_OMNI 1
+#define LIGHT_TYPE_SPOT 2
+
+#ifdef MODE_COMPUTE_LIGHT
+
+struct Light {
+
+ uint type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ vec3 color;
+ float spot_angle_radians;
+
+ vec3 position;
+ float spot_attenuation;
+
+ vec3 direction;
+ bool has_shadow;
+};
+
+
+layout(set=0,binding=3,std140) uniform Lights {
+ Light data[MAX_LIGHTS];
+} lights;
+
+#endif
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+ ivec3 limits;
+ uint stack_size;
+
+ float emission_scale;
+ float propagation;
+ float dynamic_range;
+
+ uint light_count;
+ uint cell_offset;
+ uint cell_count;
+ uint pad[2];
+
+} params;
+
+
+layout(set=0,binding=4,std140) uniform Outputs {
+ vec4 data[];
+} output;
+
+
+
+#ifdef MODE_COMPUTE_LIGHT
+
+uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+
+ uint result = NO_CHILDREN;
+
+ ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
+
+ while (distance > -distance_adv) { //use this to avoid precision errors
+
+ uint cell = 0;
+
+ ivec3 pos = ivec3(from);
+
+ if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
+
+ ivec3 ofs = ivec3(0);
+ ivec3 half_size = size / 2;
+
+ for (int i = 0; i < params.stack_size - 1; i++) {
+
+ bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+
+ ofs += mix(ivec3(0),half_size,greater);
+
+ 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;
+ }
+
+ cell = cell_children.data[cell].children[child];
+ if (cell == NO_CHILDREN)
+ break;
+
+ half_size >>= ivec3(1);
+ }
+
+ if ( cell != NO_CHILDREN) {
+ return cell; //found cell!
+ }
+
+ }
+
+ from += direction * distance_adv;
+ distance -= distance_adv;
+ }
+
+ return NO_CHILDREN;
+}
+
+bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+
+
+ if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
+
+ light_pos = pos - lights.data[light].direction * length(vec3(params.limits));
+ attenuation = 1.0;
+
+ } else {
+
+ light_pos = lights.data[light].position;
+ float distance = length(pos - light_pos);
+ if (distance >= lights.data[light].radius) {
+ return false;
+ }
+
+
+ attenuation = pow( clamp( 1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation );
+
+
+ if (lights.data[light].type==LIGHT_TYPE_SPOT) {
+
+ vec3 rel = normalize(pos - light_pos);
+ float angle = acos(dot(rel,lights.data[light].direction));
+ if (angle > lights.data[light].spot_angle_radians) {
+ return false;
+ }
+
+ float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
+ attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+ }
+ }
+
+ return true;
+}
+
+float get_normal_advance(vec3 p_normal) {
+
+ vec3 normal = p_normal;
+ vec3 unorm = abs(normal);
+
+ if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+ } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+ } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
+ } else {
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3(1.0, 0.0, 0.0);
+ }
+
+ return 1.0 / dot(normal,unorm);
+}
+
+#endif
+
+
+
+
+void main() {
+
+ uint cell_index = gl_GlobalInvocationID.x;;
+ if (cell_index >= params.cell_count) {
+ return;
+ }
+ cell_index += 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);
+ vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
+
+#ifdef MODE_COMPUTE_LIGHT
+
+ vec3 pos = vec3(posu) + vec3(0.5);
+
+ vec3 emission = vec3(ivec3(cell_data.data[cell_index].emission&0x3FF,(cell_data.data[cell_index].emission>>10)&0x7FF,cell_data.data[cell_index].emission>>21)) * params.emission_scale;
+ vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+
+#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));
+ const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+#else
+ vec3 accum = vec3(0.0);
+#endif
+
+ 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)) {
+ continue;
+ }
+
+ vec3 light_dir = pos - light_pos;
+ float distance = length(light_dir);
+ light_dir=normalize(light_dir);
+
+ if (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0) {
+ continue; //not facing the light
+ }
+
+ 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;
+
+#ifdef MODE_ANISOTROPIC
+ for(uint j=0;j<6;j++) {
+ accum[j]+=max(0.0,dot(accum_dir,-light_dir))*light+emission;
+ }
+#else
+ if (length(normal.xyz) > 0.2) {
+ accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
+ } else {
+ //all directions
+ accum+=light+emission;
+ }
+#endif
+
+ }
+
+#ifdef MODE_ANISOTROPIC
+
+ output.data[cell_index*6+0]=vec4(accum[0],0.0);
+ output.data[cell_index*6+1]=vec4(accum[1],0.0);
+ output.data[cell_index*6+2]=vec4(accum[2],0.0);
+ output.data[cell_index*6+3]=vec4(accum[3],0.0);
+ output.data[cell_index*6+4]=vec4(accum[4],0.0);
+ output.data[cell_index*6+5]=vec4(accum[5],0.0);
+#else
+ output.data[cell_index]=vec4(accum,0.0);
+
+#endif
+
+#endif //MODE_COMPUTE_LIGHT
+
+
+#ifdef MODE_UPDATE_MIPMAPS
+
+ {
+#ifdef MODE_ANISOTROPIC
+ vec3 light_accum[6] = vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
+#else
+ vec3 light_accum = vec3(0.0);
+#endif
+ float count = 0.0;
+ for(uint i=0;i<8;i++) {
+ uint child_index = cell_children.data[cell_index].children[i];
+ if (child_index==NO_CHILDREN) {
+ continue;
+ }
+#ifdef MODE_ANISOTROPIC
+ light_accum[1] += output.data[child_index*6+0].rgb;
+ light_accum[2] += output.data[child_index*6+1].rgb;
+ light_accum[3] += output.data[child_index*6+2].rgb;
+ light_accum[4] += output.data[child_index*6+3].rgb;
+ light_accum[5] += output.data[child_index*6+4].rgb;
+ light_accum[6] += output.data[child_index*6+5].rgb;
+
+#else
+ light_accum += output.data[child_index].rgb;
+
+#endif
+
+ count+=1.0;
+ }
+
+ float divisor = mix(8.0,count,params.propagation);
+#ifdef MODE_ANISOTROPIC
+ output.data[cell_index*6+0]=vec4(light_accum[0] / divisor,0.0);
+ output.data[cell_index*6+1]=vec4(light_accum[1] / divisor,0.0);
+ output.data[cell_index*6+2]=vec4(light_accum[2] / divisor,0.0);
+ output.data[cell_index*6+3]=vec4(light_accum[3] / divisor,0.0);
+ output.data[cell_index*6+4]=vec4(light_accum[4] / divisor,0.0);
+ output.data[cell_index*6+5]=vec4(light_accum[5] / divisor,0.0);
+
+#else
+ output.data[cell_index]=vec4(light_accum / divisor,0.0);
+#endif
+
+
+
+ }
+#endif
+
+#ifdef MODE_WRITE_TEXTURE
+ {
+
+
+
+ }
+#endif
+}
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
index 711da3be9b..95e64f8778 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
+++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
@@ -57,7 +57,7 @@ layout(location = 6) out vec3 binormal_interp;
#endif
#ifdef USE_MATERIAL_UNIFORMS
-layout(set = 2, binding = 0, std140) uniform MaterialUniforms {
+layout(set = 3, binding = 0, std140) uniform MaterialUniforms {
/* clang-format off */
MATERIAL_UNIFORMS
/* clang-format on */
@@ -73,7 +73,7 @@ VERTEX_SHADER_GLOBALS
// FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now.
// See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316
-//invariant gl_Position;
+invariant gl_Position;
layout(location =7) flat out uint instance_index;
@@ -274,7 +274,7 @@ VERTEX_SHADER_CODE
#endif //MODE_RENDER_DEPTH
#ifdef USE_OVERRIDE_POSITION
- gl_Position = position;;
+ gl_Position = position;
#else
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
#endif
@@ -331,7 +331,7 @@ layout(location =8) in float dp_clip;
#define projection_matrix scene_data.projection_matrix;
#ifdef USE_MATERIAL_UNIFORMS
-layout(set = 2, binding = 0, std140) uniform MaterialUniforms {
+layout(set = 3, binding = 0, std140) uniform MaterialUniforms {
/* clang-format off */
MATERIAL_UNIFORMS
/* clang-format on */
@@ -918,6 +918,265 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal,float roughness
#endif //USE_LIGHTMAP
}
+#ifdef USE_VOXEL_CONE_TRACING
+
+//standard voxel cone trace
+vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ float half_diameter = diameter * 0.5;
+ //check if outside, then break
+ if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+ break;
+ }
+ vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += half_diameter;
+
+ }
+
+ return color;
+}
+#if 0
+vec4 voxel_cone_trace_skiplod(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+ float skip_lod = 1.0;
+
+ while (dist < max_distance && color.a < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ float half_diameter = diameter * 0.5;
+ //check if outside, then break
+ if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+ break;
+ }
+ vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
+ float a = (1.0 - color.a);
+ color += a * scolor;
+
+ float upper_opacity = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, skip_lod).a;
+ float skip_factor = exp2( max( 0.0f, skip_lod * 0.5f - 1.0f ) ) * (1.0f - upper_opacity) + upper_opacity;
+
+ skip_factor = mix( skip_factor, 1.0f, min( -1.0 + upper_opacity * probeParams.vctSpecularSdfFactor + tan_half_angle * 50.0f, 1.0f ) );
+ skip_lod = clamp( skip_lod + (1.0f - upper_opacity) * 2.0f - 1.0f, 1.0f, probeParams.vctSpecSdfMaxMip );
+
+ dist += half_diameter * skip_factor;
+ }
+
+ return color;
+}
+#endif
+
+#ifndef GI_PROBE_HIGH_QUALITY
+//faster version for 45 degrees
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+
+vec4 voxel_cone_trace_anisotropic_45_degrees(texture3D probe,texture3D aniso_pos,texture3D aniso_neg,vec3 normal, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+ float radius = max(0.5, tan_half_angle * dist);
+ float lod_level = log2(radius*2.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ //check if outside, then break
+ if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + radius * cell_size)) ) ) {
+ break;
+ }
+
+ vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
+ vec3 aniso_neg = textureLod(sampler3D(aniso_neg,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
+ vec3 aniso_pos = textureLod(sampler3D(aniso_pos,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
+
+ scolor.rgb*=dot(max(vec3(0.0),(normal * aniso_pos)),vec3(1.0)) + dot(max(vec3(0.0),(-normal * aniso_neg)),vec3(1.0));
+ lod_level+=1.0;
+
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += radius;
+ radius = max(0.5, tan_half_angle * dist);
+
+
+ }
+
+ return color;
+}
+#else
+
+vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+ float radius = max(0.5, tan_half_angle * dist);
+ float lod_level = log2(radius*2.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+
+ //check if outside, then break
+ if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + radius * cell_size)) ) ) {
+ break;
+ }
+ vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
+ lod_level+=1.0;
+
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += radius;
+ radius = max(0.5, tan_half_angle * dist);
+
+ }
+
+ return color;
+}
+
+#endif
+
+
+#elif defined(GI_PROBE_USE_ANISOTROPY)
+
+
+//standard voxel cone trace
+vec4 voxel_cone_trace_anisotropic(texture3D probe,texture3D aniso_pos,texture3D aniso_neg,vec3 normal, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ float half_diameter = diameter * 0.5;
+ //check if outside, then break
+ if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+ break;
+ }
+ float log2_diameter = log2(diameter);
+ vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter);
+ vec3 aniso_neg = textureLod(sampler3D(aniso_neg,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
+ vec3 aniso_pos = textureLod(sampler3D(aniso_pos,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
+
+ scolor.rgb*=dot(max(vec3(0.0),(normal * aniso_pos)),vec3(1.0)) + dot(max(vec3(0.0),(-normal * aniso_neg)),vec3(1.0));
+
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += half_diameter;
+
+ }
+
+ return color;
+}
+
+
+
+#endif
+
+void gi_probe_compute(uint index, vec3 position, vec3 normal,vec3 ref_vec, mat3 normal_xform, float roughness,vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
+
+
+
+ position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+
+ position += normal * gi_probes.data[index].normal_bias;
+
+ //this causes corrupted pixels, i have no idea why..
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+ return;
+ }
+
+ vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
+ //float blend=1.0;
+
+ float max_distance = length(gi_probes.data[index].bounds);
+ vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+
+ //radiance
+#ifdef GI_PROBE_HIGH_QUALITY
+
+#define MAX_CONE_DIRS 6
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.0, 0.0, 1.0),
+ vec3(0.866025, 0.0, 0.5),
+ vec3(0.267617, 0.823639, 0.5),
+ vec3(-0.700629, 0.509037, 0.5),
+ vec3(-0.700629, -0.509037, 0.5),
+ vec3(0.267617, -0.823639, 0.5));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+ float cone_angle_tan = 0.577;
+#else
+
+#define MAX_CONE_DIRS 4
+
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.707107, 0.0, 0.707107),
+ vec3(0.0, 0.707107, 0.707107),
+ vec3(-0.707107, 0.0, 0.707107),
+ vec3(0.0, -0.707107, 0.707107));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
+ float cone_angle_tan = 0.98269;
+
+#endif
+ vec3 light = vec3(0.0);
+ for (int i = 0; i < MAX_CONE_DIRS; i++) {
+
+
+ vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
+
+#ifdef GI_PROBE_HIGH_QUALITY
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+ vec4 cone_light = voxel_cone_trace_anisotropic(gi_probe_textures[gi_probes.data[index].texture_slot],gi_probe_textures[gi_probes.data[index].texture_slot+1],gi_probe_textures[gi_probes.data[index].texture_slot+2],normalize(mix(dir,normal,gi_probes.data[index].anisotropy_strength)),cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#else
+ vec4 cone_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#endif // GI_PROBE_USE_ANISOTROPY
+
+#else
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+ vec4 cone_light = voxel_cone_trace_anisotropic_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot],gi_probe_textures[gi_probes.data[index].texture_slot+1],gi_probe_textures[gi_probes.data[index].texture_slot+2],normalize(mix(dir,normal,gi_probes.data[index].anisotropy_strength)),cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#else
+ vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#endif // GI_PROBE_USE_ANISOTROPY
+
+#endif
+ if (gi_probes.data[index].blend_ambient) {
+ cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
+ }
+ light+=cone_weights[i] * cone_light.rgb;
+ }
+
+ light *= gi_probes.data[index].dynamic_range;
+
+ out_diff += vec4(light * blend, blend);
+
+ //irradiance
+
+ vec4 irr_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
+ if (gi_probes.data[index].blend_ambient) {
+ irr_light.rgb = mix(environment,irr_light.rgb, min(1.0, irr_light.a / 0.95));
+ }
+ irr_light.rgb *= gi_probes.data[index].dynamic_range;
+ //irr_light=vec3(0.0);
+
+ out_spec += vec4(irr_light.rgb * blend, blend);
+}
+
+#endif //USE_VOXEL_CONE_TRACING
+
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -1118,7 +1377,42 @@ FRAGMENT_SHADER_CODE
//lightmap capture
+#ifdef USE_VOXEL_CONE_TRACING
+ { // process giprobes
+ uint index1 = instances.data[instance_index].gi_offset&0xFFFF;
+ if (index1!=0xFFFF) {
+ vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
+ //find arbitrary tangent and bitangent, then build a matrix
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, normal));
+ vec3 bitangent = normalize(cross(tangent, normal));
+ mat3 normal_mat = mat3(tangent, bitangent, normal);
+
+ vec4 amb_accum = vec4(0.0);
+ vec4 spec_accum = vec4(0.0);
+
+ gi_probe_compute(index1, vertex, normal, ref_vec,normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum );
+
+ uint index2 = instances.data[instance_index].gi_offset>>16;
+
+ if (index2!=0xFFFF) {
+ gi_probe_compute(index2, vertex, normal, ref_vec,normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum );
+ }
+
+ if (amb_accum.a > 0.0) {
+ amb_accum.rgb /= amb_accum.a;
+ }
+
+ if (spec_accum.a > 0.0) {
+ spec_accum.rgb /= spec_accum.a;
+ }
+
+ specular_light = spec_accum.rgb;
+ ambient_light = amb_accum.rgb;
+ }
+ }
+#endif
{ // process reflections
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
index 81cf47b192..c59d5ed756 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
+++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
@@ -9,22 +9,7 @@ layout(push_constant, binding = 0, std430) uniform DrawCall {
-/* Set 0 Scene data, screen and sources (changes the least) */
-
-layout(set=0,binding=1) uniform texture2D depth_buffer;
-layout(set=0,binding=2) uniform texture2D color_buffer;
-layout(set=0,binding=3) uniform texture2D normal_buffer;
-layout(set=0,binding=4) uniform texture2D roughness_limit;
-
-#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-
-layout(set = 0, binding = 5) uniform textureCubeArray radiance_cubemap;
-
-#else
-
-layout(set = 0, binding = 5) uniform textureCube radiance_cubemap;
-
-#endif
+/* Set 0 Scene data that never changes, ever */
#define SAMPLER_NEAREST_CLAMP 0
@@ -40,11 +25,11 @@ layout(set = 0, binding = 5) uniform textureCube radiance_cubemap;
#define SAMPLER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-layout(set = 0, binding = 6) uniform sampler material_samplers[12];
+layout(set = 0, binding = 1) uniform sampler material_samplers[12];
-layout(set = 0, binding = 7) uniform sampler shadow_sampler;
+layout(set = 0, binding = 2) uniform sampler shadow_sampler;
-layout(set=0,binding=8,std140) uniform SceneData {
+layout(set=0,binding=3,std140) uniform SceneData {
mat4 projection_matrix;
mat4 inv_projection_matrix;
@@ -149,28 +134,10 @@ struct InstanceData {
};
-layout(set=0,binding=9,std430) buffer Instances {
+layout(set=0,binding=4,std430) buffer Instances {
InstanceData data[];
} instances;
-struct ReflectionData {
-
- vec3 box_extents;
- float index;
- vec3 box_offset;
- uint mask;
- vec4 params; // intensity, 0, interior , boxproject
- vec4 ambient; // ambient color, energy
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
- // notes: for ambientblend, use distance to edge to blend between already existing global environment
-};
-
-layout(set=0,binding=10,std140) uniform ReflectionProbeData {
- ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
-} reflections;
-
-layout(set=0,binding=11) uniform textureCubeArray reflection_atlas;
-
struct LightData { //this structure needs to be 128 bits
vec3 position;
@@ -185,11 +152,25 @@ struct LightData { //this structure needs to be 128 bits
mat4 shadow_matrix;
};
-layout(set=0,binding=12,std140) uniform Lights {
+layout(set=0,binding=5,std140) uniform Lights {
LightData data[MAX_LIGHT_DATA_STRUCTS];
} lights;
-layout(set=0,binding=13) uniform texture2D shadow_atlas;
+struct ReflectionData {
+
+ vec3 box_extents;
+ float index;
+ vec3 box_offset;
+ uint mask;
+ vec4 params; // intensity, 0, interior , boxproject
+ vec4 ambient; // ambient color, energy
+ mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ // notes: for ambientblend, use distance to edge to blend between already existing global environment
+};
+
+layout(set=0,binding=6,std140) uniform ReflectionProbeData {
+ ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
+} reflections;
struct DirectionalLightData {
@@ -211,51 +192,65 @@ struct DirectionalLightData {
};
-layout(set=0,binding=14,std140) uniform DirectionalLights {
+layout(set=0,binding=7,std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
} directional_lights;
-layout(set=0,binding=15) uniform texture2D directional_shadow_atlas;
+struct GIProbeData {
+ mat4 xform;
+ vec3 bounds;
+ float dynamic_range;
-/*
-layout(set=0,binding=15,std430) buffer Skeletons {
- vec4 data[];
-} skeletons;
-*/
+ float bias;
+ float normal_bias;
+ bool blend_ambient;
+ uint texture_slot;
-/* Set 1 Instancing (Multimesh) */
+ float anisotropy_strength;
+ uint pad0;
+ uint pad1;
+ uint pad2;
+};
-//layout(set = 1, binding = 0) uniform textureBuffer multimesh_transforms;
+layout(set=0,binding=8,std140) uniform GIProbes {
+ GIProbeData data[MAX_GI_PROBES];
+} gi_probes;
-layout(set=1,binding=0,std430) buffer Transforms {
- vec4 data[];
-} transforms;
+layout(set=0,binding=9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TEXTURES];
-/* Set 2 Instancing (Multimesh) data */
+/* Set 1, Scene data that changes per render pass */
-#if 0
+
+layout(set=1,binding=0) uniform texture2D depth_buffer;
+layout(set=1,binding=1) uniform texture2D color_buffer;
+layout(set=1,binding=2) uniform texture2D normal_buffer;
+layout(set=1,binding=3) uniform texture2D roughness_limit;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-layout(set = 3, binding = 2) uniform textureCubeArray reflection_probes[MAX_REFLECTION_PROBES];
+layout(set = 1, binding = 4) uniform textureCubeArray radiance_cubemap;
#else
-layout(set = 3, binding = 2) uniform textureCube reflection_probes[MAX_REFLECTION_PROBES];
+layout(set = 1, binding = 4) uniform textureCube radiance_cubemap;
#endif
-#ifdef USE_VOXEL_CONE_TRACING
+layout(set=1,binding=5) uniform textureCubeArray reflection_atlas;
-layout(set = 3, binding = 4) uniform texture3D gi_probe[2];
+layout(set=1,binding=6) uniform texture2D shadow_atlas;
-#ifdef USE_ANISOTROPIC_VOXEL_CONE_TRACING
-layout(set = 3, binding = 5) uniform texture3D gi_probe_aniso_pos[2];
-layout(set = 3, binding = 6) uniform texture3D gi_probe_aniso_neg[2];
-#endif
+layout(set=1,binding=7) uniform texture2D directional_shadow_atlas;
+
+
+/* Set 2 Skeleton & Instancing (Multimesh) */
+
+layout(set=2,binding=0,std430) buffer Transforms {
+ vec4 data[];
+} transforms;
+
+/* Set 3 User Material */
-#endif
-#endif
diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h
index d0afb3f13b..f5a212b076 100644
--- a/servers/visual/rendering_device.h
+++ b/servers/visual/rendering_device.h
@@ -412,7 +412,8 @@ public:
enum TextureSliceType {
TEXTURE_SLICE_2D,
- TEXTURE_SLICE_CUBEMAP
+ TEXTURE_SLICE_CUBEMAP,
+ TEXTURE_SLICE_3D,
};
virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0;
@@ -425,6 +426,8 @@ public:
virtual bool texture_is_valid(RID p_texture) = 0;
virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0;
+ virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0;
+
/*********************/
/**** FRAMEBUFFER ****/
/*********************/
@@ -903,15 +906,13 @@ public:
enum InitialAction {
INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params)
- INITIAL_ACTION_KEEP_COLOR, //start rendering, but keep attached color texture contents (depth will be cleared)
- INITIAL_ACTION_KEEP_COLOR_AND_DEPTH, //start rendering, but keep attached color and depth texture contents (depth will be cleared)
+ INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared)
INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action prevously)
INITIAL_ACTION_MAX
};
enum FinalAction {
- FINAL_ACTION_READ_COLOR_AND_DEPTH, //will no longer render to it, allows attached textures to be read again, but depth buffer contents will be dropped (Can't be read from)
- FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, //will no longer render to it, allows attached textures to be read again
+ FINAL_ACTION_READ, //will no longer render to it, allows attached textures to be read again, but depth buffer contents will be dropped (Can't be read from)
FINAL_ACTION_DISCARD, // discard contents after rendering
FINAL_ACTION_CONTINUE, //will continue rendering later, attached textures can't be read until re-bound with "finish"
FINAL_ACTION_MAX
@@ -920,8 +921,8 @@ public:
typedef int64_t DrawListID;
virtual DrawListID draw_list_begin_for_screen(int p_screen = 0, const Color &p_clear_color = Color()) = 0;
- virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), const Rect2 &p_region = Rect2()) = 0;
- virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), const Rect2 &p_region = Rect2()) = 0;
+ virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()) = 0;
+ virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()) = 0;
virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0;
virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
@@ -930,7 +931,7 @@ public:
virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0;
virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0;
- virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1) = 0;
+ virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0) = 0;
virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
@@ -948,6 +949,8 @@ public:
virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) = 0;
virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
+ virtual void compute_list_add_barrier(ComputeListID p_list) = 0;
+
virtual void compute_list_end() = 0;
/***************/
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 510296f11c..38f5c1ec58 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -344,17 +344,20 @@ public:
BIND0R(RID, gi_probe_create)
- BIND2(gi_probe_set_bounds, RID, const AABB &)
- BIND1RC(AABB, gi_probe_get_bounds, RID)
-
- BIND2(gi_probe_set_cell_size, RID, float)
- BIND1RC(float, gi_probe_get_cell_size, RID)
+ BIND7(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &)
- BIND2(gi_probe_set_to_cell_xform, RID, const Transform &)
+ BIND1RC(AABB, gi_probe_get_bounds, RID)
+ BIND1RC(Vector3i, gi_probe_get_octree_size, RID)
+ BIND1RC(PoolVector<uint8_t>, gi_probe_get_octree_cells, RID)
+ BIND1RC(PoolVector<uint8_t>, gi_probe_get_data_cells, RID)
+ BIND1RC(PoolVector<int>, gi_probe_get_level_counts, RID)
BIND1RC(Transform, gi_probe_get_to_cell_xform, RID)
- BIND2(gi_probe_set_dynamic_range, RID, int)
- BIND1RC(int, gi_probe_get_dynamic_range, RID)
+ BIND2(gi_probe_set_dynamic_range, RID, float)
+ BIND1RC(float, gi_probe_get_dynamic_range, RID)
+
+ BIND2(gi_probe_set_propagation, RID, float)
+ BIND1RC(float, gi_probe_get_propagation, RID)
BIND2(gi_probe_set_energy, RID, float)
BIND1RC(float, gi_probe_get_energy, RID)
@@ -365,17 +368,14 @@ public:
BIND2(gi_probe_set_normal_bias, RID, float)
BIND1RC(float, gi_probe_get_normal_bias, RID)
- BIND2(gi_probe_set_propagation, RID, float)
- BIND1RC(float, gi_probe_get_propagation, RID)
-
BIND2(gi_probe_set_interior, RID, bool)
BIND1RC(bool, gi_probe_is_interior, RID)
- BIND2(gi_probe_set_compress, RID, bool)
- BIND1RC(bool, gi_probe_is_compressed, RID)
+ BIND2(gi_probe_set_use_two_bounces, RID, bool)
+ BIND1RC(bool, gi_probe_is_using_two_bounces, RID)
- BIND2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &)
- BIND1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID)
+ BIND2(gi_probe_set_anisotropy_strength, RID, float)
+ BIND1RC(float, gi_probe_get_anisotropy_strength, RID)
/* LIGHTMAP CAPTURE */
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index f240f91b12..f7b118bfe5 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -336,23 +336,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
if (instance->base_type != VS::INSTANCE_NONE) {
//free anything related to that base
- if (instance->base_type == VS::INSTANCE_GI_PROBE) {
- //if gi probe is baking, wait until done baking, else race condition may happen when removing it
- //from octree
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
-
- //make sure probes are done baking
- while (!probe_bake_list.empty()) {
- OS::get_singleton()->delay_usec(1);
- }
- //make sure this one is done baking
-
- while (gi_probe->dynamic.updating_stage == GI_UPDATE_STAGE_LIGHTING) {
- //wait until bake is done if it's baking
- OS::get_singleton()->delay_usec(1);
- }
- }
-
if (scenario && instance->octree_id) {
scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
instance->octree_id = 0;
@@ -392,9 +375,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
if (gi_probe->update_element.in_list()) {
gi_probe_update_list.remove(&gi_probe->update_element);
}
- if (gi_probe->dynamic.probe_data.is_valid()) {
- VSG::storage->free(gi_probe->dynamic.probe_data);
- }
if (instance->lightmap_capture) {
Instance *capture = (Instance *)instance->lightmap_capture;
@@ -476,7 +456,7 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
gi_probe_update_list.add(&gi_probe->update_element);
}
- gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create();
+ gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create(p_base);
} break;
default: {
@@ -891,6 +871,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
reflection_probe->reflection_dirty = true;
}
+ if (p_instance->base_type == VS::INSTANCE_GI_PROBE) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
+
+ VSG::scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform);
+ }
+
if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
VSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
@@ -1849,6 +1836,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
light_cull_count = 0;
reflection_probe_cull_count = 0;
+ gi_probe_cull_count = 0;
//light_samplers_culled=0;
@@ -1925,6 +1913,11 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
gi_probe_update_list.add(&gi_probe->update_element);
}
+ if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) {
+ gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance;
+ gi_probe_cull_count++;
+ }
+
} else if (((1 << ins->base_type) & VS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
keep = true;
@@ -2173,7 +2166,7 @@ void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_ca
/* PROCESS GEOMETRY AND DRAW SCENE */
RENDER_TIMESTAMP("Render Scene ");
- VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
+ VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
}
void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
@@ -2188,7 +2181,7 @@ void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario,
else
environment = scenario->fallback_environment;
RENDER_TIMESTAMP("Render Empty Scene ");
- VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
+ VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
#endif
}
@@ -2265,898 +2258,6 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
return false;
}
-void VisualServerScene::_gi_probe_fill_local_data(int p_idx, int p_level, int p_x, int p_y, int p_z, const GIProbeDataCell *p_cell, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, Vector<uint32_t> *prev_cell) {
-
- if ((uint32_t)p_level == p_header->cell_subdiv - 1) {
-
- Vector3 emission;
- emission.x = (p_cell[p_idx].emission >> 24) / 255.0;
- emission.y = ((p_cell[p_idx].emission >> 16) & 0xFF) / 255.0;
- emission.z = ((p_cell[p_idx].emission >> 8) & 0xFF) / 255.0;
- float l = (p_cell[p_idx].emission & 0xFF) / 255.0;
- l *= 8.0;
-
- emission *= l;
-
- p_local_data[p_idx].energy[0] = uint16_t(emission.x * 1024); //go from 0 to 1024 for light
- p_local_data[p_idx].energy[1] = uint16_t(emission.y * 1024); //go from 0 to 1024 for light
- p_local_data[p_idx].energy[2] = uint16_t(emission.z * 1024); //go from 0 to 1024 for light
- } else {
-
- p_local_data[p_idx].energy[0] = 0;
- p_local_data[p_idx].energy[1] = 0;
- p_local_data[p_idx].energy[2] = 0;
-
- int half = (1 << (p_header->cell_subdiv - 1)) >> (p_level + 1);
-
- for (int i = 0; i < 8; i++) {
-
- uint32_t child = p_cell[p_idx].children[i];
-
- if (child == 0xFFFFFFFF)
- continue;
-
- int x = p_x;
- int y = p_y;
- int z = p_z;
-
- if (i & 1)
- x += half;
- if (i & 2)
- y += half;
- if (i & 4)
- z += half;
-
- _gi_probe_fill_local_data(child, p_level + 1, x, y, z, p_cell, p_header, p_local_data, prev_cell);
- }
- }
-
- //position for each part of the mipmaped texture
- p_local_data[p_idx].pos[0] = p_x >> (p_header->cell_subdiv - p_level - 1);
- p_local_data[p_idx].pos[1] = p_y >> (p_header->cell_subdiv - p_level - 1);
- p_local_data[p_idx].pos[2] = p_z >> (p_header->cell_subdiv - p_level - 1);
-
- prev_cell[p_level].push_back(p_idx);
-}
-
-void VisualServerScene::_gi_probe_bake_threads(void *self) {
-
- VisualServerScene *vss = (VisualServerScene *)self;
- vss->_gi_probe_bake_thread();
-}
-
-void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
-
- InstanceGIProbeData *probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
-
- if (probe->dynamic.probe_data.is_valid()) {
- VSG::storage->free(probe->dynamic.probe_data);
- probe->dynamic.probe_data = RID();
- }
-
- probe->dynamic.light_data = VSG::storage->gi_probe_get_dynamic_data(p_instance->base);
-
- if (probe->dynamic.light_data.size() == 0)
- return;
- //using dynamic data
- PoolVector<int>::Read r = probe->dynamic.light_data.read();
-
- const GIProbeDataHeader *header = (GIProbeDataHeader *)r.ptr();
-
- probe->dynamic.local_data.resize(header->cell_count);
-
- int cell_count = probe->dynamic.local_data.size();
- PoolVector<InstanceGIProbeData::LocalData>::Write ldw = probe->dynamic.local_data.write();
- const GIProbeDataCell *cells = (GIProbeDataCell *)&r[16];
-
- probe->dynamic.level_cell_lists.resize(header->cell_subdiv);
-
- _gi_probe_fill_local_data(0, 0, 0, 0, 0, cells, header, ldw.ptr(), probe->dynamic.level_cell_lists.ptrw());
-
- bool compress = VSG::storage->gi_probe_is_compressed(p_instance->base);
-
- probe->dynamic.compression = compress ? VSG::storage->gi_probe_get_dynamic_data_get_preferred_compression() : RasterizerStorage::GI_PROBE_UNCOMPRESSED;
-
- probe->dynamic.probe_data = VSG::storage->gi_probe_dynamic_data_create(header->width, header->height, header->depth, probe->dynamic.compression);
-
- probe->dynamic.bake_dynamic_range = VSG::storage->gi_probe_get_dynamic_range(p_instance->base);
-
- probe->dynamic.mipmaps_3d.clear();
- probe->dynamic.propagate = VSG::storage->gi_probe_get_propagation(p_instance->base);
-
- probe->dynamic.grid_size[0] = header->width;
- probe->dynamic.grid_size[1] = header->height;
- probe->dynamic.grid_size[2] = header->depth;
-
- int size_limit = 1;
- int size_divisor = 1;
-
- if (probe->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) {
- size_limit = 4;
- size_divisor = 4;
- }
- for (int i = 0; i < (int)header->cell_subdiv; i++) {
-
- int x = header->width >> i;
- int y = header->height >> i;
- int z = header->depth >> i;
-
- //create and clear mipmap
- PoolVector<uint8_t> mipmap;
- int size = x * y * z * 4;
- size /= size_divisor;
- mipmap.resize(size);
- PoolVector<uint8_t>::Write w = mipmap.write();
- zeromem(w.ptr(), size);
- w.release();
-
- probe->dynamic.mipmaps_3d.push_back(mipmap);
-
- if (x <= size_limit || y <= size_limit || z <= size_limit)
- break;
- }
-
- probe->dynamic.updating_stage = GI_UPDATE_STAGE_CHECK;
- probe->invalid = false;
- probe->dynamic.enabled = true;
-
- Transform cell_to_xform = VSG::storage->gi_probe_get_to_cell_xform(p_instance->base);
- AABB bounds = VSG::storage->gi_probe_get_bounds(p_instance->base);
- float cell_size = VSG::storage->gi_probe_get_cell_size(p_instance->base);
-
- probe->dynamic.light_to_cell_xform = cell_to_xform * p_instance->transform.affine_inverse();
-
- VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance, p_instance->base, probe->dynamic.probe_data);
- VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance, probe->dynamic.light_to_cell_xform);
-
- VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance, bounds.size / cell_size);
-
- probe->base_version = VSG::storage->gi_probe_get_version(p_instance->base);
-
- //if compression is S3TC, fill it up
- if (probe->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) {
-
- //create all blocks
- Vector<Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> > comp_blocks;
- int mipmap_count = probe->dynamic.mipmaps_3d.size();
- comp_blocks.resize(mipmap_count);
-
- for (int i = 0; i < cell_count; i++) {
-
- const GIProbeDataCell &c = cells[i];
- const InstanceGIProbeData::LocalData &ld = ldw[i];
- int level = c.level_alpha >> 16;
- int mipmap = header->cell_subdiv - level - 1;
- if (mipmap >= mipmap_count)
- continue; //uninteresting
-
- int blockx = (ld.pos[0] >> 2);
- int blocky = (ld.pos[1] >> 2);
- int blockz = (ld.pos[2]); //compression is x/y only
-
- int blockw = (header->width >> mipmap) >> 2;
- int blockh = (header->height >> mipmap) >> 2;
-
- //print_line("cell "+itos(i)+" level "+itos(level)+"mipmap: "+itos(mipmap)+" pos: "+Vector3(blockx,blocky,blockz)+" size "+Vector2(blockw,blockh));
-
- uint32_t key = blockz * blockw * blockh + blocky * blockw + blockx;
-
- Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> &cmap = comp_blocks.write[mipmap];
-
- if (!cmap.has(key)) {
-
- InstanceGIProbeData::CompBlockS3TC k;
- k.offset = key; //use offset as counter first
- k.source_count = 0;
- cmap[key] = k;
- }
-
- InstanceGIProbeData::CompBlockS3TC &k = cmap[key];
- ERR_CONTINUE(k.source_count == 16);
- k.sources[k.source_count++] = i;
- }
-
- //fix the blocks, precomputing what is needed
- probe->dynamic.mipmaps_s3tc.resize(mipmap_count);
-
- for (int i = 0; i < mipmap_count; i++) {
- //print_line("S3TC level: " + itos(i) + " blocks: " + itos(comp_blocks[i].size()));
- probe->dynamic.mipmaps_s3tc.write[i].resize(comp_blocks[i].size());
- PoolVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc.write[i].write();
- int block_idx = 0;
-
- for (Map<uint32_t, InstanceGIProbeData::CompBlockS3TC>::Element *E = comp_blocks[i].front(); E; E = E->next()) {
-
- InstanceGIProbeData::CompBlockS3TC k = E->get();
-
- //PRECOMPUTE ALPHA
- int max_alpha = -100000;
- int min_alpha = k.source_count == 16 ? 100000 : 0; //if the block is not completely full, minimum is always 0, (and those blocks will map to 1, which will be zero)
-
- uint8_t alpha_block[4][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
-
- for (uint32_t j = 0; j < k.source_count; j++) {
-
- int alpha = (cells[k.sources[j]].level_alpha >> 8) & 0xFF;
- if (alpha < min_alpha)
- min_alpha = alpha;
- if (alpha > max_alpha)
- max_alpha = alpha;
- //fill up alpha block
- alpha_block[ldw[k.sources[j]].pos[0] % 4][ldw[k.sources[j]].pos[1] % 4] = alpha;
- }
-
- //use the first mode (8 adjustable levels)
- k.alpha[0] = max_alpha;
- k.alpha[1] = min_alpha;
-
- uint64_t alpha_bits = 0;
-
- if (max_alpha != min_alpha) {
-
- int idx = 0;
-
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
-
- //subtract minimum
- uint32_t a = uint32_t(alpha_block[x][y]) - min_alpha;
- //convert range to 3 bits
- a = int((a * 7.0 / (max_alpha - min_alpha)) + 0.5);
- a = MIN(a, 7); //just to be sure
- a = 7 - a; //because range is inverted in this mode
- if (a == 0) {
- //do none, remain
- } else if (a == 7) {
- a = 1;
- } else {
- a = a + 1;
- }
-
- alpha_bits |= uint64_t(a) << (idx * 3);
- idx++;
- }
- }
- }
-
- k.alpha[2] = (alpha_bits >> 0) & 0xFF;
- k.alpha[3] = (alpha_bits >> 8) & 0xFF;
- k.alpha[4] = (alpha_bits >> 16) & 0xFF;
- k.alpha[5] = (alpha_bits >> 24) & 0xFF;
- k.alpha[6] = (alpha_bits >> 32) & 0xFF;
- k.alpha[7] = (alpha_bits >> 40) & 0xFF;
-
- w[block_idx++] = k;
- }
- }
- }
-}
-
-void VisualServerScene::_gi_probe_bake_thread() {
-
- while (true) {
-
- probe_bake_sem->wait();
- if (probe_bake_thread_exit) {
- break;
- }
-
- Instance *to_bake = NULL;
-
- probe_bake_mutex->lock();
-
- if (!probe_bake_list.empty()) {
- to_bake = probe_bake_list.front()->get();
- probe_bake_list.pop_front();
- }
- probe_bake_mutex->unlock();
-
- if (!to_bake)
- continue;
-
- _bake_gi_probe(to_bake);
- }
-}
-
-uint32_t VisualServerScene::_gi_bake_find_cell(const GIProbeDataCell *cells, int x, int y, int z, int p_cell_subdiv) {
-
- uint32_t cell = 0;
-
- int ofs_x = 0;
- int ofs_y = 0;
- int ofs_z = 0;
- int size = 1 << (p_cell_subdiv - 1);
- int half = size / 2;
-
- if (x < 0 || x >= size)
- return -1;
- if (y < 0 || y >= size)
- return -1;
- if (z < 0 || z >= size)
- return -1;
-
- for (int i = 0; i < p_cell_subdiv - 1; i++) {
-
- const GIProbeDataCell *bc = &cells[cell];
-
- int child = 0;
- if (x >= ofs_x + half) {
- child |= 1;
- ofs_x += half;
- }
- if (y >= ofs_y + half) {
- child |= 2;
- ofs_y += half;
- }
- if (z >= ofs_z + half) {
- child |= 4;
- ofs_z += half;
- }
-
- cell = bc->children[child];
- if (cell == 0xFFFFFFFF)
- return 0xFFFFFFFF;
-
- half >>= 1;
- }
-
- return cell;
-}
-
-static float _get_normal_advance(const Vector3 &p_normal) {
-
- Vector3 normal = p_normal;
- Vector3 unorm = normal.abs();
-
- if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
- // x code
- unorm = normal.x > 0.0 ? Vector3(1.0, 0.0, 0.0) : Vector3(-1.0, 0.0, 0.0);
- } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
- // y code
- unorm = normal.y > 0.0 ? Vector3(0.0, 1.0, 0.0) : Vector3(0.0, -1.0, 0.0);
- } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
- // z code
- unorm = normal.z > 0.0 ? Vector3(0.0, 0.0, 1.0) : Vector3(0.0, 0.0, -1.0);
- } else {
- // oh-no we messed up code
- // has to be
- unorm = Vector3(1.0, 0.0, 0.0);
- }
-
- return 1.0 / normal.dot(unorm);
-}
-
-void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, const GIProbeDataCell *cells, InstanceGIProbeData::LocalData *local_data, const uint32_t *leaves, int p_leaf_count, const InstanceGIProbeData::LightCache &light_cache, int p_sign) {
-
- int light_r = int(light_cache.color.r * light_cache.energy * 1024.0) * p_sign;
- int light_g = int(light_cache.color.g * light_cache.energy * 1024.0) * p_sign;
- int light_b = int(light_cache.color.b * light_cache.energy * 1024.0) * p_sign;
-
- float limits[3] = { float(header->width), float(header->height), float(header->depth) };
- Plane clip[3];
- int clip_planes = 0;
-
- switch (light_cache.type) {
-
- case VS::LIGHT_DIRECTIONAL: {
-
- float max_len = Vector3(limits[0], limits[1], limits[2]).length() * 1.1;
-
- Vector3 light_axis = -light_cache.transform.basis.get_axis(2).normalized();
-
- for (int i = 0; i < 3; i++) {
-
- if (Math::is_zero_approx(light_axis[i]))
- continue;
- clip[clip_planes].normal[i] = 1.0;
-
- if (light_axis[i] < 0) {
-
- clip[clip_planes].d = limits[i] + 1;
- } else {
- clip[clip_planes].d -= 1.0;
- }
-
- clip_planes++;
- }
-
- float distance_adv = _get_normal_advance(light_axis);
-
- int success_count = 0;
-
- // uint64_t us = OS::get_singleton()->get_ticks_usec();
-
- for (int i = 0; i < p_leaf_count; i++) {
-
- uint32_t idx = leaves[i];
-
- const GIProbeDataCell *cell = &cells[idx];
- InstanceGIProbeData::LocalData *light = &local_data[idx];
-
- Vector3 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5);
- to += -light_axis.sign() * 0.47; //make it more likely to receive a ray
-
- Vector3 norm(
- (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 0) & 0xFF) / 255.0) * 2.0 - 1.0);
-
- float att = norm.dot(-light_axis);
- if (att < 0.001) {
- //not lighting towards this
- continue;
- }
-
- Vector3 from = to - max_len * light_axis;
-
- for (int j = 0; j < clip_planes; j++) {
-
- clip[j].intersects_segment(from, to, &from);
- }
-
- float distance = (to - from).length();
- distance += distance_adv - Math::fmod(distance, distance_adv); //make it reach the center of the box always
- from = to - light_axis * distance;
-
- uint32_t result = 0xFFFFFFFF;
-
- while (distance > -distance_adv) { //use this to avoid precision errors
-
- result = _gi_bake_find_cell(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)), header->cell_subdiv);
- if (result != 0xFFFFFFFF) {
- break;
- }
-
- from += light_axis * distance_adv;
- distance -= distance_adv;
- }
-
- if (result == idx) {
- //cell hit itself! hooray!
- light->energy[0] += int32_t(light_r * att * ((cell->albedo >> 16) & 0xFF) / 255.0);
- light->energy[1] += int32_t(light_g * att * ((cell->albedo >> 8) & 0xFF) / 255.0);
- light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0);
- success_count++;
- }
- }
-
- // print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
- // print_line("valid cells: " + itos(success_count));
-
- } break;
- case VS::LIGHT_OMNI:
- case VS::LIGHT_SPOT: {
-
- // uint64_t us = OS::get_singleton()->get_ticks_usec();
-
- Vector3 light_pos = light_cache.transform.origin;
- Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized();
-
- float local_radius = light_cache.radius * light_cache.transform.basis.get_axis(2).length();
-
- for (int i = 0; i < p_leaf_count; i++) {
-
- uint32_t idx = leaves[i];
-
- const GIProbeDataCell *cell = &cells[idx];
- InstanceGIProbeData::LocalData *light = &local_data[idx];
-
- Vector3 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5);
- to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray
-
- Vector3 norm(
- (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 0) & 0xFF) / 255.0) * 2.0 - 1.0);
-
- Vector3 light_axis = (to - light_pos).normalized();
- float distance_adv = _get_normal_advance(light_axis);
-
- float att = norm.dot(-light_axis);
- if (att < 0.001) {
- //not lighting towards this
- continue;
- }
-
- {
- float d = light_pos.distance_to(to);
- if (d + distance_adv > local_radius)
- continue; // too far away
-
- float dt = CLAMP((d + distance_adv) / local_radius, 0, 1);
- att *= powf(1.0 - dt, light_cache.attenuation);
- }
-
- if (light_cache.type == VS::LIGHT_SPOT) {
-
- float angle = Math::rad2deg(acos(light_axis.dot(spot_axis)));
- if (angle > light_cache.spot_angle)
- continue;
-
- float d = CLAMP(angle / light_cache.spot_angle, 0, 1);
- att *= powf(1.0 - d, light_cache.spot_attenuation);
- }
-
- clip_planes = 0;
-
- for (int c = 0; c < 3; c++) {
-
- if (Math::is_zero_approx(light_axis[c]))
- continue;
- clip[clip_planes].normal[c] = 1.0;
-
- if (light_axis[c] < 0) {
-
- clip[clip_planes].d = limits[c] + 1;
- } else {
- clip[clip_planes].d -= 1.0;
- }
-
- clip_planes++;
- }
-
- Vector3 from = light_pos;
-
- for (int j = 0; j < clip_planes; j++) {
-
- clip[j].intersects_segment(from, to, &from);
- }
-
- float distance = (to - from).length();
-
- distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer
- from = to - light_axis * distance;
-
- uint32_t result = 0xFFFFFFFF;
-
- while (distance > -distance_adv) { //use this to avoid precision errors
-
- result = _gi_bake_find_cell(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)), header->cell_subdiv);
- if (result != 0xFFFFFFFF) {
- break;
- }
-
- from += light_axis * distance_adv;
- distance -= distance_adv;
- }
-
- if (result == idx) {
- //cell hit itself! hooray!
-
- light->energy[0] += int32_t(light_r * att * ((cell->albedo >> 16) & 0xFF) / 255.0);
- light->energy[1] += int32_t(light_g * att * ((cell->albedo >> 8) & 0xFF) / 255.0);
- light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0);
- }
- }
- //print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
- } break;
- }
-}
-
-void VisualServerScene::_bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell *p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, float p_propagate) {
-
- //average light to upper level
-
- float divisor = 0;
- float sum[3] = { 0.0, 0.0, 0.0 };
-
- for (int i = 0; i < 8; i++) {
-
- uint32_t child = p_cells[p_idx].children[i];
-
- if (child == 0xFFFFFFFF)
- continue;
-
- if (p_level + 1 < (int)p_header->cell_subdiv - 1) {
- _bake_gi_downscale_light(child, p_level + 1, p_cells, p_header, p_local_data, p_propagate);
- }
-
- sum[0] += p_local_data[child].energy[0];
- sum[1] += p_local_data[child].energy[1];
- sum[2] += p_local_data[child].energy[2];
- divisor += 1.0;
- }
-
- divisor = Math::lerp((float)8.0, divisor, p_propagate);
- sum[0] /= divisor;
- sum[1] /= divisor;
- sum[2] /= divisor;
-
- //divide by eight for average
- p_local_data[p_idx].energy[0] = Math::fast_ftoi(sum[0]);
- p_local_data[p_idx].energy[1] = Math::fast_ftoi(sum[1]);
- p_local_data[p_idx].energy[2] = Math::fast_ftoi(sum[2]);
-}
-
-void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) {
-
- InstanceGIProbeData *probe_data = static_cast<InstanceGIProbeData *>(p_gi_probe->base_data);
-
- PoolVector<int>::Read r = probe_data->dynamic.light_data.read();
-
- const GIProbeDataHeader *header = (const GIProbeDataHeader *)r.ptr();
- const GIProbeDataCell *cells = (const GIProbeDataCell *)&r[16];
-
- int leaf_count = probe_data->dynamic.level_cell_lists[header->cell_subdiv - 1].size();
- const uint32_t *leaves = probe_data->dynamic.level_cell_lists[header->cell_subdiv - 1].ptr();
-
- PoolVector<InstanceGIProbeData::LocalData>::Write ldw = probe_data->dynamic.local_data.write();
-
- InstanceGIProbeData::LocalData *local_data = ldw.ptr();
-
- //remove what must be removed
- for (Map<RID, InstanceGIProbeData::LightCache>::Element *E = probe_data->dynamic.light_cache.front(); E; E = E->next()) {
-
- RID rid = E->key();
- const InstanceGIProbeData::LightCache &lc = E->get();
-
- if ((!probe_data->dynamic.light_cache_changes.has(rid) || probe_data->dynamic.light_cache_changes[rid] != lc) && lc.visible) {
- //erase light data
-
- _bake_gi_probe_light(header, cells, local_data, leaves, leaf_count, lc, -1);
- }
- }
-
- //add what must be added
- for (Map<RID, InstanceGIProbeData::LightCache>::Element *E = probe_data->dynamic.light_cache_changes.front(); E; E = E->next()) {
-
- RID rid = E->key();
- const InstanceGIProbeData::LightCache &lc = E->get();
-
- if ((!probe_data->dynamic.light_cache.has(rid) || probe_data->dynamic.light_cache[rid] != lc) && lc.visible) {
- //add light data
-
- _bake_gi_probe_light(header, cells, local_data, leaves, leaf_count, lc, 1);
- }
- }
-
- SWAP(probe_data->dynamic.light_cache_changes, probe_data->dynamic.light_cache);
-
- //downscale to lower res levels
- _bake_gi_downscale_light(0, 0, cells, header, local_data, probe_data->dynamic.propagate);
-
- //plot result to 3D texture!
-
- if (probe_data->dynamic.compression == RasterizerStorage::GI_PROBE_UNCOMPRESSED) {
-
- for (int i = 0; i < (int)header->cell_subdiv; i++) {
-
- int stage = header->cell_subdiv - i - 1;
-
- if (stage >= probe_data->dynamic.mipmaps_3d.size())
- continue; //no mipmap for this one
-
- //print_line("generating mipmap stage: " + itos(stage));
- int level_cell_count = probe_data->dynamic.level_cell_lists[i].size();
- const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[i].ptr();
-
- PoolVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d.write[stage].write();
- uint8_t *mipmapw = lw.ptr();
-
- uint32_t sizes[3] = { header->width >> stage, header->height >> stage, header->depth >> stage };
-
- for (int j = 0; j < level_cell_count; j++) {
-
- uint32_t idx = level_cells[j];
-
- uint32_t r2 = (uint32_t(local_data[idx].energy[0]) / probe_data->dynamic.bake_dynamic_range) >> 2;
- uint32_t g = (uint32_t(local_data[idx].energy[1]) / probe_data->dynamic.bake_dynamic_range) >> 2;
- uint32_t b = (uint32_t(local_data[idx].energy[2]) / probe_data->dynamic.bake_dynamic_range) >> 2;
- uint32_t a = (cells[idx].level_alpha >> 8) & 0xFF;
-
- uint32_t mm_ofs = sizes[0] * sizes[1] * (local_data[idx].pos[2]) + sizes[0] * (local_data[idx].pos[1]) + (local_data[idx].pos[0]);
- mm_ofs *= 4; //for RGBA (4 bytes)
-
- mipmapw[mm_ofs + 0] = uint8_t(MIN(r2, 255));
- mipmapw[mm_ofs + 1] = uint8_t(MIN(g, 255));
- mipmapw[mm_ofs + 2] = uint8_t(MIN(b, 255));
- mipmapw[mm_ofs + 3] = uint8_t(MIN(a, 255));
- }
- }
- } else if (probe_data->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) {
-
- int mipmap_count = probe_data->dynamic.mipmaps_3d.size();
-
- for (int mmi = 0; mmi < mipmap_count; mmi++) {
-
- PoolVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d.write[mmi].write();
- int block_count = probe_data->dynamic.mipmaps_s3tc[mmi].size();
- PoolVector<InstanceGIProbeData::CompBlockS3TC>::Read mmr = probe_data->dynamic.mipmaps_s3tc[mmi].read();
-
- for (int i = 0; i < block_count; i++) {
-
- const InstanceGIProbeData::CompBlockS3TC &b = mmr[i];
-
- uint8_t *blockptr = &mmw[b.offset * 16];
- copymem(blockptr, b.alpha, 8); //copy alpha part, which is precomputed
-
- Vector3 colors[16];
-
- for (uint32_t j = 0; j < b.source_count; j++) {
-
- colors[j].x = (local_data[b.sources[j]].energy[0] / float(probe_data->dynamic.bake_dynamic_range)) / 1024.0;
- colors[j].y = (local_data[b.sources[j]].energy[1] / float(probe_data->dynamic.bake_dynamic_range)) / 1024.0;
- colors[j].z = (local_data[b.sources[j]].energy[2] / float(probe_data->dynamic.bake_dynamic_range)) / 1024.0;
- }
- //super quick and dirty compression
- //find 2 most further apart
- float distance = 0;
- Vector3 from, to;
-
- if (b.source_count == 16) {
- //all cells are used so, find minmax between them
- int further_apart[2] = { 0, 0 };
- for (uint32_t j = 0; j < b.source_count; j++) {
- for (uint32_t k = j + 1; k < b.source_count; k++) {
- float d = colors[j].distance_squared_to(colors[k]);
- if (d > distance) {
- distance = d;
- further_apart[0] = j;
- further_apart[1] = k;
- }
- }
- }
-
- from = colors[further_apart[0]];
- to = colors[further_apart[1]];
-
- } else {
- //if a block is missing, the priority is that this block remains black,
- //otherwise the geometry will appear deformed
- //correct shape wins over correct color in this case
- //average all colors first
- Vector3 average;
-
- for (uint32_t j = 0; j < b.source_count; j++) {
- average += colors[j];
- }
- average.normalize();
- //find max distance in normal from average
- for (uint32_t j = 0; j < b.source_count; j++) {
- float d = average.dot(colors[j]);
- distance = MAX(d, distance);
- }
-
- from = Vector3(); //from black
- to = average * distance;
- //find max distance
- }
-
- int indices[16];
- uint16_t color_0 = 0;
- color_0 = CLAMP(int(from.x * 31), 0, 31) << 11;
- color_0 |= CLAMP(int(from.y * 63), 0, 63) << 5;
- color_0 |= CLAMP(int(from.z * 31), 0, 31);
-
- uint16_t color_1 = 0;
- color_1 = CLAMP(int(to.x * 31), 0, 31) << 11;
- color_1 |= CLAMP(int(to.y * 63), 0, 63) << 5;
- color_1 |= CLAMP(int(to.z * 31), 0, 31);
-
- if (color_1 > color_0) {
- SWAP(color_1, color_0);
- SWAP(from, to);
- }
-
- if (distance > 0) {
-
- Vector3 dir = (to - from).normalized();
-
- for (uint32_t j = 0; j < b.source_count; j++) {
-
- float d = (colors[j] - from).dot(dir) / distance;
- indices[j] = int(d * 3 + 0.5);
-
- static const int index_swap[4] = { 0, 3, 1, 2 };
-
- indices[j] = index_swap[CLAMP(indices[j], 0, 3)];
- }
- } else {
- for (uint32_t j = 0; j < b.source_count; j++) {
- indices[j] = 0;
- }
- }
-
- //by default, 1 is black, otherwise it will be overridden by source
-
- uint32_t index_block[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-
- for (uint32_t j = 0; j < b.source_count; j++) {
-
- int x = local_data[b.sources[j]].pos[0] % 4;
- int y = local_data[b.sources[j]].pos[1] % 4;
-
- index_block[y * 4 + x] = indices[j];
- }
-
- uint32_t encode = 0;
-
- for (int j = 0; j < 16; j++) {
- encode |= index_block[j] << (j * 2);
- }
-
- blockptr[8] = color_0 & 0xFF;
- blockptr[9] = (color_0 >> 8) & 0xFF;
- blockptr[10] = color_1 & 0xFF;
- blockptr[11] = (color_1 >> 8) & 0xFF;
- blockptr[12] = encode & 0xFF;
- blockptr[13] = (encode >> 8) & 0xFF;
- blockptr[14] = (encode >> 16) & 0xFF;
- blockptr[15] = (encode >> 24) & 0xFF;
- }
- }
- }
-
- //send back to main thread to update un little chunks
- if (probe_bake_mutex) {
- probe_bake_mutex->lock();
- }
-
- probe_data->dynamic.updating_stage = GI_UPDATE_STAGE_UPLOADING;
-
- if (probe_bake_mutex) {
- probe_bake_mutex->unlock();
- }
-}
-
-bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) {
-
- InstanceGIProbeData *probe_data = static_cast<InstanceGIProbeData *>(p_gi_probe->base_data);
-
- probe_data->dynamic.light_cache_changes.clear();
-
- bool all_equal = true;
-
- for (List<Instance *>::Element *E = p_gi_probe->scenario->directional_lights.front(); E; E = E->next()) {
-
- if (!VSG::storage->light_get_use_gi(E->get()->base))
- continue;
-
- InstanceGIProbeData::LightCache lc;
- lc.type = VSG::storage->light_get_type(E->get()->base);
- lc.color = VSG::storage->light_get_color(E->get()->base);
- lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY) * VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- lc.radius = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_RANGE);
- lc.attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ATTENUATION);
- lc.spot_angle = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ANGLE);
- lc.spot_attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
- lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform;
- lc.visible = E->get()->visible;
-
- if (!probe_data->dynamic.light_cache.has(E->get()->self) || probe_data->dynamic.light_cache[E->get()->self] != lc) {
- all_equal = false;
- }
-
- probe_data->dynamic.light_cache_changes[E->get()->self] = lc;
- }
-
- for (Set<Instance *>::Element *E = probe_data->lights.front(); E; E = E->next()) {
-
- if (!VSG::storage->light_get_use_gi(E->get()->base))
- continue;
-
- InstanceGIProbeData::LightCache lc;
- lc.type = VSG::storage->light_get_type(E->get()->base);
- lc.color = VSG::storage->light_get_color(E->get()->base);
- lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY) * VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- lc.radius = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_RANGE);
- lc.attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ATTENUATION);
- lc.spot_angle = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ANGLE);
- lc.spot_attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
- lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform;
- lc.visible = E->get()->visible;
-
- if (!probe_data->dynamic.light_cache.has(E->get()->self) || probe_data->dynamic.light_cache[E->get()->self] != lc) {
- all_equal = false;
- }
-
- probe_data->dynamic.light_cache_changes[E->get()->self] = lc;
- }
-
- //lighting changed from after to before, must do some updating
- return !all_equal || probe_data->dynamic.light_cache_changes.size() != probe_data->dynamic.light_cache.size();
-}
-
void VisualServerScene::render_probes() {
/* REFLECTION PROBES */
@@ -3205,71 +2306,169 @@ void VisualServerScene::render_probes() {
SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
+ if (gi_probe) {
+ RENDER_TIMESTAMP("Render GI Probes");
+ }
+
while (gi_probe) {
SelfList<InstanceGIProbeData> *next = gi_probe->next();
InstanceGIProbeData *probe = gi_probe->self();
- Instance *instance_probe = probe->owner;
+ //Instance *instance_probe = probe->owner;
//check if probe must be setup, but don't do if on the lighting thread
- bool force_lighting = false;
+ bool cache_dirty = false;
+ int cache_count = 0;
+ {
- if (probe->invalid || (probe->dynamic.updating_stage == GI_UPDATE_STAGE_CHECK && probe->base_version != VSG::storage->gi_probe_get_version(instance_probe->base))) {
+ int light_cache_size = probe->light_cache.size();
+ const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr();
+ const RID *instance_caches = probe->light_instances.ptr();
- _setup_gi_probe(instance_probe);
- force_lighting = true;
- }
+ int idx = 0; //must count visible lights
+ for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+ if (cache_dirty) {
+ //do nothing, since idx must count all visible lights anyway
+ } else if (idx >= light_cache_size) {
+ cache_dirty = true;
+ } else {
- float propagate = VSG::storage->gi_probe_get_propagation(instance_probe->base);
+ const InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ if (
+ instance_caches[idx] != instance_light->instance ||
+ cache->has_shadow != VSG::storage->light_has_shadow(instance->base) ||
+ cache->type != VSG::storage->light_get_type(instance->base) ||
+ cache->transform != instance->transform ||
+ cache->color != VSG::storage->light_get_color(instance->base) ||
+ cache->energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY) ||
+ cache->bake_energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY) ||
+ cache->radius != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE) ||
+ cache->attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION) ||
+ cache->spot_angle != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE) ||
+ cache->spot_attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache_dirty = true;
+ }
+ }
- if (probe->dynamic.propagate != propagate) {
- probe->dynamic.propagate = propagate;
- force_lighting = true;
- }
+ idx++;
+ }
- if (!probe->invalid && probe->dynamic.enabled) {
+ for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
- switch (probe->dynamic.updating_stage) {
- case GI_UPDATE_STAGE_CHECK: {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+ if (cache_dirty) {
+ //do nothing, since idx must count all visible lights anyway
+ } else if (idx >= light_cache_size) {
+ cache_dirty = true;
+ } else {
- if (_check_gi_probe(instance_probe) || force_lighting) { //send to lighting thread
+ const InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ if (
+ instance_caches[idx] != instance_light->instance ||
+ cache->has_shadow != VSG::storage->light_has_shadow(instance->base) ||
+ cache->type != VSG::storage->light_get_type(instance->base) ||
+ cache->transform != instance->transform ||
+ cache->color != VSG::storage->light_get_color(instance->base) ||
+ cache->energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY) ||
+ cache->bake_energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY) ||
+ cache->radius != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE) ||
+ cache->attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION) ||
+ cache->spot_angle != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE) ||
+ cache->spot_attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache_dirty = true;
+ }
+ }
-#ifndef NO_THREADS
- probe_bake_mutex->lock();
- probe->dynamic.updating_stage = GI_UPDATE_STAGE_LIGHTING;
- probe_bake_list.push_back(instance_probe);
- probe_bake_mutex->unlock();
- probe_bake_sem->post();
+ idx++;
+ }
-#else
+ if (idx != light_cache_size) {
+ cache_dirty = true;
+ }
- _bake_gi_probe(instance_probe);
-#endif
- }
- } break;
- case GI_UPDATE_STAGE_LIGHTING: {
- //do none, wait til done!
+ cache_count = idx;
+ }
- } break;
- case GI_UPDATE_STAGE_UPLOADING: {
+ bool update_probe = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
- //uint64_t us = OS::get_singleton()->get_ticks_usec();
+ if (cache_dirty) {
+ probe->light_cache.resize(cache_count);
+ probe->light_instances.resize(cache_count);
- for (int i = 0; i < (int)probe->dynamic.mipmaps_3d.size(); i++) {
+ if (cache_count) {
+ InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw();
+ RID *instance_caches = probe->light_instances.ptrw();
- PoolVector<uint8_t>::Read r = probe->dynamic.mipmaps_3d[i].read();
- VSG::storage->gi_probe_dynamic_data_update(probe->dynamic.probe_data, 0, probe->dynamic.grid_size[2] >> i, i, r.ptr());
+ int idx = 0; //must count visible lights
+ for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
}
- probe->dynamic.updating_stage = GI_UPDATE_STAGE_CHECK;
+ InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ instance_caches[idx] = instance_light->instance;
+ cache->has_shadow = VSG::storage->light_has_shadow(instance->base);
+ cache->type = VSG::storage->light_get_type(instance->base);
+ cache->transform = instance->transform;
+ cache->color = VSG::storage->light_get_color(instance->base);
+ cache->energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY);
+ cache->bake_energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
+ cache->radius = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE);
+ cache->attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION);
+ cache->spot_angle = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
+ cache->spot_attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+ for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
- //print_line("UPLOAD TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
- } break;
+ InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ instance_caches[idx] = instance_light->instance;
+ cache->has_shadow = VSG::storage->light_has_shadow(instance->base);
+ cache->type = VSG::storage->light_get_type(instance->base);
+ cache->transform = instance->transform;
+ cache->color = VSG::storage->light_get_color(instance->base);
+ cache->energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY);
+ cache->bake_energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
+ cache->radius = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE);
+ cache->attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION);
+ cache->spot_angle = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
+ cache->spot_attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
}
+
+ update_probe = true;
+ }
+
+ if (update_probe) {
+ VSG::scene_render->gi_probe_update(probe->probe_instance, probe->light_instances);
}
- //_update_gi_probe(gi_probe->self()->owner);
+
+ gi_probe_update_list.remove(gi_probe);
gi_probe = next;
}
@@ -3527,26 +2726,9 @@ VisualServerScene *VisualServerScene::singleton = NULL;
VisualServerScene::VisualServerScene() {
-#ifndef NO_THREADS
- probe_bake_sem = SemaphoreOld::create();
- probe_bake_mutex = Mutex::create();
- probe_bake_thread = Thread::create(_gi_probe_bake_threads, this);
- probe_bake_thread_exit = false;
-#endif
-
render_pass = 1;
singleton = this;
}
VisualServerScene::~VisualServerScene() {
-
-#ifndef NO_THREADS
- probe_bake_thread_exit = true;
- probe_bake_sem->post();
- Thread::wait_to_finish(probe_bake_thread);
- memdelete(probe_bake_thread);
- memdelete(probe_bake_sem);
- memdelete(probe_bake_mutex);
-
-#endif
}
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index 2fadd778be..b4ff26653b 100644
--- a/servers/visual/visual_server_scene.h
+++ b/servers/visual/visual_server_scene.h
@@ -48,6 +48,7 @@ public:
MAX_INSTANCE_CULL = 65536,
MAX_LIGHTS_CULLED = 4096,
MAX_REFLECTION_PROBES_CULLED = 4096,
+ MAX_GI_PROBES_CULLED = 4096,
MAX_ROOM_CULL = 32,
MAX_EXTERIOR_PORTALS = 128,
};
@@ -324,77 +325,16 @@ public:
Transform transform;
Color color;
float energy;
+ float bake_energy;
float radius;
float attenuation;
float spot_angle;
float spot_attenuation;
- bool visible;
-
- bool operator==(const LightCache &p_cache) {
-
- return (type == p_cache.type &&
- transform == p_cache.transform &&
- color == p_cache.color &&
- energy == p_cache.energy &&
- radius == p_cache.radius &&
- attenuation == p_cache.attenuation &&
- spot_angle == p_cache.spot_angle &&
- spot_attenuation == p_cache.spot_attenuation &&
- visible == p_cache.visible);
- }
-
- bool operator!=(const LightCache &p_cache) {
-
- return !operator==(p_cache);
- }
-
- LightCache() {
-
- type = VS::LIGHT_DIRECTIONAL;
- energy = 1.0;
- radius = 1.0;
- attenuation = 1.0;
- spot_angle = 1.0;
- spot_attenuation = 1.0;
- visible = true;
- }
- };
-
- struct LocalData {
- uint16_t pos[3];
- uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights
- };
-
- struct CompBlockS3TC {
- uint32_t offset; //offset in mipmap
- uint32_t source_count; //sources
- uint32_t sources[16]; //id for each source
- uint8_t alpha[8]; //alpha block is pre-computed
+ bool has_shadow;
};
- struct Dynamic {
-
- Map<RID, LightCache> light_cache;
- Map<RID, LightCache> light_cache_changes;
- PoolVector<int> light_data;
- PoolVector<LocalData> local_data;
- Vector<Vector<uint32_t> > level_cell_lists;
- RID probe_data;
- bool enabled;
- int bake_dynamic_range;
- RasterizerStorage::GIProbeCompression compression;
-
- Vector<PoolVector<uint8_t> > mipmaps_3d;
- Vector<PoolVector<CompBlockS3TC> > mipmaps_s3tc; //for s3tc
-
- int updating_stage;
- float propagate;
-
- int grid_size[3];
-
- Transform light_to_cell_xform;
-
- } dynamic;
+ Vector<LightCache> light_cache;
+ Vector<RID> light_instances;
RID probe_instance;
@@ -407,7 +347,6 @@ public:
update_element(this) {
invalid = true;
base_version = 0;
- dynamic.updating_stage = GI_UPDATE_STAGE_CHECK;
}
};
@@ -436,6 +375,8 @@ public:
int directional_light_count;
RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
int reflection_probe_cull_count;
+ RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED];
+ int gi_probe_cull_count;
RID_PtrOwner<Instance> instance_owner;
@@ -477,6 +418,7 @@ public:
_FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario);
+ bool _render_reflection_probe_step(Instance *p_instance, int p_step);
void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true);
void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
@@ -485,52 +427,6 @@ public:
void render_camera(RID p_render_buffers, Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);
void update_dirty_instances();
- //probes
- struct GIProbeDataHeader {
-
- uint32_t version;
- uint32_t cell_subdiv;
- uint32_t width;
- uint32_t height;
- uint32_t depth;
- uint32_t cell_count;
- uint32_t leaf_cell_count;
- };
-
- struct GIProbeDataCell {
-
- uint32_t children[8];
- uint32_t albedo;
- uint32_t emission;
- uint32_t normal;
- uint32_t level_alpha;
- };
-
- enum {
- GI_UPDATE_STAGE_CHECK,
- GI_UPDATE_STAGE_LIGHTING,
- GI_UPDATE_STAGE_UPLOADING,
- };
-
- void _gi_probe_bake_thread();
- static void _gi_probe_bake_threads(void *);
-
- volatile bool probe_bake_thread_exit;
- Thread *probe_bake_thread;
- SemaphoreOld *probe_bake_sem;
- Mutex *probe_bake_mutex;
- List<Instance *> probe_bake_list;
-
- bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _gi_probe_fill_local_data(int p_idx, int p_level, int p_x, int p_y, int p_z, const GIProbeDataCell *p_cell, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, Vector<uint32_t> *prev_cell);
-
- _FORCE_INLINE_ uint32_t _gi_bake_find_cell(const GIProbeDataCell *cells, int x, int y, int z, int p_cell_subdiv);
- void _bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell *p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, float p_propagate);
- void _bake_gi_probe_light(const GIProbeDataHeader *header, const GIProbeDataCell *cells, InstanceGIProbeData::LocalData *local_data, const uint32_t *leaves, int p_leaf_count, const InstanceGIProbeData::LightCache &light_cache, int p_sign);
- void _bake_gi_probe(Instance *p_gi_probe);
- bool _check_gi_probe(Instance *p_gi_probe);
- void _setup_gi_probe(Instance *p_instance);
-
void render_probes();
bool free(RID p_rid);
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index e1873e5999..37a2fffa7a 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -268,17 +268,20 @@ public:
FUNCRID(gi_probe)
- FUNC2(gi_probe_set_bounds, RID, const AABB &)
- FUNC1RC(AABB, gi_probe_get_bounds, RID)
-
- FUNC2(gi_probe_set_cell_size, RID, float)
- FUNC1RC(float, gi_probe_get_cell_size, RID)
+ FUNC7(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &)
- FUNC2(gi_probe_set_to_cell_xform, RID, const Transform &)
+ FUNC1RC(AABB, gi_probe_get_bounds, RID)
+ FUNC1RC(Vector3i, gi_probe_get_octree_size, RID)
+ FUNC1RC(PoolVector<uint8_t>, gi_probe_get_octree_cells, RID)
+ FUNC1RC(PoolVector<uint8_t>, gi_probe_get_data_cells, RID)
+ FUNC1RC(PoolVector<int>, gi_probe_get_level_counts, RID)
FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID)
- FUNC2(gi_probe_set_dynamic_range, RID, int)
- FUNC1RC(int, gi_probe_get_dynamic_range, RID)
+ FUNC2(gi_probe_set_dynamic_range, RID, float)
+ FUNC1RC(float, gi_probe_get_dynamic_range, RID)
+
+ FUNC2(gi_probe_set_propagation, RID, float)
+ FUNC1RC(float, gi_probe_get_propagation, RID)
FUNC2(gi_probe_set_energy, RID, float)
FUNC1RC(float, gi_probe_get_energy, RID)
@@ -289,17 +292,14 @@ public:
FUNC2(gi_probe_set_normal_bias, RID, float)
FUNC1RC(float, gi_probe_get_normal_bias, RID)
- FUNC2(gi_probe_set_propagation, RID, float)
- FUNC1RC(float, gi_probe_get_propagation, RID)
-
FUNC2(gi_probe_set_interior, RID, bool)
FUNC1RC(bool, gi_probe_is_interior, RID)
- FUNC2(gi_probe_set_compress, RID, bool)
- FUNC1RC(bool, gi_probe_is_compressed, RID)
+ FUNC2(gi_probe_set_use_two_bounces, RID, bool)
+ FUNC1RC(bool, gi_probe_is_using_two_bounces, RID)
- FUNC2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &)
- FUNC1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID)
+ FUNC2(gi_probe_set_anisotropy_strength, RID, float)
+ FUNC1RC(float, gi_probe_get_anisotropy_strength, RID)
/* LIGHTMAP CAPTURE */