mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 09:16:35 +08:00
Dynamic object support for GI Probes (a bit buggy still)
This commit is contained in:
parent
a95fb114ba
commit
561b431d85
@ -2656,7 +2656,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.pNext = NULL;
|
||||
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
image_memory_barrier.newLayout = src_tex->layout;
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
@ -2677,7 +2677,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.pNext = NULL;
|
||||
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
image_memory_barrier.newLayout = dst_tex->layout;
|
||||
|
||||
|
@ -60,6 +60,9 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(VkDebugU
|
||||
strstr(pCallbackData->pMessage, "must be a memory object") != NULL) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
if (strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != NULL) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
|
||||
strcat(prefix, "VERBOSE : ");
|
||||
|
@ -298,6 +298,7 @@ void GeometryInstance::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_dynamic_gi"), "set_flag", "get_flag", FLAG_USE_DYNAMIC_GI);
|
||||
|
||||
ADD_GROUP("LOD", "lod_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance");
|
||||
@ -313,6 +314,7 @@ void GeometryInstance::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
|
||||
|
||||
BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT);
|
||||
BIND_ENUM_CONSTANT(FLAG_USE_DYNAMIC_GI);
|
||||
BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
|
||||
BIND_ENUM_CONSTANT(FLAG_MAX);
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ class GeometryInstance : public VisualInstance {
|
||||
public:
|
||||
enum Flags {
|
||||
FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT,
|
||||
FLAG_USE_DYNAMIC_GI = VS::INSTANCE_FLAG_USE_DYNAMIC_GI,
|
||||
FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
|
||||
FLAG_MAX = VS::INSTANCE_FLAG_MAX,
|
||||
};
|
||||
|
@ -140,7 +140,8 @@ public:
|
||||
bool mirror : 8;
|
||||
bool receive_shadows : 8;
|
||||
bool visible : 8;
|
||||
bool baked_light : 4; //this flag is only to know if it actually did use baked light
|
||||
bool baked_light : 2; //this flag is only to know if it actually did use baked light
|
||||
bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light
|
||||
bool redraw_if_visible : 4;
|
||||
|
||||
float depth; //used for sorting
|
||||
@ -151,6 +152,9 @@ public:
|
||||
RID lightmap;
|
||||
Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
|
||||
|
||||
AABB aabb;
|
||||
AABB transformed_aabb;
|
||||
|
||||
virtual void dependency_deleted(RID p_dependency) = 0;
|
||||
virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0;
|
||||
|
||||
@ -204,6 +208,7 @@ public:
|
||||
layer_mask = 1;
|
||||
instance_version = 0;
|
||||
baked_light = false;
|
||||
dynamic_gi = false;
|
||||
redraw_if_visible = false;
|
||||
lightmap_capture = NULL;
|
||||
}
|
||||
@ -233,11 +238,12 @@ public:
|
||||
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 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 gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 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_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0;
|
||||
virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
|
||||
|
||||
virtual void set_scene_pass(uint64_t p_pass) = 0;
|
||||
virtual void set_time(double p_time) = 0;
|
||||
|
@ -308,9 +308,11 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
|
||||
if (depth_draw == DEPTH_DRAW_OPAQUE) {
|
||||
depth_stencil.enable_depth_write = false; //alpha does not draw depth
|
||||
}
|
||||
} else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS)) {
|
||||
} else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
|
||||
if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
|
||||
//none, blend state contains nothing
|
||||
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
|
||||
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
|
||||
} else {
|
||||
blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
|
||||
}
|
||||
@ -326,6 +328,9 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
|
||||
//none, leave empty
|
||||
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
|
||||
blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
|
||||
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
|
||||
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
|
||||
|
||||
} else {
|
||||
//specular write
|
||||
blend_state = blend_state_opaque_specular;
|
||||
@ -601,7 +606,7 @@ bool RasterizerSceneForwardRD::free(RID p_rid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count) {
|
||||
void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth) {
|
||||
|
||||
for (int i = 0; i < p_element_count; i++) {
|
||||
|
||||
@ -637,6 +642,10 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements,
|
||||
}
|
||||
}
|
||||
|
||||
if (p_for_depth) {
|
||||
id.gi_offset = 0xFFFFFFFF;
|
||||
continue;
|
||||
}
|
||||
//forward
|
||||
|
||||
uint32_t reflection_count = 0;
|
||||
@ -850,6 +859,9 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
|
||||
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
|
||||
shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
|
||||
} break;
|
||||
case PASS_MODE_DEPTH_MATERIAL: {
|
||||
shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
|
||||
} break;
|
||||
}
|
||||
|
||||
RenderPipelineVertexFormatCacheRD *pipeline = nullptr;
|
||||
@ -939,12 +951,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) {
|
||||
void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y) {
|
||||
|
||||
//CameraMatrix projection = p_cam_projection;
|
||||
//projection.flip_y(); // Vulkan and modern APIs use Y-Down
|
||||
CameraMatrix correction;
|
||||
correction.set_depth_correction(!p_reflection_probe.is_valid());
|
||||
correction.set_depth_correction(p_flip_y);
|
||||
CameraMatrix projection = correction * p_cam_projection;
|
||||
|
||||
//store camera into ubo
|
||||
@ -1236,7 +1248,7 @@ void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_insta
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
|
||||
if (p_pass_mode != PASS_MODE_DEPTH_MATERIAL && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
|
||||
//shader does not use discard and does not write a vertex position, use generic material
|
||||
if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) {
|
||||
p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
|
||||
@ -1837,7 +1849,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
|
||||
_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
|
||||
_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
|
||||
_setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
|
||||
_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas);
|
||||
_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid());
|
||||
|
||||
render_list.clear();
|
||||
_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
|
||||
@ -1896,7 +1908,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
|
||||
|
||||
render_list.sort_by_key(false);
|
||||
|
||||
_fill_instances(render_list.elements, render_list.element_count);
|
||||
_fill_instances(render_list.elements, render_list.element_count, false);
|
||||
|
||||
bool can_continue = true; //unless the middle buffers are needed
|
||||
bool debug_giprobes = debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
|
||||
@ -1952,7 +1964,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
|
||||
|
||||
render_list.sort_by_reverse_depth_and_priority(true);
|
||||
|
||||
_fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count);
|
||||
_fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false);
|
||||
|
||||
{
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
|
||||
@ -2087,7 +2099,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
|
||||
scene_state.ubo.z_far = p_zfar;
|
||||
scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
|
||||
|
||||
_setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID());
|
||||
_setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true);
|
||||
|
||||
render_list.clear();
|
||||
|
||||
@ -2101,7 +2113,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
|
||||
|
||||
render_list.sort_by_key(false);
|
||||
|
||||
_fill_instances(render_list.elements, render_list.element_count);
|
||||
_fill_instances(render_list.elements, render_list.element_count, true);
|
||||
|
||||
{
|
||||
//regular forward for now
|
||||
@ -2111,6 +2123,47 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneForwardRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
|
||||
RENDER_TIMESTAMP("Setup Rendering Shadow");
|
||||
|
||||
_update_render_base_uniform_set();
|
||||
|
||||
render_pass++;
|
||||
|
||||
scene_state.ubo.shadow_z_offset = 0;
|
||||
scene_state.ubo.shadow_z_slope_scale = 0;
|
||||
scene_state.ubo.z_far = 0;
|
||||
scene_state.ubo.dual_paraboloid_side = 0;
|
||||
|
||||
_setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false);
|
||||
|
||||
render_list.clear();
|
||||
|
||||
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
|
||||
_fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
|
||||
|
||||
_setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
|
||||
|
||||
RENDER_TIMESTAMP("Render Material");
|
||||
|
||||
render_list.sort_by_key(false);
|
||||
|
||||
_fill_instances(render_list.elements, render_list.element_count, true);
|
||||
|
||||
{
|
||||
//regular forward for now
|
||||
Vector<Color> clear;
|
||||
clear.push_back(Color(0, 0, 0, 0));
|
||||
clear.push_back(Color(0, 0, 0, 0));
|
||||
clear.push_back(Color(0, 0, 0, 0));
|
||||
clear.push_back(Color(0, 0, 0, 0));
|
||||
clear.push_back(Color(0, 0, 0, 0));
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
|
||||
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneForwardRD::_update_render_base_uniform_set() {
|
||||
|
||||
if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || gi_probe_slots_are_dirty()) {
|
||||
@ -2425,6 +2478,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
|
||||
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
|
||||
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_BUFFER\n");
|
||||
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_ROUGHNESS_BUFFER\n");
|
||||
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
|
||||
shader_versions.push_back("");
|
||||
shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
|
||||
shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n");
|
||||
|
@ -45,6 +45,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
|
||||
SHADER_VERSION_DEPTH_PASS_DP,
|
||||
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL,
|
||||
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
|
||||
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
|
||||
SHADER_VERSION_COLOR_PASS,
|
||||
SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
|
||||
SHADER_VERSION_VCT_COLOR_PASS,
|
||||
@ -519,14 +520,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
|
||||
PASS_MODE_DEPTH,
|
||||
PASS_MODE_DEPTH_NORMAL,
|
||||
PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
|
||||
PASS_MODE_DEPTH_MATERIAL,
|
||||
};
|
||||
|
||||
void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas);
|
||||
void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y);
|
||||
void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
|
||||
void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
|
||||
void _setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform);
|
||||
|
||||
void _fill_instances(RenderList::Element **p_elements, int p_element_count);
|
||||
void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth);
|
||||
void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi);
|
||||
_FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index);
|
||||
_FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index);
|
||||
@ -540,6 +542,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
|
||||
protected:
|
||||
virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
|
||||
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip);
|
||||
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
|
||||
|
||||
public:
|
||||
virtual void set_time(double p_time);
|
||||
|
@ -1245,7 +1245,7 @@ bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const {
|
||||
return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances) {
|
||||
void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) {
|
||||
|
||||
GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
|
||||
ERR_FAIL_COND(!gi_probe);
|
||||
@ -1266,6 +1266,13 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
|
||||
gi_probe->mipmaps.clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
|
||||
RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
|
||||
RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
|
||||
}
|
||||
|
||||
gi_probe->dynamic_maps.clear();
|
||||
|
||||
Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
|
||||
|
||||
if (octree_size != Vector3i()) {
|
||||
@ -1354,6 +1361,21 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
|
||||
u.ids.push_back(gi_probe->write_buffer);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 9;
|
||||
u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 10;
|
||||
u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
Vector<RD::Uniform> copy_uniforms = uniforms;
|
||||
if (i == 0) {
|
||||
@ -1376,13 +1398,6 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
|
||||
u.ids.push_back(gi_probe->texture);
|
||||
copy_uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 6;
|
||||
u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
|
||||
copy_uniforms.push_back(u);
|
||||
}
|
||||
|
||||
if (gi_probe_use_anisotropy) {
|
||||
{
|
||||
@ -1436,138 +1451,579 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
|
||||
|
||||
gi_probe->mipmaps.push_back(mipmap);
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
|
||||
uint32_t oversample = nearest_power_of_2_templated(4);
|
||||
int mipmap_index = 0;
|
||||
|
||||
while (mipmap_index < gi_probe->mipmaps.size()) {
|
||||
GIProbeInstance::DynamicMap dmap;
|
||||
|
||||
if (oversample > 0) {
|
||||
dmap.size = dynamic_map_size * (1 << oversample);
|
||||
dmap.mipmap = -1;
|
||||
oversample--;
|
||||
} else {
|
||||
dmap.size = dynamic_map_size >> mipmap_index;
|
||||
dmap.mipmap = mipmap_index;
|
||||
mipmap_index++;
|
||||
}
|
||||
|
||||
RD::TextureFormat dtf;
|
||||
dtf.width = dmap.size;
|
||||
dtf.height = dmap.size;
|
||||
dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
|
||||
dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
if (gi_probe->dynamic_maps.size() == 0) {
|
||||
dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
|
||||
|
||||
if (gi_probe->dynamic_maps.size() == 0) {
|
||||
//render depth for first one
|
||||
dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
|
||||
dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
|
||||
}
|
||||
|
||||
//just use depth as-is
|
||||
dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
|
||||
dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
|
||||
|
||||
if (gi_probe->dynamic_maps.size() == 0) {
|
||||
|
||||
dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||
dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
|
||||
dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
|
||||
dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
|
||||
|
||||
Vector<RID> fb;
|
||||
fb.push_back(dmap.albedo);
|
||||
fb.push_back(dmap.normal);
|
||||
fb.push_back(dmap.orm);
|
||||
fb.push_back(dmap.texture); //emission
|
||||
fb.push_back(dmap.depth);
|
||||
fb.push_back(dmap.fb_depth);
|
||||
|
||||
dmap.fb = RD::get_singleton()->framebuffer_create(fb);
|
||||
|
||||
{
|
||||
Vector<RD::Uniform> uniforms;
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
|
||||
u.binding = 3;
|
||||
u.ids.push_back(gi_probe_lights_uniform);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 5;
|
||||
u.ids.push_back(dmap.albedo);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 6;
|
||||
u.ids.push_back(dmap.normal);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 7;
|
||||
u.ids.push_back(dmap.orm);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 8;
|
||||
u.ids.push_back(dmap.fb_depth);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 9;
|
||||
u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 10;
|
||||
u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 11;
|
||||
u.ids.push_back(dmap.texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 12;
|
||||
u.ids.push_back(dmap.depth);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
|
||||
}
|
||||
} else {
|
||||
bool plot = dmap.mipmap >= 0;
|
||||
bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1);
|
||||
|
||||
Vector<RD::Uniform> uniforms;
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 5;
|
||||
u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 6;
|
||||
u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
if (write) {
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 7;
|
||||
u.ids.push_back(dmap.texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 8;
|
||||
u.ids.push_back(dmap.depth);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 9;
|
||||
u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 10;
|
||||
u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
if (plot) {
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 11;
|
||||
u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
if (gi_probe_is_anisotropic()) {
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 12;
|
||||
u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[0]);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 13;
|
||||
u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[1]);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT], 0);
|
||||
}
|
||||
|
||||
gi_probe->dynamic_maps.push_back(dmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gi_probe->last_probe_data_version = data_version;
|
||||
gi_probe_slots_dirty = true;
|
||||
p_update_light_instances = true; //just in case
|
||||
}
|
||||
|
||||
// UDPDATE TIME
|
||||
|
||||
uint32_t light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
|
||||
{
|
||||
Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
|
||||
Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
|
||||
//update lights
|
||||
|
||||
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);
|
||||
if (gi_probe->has_dynamic_object_data) {
|
||||
//if it has dynamic object data, it needs to be cleared
|
||||
RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
|
||||
}
|
||||
|
||||
// PROCESS MIPMAPS
|
||||
if (gi_probe->mipmaps.size()) {
|
||||
//can update mipmaps
|
||||
uint32_t light_count = 0;
|
||||
|
||||
Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
|
||||
if (p_update_light_instances || p_dynamic_object_count > 0) {
|
||||
|
||||
GIProbePushConstant push_constant;
|
||||
light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
|
||||
|
||||
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);
|
||||
{
|
||||
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
|
||||
|
||||
/* 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();
|
||||
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);
|
||||
|
||||
int passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
|
||||
int wg_size = 64;
|
||||
int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
|
||||
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;
|
||||
|
||||
for (int pass = 0; pass < passes; pass++) {
|
||||
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);
|
||||
|
||||
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]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) {
|
||||
// PROCESS MIPMAPS
|
||||
if (gi_probe->mipmaps.size()) {
|
||||
//can update mipmaps
|
||||
|
||||
Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
|
||||
|
||||
GIProbePushConstant push_constant;
|
||||
|
||||
push_constant.limits[0] = probe_size.x;
|
||||
push_constant.limits[1] = probe_size.y;
|
||||
push_constant.limits[2] = probe_size.z;
|
||||
push_constant.stack_size = gi_probe->mipmaps.size();
|
||||
push_constant.emission_scale = 1.0;
|
||||
push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
|
||||
push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
|
||||
push_constant.light_count = light_count;
|
||||
push_constant.aniso_strength = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
|
||||
|
||||
/* print_line("probe update to version " + itos(gi_probe->last_probe_version));
|
||||
print_line("propagation " + rtos(push_constant.propagation));
|
||||
print_line("dynrange " + rtos(push_constant.dynamic_range));
|
||||
*/
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
|
||||
int passes;
|
||||
if (p_update_light_instances) {
|
||||
passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
|
||||
} else {
|
||||
passes = 1; //only re-blitting is necessary
|
||||
}
|
||||
int wg_size = 64;
|
||||
int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
|
||||
|
||||
for (int pass = 0; pass < passes; pass++) {
|
||||
|
||||
if (p_update_light_instances) {
|
||||
|
||||
for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
|
||||
if (i == 0) {
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
|
||||
} else if (i == 1) {
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
|
||||
}
|
||||
|
||||
if (pass == 1 || i > 0) {
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
|
||||
}
|
||||
if (pass == 0 || i > 0) {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
|
||||
} else {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
|
||||
}
|
||||
|
||||
push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
|
||||
push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
|
||||
|
||||
int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
|
||||
while (wg_todo) {
|
||||
int wg_count = MIN(wg_todo, wg_limit_x);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
|
||||
wg_todo -= wg_count;
|
||||
push_constant.cell_offset += wg_count * wg_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass == 1 || i > 0) {
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
|
||||
}
|
||||
if (pass == 0 || i > 0) {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
|
||||
} else {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
|
||||
}
|
||||
|
||||
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_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
|
||||
|
||||
int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
|
||||
while (wg_todo) {
|
||||
int wg_count = MIN(wg_todo, wg_limit_x);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
|
||||
wg_todo -= wg_count;
|
||||
push_constant.cell_offset += wg_count * wg_size;
|
||||
for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
|
||||
|
||||
push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
|
||||
push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
|
||||
|
||||
int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
|
||||
while (wg_todo) {
|
||||
int wg_count = MIN(wg_todo, wg_limit_x);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
|
||||
wg_todo -= wg_count;
|
||||
push_constant.cell_offset += wg_count * wg_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
|
||||
gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again
|
||||
|
||||
for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
|
||||
if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) {
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
|
||||
Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
|
||||
int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
|
||||
|
||||
push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
|
||||
push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
|
||||
Transform oversample_scale;
|
||||
oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
|
||||
|
||||
int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
|
||||
while (wg_todo) {
|
||||
int wg_count = MIN(wg_todo, wg_limit_x);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
|
||||
wg_todo -= wg_count;
|
||||
push_constant.cell_offset += wg_count * wg_size;
|
||||
Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe);
|
||||
Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse();
|
||||
Transform to_probe_xform = to_world_xform.affine_inverse();
|
||||
|
||||
AABB probe_aabb(Vector3(), octree_size);
|
||||
|
||||
//this could probably be better parallelized in compute..
|
||||
for (int i = 0; i < p_dynamic_object_count; i++) {
|
||||
|
||||
InstanceBase *instance = p_dynamic_objects[i];
|
||||
//not used, so clear
|
||||
instance->depth_layer = 0;
|
||||
instance->depth = 0;
|
||||
|
||||
//transform aabb to giprobe
|
||||
AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb);
|
||||
|
||||
//this needs to wrap to grid resolution to avoid jitter
|
||||
//also extend margin a bit just in case
|
||||
Vector3i begin = aabb.position - Vector3i(1, 1, 1);
|
||||
Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if ((end[j] - begin[j]) & 1) {
|
||||
end[j]++; //for half extents split, it needs to be even
|
||||
}
|
||||
begin[j] = MAX(begin[j], 0);
|
||||
end[j] = MIN(end[j], octree_size[j] * multiplier);
|
||||
}
|
||||
|
||||
//aabb = aabb.intersection(probe_aabb); //intersect
|
||||
aabb.position = begin;
|
||||
aabb.size = end - begin;
|
||||
|
||||
//print_line("aabb: " + aabb);
|
||||
|
||||
for (int j = 0; j < 6; j++) {
|
||||
|
||||
//if (j != 0 && j != 3) {
|
||||
// continue;
|
||||
//}
|
||||
static const Vector3 render_z[6] = {
|
||||
Vector3(1, 0, 0),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(0, 0, 1),
|
||||
Vector3(-1, 0, 0),
|
||||
Vector3(0, -1, 0),
|
||||
Vector3(0, 0, -1),
|
||||
};
|
||||
static const Vector3 render_up[6] = {
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(0, 0, 1),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(0, 0, 1),
|
||||
Vector3(0, 1, 0),
|
||||
};
|
||||
|
||||
Vector3 render_dir = render_z[j];
|
||||
Vector3 up_dir = render_up[j];
|
||||
|
||||
Vector3 center = aabb.position + aabb.size * 0.5;
|
||||
Transform xform;
|
||||
xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
|
||||
|
||||
Vector3 x_dir = xform.basis.get_axis(0).abs();
|
||||
int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
|
||||
Vector3 y_dir = xform.basis.get_axis(1).abs();
|
||||
int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
|
||||
Vector3 z_dir = -xform.basis.get_axis(2);
|
||||
int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
|
||||
|
||||
Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
|
||||
bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
|
||||
bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
|
||||
bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
|
||||
|
||||
CameraMatrix cm;
|
||||
cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
|
||||
|
||||
_render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
|
||||
|
||||
GIProbeDynamicPushConstant push_constant;
|
||||
zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant));
|
||||
push_constant.limits[0] = octree_size.x;
|
||||
push_constant.limits[1] = octree_size.y;
|
||||
push_constant.limits[2] = octree_size.z;
|
||||
push_constant.light_count = p_light_instances.size();
|
||||
push_constant.x_dir[0] = x_dir[0];
|
||||
push_constant.x_dir[1] = x_dir[1];
|
||||
push_constant.x_dir[2] = x_dir[2];
|
||||
push_constant.y_dir[0] = y_dir[0];
|
||||
push_constant.y_dir[1] = y_dir[1];
|
||||
push_constant.y_dir[2] = y_dir[2];
|
||||
push_constant.z_dir[0] = z_dir[0];
|
||||
push_constant.z_dir[1] = z_dir[1];
|
||||
push_constant.z_dir[2] = z_dir[2];
|
||||
push_constant.z_base = xform.origin[z_axis];
|
||||
push_constant.z_sign = (z_flip ? -1.0 : 1.0);
|
||||
push_constant.pos_multiplier = float(1.0) / multiplier;
|
||||
push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
|
||||
push_constant.flip_x = x_flip;
|
||||
push_constant.flip_y = y_flip;
|
||||
push_constant.rect_pos[0] = rect.position[0];
|
||||
push_constant.rect_pos[1] = rect.position[1];
|
||||
push_constant.rect_size[0] = rect.size[0];
|
||||
push_constant.rect_size[1] = rect.size[1];
|
||||
push_constant.prev_rect_ofs[0] = 0;
|
||||
push_constant.prev_rect_ofs[1] = 0;
|
||||
push_constant.prev_rect_size[0] = 0;
|
||||
push_constant.prev_rect_size[1] = 0;
|
||||
push_constant.keep_downsample_color = true;
|
||||
|
||||
//process lighting
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
|
||||
//print_line("rect: " + itos(i) + ": " + rect);
|
||||
|
||||
for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) {
|
||||
|
||||
// enlarge the rect if needed so all pixels fit when downscaled,
|
||||
// this ensures downsampling is smooth and optimal because no pixels are left behind
|
||||
|
||||
//x
|
||||
if (rect.position.x & 1) {
|
||||
rect.size.x++;
|
||||
push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
|
||||
} else {
|
||||
push_constant.prev_rect_ofs[0] = 0;
|
||||
}
|
||||
if (rect.size.x & 1) {
|
||||
rect.size.x++;
|
||||
}
|
||||
|
||||
rect.position.x >>= 1;
|
||||
rect.size.x = MAX(1, rect.size.x >> 1);
|
||||
|
||||
//y
|
||||
if (rect.position.y & 1) {
|
||||
rect.size.y++;
|
||||
push_constant.prev_rect_ofs[1] = 1;
|
||||
} else {
|
||||
push_constant.prev_rect_ofs[1] = 0;
|
||||
}
|
||||
if (rect.size.y & 1) {
|
||||
rect.size.y++;
|
||||
}
|
||||
|
||||
rect.position.y >>= 1;
|
||||
rect.size.y = MAX(1, rect.size.y >> 1);
|
||||
|
||||
//shrink limits to ensure plot does not go outside map
|
||||
if (gi_probe->dynamic_maps[i].mipmap > 0) {
|
||||
for (int l = 0; l < 3; l++) {
|
||||
push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
//print_line("rect: " + itos(i) + ": " + rect);
|
||||
push_constant.rect_pos[0] = rect.position[0];
|
||||
push_constant.rect_pos[1] = rect.position[1];
|
||||
push_constant.prev_rect_size[0] = push_constant.rect_size[0];
|
||||
push_constant.prev_rect_size[1] = push_constant.rect_size[1];
|
||||
push_constant.rect_size[0] = rect.size[0];
|
||||
push_constant.rect_size[1] = rect.size[1];
|
||||
push_constant.keep_downsample_color = gi_probe->dynamic_maps[i].mipmap <= 0;
|
||||
;
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
if (gi_probe->dynamic_maps[k].mipmap < 0) {
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
|
||||
} else if (k < gi_probe->dynamic_maps.size() - 1) {
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
|
||||
} else {
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
|
||||
}
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again
|
||||
}
|
||||
|
||||
gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
|
||||
@ -1584,6 +2040,7 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
|
||||
CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse());
|
||||
|
||||
int level = 0;
|
||||
Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
|
||||
|
||||
GIProbeDebugPushConstant push_constant;
|
||||
push_constant.alpha = p_alpha;
|
||||
@ -1591,7 +2048,10 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
|
||||
push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
|
||||
push_constant.level = level;
|
||||
|
||||
int cell_count = gi_probe->mipmaps[level].cell_count;
|
||||
push_constant.bounds[0] = octree_size.x >> level;
|
||||
push_constant.bounds[1] = octree_size.y >> level;
|
||||
push_constant.bounds[2] = octree_size.z >> level;
|
||||
push_constant.pad = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
@ -1643,8 +2103,15 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
|
||||
}
|
||||
}
|
||||
|
||||
int cell_count;
|
||||
if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) {
|
||||
cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
|
||||
} else {
|
||||
cell_count = gi_probe->mipmaps[level].cell_count;
|
||||
}
|
||||
|
||||
giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? GI_PROBE_DEBUG_LIGHT : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0);
|
||||
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
|
||||
RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
|
||||
@ -1875,6 +2342,11 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
|
||||
|
||||
_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region);
|
||||
}
|
||||
|
||||
bool RasterizerSceneRD::free(RID p_rid) {
|
||||
|
||||
if (render_buffers_owner.owns(p_rid)) {
|
||||
@ -1903,6 +2375,11 @@ bool RasterizerSceneRD::free(RID p_rid) {
|
||||
RD::get_singleton()->free(gi_probe->anisotropy[1]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
|
||||
RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
|
||||
RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
|
||||
}
|
||||
|
||||
gi_probe_slots.write[gi_probe->slot] = RID();
|
||||
|
||||
gi_probe_instance_owner.free(p_rid);
|
||||
@ -2002,6 +2479,10 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
|
||||
versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
|
||||
versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
|
||||
versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
|
||||
versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
|
||||
versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
|
||||
versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
|
||||
versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
|
||||
|
||||
giprobe_shader.initialize(versions, defines);
|
||||
giprobe_lighting_shader_version = giprobe_shader.version_create();
|
||||
@ -2021,6 +2502,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
|
||||
versions.push_back("\n#define MODE_DEBUG_COLOR\n");
|
||||
versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
|
||||
versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
|
||||
versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
|
||||
|
||||
giprobe_debug_shader.initialize(versions, defines);
|
||||
giprobe_debug_shader_version = giprobe_debug_shader.version_create();
|
||||
|
@ -26,6 +26,7 @@ protected:
|
||||
|
||||
virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
|
||||
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip) = 0;
|
||||
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
|
||||
|
||||
virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
|
||||
|
||||
@ -155,6 +156,26 @@ private:
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
struct GIProbeDynamicPushConstant {
|
||||
|
||||
int32_t limits[3];
|
||||
uint32_t light_count;
|
||||
int32_t x_dir[3];
|
||||
float z_base;
|
||||
int32_t y_dir[3];
|
||||
float z_sign;
|
||||
int32_t z_dir[3];
|
||||
float pos_multiplier;
|
||||
uint32_t rect_pos[2];
|
||||
uint32_t rect_size[2];
|
||||
uint32_t prev_rect_ofs[2];
|
||||
uint32_t prev_rect_size[2];
|
||||
uint32_t flip_x;
|
||||
uint32_t flip_y;
|
||||
float dynamic_range;
|
||||
uint32_t keep_downsample_color;
|
||||
};
|
||||
|
||||
struct GIProbeInstance {
|
||||
|
||||
RID probe;
|
||||
@ -174,6 +195,21 @@ private:
|
||||
};
|
||||
Vector<Mipmap> mipmaps;
|
||||
|
||||
struct DynamicMap {
|
||||
RID texture; //color normally, or emission on first pass
|
||||
RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
|
||||
RID depth; //actual depth buffer for the first pass, float depth for later passes
|
||||
RID normal; //normal buffer for the first pass
|
||||
RID albedo; //emission buffer for the first pass
|
||||
RID orm; //orm buffer for the first pass
|
||||
RID fb; //used for rendering, only valid on first map
|
||||
RID uniform_set;
|
||||
uint32_t size;
|
||||
int mipmap; // mipmap to write to, -1 if no mipmap assigned
|
||||
};
|
||||
|
||||
Vector<DynamicMap> dynamic_maps;
|
||||
|
||||
int slot = -1;
|
||||
uint32_t last_probe_version = 0;
|
||||
uint32_t last_probe_data_version = 0;
|
||||
@ -181,6 +217,8 @@ private:
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t render_index = 0;
|
||||
|
||||
bool has_dynamic_object_data = false;
|
||||
|
||||
Transform transform;
|
||||
};
|
||||
|
||||
@ -198,6 +236,10 @@ private:
|
||||
GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
|
||||
GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
|
||||
GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
|
||||
GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
|
||||
GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
|
||||
GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
|
||||
GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
|
||||
GI_PROBE_SHADER_VERSION_MAX
|
||||
};
|
||||
GiprobeShaderRD giprobe_shader;
|
||||
@ -211,6 +253,7 @@ private:
|
||||
GI_PROBE_DEBUG_COLOR,
|
||||
GI_PROBE_DEBUG_LIGHT,
|
||||
GI_PROBE_DEBUG_EMISSION,
|
||||
GI_PROBE_DEBUG_LIGHT_FULL,
|
||||
GI_PROBE_DEBUG_MAX
|
||||
};
|
||||
|
||||
@ -220,6 +263,8 @@ private:
|
||||
float dynamic_range;
|
||||
float alpha;
|
||||
uint32_t level;
|
||||
int32_t bounds[3];
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
GiprobeDebugShaderRD giprobe_debug_shader;
|
||||
@ -662,7 +707,8 @@ public:
|
||||
RID gi_probe_instance_create(RID p_base);
|
||||
void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
|
||||
bool gi_probe_needs_update(RID p_probe) const;
|
||||
void gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances);
|
||||
void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects);
|
||||
|
||||
_FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) {
|
||||
GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
|
||||
return gi_probe->slot;
|
||||
@ -726,6 +772,8 @@ public:
|
||||
|
||||
void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
|
||||
|
||||
void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
|
||||
|
||||
virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; }
|
||||
_FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; }
|
||||
|
||||
|
@ -3558,41 +3558,19 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
|
||||
|
||||
bool data_version_changed = false;
|
||||
|
||||
if (gi_probe->octree_buffer_size != p_octree_cells.size() || gi_probe->data_buffer_size != p_data_cells.size()) {
|
||||
//buffer size changed, clear if needed
|
||||
if (gi_probe->octree_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(gi_probe->octree_buffer);
|
||||
RD::get_singleton()->free(gi_probe->data_buffer);
|
||||
|
||||
gi_probe->octree_buffer = RID();
|
||||
gi_probe->data_buffer = RID();
|
||||
gi_probe->octree_buffer_size = 0;
|
||||
gi_probe->data_buffer_size = 0;
|
||||
gi_probe->cell_count = 0;
|
||||
if (gi_probe->octree_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(gi_probe->octree_buffer);
|
||||
RD::get_singleton()->free(gi_probe->data_buffer);
|
||||
if (gi_probe->sdf_texture.is_valid()) {
|
||||
RD::get_singleton()->free(gi_probe->sdf_texture);
|
||||
}
|
||||
|
||||
data_version_changed = true;
|
||||
|
||||
} else if (gi_probe->octree_buffer_size) {
|
||||
//they are the same and size did not change..
|
||||
//update
|
||||
|
||||
PoolVector<uint8_t>::Read rc = p_octree_cells.read();
|
||||
PoolVector<uint8_t>::Read rd = p_data_cells.read();
|
||||
|
||||
RD::get_singleton()->buffer_update(gi_probe->octree_buffer, 0, gi_probe->octree_buffer_size, rc.ptr());
|
||||
RD::get_singleton()->buffer_update(gi_probe->data_buffer, 0, gi_probe->data_buffer_size, rd.ptr());
|
||||
}
|
||||
|
||||
if (gi_probe->level_counts.size() != p_level_counts.size()) {
|
||||
data_version_changed = true;
|
||||
} else {
|
||||
for (int i = 0; i < p_level_counts.size(); i++) {
|
||||
if (gi_probe->level_counts[i] != p_level_counts[i]) {
|
||||
data_version_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gi_probe->sdf_texture = RID();
|
||||
gi_probe->octree_buffer = RID();
|
||||
gi_probe->data_buffer = RID();
|
||||
gi_probe->octree_buffer_size = 0;
|
||||
gi_probe->data_buffer_size = 0;
|
||||
gi_probe->cell_count = 0;
|
||||
}
|
||||
|
||||
gi_probe->to_cell_xform = p_to_cell_xform;
|
||||
@ -3600,7 +3578,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
|
||||
gi_probe->octree_size = p_octree_size;
|
||||
gi_probe->level_counts = p_level_counts;
|
||||
|
||||
if (p_octree_cells.size() && gi_probe->octree_buffer.is_null()) {
|
||||
if (p_octree_cells.size()) {
|
||||
ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32
|
||||
|
||||
uint32_t cell_count = p_octree_cells.size() / 32;
|
||||
@ -3612,13 +3590,80 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
|
||||
gi_probe->octree_buffer_size = p_octree_cells.size();
|
||||
gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
|
||||
gi_probe->data_buffer_size = p_data_cells.size();
|
||||
data_version_changed = true;
|
||||
|
||||
{
|
||||
{
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R8_UNORM;
|
||||
tf.width = gi_probe->octree_size.x;
|
||||
tf.height = gi_probe->octree_size.y;
|
||||
tf.depth = gi_probe->octree_size.z;
|
||||
tf.type = RD::TEXTURE_TYPE_3D;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
|
||||
tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
|
||||
tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
|
||||
gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
}
|
||||
RID shared_tex;
|
||||
{
|
||||
|
||||
RD::TextureView tv;
|
||||
tv.format_override = RD::DATA_FORMAT_R8_UINT;
|
||||
shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture);
|
||||
}
|
||||
//update SDF texture
|
||||
Vector<RD::Uniform> uniforms;
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
u.binding = 1;
|
||||
u.ids.push_back(gi_probe->octree_buffer);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
u.binding = 2;
|
||||
u.ids.push_back(gi_probe->data_buffer);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 3;
|
||||
u.ids.push_back(shared_tex);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
|
||||
|
||||
{
|
||||
uint32_t push_constant[4] = { 0, 0, 0, 0 };
|
||||
|
||||
for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) {
|
||||
push_constant[0] += gi_probe->level_counts[i];
|
||||
}
|
||||
push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
|
||||
|
||||
print_line("offset: " + itos(push_constant[0]));
|
||||
print_line("size: " + itos(push_constant[1]));
|
||||
//create SDF
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4);
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4);
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
RD::get_singleton()->free(uniform_set);
|
||||
RD::get_singleton()->free(shared_tex);
|
||||
}
|
||||
}
|
||||
|
||||
gi_probe->version++;
|
||||
if (data_version_changed) {
|
||||
gi_probe->data_version++;
|
||||
}
|
||||
gi_probe->data_version++;
|
||||
|
||||
gi_probe->instance_dependency.instance_notify_changed(true, false);
|
||||
}
|
||||
|
||||
@ -3794,6 +3839,13 @@ RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
|
||||
return gi_probe->data_buffer;
|
||||
}
|
||||
|
||||
RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
|
||||
GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
|
||||
ERR_FAIL_COND_V(!gi_probe, RID());
|
||||
|
||||
return gi_probe->sdf_texture;
|
||||
}
|
||||
|
||||
/* RENDER TARGET API */
|
||||
|
||||
void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
|
||||
@ -4583,110 +4635,121 @@ RasterizerStorageRD::RasterizerStorageRD() {
|
||||
{
|
||||
|
||||
{ //vertex
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 3);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //normal
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 3);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 1.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //tangent
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 1.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
fptr[3] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //color
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 1.0;
|
||||
fptr[1] = 1.0;
|
||||
fptr[2] = 1.0;
|
||||
fptr[3] = 1.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //tex uv 1
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 2);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
{ //tex uv 2
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 2);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //bones
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(uint32_t) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
uint32_t *fptr = (uint32_t *)w.ptr();
|
||||
fptr[0] = 0;
|
||||
fptr[1] = 0;
|
||||
fptr[2] = 0;
|
||||
fptr[3] = 0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //weights
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
fptr[3] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 3);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //normal
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 3);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 1.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //tangent
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 1.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
fptr[3] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //color
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 1.0;
|
||||
fptr[1] = 1.0;
|
||||
fptr[2] = 1.0;
|
||||
fptr[3] = 1.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //tex uv 1
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 2);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
{ //tex uv 2
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 2);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //bones
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(uint32_t) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
uint32_t *fptr = (uint32_t *)w.ptr();
|
||||
fptr[0] = 0;
|
||||
fptr[1] = 0;
|
||||
fptr[2] = 0;
|
||||
fptr[3] = 0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
|
||||
{ //weights
|
||||
PoolVector<uint8_t> buffer;
|
||||
buffer.resize(sizeof(float) * 4);
|
||||
{
|
||||
PoolVector<uint8_t>::Write w = buffer.write();
|
||||
float *fptr = (float *)w.ptr();
|
||||
fptr[0] = 0.0;
|
||||
fptr[1] = 0.0;
|
||||
fptr[2] = 0.0;
|
||||
fptr[3] = 0.0;
|
||||
}
|
||||
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Vector<String> sdf_versions;
|
||||
sdf_versions.push_back(""); //one only
|
||||
giprobe_sdf_shader.initialize(sdf_versions);
|
||||
giprobe_sdf_shader_version = giprobe_sdf_shader.version_create();
|
||||
giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector<String>());
|
||||
giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0);
|
||||
giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader);
|
||||
}
|
||||
}
|
||||
|
||||
RasterizerStorageRD::~RasterizerStorageRD() {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "servers/visual/rasterizer.h"
|
||||
#include "servers/visual/rasterizer_rd/rasterizer_effects_rd.h"
|
||||
#include "servers/visual/rasterizer_rd/shader_compiler_rd.h"
|
||||
#include "servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
|
||||
#include "servers/visual/rendering_device.h"
|
||||
|
||||
class RasterizerStorageRD : public RasterizerStorage {
|
||||
@ -407,6 +408,7 @@ private:
|
||||
|
||||
RID octree_buffer;
|
||||
RID data_buffer;
|
||||
RID sdf_texture;
|
||||
|
||||
uint32_t octree_buffer_size = 0;
|
||||
uint32_t data_buffer_size = 0;
|
||||
@ -435,6 +437,11 @@ private:
|
||||
RasterizerScene::InstanceDependency instance_dependency;
|
||||
};
|
||||
|
||||
GiprobeSdfShaderRD giprobe_sdf_shader;
|
||||
RID giprobe_sdf_shader_version;
|
||||
RID giprobe_sdf_shader_version_shader;
|
||||
RID giprobe_sdf_shader_pipeline;
|
||||
|
||||
mutable RID_Owner<GIProbe> gi_probe_owner;
|
||||
|
||||
/* RENDER TARGET */
|
||||
@ -999,6 +1006,8 @@ public:
|
||||
RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
|
||||
RID gi_probe_get_data_buffer(RID p_gi_probe) const;
|
||||
|
||||
RID gi_probe_get_sdf_texture(RID p_gi_probe);
|
||||
|
||||
/* LIGHTMAP CAPTURE */
|
||||
|
||||
void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
|
||||
|
@ -13,4 +13,6 @@ if 'RD_GLSL' in env['BUILDERS']:
|
||||
env.RD_GLSL('copy.glsl');
|
||||
env.RD_GLSL('giprobe.glsl');
|
||||
env.RD_GLSL('giprobe_debug.glsl');
|
||||
env.RD_GLSL('giprobe_sdf.glsl');
|
||||
|
||||
|
||||
|
@ -4,8 +4,18 @@
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#ifdef MODE_DYNAMIC
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
#else
|
||||
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef MODE_DYNAMIC
|
||||
|
||||
#define NO_CHILDREN 0xFFFFFFFF
|
||||
#define GREY_VEC vec3(0.33333,0.33333,0.33333)
|
||||
|
||||
@ -28,11 +38,14 @@ layout(set=0,binding=2,std430) buffer CellDataBuffer {
|
||||
CellData data[];
|
||||
} cell_data;
|
||||
|
||||
|
||||
#endif // MODE DYNAMIC
|
||||
|
||||
#define LIGHT_TYPE_DIRECTIONAL 0
|
||||
#define LIGHT_TYPE_OMNI 1
|
||||
#define LIGHT_TYPE_SPOT 2
|
||||
|
||||
#ifdef MODE_COMPUTE_LIGHT
|
||||
#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING)
|
||||
|
||||
struct Light {
|
||||
|
||||
@ -64,7 +77,6 @@ layout(set=0,binding=3,std140) uniform Lights {
|
||||
#ifdef MODE_SECOND_BOUNCE
|
||||
|
||||
layout (set=0,binding=5) uniform texture3D color_texture;
|
||||
layout (set=0,binding=6) uniform sampler texture_sampler;
|
||||
|
||||
#ifdef MODE_ANISOTROPIC
|
||||
layout (set=0,binding=7) uniform texture3D aniso_pos_texture;
|
||||
@ -73,6 +85,7 @@ layout (set=0,binding=8) uniform texture3D aniso_neg_texture;
|
||||
|
||||
#endif // MODE_SECOND_BOUNCE
|
||||
|
||||
#ifndef MODE_DYNAMIC
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
|
||||
@ -96,6 +109,11 @@ layout(set=0,binding=4,std430) buffer Outputs {
|
||||
vec4 data[];
|
||||
} outputs;
|
||||
|
||||
#endif // MODE DYNAMIC
|
||||
|
||||
layout (set=0,binding=9) uniform texture3D texture_sdf;
|
||||
layout (set=0,binding=10) uniform sampler texture_sampler;
|
||||
|
||||
#ifdef MODE_WRITE_TEXTURE
|
||||
|
||||
layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
|
||||
@ -111,63 +129,97 @@ layout (r16ui,set=0,binding=7) uniform restrict writeonly uimage3D aniso_neg_tex
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODE_COMPUTE_LIGHT
|
||||
#ifdef MODE_DYNAMIC
|
||||
|
||||
uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
|
||||
uint result = NO_CHILDREN;
|
||||
ivec3 limits;
|
||||
uint light_count;
|
||||
ivec3 x_dir;
|
||||
float z_base;
|
||||
ivec3 y_dir;
|
||||
float z_sign;
|
||||
ivec3 z_dir;
|
||||
float pos_multiplier;
|
||||
ivec2 rect_pos;
|
||||
ivec2 rect_size;
|
||||
ivec2 prev_rect_ofs;
|
||||
ivec2 prev_rect_size;
|
||||
bool flip_x;
|
||||
bool flip_y;
|
||||
float dynamic_range;
|
||||
bool keep_downsample_color;
|
||||
|
||||
ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
|
||||
} params;
|
||||
|
||||
while (distance > -distance_adv) { //use this to avoid precision errors
|
||||
#ifdef MODE_DYNAMIC_LIGHTING
|
||||
|
||||
uint cell = 0;
|
||||
layout (rgba8,set=0,binding=5) uniform restrict readonly image2D source_albedo;
|
||||
layout (rgba8,set=0,binding=6) uniform restrict readonly image2D source_normal;
|
||||
layout (rgba8,set=0,binding=7) uniform restrict readonly image2D source_orm;
|
||||
//layout (set=0,binding=8) uniform texture2D source_depth;
|
||||
layout (rgba16f,set=0,binding=11) uniform restrict image2D emission;
|
||||
layout (r32f,set=0,binding=12) uniform restrict image2D depth;
|
||||
|
||||
ivec3 pos = ivec3(from);
|
||||
#endif
|
||||
|
||||
if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
|
||||
#ifdef MODE_DYNAMIC_SHRINK
|
||||
|
||||
ivec3 ofs = ivec3(0);
|
||||
ivec3 half_size = size / 2;
|
||||
layout (rgba16f,set=0,binding=5) uniform restrict readonly image2D source_light;
|
||||
layout (r32f,set=0,binding=6) uniform restrict readonly image2D source_depth;
|
||||
|
||||
for (int i = 0; i < params.stack_size - 1; i++) {
|
||||
#ifdef MODE_DYNAMIC_SHRINK_WRITE
|
||||
|
||||
bvec3 greater = greaterThanEqual(pos,ofs+half_size);
|
||||
layout (rgba16f,set=0,binding=7) uniform restrict writeonly image2D light;
|
||||
layout (r32f,set=0,binding=8) uniform restrict writeonly image2D depth;
|
||||
|
||||
ofs += mix(ivec3(0),half_size,greater);
|
||||
#endif // MODE_DYNAMIC_SHRINK_WRITE
|
||||
|
||||
uint child = 0; //wonder if this can be done faster
|
||||
if (greater.x) {
|
||||
child|=1;
|
||||
}
|
||||
if (greater.y) {
|
||||
child|=2;
|
||||
}
|
||||
if (greater.z) {
|
||||
child|=4;
|
||||
}
|
||||
#ifdef MODE_DYNAMIC_SHRINK_PLOT
|
||||
|
||||
cell = cell_children.data[cell].children[child];
|
||||
if (cell == NO_CHILDREN)
|
||||
break;
|
||||
layout (rgba8,set=0,binding=11) uniform restrict image3D color_texture;
|
||||
|
||||
half_size >>= ivec3(1);
|
||||
}
|
||||
#ifdef MODE_ANISOTROPIC
|
||||
|
||||
if ( cell != NO_CHILDREN) {
|
||||
return cell; //found cell!
|
||||
}
|
||||
layout (r16ui,set=0,binding=12) uniform restrict writeonly uimage3D aniso_pos_texture;
|
||||
layout (r16ui,set=0,binding=13) uniform restrict writeonly uimage3D aniso_neg_texture;
|
||||
|
||||
#endif // MODE ANISOTROPIC
|
||||
|
||||
#endif //MODE_DYNAMIC_SHRINK_PLOT
|
||||
|
||||
#endif // MODE_DYNAMIC_SHRINK
|
||||
|
||||
//layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
|
||||
|
||||
|
||||
#endif // MODE DYNAMIC
|
||||
|
||||
#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING)
|
||||
|
||||
float raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
|
||||
|
||||
|
||||
|
||||
vec3 cell_size = 1.0 / vec3(params.limits);
|
||||
|
||||
while (distance > 0.0) { //use this to avoid precision errors
|
||||
float advance = texture(sampler3D(texture_sdf,texture_sampler),from * cell_size).r * 255.0 - 1.0;
|
||||
if (advance<0.0) {
|
||||
break;
|
||||
}
|
||||
|
||||
from += direction * distance_adv;
|
||||
distance -= distance_adv;
|
||||
advance = max(distance_adv, advance - mod(advance, distance_adv)); //should always advance in multiples of distance_adv
|
||||
|
||||
from += direction * advance;
|
||||
distance -= advance;
|
||||
}
|
||||
|
||||
return NO_CHILDREN;
|
||||
return max(0.0,distance);
|
||||
|
||||
}
|
||||
|
||||
bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
|
||||
bool compute_light_vector(uint light, vec3 pos,out float attenuation, out vec3 light_pos) {
|
||||
|
||||
|
||||
if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
|
||||
@ -226,13 +278,84 @@ float get_normal_advance(vec3 p_normal) {
|
||||
return 1.0 / dot(normal,unorm);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void clip_segment(vec4 plane, vec3 begin, inout vec3 end) {
|
||||
|
||||
vec3 segment = begin - end;
|
||||
float den = dot(plane.xyz,segment);
|
||||
|
||||
//printf("den is %i\n",den);
|
||||
if (den < 0.0001) {
|
||||
return;
|
||||
}
|
||||
|
||||
float dist = (dot(plane.xyz,begin) - plane.w) / den;
|
||||
|
||||
if (dist < 0.0001 || dist > 1.0001) {
|
||||
return;
|
||||
}
|
||||
|
||||
end = begin + segment * -dist;
|
||||
}
|
||||
|
||||
bool compute_light_at_pos(uint index, vec3 pos, vec3 normal, inout vec3 light, inout vec3 light_dir) {
|
||||
float attenuation;
|
||||
vec3 light_pos;
|
||||
|
||||
if (!compute_light_vector(index,pos,attenuation,light_pos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
light_dir = normalize(pos - light_pos);
|
||||
|
||||
if (attenuation < 0.01 || (length(normal) > 0.2 && dot(normal,light_dir)>=0)) {
|
||||
return false; //not facing the light, or attenuation is near zero
|
||||
}
|
||||
|
||||
if (lights.data[index].has_shadow) {
|
||||
|
||||
float distance_adv = get_normal_advance(light_dir);
|
||||
|
||||
|
||||
vec3 to = pos;
|
||||
to-= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
|
||||
|
||||
//clip
|
||||
clip_segment(mix(vec4(-1.0,0.0,0.0,0.0),vec4(1.0,0.0,0.0,float(params.limits.x-1)),bvec4(light_dir.x < 0.0)),to,light_pos);
|
||||
clip_segment(mix(vec4(0.0,-1.0,0.0,0.0),vec4(0.0,1.0,0.0,float(params.limits.y-1)),bvec4(light_dir.y < 0.0)),to,light_pos);
|
||||
clip_segment(mix(vec4(0.0,0.0,-1.0,0.0),vec4(0.0,0.0,1.0,float(params.limits.z-1)),bvec4(light_dir.z < 0.0)),to,light_pos);
|
||||
|
||||
|
||||
float distance = length(to-light_pos);
|
||||
if (distance < 0.1) {
|
||||
return false; // hit
|
||||
}
|
||||
|
||||
distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
|
||||
light_pos = to - light_dir * distance;
|
||||
|
||||
//from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
|
||||
float dist = raymarch(distance,distance_adv,light_pos,light_dir);
|
||||
|
||||
if (dist > distance_adv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
light = lights.data[index].color * attenuation * lights.data[index].energy;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // MODE COMPUTE LIGHT
|
||||
|
||||
void main() {
|
||||
|
||||
#ifndef MODE_DYNAMIC
|
||||
|
||||
uint cell_index = gl_GlobalInvocationID.x;;
|
||||
if (cell_index >= params.cell_count) {
|
||||
return;
|
||||
@ -242,6 +365,8 @@ void main() {
|
||||
uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21);
|
||||
vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
|
||||
|
||||
#endif
|
||||
|
||||
/////////////////COMPUTE LIGHT///////////////////////////////
|
||||
|
||||
#ifdef MODE_COMPUTE_LIGHT
|
||||
@ -249,7 +374,7 @@ void main() {
|
||||
vec3 pos = vec3(posu) + vec3(0.5);
|
||||
|
||||
vec3 emission = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
|
||||
vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
|
||||
vec3 normal = unpackSnorm4x8(cell_data.data[cell_index].normal).xyz;
|
||||
|
||||
#ifdef MODE_ANISOTROPIC
|
||||
vec3 accum[6]=vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
|
||||
@ -260,41 +385,13 @@ void main() {
|
||||
|
||||
for(uint i=0;i<params.light_count;i++) {
|
||||
|
||||
float attenuation;
|
||||
vec3 light_pos;
|
||||
|
||||
if (!compute_light_vector(i,cell_index,pos,attenuation,light_pos)) {
|
||||
vec3 light;
|
||||
vec3 light_dir;
|
||||
if (!compute_light_at_pos(i,pos,normal.xyz,light,light_dir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec3 light_dir = pos - light_pos;
|
||||
float distance = length(light_dir);
|
||||
light_dir=normalize(light_dir);
|
||||
|
||||
if (attenuation < 0.01 || (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0)) {
|
||||
continue; //not facing the light, or attenuation is near zero
|
||||
}
|
||||
|
||||
if (lights.data[i].has_shadow) {
|
||||
|
||||
float distance_adv = get_normal_advance(light_dir);
|
||||
|
||||
|
||||
distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
|
||||
|
||||
vec3 from = pos - light_dir * distance; //approximate
|
||||
from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
|
||||
|
||||
|
||||
|
||||
uint result = raymarch(distance,distance_adv,from,light_dir);
|
||||
|
||||
if (result != cell_index) {
|
||||
continue; //was occluded
|
||||
}
|
||||
}
|
||||
|
||||
vec3 light = lights.data[i].color * albedo.rgb * attenuation * lights.data[i].energy;
|
||||
light*= albedo.rgb;
|
||||
|
||||
#ifdef MODE_ANISOTROPIC
|
||||
for(uint j=0;j<6;j++) {
|
||||
@ -302,11 +399,11 @@ void main() {
|
||||
accum[j]+=max(0.0,dot(accum_dirs[j],-light_dir))*light;
|
||||
}
|
||||
#else
|
||||
if (length(normal.xyz) > 0.2) {
|
||||
accum+=max(0.0,dot(normal.xyz,-light_dir))*light;
|
||||
if (length(normal) > 0.2) {
|
||||
accum+=max(0.0,dot(normal,-light_dir))*light;
|
||||
} else {
|
||||
//all directions
|
||||
accum+=light+emission;
|
||||
accum+=light;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -314,12 +411,17 @@ void main() {
|
||||
|
||||
#ifdef MODE_ANISOTROPIC
|
||||
|
||||
outputs.data[cell_index*6+0]=vec4(accum[0] + emission,0.0);
|
||||
outputs.data[cell_index*6+1]=vec4(accum[1] + emission,0.0);
|
||||
outputs.data[cell_index*6+2]=vec4(accum[2] + emission,0.0);
|
||||
outputs.data[cell_index*6+3]=vec4(accum[3] + emission,0.0);
|
||||
outputs.data[cell_index*6+4]=vec4(accum[4] + emission,0.0);
|
||||
outputs.data[cell_index*6+5]=vec4(accum[5] + emission,0.0);
|
||||
for(uint i=0;i<6;i++) {
|
||||
vec3 light = accum[i];
|
||||
if (length(normal) > 0.2) {
|
||||
light += max(0.0,dot(accum_dirs[i],-normal)) * emission;
|
||||
} else {
|
||||
light += emission;
|
||||
}
|
||||
|
||||
outputs.data[cell_index*6+i] = vec4(light,0.0);
|
||||
}
|
||||
|
||||
#else
|
||||
outputs.data[cell_index]=vec4(accum + emission,0.0);
|
||||
|
||||
@ -540,4 +642,167 @@ void main() {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////DYNAMIC LIGHTING/////////////////////////////
|
||||
|
||||
#ifdef MODE_DYNAMIC
|
||||
|
||||
ivec2 pos_xy = ivec2(gl_GlobalInvocationID.xy);
|
||||
if (any(greaterThanEqual(pos_xy,params.rect_size))) {
|
||||
return; //out of bounds
|
||||
}
|
||||
|
||||
ivec2 uv_xy = pos_xy;
|
||||
if (params.flip_x) {
|
||||
uv_xy.x = params.rect_size.x - pos_xy.x - 1;
|
||||
}
|
||||
if (params.flip_y) {
|
||||
uv_xy.y = params.rect_size.y - pos_xy.y - 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODE_DYNAMIC_LIGHTING
|
||||
|
||||
|
||||
{
|
||||
|
||||
|
||||
float z = params.z_base + imageLoad(depth,uv_xy).x * params.z_sign;
|
||||
|
||||
ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(z);
|
||||
|
||||
vec3 normal = imageLoad(source_normal,uv_xy).xyz * 2.0 - 1.0;
|
||||
normal = vec3(params.x_dir) * normal.x * mix(1.0,-1.0,params.flip_x) + vec3(params.y_dir) * normal.y * mix(1.0,-1.0,params.flip_y) - vec3(params.z_dir) * normal.z;
|
||||
|
||||
|
||||
|
||||
|
||||
vec4 albedo = imageLoad(source_albedo,uv_xy);
|
||||
|
||||
//determine the position in space
|
||||
|
||||
vec3 accum = vec3(0.0);
|
||||
for(uint i=0;i<params.light_count;i++) {
|
||||
|
||||
vec3 light;
|
||||
vec3 light_dir;
|
||||
if (!compute_light_at_pos(i,vec3(pos) * params.pos_multiplier,normal,light,light_dir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
light*= albedo.rgb;
|
||||
|
||||
accum+=max(0.0,dot(normal,-light_dir))*light;
|
||||
|
||||
}
|
||||
|
||||
accum+=imageLoad(emission,uv_xy).xyz;
|
||||
|
||||
imageStore(emission,uv_xy,vec4(accum,albedo.a));
|
||||
imageStore(depth,uv_xy,vec4(z));
|
||||
|
||||
}
|
||||
|
||||
#endif // MODE DYNAMIC LIGHTING
|
||||
|
||||
#ifdef MODE_DYNAMIC_SHRINK
|
||||
|
||||
{
|
||||
vec4 accum = vec4(0.0);
|
||||
float accum_z = 0.0;
|
||||
float count = 0.0;
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
ivec2 ofs = pos_xy*2 + ivec2(i&1,i>>1) - params.prev_rect_ofs;
|
||||
if (any(lessThan(ofs,ivec2(0))) || any(greaterThanEqual(ofs,params.prev_rect_size))) {
|
||||
continue;
|
||||
}
|
||||
if (params.flip_x) {
|
||||
ofs.x = params.prev_rect_size.x - ofs.x - 1;
|
||||
}
|
||||
if (params.flip_y) {
|
||||
ofs.y = params.prev_rect_size.y - ofs.y - 1;
|
||||
}
|
||||
|
||||
vec4 light = imageLoad(source_light,ofs);
|
||||
if (light.a==0.0) { //ignore empty
|
||||
continue;
|
||||
}
|
||||
accum += light;
|
||||
float z = imageLoad(source_depth,ofs).x;
|
||||
accum_z += z*0.5; //shrink half too
|
||||
count+=1.0;
|
||||
}
|
||||
|
||||
|
||||
accum/=4.0;
|
||||
|
||||
if (count==0.0) {
|
||||
accum_z=0.0; //avoid nan
|
||||
} else {
|
||||
accum_z/=count;
|
||||
}
|
||||
|
||||
#ifdef MODE_DYNAMIC_SHRINK_WRITE
|
||||
|
||||
imageStore(light,uv_xy,accum);
|
||||
imageStore(depth,uv_xy,vec4(accum_z));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_DYNAMIC_SHRINK_PLOT
|
||||
|
||||
|
||||
if (accum.a<0.001) {
|
||||
return; //do not blit if alpha is too low
|
||||
}
|
||||
|
||||
ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(accum_z);
|
||||
|
||||
float z_frac = fract(accum_z);
|
||||
|
||||
for(int i = 0; i< 2; i++) {
|
||||
ivec3 pos3d = pos + abs(params.z_dir) * i;
|
||||
if (any(lessThan(pos3d,ivec3(0))) || any(greaterThanEqual(pos3d,params.limits))) {
|
||||
//skip if offlimits
|
||||
continue;
|
||||
}
|
||||
vec4 color_blit = accum * (i==0 ? 1.0 - z_frac : z_frac );
|
||||
vec4 color = imageLoad(color_texture,pos3d);
|
||||
color.rgb *=params.dynamic_range;
|
||||
|
||||
#if 0
|
||||
color.rgb = mix(color.rgb,color_blit.rgb,color_blit.a);
|
||||
color.a+=color_blit.a;
|
||||
#else
|
||||
|
||||
|
||||
float sa = 1.0 - color_blit.a;
|
||||
vec4 result;
|
||||
result.a = color.a * sa + color_blit.a;
|
||||
if (result.a==0.0) {
|
||||
result = vec4(0.0);
|
||||
} else {
|
||||
result.rgb = (color.rgb * color.a * sa + color_blit.rgb * color_blit.a) / result.a;
|
||||
color = result;
|
||||
}
|
||||
|
||||
#endif
|
||||
color.rgb /= params.dynamic_range;
|
||||
imageStore(color_texture,pos3d,color);
|
||||
//imageStore(color_texture,pos3d,vec4(1,1,1,1));
|
||||
|
||||
#ifdef MODE_ANISOTROPIC
|
||||
//do not care about anisotropy for dynamic objects, just store full lit in all directions
|
||||
imageStore(aniso_pos_texture,pos3d,uvec4(0xFFFF));
|
||||
imageStore(aniso_neg_texture,pos3d,uvec4(0xFFFF));
|
||||
|
||||
#endif // ANISOTROPIC
|
||||
}
|
||||
#endif // MODE_DYNAMIC_SHRINK_PLOT
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MODE DYNAMIC
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ layout(push_constant, binding = 0, std430) uniform Params {
|
||||
float dynamic_range;
|
||||
float alpha;
|
||||
uint level;
|
||||
ivec3 bounds;
|
||||
uint pad;
|
||||
|
||||
} params;
|
||||
|
||||
@ -80,10 +82,13 @@ void main() {
|
||||
|
||||
|
||||
vec3 vertex = cube_triangles[gl_VertexIndex] * 0.5 + 0.5;
|
||||
|
||||
#ifdef MODE_DEBUG_LIGHT_FULL
|
||||
uvec3 posu = uvec3( gl_InstanceIndex % params.bounds.x, (gl_InstanceIndex / params.bounds.x) % params.bounds.y,gl_InstanceIndex / (params.bounds.y * params.bounds.x) );
|
||||
#else
|
||||
uint cell_index = gl_InstanceIndex + params.cell_offset;
|
||||
|
||||
uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21);
|
||||
#endif
|
||||
|
||||
#ifdef MODE_DEBUG_EMISSION
|
||||
color_interp.xyz = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
|
||||
@ -138,16 +143,24 @@ void main() {
|
||||
color_interp.xyz *= strength;
|
||||
|
||||
#else
|
||||
color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).xyz * params.dynamic_range;
|
||||
color_interp = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level));
|
||||
color_interp.xyz * params.dynamic_range;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
float scale = (1<<params.level);
|
||||
color_interp.a = params.alpha;
|
||||
|
||||
gl_Position = params.projection * vec4((vec3(posu)+vertex)*scale,1.0);
|
||||
|
||||
#ifdef MODE_DEBUG_LIGHT_FULL
|
||||
if (color_interp.a == 0.0) {
|
||||
gl_Position = vec4(0.0); //force clip and not draw
|
||||
}
|
||||
#else
|
||||
color_interp.a = params.alpha;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
[fragment]
|
||||
@ -162,4 +175,35 @@ layout(location=0) out vec4 frag_color;
|
||||
void main() {
|
||||
|
||||
frag_color = color_interp;
|
||||
|
||||
#ifdef MODE_DEBUG_LIGHT_FULL
|
||||
|
||||
//there really is no alpha, so use dither
|
||||
|
||||
int x = int(gl_FragCoord.x) % 4;
|
||||
int y = int(gl_FragCoord.y) % 4;
|
||||
int index = x + y * 4;
|
||||
float limit = 0.0;
|
||||
if (x < 8) {
|
||||
if (index == 0) limit = 0.0625;
|
||||
if (index == 1) limit = 0.5625;
|
||||
if (index == 2) limit = 0.1875;
|
||||
if (index == 3) limit = 0.6875;
|
||||
if (index == 4) limit = 0.8125;
|
||||
if (index == 5) limit = 0.3125;
|
||||
if (index == 6) limit = 0.9375;
|
||||
if (index == 7) limit = 0.4375;
|
||||
if (index == 8) limit = 0.25;
|
||||
if (index == 9) limit = 0.75;
|
||||
if (index == 10) limit = 0.125;
|
||||
if (index == 11) limit = 0.625;
|
||||
if (index == 12) limit = 1.0;
|
||||
if (index == 13) limit = 0.5;
|
||||
if (index == 14) limit = 0.875;
|
||||
if (index == 15) limit = 0.375;
|
||||
}
|
||||
if (frag_color.a < limit) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
194
servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl
Normal file
194
servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl
Normal file
@ -0,0 +1,194 @@
|
||||
[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||
|
||||
#define MAX_DISTANCE 100000
|
||||
|
||||
#define NO_CHILDREN 0xFFFFFFFF
|
||||
#define GREY_VEC vec3(0.33333,0.33333,0.33333)
|
||||
|
||||
struct CellChildren {
|
||||
uint children[8];
|
||||
};
|
||||
|
||||
layout(set=0,binding=1,std430) buffer CellChildrenBuffer {
|
||||
CellChildren data[];
|
||||
} cell_children;
|
||||
|
||||
|
||||
struct CellData {
|
||||
uint position; // xyz 10 bits
|
||||
uint albedo; //rgb albedo
|
||||
uint emission; //rgb normalized with e as multiplier
|
||||
uint normal; //RGB normal encoded
|
||||
};
|
||||
|
||||
layout(set=0,binding=2,std430) buffer CellDataBuffer {
|
||||
CellData data[];
|
||||
} cell_data;
|
||||
|
||||
layout (r8ui,set=0,binding=3) uniform restrict writeonly uimage3D sdf_tex;
|
||||
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
|
||||
uint offset;
|
||||
uint end;
|
||||
uint pad0;
|
||||
uint pad1;
|
||||
} params;
|
||||
|
||||
void main() {
|
||||
|
||||
vec3 pos = vec3(gl_GlobalInvocationID);
|
||||
float closest_dist = 100000.0;
|
||||
|
||||
for(uint i=params.offset;i<params.end;i++) {
|
||||
vec3 posu = vec3(uvec3(cell_data.data[i].position&0x7FF,(cell_data.data[i].position>>11)&0x3FF,cell_data.data[i].position>>21));
|
||||
float dist = length(pos-posu);
|
||||
if (dist < closest_dist) {
|
||||
closest_dist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
uint dist_8;
|
||||
|
||||
if (closest_dist<0.0001) { // same cell
|
||||
dist_8=0; //equals to -1
|
||||
} else {
|
||||
dist_8 = clamp(uint(closest_dist),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid
|
||||
}
|
||||
|
||||
imageStore(sdf_tex,ivec3(gl_GlobalInvocationID),uvec4(dist_8));
|
||||
//imageStore(sdf_tex,pos,uvec4(pos*2,0));
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
|
||||
ivec3 limits;
|
||||
uint stack_size;
|
||||
} params;
|
||||
|
||||
|
||||
float distance_to_aabb(ivec3 pos, ivec3 aabb_pos, ivec3 aabb_size) {
|
||||
|
||||
vec3 delta = vec3(max(ivec3(0),max(aabb_pos - pos, pos - (aabb_pos + aabb_size - ivec3(1)))));
|
||||
return length(delta);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
ivec3 pos = ivec3(gl_GlobalInvocationID);
|
||||
|
||||
uint stack[10]=uint[](0,0,0,0,0,0,0,0,0,0);
|
||||
uint stack_indices[10]=uint[](0,0,0,0,0,0,0,0,0,0);
|
||||
ivec3 stack_positions[10]=ivec3[](ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0));
|
||||
|
||||
const uint cell_orders[8]=uint[](
|
||||
0x11f58d1,
|
||||
0xe2e70a,
|
||||
0xd47463,
|
||||
0xbb829c,
|
||||
0x8d11f5,
|
||||
0x70ae2e,
|
||||
0x463d47,
|
||||
0x29cbb8
|
||||
);
|
||||
|
||||
bool cell_found = false;
|
||||
bool cell_found_exact = false;
|
||||
ivec3 closest_cell_pos;
|
||||
float closest_distance = MAX_DISTANCE;
|
||||
int stack_pos = 0;
|
||||
|
||||
while(true) {
|
||||
|
||||
uint index = stack_indices[stack_pos]>>24;
|
||||
|
||||
if (index == 8) {
|
||||
//go up
|
||||
if (stack_pos==0) {
|
||||
break; //done going through octree
|
||||
}
|
||||
stack_pos--;
|
||||
continue;
|
||||
}
|
||||
|
||||
stack_indices[stack_pos] = (stack_indices[stack_pos]&((1<<24)-1))|((index + 1)<<24);
|
||||
|
||||
|
||||
uint cell_index = (stack_indices[stack_pos]>>(index*3))&0x7;
|
||||
uint child_cell = cell_children.data[stack[stack_pos]].children[cell_index];
|
||||
|
||||
if (child_cell == NO_CHILDREN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ivec3 child_cell_size = params.limits >> (stack_pos+1);
|
||||
ivec3 child_cell_pos = stack_positions[stack_pos];
|
||||
|
||||
child_cell_pos+=mix(ivec3(0),child_cell_size,bvec3(uvec3(index&1,index&2,index&4)!=uvec3(0)));
|
||||
|
||||
bool is_leaf = stack_pos == (params.stack_size-2);
|
||||
|
||||
if (child_cell_pos==pos && is_leaf) {
|
||||
//we may actually end up in the exact cell.
|
||||
//if this happens, just abort
|
||||
cell_found_exact=true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell_found) {
|
||||
//discard by distance
|
||||
float distance = distance_to_aabb(pos,child_cell_pos,child_cell_size);
|
||||
if (distance >= closest_distance) {
|
||||
continue; //pointless, just test next child
|
||||
} else if (is_leaf) {
|
||||
//closer than what we have AND end of stack, save and continue
|
||||
closest_cell_pos = child_cell_pos;
|
||||
closest_distance = distance;
|
||||
continue;
|
||||
}
|
||||
} else if (is_leaf) {
|
||||
//first solid cell we find, save and continue
|
||||
closest_distance = distance_to_aabb(pos,child_cell_pos,child_cell_size);
|
||||
closest_cell_pos = child_cell_pos;
|
||||
cell_found=true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bvec3 direction = greaterThan(( pos - ( child_cell_pos + (child_cell_size >>1) ) ) , ivec3(0) );
|
||||
uint cell_order = 0;
|
||||
cell_order|=mix(0,1,direction.x);
|
||||
cell_order|=mix(0,2,direction.y);
|
||||
cell_order|=mix(0,4,direction.z);
|
||||
|
||||
stack[stack_pos+1]=child_cell;
|
||||
stack_indices[stack_pos+1]=cell_orders[cell_order]; //start counting
|
||||
stack_positions[stack_pos+1]=child_cell_pos;
|
||||
stack_pos++; //go up stack
|
||||
|
||||
}
|
||||
|
||||
uint dist_8;
|
||||
|
||||
if (cell_found_exact) {
|
||||
dist_8=0; //equals to -1
|
||||
} else {
|
||||
float closest_distance = length(vec3(pos-closest_cell_pos));
|
||||
dist_8 = clamp(uint(closest_distance),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid
|
||||
}
|
||||
|
||||
imageStore(sdf_tex,pos,uvec4(dist_8));
|
||||
|
||||
}
|
||||
#endif
|
@ -344,17 +344,30 @@ FRAGMENT_SHADER_GLOBALS
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifdef MODE_RENDER_DEPTH
|
||||
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
|
||||
layout(location = 0) out vec4 albedo_output_buffer;
|
||||
layout(location = 1) out vec4 normal_output_buffer;
|
||||
layout(location = 2) out vec4 orm_output_buffer;
|
||||
layout(location = 3) out vec4 emission_output_buffer;
|
||||
layout(location = 4) out float depth_output_buffer;
|
||||
|
||||
#endif
|
||||
|
||||
#else // RENDER DEPTH
|
||||
|
||||
#ifdef MODE_MULTIPLE_RENDER_TARGETS
|
||||
|
||||
layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
|
||||
layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
|
||||
#else
|
||||
|
||||
#ifndef MODE_RENDER_DEPTH
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // RENDER DEPTH
|
||||
|
||||
|
||||
|
||||
@ -1668,6 +1681,29 @@ FRAGMENT_SHADER_CODE
|
||||
|
||||
|
||||
#ifdef MODE_RENDER_DEPTH
|
||||
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
|
||||
albedo_output_buffer.rgb = albedo;
|
||||
albedo_output_buffer.a = alpha;
|
||||
|
||||
normal_output_buffer.rgb = normal * 0.5 + 0.5;
|
||||
normal_output_buffer.a = 0.0;
|
||||
depth_output_buffer.r = -vertex.z;
|
||||
|
||||
#if defined(AO_USED)
|
||||
orm_output_buffer.r = ao;
|
||||
#else
|
||||
orm_output_buffer.r = 0.0;
|
||||
#endif
|
||||
orm_output_buffer.g = roughness;
|
||||
orm_output_buffer.b = metallic;
|
||||
orm_output_buffer.a = sss_strength;
|
||||
|
||||
emission_output_buffer.rgb = emission;
|
||||
emission_output_buffer.a = 0.0;
|
||||
#endif
|
||||
|
||||
//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
|
||||
#else
|
||||
|
||||
|
@ -170,7 +170,12 @@ void *VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance
|
||||
pinfo.geometry = A;
|
||||
pinfo.L = geom->gi_probes.push_back(B);
|
||||
|
||||
List<InstanceGIProbeData::PairInfo>::Element *E = gi_probe->geometries.push_back(pinfo);
|
||||
List<InstanceGIProbeData::PairInfo>::Element *E;
|
||||
if (A->dynamic_gi) {
|
||||
E = gi_probe->dynamic_geometries.push_back(pinfo);
|
||||
} else {
|
||||
E = gi_probe->geometries.push_back(pinfo);
|
||||
}
|
||||
|
||||
geom->gi_probes_dirty = true;
|
||||
|
||||
@ -240,7 +245,11 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance
|
||||
List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata);
|
||||
|
||||
geom->gi_probes.erase(E->get().L);
|
||||
gi_probe->geometries.erase(E);
|
||||
if (A->dynamic_gi) {
|
||||
gi_probe->dynamic_geometries.erase(E);
|
||||
} else {
|
||||
gi_probe->geometries.erase(E);
|
||||
}
|
||||
|
||||
geom->gi_probes_dirty = true;
|
||||
|
||||
@ -842,12 +851,32 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF
|
||||
Instance *instance = instance_owner.getornull(p_instance);
|
||||
ERR_FAIL_COND(!instance);
|
||||
|
||||
ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK));
|
||||
|
||||
switch (p_flags) {
|
||||
|
||||
case VS::INSTANCE_FLAG_USE_BAKED_LIGHT: {
|
||||
|
||||
instance->baked_light = p_enabled;
|
||||
|
||||
} break;
|
||||
case VS::INSTANCE_FLAG_USE_DYNAMIC_GI: {
|
||||
|
||||
if (p_enabled == instance->dynamic_gi) {
|
||||
//bye, redundant
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance->octree_id != 0) {
|
||||
//remove from octree, it needs to be re-paired
|
||||
instance->scenario->octree.erase(instance->octree_id);
|
||||
instance->octree_id = 0;
|
||||
_instance_queue_update(instance, true, true);
|
||||
}
|
||||
|
||||
//once out of octree, can be changed
|
||||
instance->dynamic_gi = p_enabled;
|
||||
|
||||
} break;
|
||||
case VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: {
|
||||
|
||||
@ -2431,7 +2460,7 @@ void VisualServerScene::render_probes() {
|
||||
cache_count = idx;
|
||||
}
|
||||
|
||||
bool update_probe = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
|
||||
bool update_lights = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
|
||||
|
||||
if (cache_dirty) {
|
||||
probe->light_cache.resize(cache_count);
|
||||
@ -2490,13 +2519,37 @@ void VisualServerScene::render_probes() {
|
||||
}
|
||||
}
|
||||
|
||||
update_probe = true;
|
||||
update_lights = true;
|
||||
}
|
||||
|
||||
if (update_probe) {
|
||||
VSG::scene_render->gi_probe_update(probe->probe_instance, probe->light_instances);
|
||||
instance_cull_count = 0;
|
||||
for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) {
|
||||
if (instance_cull_count < MAX_INSTANCE_CULL) {
|
||||
Instance *ins = E->get().geometry;
|
||||
InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
|
||||
|
||||
if (geom->gi_probes_dirty) {
|
||||
//giprobes may be dirty, so update
|
||||
int l = 0;
|
||||
//only called when reflection probe AABB enter/exit this geometry
|
||||
ins->gi_probe_instances.resize(geom->gi_probes.size());
|
||||
|
||||
for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) {
|
||||
|
||||
InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data);
|
||||
|
||||
ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance;
|
||||
}
|
||||
|
||||
geom->gi_probes_dirty = false;
|
||||
}
|
||||
|
||||
instance_cull_result[instance_cull_count++] = E->get().geometry;
|
||||
}
|
||||
}
|
||||
|
||||
VSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result);
|
||||
|
||||
gi_probe_update_list.remove(gi_probe);
|
||||
|
||||
gi_probe = next;
|
||||
|
@ -156,8 +156,6 @@ public:
|
||||
|
||||
SelfList<Instance> update_item;
|
||||
|
||||
AABB aabb;
|
||||
AABB transformed_aabb;
|
||||
AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better?
|
||||
float extra_margin;
|
||||
uint32_t object_id;
|
||||
@ -316,6 +314,7 @@ public:
|
||||
};
|
||||
|
||||
List<PairInfo> geometries;
|
||||
List<PairInfo> dynamic_geometries;
|
||||
|
||||
Set<Instance *> lights;
|
||||
|
||||
|
@ -834,6 +834,7 @@ public:
|
||||
|
||||
enum InstanceFlags {
|
||||
INSTANCE_FLAG_USE_BAKED_LIGHT,
|
||||
INSTANCE_FLAG_USE_DYNAMIC_GI,
|
||||
INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
|
||||
INSTANCE_FLAG_MAX
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user