2020-12-03 22:09:47 +01:00
/*************************************************************************/
2020-12-04 19:26:24 +01:00
/* renderer_scene_cull.cpp */
2020-12-03 22:09:47 +01:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2021-01-01 20:13:46 +01:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2020-12-03 22:09:47 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2020-12-04 19:26:24 +01:00
# include "renderer_scene_cull.h"
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
# include "core/config/project_settings.h"
2020-12-03 22:09:47 +01:00
# include "core/os/os.h"
# include "rendering_server_default.h"
# include "rendering_server_globals.h"
# include <new>
/* CAMERA API */
2020-12-04 19:26:24 +01:00
RID RendererSceneCull : : camera_create ( ) {
2020-12-03 22:09:47 +01:00
Camera * camera = memnew ( Camera ) ;
return camera_owner . make_rid ( camera ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_perspective ( RID p_camera , float p_fovy_degrees , float p_z_near , float p_z_far ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > type = Camera : : PERSPECTIVE ;
camera - > fov = p_fovy_degrees ;
camera - > znear = p_z_near ;
camera - > zfar = p_z_far ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_orthogonal ( RID p_camera , float p_size , float p_z_near , float p_z_far ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > type = Camera : : ORTHOGONAL ;
camera - > size = p_size ;
camera - > znear = p_z_near ;
camera - > zfar = p_z_far ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_frustum ( RID p_camera , float p_size , Vector2 p_offset , float p_z_near , float p_z_far ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > type = Camera : : FRUSTUM ;
camera - > size = p_size ;
camera - > offset = p_offset ;
camera - > znear = p_z_near ;
camera - > zfar = p_z_far ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_transform ( RID p_camera , const Transform & p_transform ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > transform = p_transform . orthonormalized ( ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_cull_mask ( RID p_camera , uint32_t p_layers ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > visible_layers = p_layers ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_environment ( RID p_camera , RID p_env ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > env = p_env ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_camera_effects ( RID p_camera , RID p_fx ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > effects = p_fx ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : camera_set_use_vertical_aspect ( RID p_camera , bool p_enable ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
camera - > vaspect = p_enable ;
}
2020-12-04 19:26:24 +01:00
bool RendererSceneCull : : is_camera ( RID p_camera ) const {
2020-12-03 22:09:47 +01:00
return camera_owner . owns ( p_camera ) ;
}
/* SCENARIO API */
2020-12-23 17:52:58 +01:00
void RendererSceneCull : : _instance_pair ( Instance * p_A , Instance * p_B ) {
RendererSceneCull * self = ( RendererSceneCull * ) singleton ;
2020-12-03 22:09:47 +01:00
Instance * A = p_A ;
Instance * B = p_B ;
//instance indices are designed so greater always contains lesser
if ( A - > base_type > B - > base_type ) {
SWAP ( A , B ) ; //lesser always first
}
if ( B - > base_type = = RS : : INSTANCE_LIGHT & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > lights . insert ( B ) ;
light - > geometries . insert ( A ) ;
2020-12-03 22:09:47 +01:00
if ( geom - > can_cast_shadows ) {
light - > shadow_dirty = true ;
}
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_LIGHTING_DIRTY ;
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
} else if ( self - > pair_volumes_to_mesh & & B - > base_type = = RS : : INSTANCE_REFLECTION_PROBE & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
2020-12-03 22:09:47 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > reflection_probes . insert ( B ) ;
reflection_probe - > geometries . insert ( A ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_REFLECTION_DIRTY ;
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
} else if ( self - > pair_volumes_to_mesh & & B - > base_type = = RS : : INSTANCE_DECAL & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
2020-12-03 22:09:47 +01:00
InstanceDecalData * decal = static_cast < InstanceDecalData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > decals . insert ( B ) ;
decal - > geometries . insert ( A ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_DECAL_DIRTY ;
}
2020-12-03 22:09:47 +01:00
} else if ( B - > base_type = = RS : : INSTANCE_LIGHTMAP & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceLightmapData * lightmap_data = static_cast < InstanceLightmapData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
if ( A - > dynamic_gi ) {
2020-12-23 17:52:58 +01:00
geom - > lightmap_captures . insert ( A ) ;
lightmap_data - > geometries . insert ( B ) ;
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_LIGHTMAP_CAPTURE ;
}
2020-12-23 17:52:58 +01:00
( ( RendererSceneCull * ) self ) - > _instance_queue_update ( A , false , false ) ; //need to update capture
2020-12-03 22:09:47 +01:00
}
} else if ( B - > base_type = = RS : : INSTANCE_GI_PROBE & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > gi_probes . insert ( B ) ;
2020-12-03 22:09:47 +01:00
if ( A - > dynamic_gi ) {
2020-12-23 17:52:58 +01:00
gi_probe - > dynamic_geometries . insert ( A ) ;
2020-12-03 22:09:47 +01:00
} else {
2020-12-23 17:52:58 +01:00
gi_probe - > geometries . insert ( A ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_GI_PROBE_DIRTY ;
}
2020-12-03 22:09:47 +01:00
} else if ( B - > base_type = = RS : : INSTANCE_GI_PROBE & & A - > base_type = = RS : : INSTANCE_LIGHT ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
2020-12-23 17:52:58 +01:00
gi_probe - > lights . insert ( A ) ;
2020-12-03 22:09:47 +01:00
} else if ( B - > base_type = = RS : : INSTANCE_PARTICLES_COLLISION & & A - > base_type = = RS : : INSTANCE_PARTICLES ) {
RSG : : storage - > particles_add_collision ( A - > base , B ) ;
}
}
2020-12-23 17:52:58 +01:00
void RendererSceneCull : : _instance_unpair ( Instance * p_A , Instance * p_B ) {
RendererSceneCull * self = ( RendererSceneCull * ) singleton ;
2020-12-03 22:09:47 +01:00
Instance * A = p_A ;
Instance * B = p_B ;
//instance indices are designed so greater always contains lesser
if ( A - > base_type > B - > base_type ) {
SWAP ( A , B ) ; //lesser always first
}
if ( B - > base_type = = RS : : INSTANCE_LIGHT & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > lights . erase ( B ) ;
light - > geometries . erase ( A ) ;
2020-12-03 22:09:47 +01:00
if ( geom - > can_cast_shadows ) {
light - > shadow_dirty = true ;
}
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_LIGHTING_DIRTY ;
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
} else if ( self - > pair_volumes_to_mesh & & B - > base_type = = RS : : INSTANCE_REFLECTION_PROBE & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
2020-12-03 22:09:47 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > reflection_probes . erase ( B ) ;
reflection_probe - > geometries . erase ( A ) ;
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_REFLECTION_DIRTY ;
}
2020-12-23 17:52:58 +01:00
} else if ( self - > pair_volumes_to_mesh & & B - > base_type = = RS : : INSTANCE_DECAL & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
2020-12-03 22:09:47 +01:00
InstanceDecalData * decal = static_cast < InstanceDecalData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > decals . erase ( B ) ;
decal - > geometries . erase ( A ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_DECAL_DIRTY ;
}
2020-12-03 22:09:47 +01:00
} else if ( B - > base_type = = RS : : INSTANCE_LIGHTMAP & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
2020-12-23 17:52:58 +01:00
InstanceLightmapData * lightmap_data = static_cast < InstanceLightmapData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
if ( A - > dynamic_gi ) {
geom - > lightmap_captures . erase ( B ) ;
2020-12-26 13:05:36 +01:00
2020-12-15 13:04:21 +01:00
if ( geom - > lightmap_captures . is_empty ( ) & & A - > scenario & & A - > array_index > = 0 ) {
2020-12-26 13:05:36 +01:00
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_LIGHTMAP_CAPTURE ) ;
}
2020-12-23 17:52:58 +01:00
lightmap_data - > geometries . erase ( A ) ;
( ( RendererSceneCull * ) self ) - > _instance_queue_update ( A , false , false ) ; //need to update capture
2020-12-03 22:09:47 +01:00
}
} else if ( B - > base_type = = RS : : INSTANCE_GI_PROBE & & ( ( 1 < < A - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2020-12-23 17:52:58 +01:00
geom - > gi_probes . erase ( B ) ;
2020-12-03 22:09:47 +01:00
if ( A - > dynamic_gi ) {
2020-12-23 17:52:58 +01:00
gi_probe - > dynamic_geometries . erase ( A ) ;
2020-12-03 22:09:47 +01:00
} else {
2020-12-23 17:52:58 +01:00
gi_probe - > geometries . erase ( A ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
if ( A - > scenario & & A - > array_index > = 0 ) {
InstanceData & idata = A - > scenario - > instance_data [ A - > array_index ] ;
idata . flags | = InstanceData : : FLAG_GEOM_GI_PROBE_DIRTY ;
}
2020-12-03 22:09:47 +01:00
} else if ( B - > base_type = = RS : : INSTANCE_GI_PROBE & & A - > base_type = = RS : : INSTANCE_LIGHT ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
2020-12-23 17:52:58 +01:00
gi_probe - > lights . erase ( A ) ;
2020-12-03 22:09:47 +01:00
} else if ( B - > base_type = = RS : : INSTANCE_PARTICLES_COLLISION & & A - > base_type = = RS : : INSTANCE_PARTICLES ) {
RSG : : storage - > particles_remove_collision ( A - > base , B ) ;
}
}
2020-12-04 19:26:24 +01:00
RID RendererSceneCull : : scenario_create ( ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = memnew ( Scenario ) ;
ERR_FAIL_COND_V ( ! scenario , RID ( ) ) ;
RID scenario_rid = scenario_owner . make_rid ( scenario ) ;
scenario - > self = scenario_rid ;
scenario - > reflection_probe_shadow_atlas = scene_render - > shadow_atlas_create ( ) ;
scene_render - > shadow_atlas_set_size ( scenario - > reflection_probe_shadow_atlas , 1024 ) ; //make enough shadows for close distance, don't bother with rest
scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 0 , 4 ) ;
scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 1 , 4 ) ;
scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 2 , 4 ) ;
scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 3 , 8 ) ;
scenario - > reflection_atlas = scene_render - > reflection_atlas_create ( ) ;
2020-12-26 13:05:36 +01:00
scenario - > instance_aabbs . set_page_pool ( & instance_aabb_page_pool ) ;
scenario - > instance_data . set_page_pool ( & instance_data_page_pool ) ;
2020-12-03 22:09:47 +01:00
return scenario_rid ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : scenario_set_debug ( RID p_scenario , RS : : ScenarioDebugMode p_debug_mode ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > debug = p_debug_mode ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : scenario_set_environment ( RID p_scenario , RID p_environment ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > environment = p_environment ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : scenario_set_camera_effects ( RID p_scenario , RID p_camera_effects ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > camera_effects = p_camera_effects ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : scenario_set_fallback_environment ( RID p_scenario , RID p_environment ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > fallback_environment = p_environment ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : scenario_set_reflection_atlas_size ( RID p_scenario , int p_reflection_size , int p_reflection_count ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scene_render - > reflection_atlas_set_size ( scenario - > reflection_atlas , p_reflection_size , p_reflection_count ) ;
}
2020-12-04 19:26:24 +01:00
bool RendererSceneCull : : is_scenario ( RID p_scenario ) const {
2020-12-03 22:09:47 +01:00
return scenario_owner . owns ( p_scenario ) ;
}
2020-12-04 19:26:24 +01:00
RID RendererSceneCull : : scenario_get_environment ( RID p_scenario ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , RID ( ) ) ;
return scenario - > environment ;
}
/* INSTANCING API */
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : _instance_queue_update ( Instance * p_instance , bool p_update_aabb , bool p_update_dependencies ) {
2020-12-03 22:09:47 +01:00
if ( p_update_aabb ) {
p_instance - > update_aabb = true ;
}
if ( p_update_dependencies ) {
p_instance - > update_dependencies = true ;
}
if ( p_instance - > update_item . in_list ( ) ) {
return ;
}
_instance_update_list . add ( & p_instance - > update_item ) ;
}
2020-12-04 19:26:24 +01:00
RID RendererSceneCull : : instance_create ( ) {
2020-12-03 22:09:47 +01:00
Instance * instance = memnew ( Instance ) ;
ERR_FAIL_COND_V ( ! instance , RID ( ) ) ;
RID instance_rid = instance_owner . make_rid ( instance ) ;
instance - > self = instance_rid ;
return instance_rid ;
}
2020-12-16 15:07:08 +01:00
void RendererSceneCull : : _instance_update_mesh_instance ( Instance * p_instance ) {
bool needs_instance = RSG : : storage - > mesh_needs_instance ( p_instance - > base , p_instance - > skeleton . is_valid ( ) ) ;
if ( needs_instance ! = p_instance - > mesh_instance . is_valid ( ) ) {
if ( needs_instance ) {
p_instance - > mesh_instance = RSG : : storage - > mesh_instance_create ( p_instance - > base ) ;
2020-12-26 13:05:36 +01:00
2020-12-16 15:07:08 +01:00
} else {
RSG : : storage - > free ( p_instance - > mesh_instance ) ;
p_instance - > mesh_instance = RID ( ) ;
}
2020-12-26 13:05:36 +01:00
if ( p_instance - > scenario & & p_instance - > array_index > = 0 ) {
InstanceData & idata = p_instance - > scenario - > instance_data [ p_instance - > array_index ] ;
if ( p_instance - > mesh_instance . is_valid ( ) ) {
idata . flags | = InstanceData : : FLAG_USES_MESH_INSTANCE ;
} else {
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_USES_MESH_INSTANCE ) ;
}
}
2020-12-16 15:07:08 +01:00
}
if ( p_instance - > mesh_instance . is_valid ( ) ) {
RSG : : storage - > mesh_instance_set_skeleton ( p_instance - > mesh_instance , p_instance - > skeleton ) ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_base ( RID p_instance , RID p_base ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
Scenario * scenario = instance - > scenario ;
if ( instance - > base_type ! = RS : : INSTANCE_NONE ) {
//free anything related to that base
2020-12-23 17:52:58 +01:00
if ( scenario & & instance - > indexer_id . is_valid ( ) ) {
_unpair_instance ( instance ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-16 15:07:08 +01:00
if ( instance - > mesh_instance . is_valid ( ) ) {
RSG : : storage - > free ( instance - > mesh_instance ) ;
instance - > mesh_instance = RID ( ) ;
2020-12-26 13:05:36 +01:00
// no need to set instance data flag here, as it was freed above
2020-12-16 15:07:08 +01:00
}
2020-12-03 22:09:47 +01:00
switch ( instance - > base_type ) {
case RS : : INSTANCE_LIGHT : {
InstanceLightData * light = static_cast < InstanceLightData * > ( instance - > base_data ) ;
if ( scenario & & RSG : : storage - > light_get_type ( instance - > base ) ! = RS : : LIGHT_DIRECTIONAL & & light - > bake_mode = = RS : : LIGHT_BAKE_DYNAMIC ) {
scenario - > dynamic_lights . erase ( light - > instance ) ;
}
# ifdef DEBUG_ENABLED
if ( light - > geometries . size ( ) ) {
ERR_PRINT ( " BUG, indexing did not unpair geometries from light. " ) ;
}
# endif
if ( scenario & & light - > D ) {
scenario - > directional_lights . erase ( light - > D ) ;
light - > D = nullptr ;
}
scene_render - > free ( light - > instance ) ;
} break ;
case RS : : INSTANCE_REFLECTION_PROBE : {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( instance - > base_data ) ;
scene_render - > free ( reflection_probe - > instance ) ;
if ( reflection_probe - > update_list . in_list ( ) ) {
reflection_probe_render_list . remove ( & reflection_probe - > update_list ) ;
}
} break ;
case RS : : INSTANCE_DECAL : {
InstanceDecalData * decal = static_cast < InstanceDecalData * > ( instance - > base_data ) ;
scene_render - > free ( decal - > instance ) ;
} break ;
case RS : : INSTANCE_LIGHTMAP : {
InstanceLightmapData * lightmap_data = static_cast < InstanceLightmapData * > ( instance - > base_data ) ;
//erase dependencies, since no longer a lightmap
while ( lightmap_data - > users . front ( ) ) {
instance_geometry_set_lightmap ( lightmap_data - > users . front ( ) - > get ( ) - > self , RID ( ) , Rect2 ( ) , 0 ) ;
}
} break ;
case RS : : INSTANCE_GI_PROBE : {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
# ifdef DEBUG_ENABLED
if ( gi_probe - > geometries . size ( ) ) {
ERR_PRINT ( " BUG, indexing did not unpair geometries from GIProbe. " ) ;
}
# endif
# ifdef DEBUG_ENABLED
if ( gi_probe - > lights . size ( ) ) {
ERR_PRINT ( " BUG, indexing did not unpair lights from GIProbe. " ) ;
}
# endif
if ( gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . remove ( & gi_probe - > update_element ) ;
}
scene_render - > free ( gi_probe - > probe_instance ) ;
} break ;
default : {
}
}
if ( instance - > base_data ) {
memdelete ( instance - > base_data ) ;
instance - > base_data = nullptr ;
}
instance - > materials . clear ( ) ;
}
instance - > base_type = RS : : INSTANCE_NONE ;
instance - > base = RID ( ) ;
if ( p_base . is_valid ( ) ) {
instance - > base_type = RSG : : storage - > get_base_type ( p_base ) ;
ERR_FAIL_COND ( instance - > base_type = = RS : : INSTANCE_NONE ) ;
switch ( instance - > base_type ) {
case RS : : INSTANCE_LIGHT : {
InstanceLightData * light = memnew ( InstanceLightData ) ;
if ( scenario & & RSG : : storage - > light_get_type ( p_base ) = = RS : : LIGHT_DIRECTIONAL ) {
light - > D = scenario - > directional_lights . push_back ( instance ) ;
}
light - > instance = scene_render - > light_instance_create ( p_base ) ;
instance - > base_data = light ;
} break ;
case RS : : INSTANCE_MESH :
case RS : : INSTANCE_MULTIMESH :
case RS : : INSTANCE_IMMEDIATE :
case RS : : INSTANCE_PARTICLES : {
InstanceGeometryData * geom = memnew ( InstanceGeometryData ) ;
instance - > base_data = geom ;
2020-12-16 15:07:08 +01:00
2020-12-03 22:09:47 +01:00
} break ;
case RS : : INSTANCE_REFLECTION_PROBE : {
InstanceReflectionProbeData * reflection_probe = memnew ( InstanceReflectionProbeData ) ;
reflection_probe - > owner = instance ;
instance - > base_data = reflection_probe ;
reflection_probe - > instance = scene_render - > reflection_probe_instance_create ( p_base ) ;
} break ;
case RS : : INSTANCE_DECAL : {
InstanceDecalData * decal = memnew ( InstanceDecalData ) ;
decal - > owner = instance ;
instance - > base_data = decal ;
decal - > instance = scene_render - > decal_instance_create ( p_base ) ;
} break ;
case RS : : INSTANCE_LIGHTMAP : {
InstanceLightmapData * lightmap_data = memnew ( InstanceLightmapData ) ;
instance - > base_data = lightmap_data ;
//lightmap_data->instance = scene_render->lightmap_data_instance_create(p_base);
} break ;
case RS : : INSTANCE_GI_PROBE : {
InstanceGIProbeData * gi_probe = memnew ( InstanceGIProbeData ) ;
instance - > base_data = gi_probe ;
gi_probe - > owner = instance ;
if ( scenario & & ! gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . add ( & gi_probe - > update_element ) ;
}
gi_probe - > probe_instance = scene_render - > gi_probe_instance_create ( p_base ) ;
} break ;
default : {
}
}
instance - > base = p_base ;
2020-12-16 15:07:08 +01:00
if ( instance - > base_type = = RS : : INSTANCE_MESH ) {
_instance_update_mesh_instance ( instance ) ;
}
2020-12-03 22:09:47 +01:00
//forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it
RSG : : storage - > base_update_dependency ( p_base , instance ) ;
}
_instance_queue_update ( instance , true , true ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_scenario ( RID p_instance , RID p_scenario ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > scenario ) {
instance - > scenario - > instances . remove ( & instance - > scenario_item ) ;
2020-12-23 17:52:58 +01:00
if ( instance - > indexer_id . is_valid ( ) ) {
_unpair_instance ( instance ) ;
2020-12-03 22:09:47 +01:00
}
switch ( instance - > base_type ) {
case RS : : INSTANCE_LIGHT : {
InstanceLightData * light = static_cast < InstanceLightData * > ( instance - > base_data ) ;
# ifdef DEBUG_ENABLED
if ( light - > geometries . size ( ) ) {
ERR_PRINT ( " BUG, indexing did not unpair geometries from light. " ) ;
}
# endif
if ( light - > D ) {
instance - > scenario - > directional_lights . erase ( light - > D ) ;
light - > D = nullptr ;
}
} break ;
case RS : : INSTANCE_REFLECTION_PROBE : {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( instance - > base_data ) ;
scene_render - > reflection_probe_release_atlas_index ( reflection_probe - > instance ) ;
} break ;
case RS : : INSTANCE_PARTICLES_COLLISION : {
heightfield_particle_colliders_update_list . erase ( instance ) ;
} break ;
case RS : : INSTANCE_GI_PROBE : {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
# ifdef DEBUG_ENABLED
if ( gi_probe - > geometries . size ( ) ) {
ERR_PRINT ( " BUG, indexing did not unpair geometries from GIProbe. " ) ;
}
# endif
# ifdef DEBUG_ENABLED
if ( gi_probe - > lights . size ( ) ) {
ERR_PRINT ( " BUG, indexing did not unpair lights from GIProbe. " ) ;
}
# endif
if ( gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . remove ( & gi_probe - > update_element ) ;
}
} break ;
default : {
}
}
instance - > scenario = nullptr ;
}
if ( p_scenario . is_valid ( ) ) {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
instance - > scenario = scenario ;
scenario - > instances . add ( & instance - > scenario_item ) ;
switch ( instance - > base_type ) {
case RS : : INSTANCE_LIGHT : {
InstanceLightData * light = static_cast < InstanceLightData * > ( instance - > base_data ) ;
if ( RSG : : storage - > light_get_type ( instance - > base ) = = RS : : LIGHT_DIRECTIONAL ) {
light - > D = scenario - > directional_lights . push_back ( instance ) ;
}
} break ;
case RS : : INSTANCE_GI_PROBE : {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
if ( ! gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . add ( & gi_probe - > update_element ) ;
}
} break ;
default : {
}
}
_instance_queue_update ( instance , true , true ) ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_layer_mask ( RID p_instance , uint32_t p_mask ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > layer_mask = p_mask ;
2020-12-26 13:05:36 +01:00
if ( instance - > scenario & & instance - > array_index > = 0 ) {
instance - > scenario - > instance_data [ instance - > array_index ] . layer_mask = p_mask ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_transform ( RID p_instance , const Transform & p_transform ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > transform = = p_transform ) {
return ; //must be checked to avoid worst evil
}
# ifdef DEBUG_ENABLED
for ( int i = 0 ; i < 4 ; i + + ) {
const Vector3 & v = i < 3 ? p_transform . basis . elements [ i ] : p_transform . origin ;
ERR_FAIL_COND ( Math : : is_inf ( v . x ) ) ;
ERR_FAIL_COND ( Math : : is_nan ( v . x ) ) ;
ERR_FAIL_COND ( Math : : is_inf ( v . y ) ) ;
ERR_FAIL_COND ( Math : : is_nan ( v . y ) ) ;
ERR_FAIL_COND ( Math : : is_inf ( v . z ) ) ;
ERR_FAIL_COND ( Math : : is_nan ( v . z ) ) ;
}
# endif
instance - > transform = p_transform ;
_instance_queue_update ( instance , true ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_attach_object_instance_id ( RID p_instance , ObjectID p_id ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > object_id = p_id ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_blend_shape_weight ( RID p_instance , int p_shape , float p_weight ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > update_item . in_list ( ) ) {
_update_dirty_instance ( instance ) ;
}
2020-12-16 15:07:08 +01:00
if ( instance - > mesh_instance . is_valid ( ) ) {
RSG : : storage - > mesh_instance_set_blend_shape_weight ( instance - > mesh_instance , p_shape , p_weight ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_surface_material ( RID p_instance , int p_surface , RID p_material ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > base_type = = RS : : INSTANCE_MESH ) {
//may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
instance - > materials . resize ( MAX ( p_surface + 1 , RSG : : storage - > mesh_get_surface_count ( instance - > base ) ) ) ;
}
ERR_FAIL_INDEX ( p_surface , instance - > materials . size ( ) ) ;
instance - > materials . write [ p_surface ] = p_material ;
_instance_queue_update ( instance , false , true ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_visible ( RID p_instance , bool p_visible ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > visible = = p_visible ) {
return ;
}
instance - > visible = p_visible ;
2020-12-23 17:52:58 +01:00
if ( p_visible ) {
if ( instance - > scenario ! = nullptr ) {
_instance_queue_update ( instance , true , false ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
} else if ( instance - > indexer_id . is_valid ( ) ) {
_unpair_instance ( instance ) ;
2020-12-03 22:09:47 +01:00
}
}
inline bool is_geometry_instance ( RenderingServer : : InstanceType p_type ) {
return p_type = = RS : : INSTANCE_MESH | | p_type = = RS : : INSTANCE_MULTIMESH | | p_type = = RS : : INSTANCE_PARTICLES | | p_type = = RS : : INSTANCE_IMMEDIATE ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_custom_aabb ( RID p_instance , AABB p_aabb ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
ERR_FAIL_COND ( ! is_geometry_instance ( instance - > base_type ) ) ;
if ( p_aabb ! = AABB ( ) ) {
// Set custom AABB
if ( instance - > custom_aabb = = nullptr ) {
instance - > custom_aabb = memnew ( AABB ) ;
}
* instance - > custom_aabb = p_aabb ;
} else {
// Clear custom AABB
if ( instance - > custom_aabb ! = nullptr ) {
memdelete ( instance - > custom_aabb ) ;
instance - > custom_aabb = nullptr ;
}
}
if ( instance - > scenario ) {
_instance_queue_update ( instance , true , false ) ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_attach_skeleton ( RID p_instance , RID p_skeleton ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > skeleton = = p_skeleton ) {
return ;
}
instance - > skeleton = p_skeleton ;
if ( p_skeleton . is_valid ( ) ) {
//update the dependency now, so if cleared, we remove it
RSG : : storage - > skeleton_update_dependency ( p_skeleton , instance ) ;
}
2020-12-16 15:07:08 +01:00
_instance_update_mesh_instance ( instance ) ;
2020-12-03 22:09:47 +01:00
_instance_queue_update ( instance , true , true ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_exterior ( RID p_instance , bool p_enabled ) {
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_set_extra_visibility_margin ( RID p_instance , real_t p_margin ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > extra_margin = p_margin ;
_instance_queue_update ( instance , true , false ) ;
}
2020-12-04 19:26:24 +01:00
Vector < ObjectID > RendererSceneCull : : instances_cull_aabb ( const AABB & p_aabb , RID p_scenario ) const {
2020-12-03 22:09:47 +01:00
Vector < ObjectID > instances ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , instances ) ;
2020-12-04 19:26:24 +01:00
const_cast < RendererSceneCull * > ( this ) - > update_dirty_instances ( ) ; // check dirty instances before culling
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
struct CullAABB {
Vector < ObjectID > instances ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
if ( ! p_instance - > object_id . is_null ( ) ) {
instances . push_back ( p_instance - > object_id ) ;
}
return false ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
} ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
CullAABB cull_aabb ;
scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . aabb_query ( p_aabb , cull_aabb ) ;
scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . aabb_query ( p_aabb , cull_aabb ) ;
return cull_aabb . instances ;
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
Vector < ObjectID > RendererSceneCull : : instances_cull_ray ( const Vector3 & p_from , const Vector3 & p_to , RID p_scenario ) const {
2020-12-03 22:09:47 +01:00
Vector < ObjectID > instances ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , instances ) ;
2020-12-04 19:26:24 +01:00
const_cast < RendererSceneCull * > ( this ) - > update_dirty_instances ( ) ; // check dirty instances before culling
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
struct CullRay {
Vector < ObjectID > instances ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
if ( ! p_instance - > object_id . is_null ( ) ) {
instances . push_back ( p_instance - > object_id ) ;
}
return false ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
} ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
CullRay cull_ray ;
scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . ray_query ( p_from , p_to , cull_ray ) ;
scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . ray_query ( p_from , p_to , cull_ray ) ;
return cull_ray . instances ;
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
Vector < ObjectID > RendererSceneCull : : instances_cull_convex ( const Vector < Plane > & p_convex , RID p_scenario ) const {
2020-12-03 22:09:47 +01:00
Vector < ObjectID > instances ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , instances ) ;
2020-12-04 19:26:24 +01:00
const_cast < RendererSceneCull * > ( this ) - > update_dirty_instances ( ) ; // check dirty instances before culling
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
Vector < Vector3 > points = Geometry3D : : compute_convex_mesh_points ( & p_convex [ 0 ] , p_convex . size ( ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
struct CullConvex {
Vector < ObjectID > instances ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
if ( ! p_instance - > object_id . is_null ( ) ) {
instances . push_back ( p_instance - > object_id ) ;
}
return false ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
} ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
CullConvex cull_convex ;
scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . convex_query ( p_convex . ptr ( ) , p_convex . size ( ) , points . ptr ( ) , points . size ( ) , cull_convex ) ;
scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . convex_query ( p_convex . ptr ( ) , p_convex . size ( ) , points . ptr ( ) , points . size ( ) , cull_convex ) ;
return cull_convex . instances ;
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_flag ( RID p_instance , RS : : InstanceFlags p_flags , bool p_enabled ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
//ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK));
switch ( p_flags ) {
case RS : : INSTANCE_FLAG_USE_BAKED_LIGHT : {
instance - > baked_light = p_enabled ;
2020-12-26 13:05:36 +01:00
if ( instance - > scenario & & instance - > array_index > = 0 ) {
InstanceData & idata = instance - > scenario - > instance_data [ instance - > array_index ] ;
if ( instance - > baked_light ) {
idata . flags | = InstanceData : : FLAG_USES_BAKED_LIGHT ;
} else {
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_USES_BAKED_LIGHT ) ;
}
}
2020-12-03 22:09:47 +01:00
} break ;
case RS : : INSTANCE_FLAG_USE_DYNAMIC_GI : {
if ( p_enabled = = instance - > dynamic_gi ) {
//bye, redundant
return ;
}
2020-12-23 17:52:58 +01:00
if ( instance - > indexer_id . is_valid ( ) ) {
_unpair_instance ( instance ) ;
2020-12-03 22:09:47 +01:00
_instance_queue_update ( instance , true , true ) ;
}
//once out of octree, can be changed
instance - > dynamic_gi = p_enabled ;
} break ;
case RS : : INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE : {
instance - > redraw_if_visible = p_enabled ;
2020-12-26 13:05:36 +01:00
if ( instance - > scenario & & instance - > array_index > = 0 ) {
InstanceData & idata = instance - > scenario - > instance_data [ instance - > array_index ] ;
if ( instance - > redraw_if_visible ) {
idata . flags | = InstanceData : : FLAG_REDRAW_IF_VISIBLE ;
} else {
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_REDRAW_IF_VISIBLE ) ;
}
}
2020-12-03 22:09:47 +01:00
} break ;
default : {
}
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_cast_shadows_setting ( RID p_instance , RS : : ShadowCastingSetting p_shadow_casting_setting ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > cast_shadows = p_shadow_casting_setting ;
2020-12-26 13:05:36 +01:00
if ( instance - > scenario & & instance - > array_index > = 0 ) {
InstanceData & idata = instance - > scenario - > instance_data [ instance - > array_index ] ;
if ( instance - > cast_shadows ! = RS : : SHADOW_CASTING_SETTING_SHADOWS_ONLY ) {
idata . flags | = InstanceData : : FLAG_CAST_SHADOWS ;
} else {
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_CAST_SHADOWS ) ;
}
if ( instance - > cast_shadows = = RS : : SHADOW_CASTING_SETTING_SHADOWS_ONLY ) {
idata . flags | = InstanceData : : FLAG_CAST_SHADOWS_ONLY ;
} else {
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_CAST_SHADOWS_ONLY ) ;
}
}
2020-12-03 22:09:47 +01:00
_instance_queue_update ( instance , false , true ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_material_override ( RID p_instance , RID p_material ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > material_override = p_material ;
_instance_queue_update ( instance , false , true ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_draw_range ( RID p_instance , float p_min , float p_max , float p_min_margin , float p_max_margin ) {
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_as_instance_lod ( RID p_instance , RID p_as_lod_of_instance ) {
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_lightmap ( RID p_instance , RID p_lightmap , const Rect2 & p_lightmap_uv_scale , int p_slice_index ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > lightmap ) {
InstanceLightmapData * lightmap_data = static_cast < InstanceLightmapData * > ( ( ( Instance * ) instance - > lightmap ) - > base_data ) ;
lightmap_data - > users . erase ( instance ) ;
instance - > lightmap = nullptr ;
}
Instance * lightmap_instance = instance_owner . getornull ( p_lightmap ) ;
instance - > lightmap = lightmap_instance ;
instance - > lightmap_uv_scale = p_lightmap_uv_scale ;
instance - > lightmap_slice_index = p_slice_index ;
if ( lightmap_instance ) {
InstanceLightmapData * lightmap_data = static_cast < InstanceLightmapData * > ( lightmap_instance - > base_data ) ;
lightmap_data - > users . insert ( instance ) ;
}
}
2020-12-17 19:56:59 +01:00
void RendererSceneCull : : instance_geometry_set_lod_bias ( RID p_instance , float p_lod_bias ) {
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > lod_bias = p_lod_bias ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_set_shader_parameter ( RID p_instance , const StringName & p_parameter , const Variant & p_value ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2020-12-04 19:26:24 +01:00
Map < StringName , RendererSceneRender : : InstanceBase : : InstanceShaderParameter > : : Element * E = instance - > instance_shader_parameters . find ( p_parameter ) ;
2020-12-03 22:09:47 +01:00
if ( ! E ) {
2020-12-04 19:26:24 +01:00
RendererSceneRender : : InstanceBase : : InstanceShaderParameter isp ;
2020-12-03 22:09:47 +01:00
isp . index = - 1 ;
isp . info = PropertyInfo ( ) ;
isp . value = p_value ;
instance - > instance_shader_parameters [ p_parameter ] = isp ;
} else {
E - > get ( ) . value = p_value ;
if ( E - > get ( ) . index > = 0 & & instance - > instance_allocated_shader_parameters ) {
//update directly
RSG : : storage - > global_variables_instance_update ( p_instance , E - > get ( ) . index , p_value ) ;
}
}
}
2020-12-04 19:26:24 +01:00
Variant RendererSceneCull : : instance_geometry_get_shader_parameter ( RID p_instance , const StringName & p_parameter ) const {
const Instance * instance = const_cast < RendererSceneCull * > ( this ) - > instance_owner . getornull ( p_instance ) ;
2020-12-03 22:09:47 +01:00
ERR_FAIL_COND_V ( ! instance , Variant ( ) ) ;
if ( instance - > instance_shader_parameters . has ( p_parameter ) ) {
return instance - > instance_shader_parameters [ p_parameter ] . value ;
}
return Variant ( ) ;
}
2020-12-04 19:26:24 +01:00
Variant RendererSceneCull : : instance_geometry_get_shader_parameter_default_value ( RID p_instance , const StringName & p_parameter ) const {
const Instance * instance = const_cast < RendererSceneCull * > ( this ) - > instance_owner . getornull ( p_instance ) ;
2020-12-03 22:09:47 +01:00
ERR_FAIL_COND_V ( ! instance , Variant ( ) ) ;
if ( instance - > instance_shader_parameters . has ( p_parameter ) ) {
return instance - > instance_shader_parameters [ p_parameter ] . default_value ;
}
return Variant ( ) ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : instance_geometry_get_shader_parameter_list ( RID p_instance , List < PropertyInfo > * p_parameters ) const {
const Instance * instance = const_cast < RendererSceneCull * > ( this ) - > instance_owner . getornull ( p_instance ) ;
2020-12-03 22:09:47 +01:00
ERR_FAIL_COND ( ! instance ) ;
2020-12-04 19:26:24 +01:00
const_cast < RendererSceneCull * > ( this ) - > update_dirty_instances ( ) ;
2020-12-03 22:09:47 +01:00
Vector < StringName > names ;
2020-12-04 19:26:24 +01:00
for ( Map < StringName , RendererSceneRender : : InstanceBase : : InstanceShaderParameter > : : Element * E = instance - > instance_shader_parameters . front ( ) ; E ; E = E - > next ( ) ) {
2020-12-03 22:09:47 +01:00
names . push_back ( E - > key ( ) ) ;
}
names . sort_custom < StringName : : AlphCompare > ( ) ;
for ( int i = 0 ; i < names . size ( ) ; i + + ) {
PropertyInfo pinfo = instance - > instance_shader_parameters [ names [ i ] ] . info ;
p_parameters - > push_back ( pinfo ) ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : _update_instance ( Instance * p_instance ) {
2020-12-03 22:09:47 +01:00
p_instance - > version + + ;
if ( p_instance - > base_type = = RS : : INSTANCE_LIGHT ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( p_instance - > base_data ) ;
scene_render - > light_instance_set_transform ( light - > instance , p_instance - > transform ) ;
scene_render - > light_instance_set_aabb ( light - > instance , p_instance - > transform . xform ( p_instance - > aabb ) ) ;
light - > shadow_dirty = true ;
RS : : LightBakeMode bake_mode = RSG : : storage - > light_get_bake_mode ( p_instance - > base ) ;
if ( RSG : : storage - > light_get_type ( p_instance - > base ) ! = RS : : LIGHT_DIRECTIONAL & & bake_mode ! = light - > bake_mode ) {
if ( p_instance - > scenario & & light - > bake_mode = = RS : : LIGHT_BAKE_DYNAMIC ) {
p_instance - > scenario - > dynamic_lights . erase ( light - > instance ) ;
}
light - > bake_mode = bake_mode ;
if ( p_instance - > scenario & & light - > bake_mode = = RS : : LIGHT_BAKE_DYNAMIC ) {
p_instance - > scenario - > dynamic_lights . push_back ( light - > instance ) ;
}
}
uint32_t max_sdfgi_cascade = RSG : : storage - > light_get_max_sdfgi_cascade ( p_instance - > base ) ;
if ( light - > max_sdfgi_cascade ! = max_sdfgi_cascade ) {
light - > max_sdfgi_cascade = max_sdfgi_cascade ; //should most likely make sdfgi dirty in scenario
}
}
if ( p_instance - > base_type = = RS : : INSTANCE_REFLECTION_PROBE ) {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( p_instance - > base_data ) ;
scene_render - > reflection_probe_instance_set_transform ( reflection_probe - > instance , p_instance - > transform ) ;
2020-12-26 13:05:36 +01:00
if ( p_instance - > scenario & & p_instance - > array_index > = 0 ) {
InstanceData & idata = p_instance - > scenario - > instance_data [ p_instance - > array_index ] ;
idata . flags | = InstanceData : : FLAG_REFLECTION_PROBE_DIRTY ;
}
2020-12-03 22:09:47 +01:00
}
if ( p_instance - > base_type = = RS : : INSTANCE_DECAL ) {
InstanceDecalData * decal = static_cast < InstanceDecalData * > ( p_instance - > base_data ) ;
scene_render - > decal_instance_set_transform ( decal - > instance , p_instance - > transform ) ;
}
if ( p_instance - > base_type = = RS : : INSTANCE_GI_PROBE ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( p_instance - > base_data ) ;
scene_render - > gi_probe_instance_set_transform_to_data ( gi_probe - > probe_instance , p_instance - > transform ) ;
}
if ( p_instance - > base_type = = RS : : INSTANCE_PARTICLES ) {
RSG : : storage - > particles_set_emission_transform ( p_instance - > base , p_instance - > transform ) ;
}
if ( p_instance - > base_type = = RS : : INSTANCE_PARTICLES_COLLISION ) {
//remove materials no longer used and un-own them
if ( RSG : : storage - > particles_collision_is_heightfield ( p_instance - > base ) ) {
heightfield_particle_colliders_update_list . insert ( p_instance ) ;
}
}
if ( p_instance - > aabb . has_no_surface ( ) ) {
return ;
}
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( p_instance - > base_data ) ;
//make sure lights are updated if it casts shadow
if ( geom - > can_cast_shadows ) {
2020-12-23 17:52:58 +01:00
for ( Set < Instance * > : : Element * E = geom - > lights . front ( ) ; E ; E = E - > next ( ) ) {
2020-12-03 22:09:47 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
light - > shadow_dirty = true ;
}
}
if ( ! p_instance - > lightmap & & geom - > lightmap_captures . size ( ) ) {
//affected by lightmap captures, must update capture info!
_update_instance_lightmap_captures ( p_instance ) ;
} else {
2020-12-15 13:04:21 +01:00
if ( ! p_instance - > lightmap_sh . is_empty ( ) ) {
2020-12-03 22:09:47 +01:00
p_instance - > lightmap_sh . clear ( ) ; //don't need SH
p_instance - > lightmap_target_sh . clear ( ) ; //don't need SH
}
}
}
if ( p_instance - > base_type = = RS : : INSTANCE_LIGHTMAP ) {
//if this moved, update the captured objects
InstanceLightmapData * lightmap_data = static_cast < InstanceLightmapData * > ( p_instance - > base_data ) ;
//erase dependencies, since no longer a lightmap
2020-12-23 17:52:58 +01:00
for ( Set < Instance * > : : Element * E = lightmap_data - > geometries . front ( ) ; E ; E = E - > next ( ) ) {
Instance * geom = E - > get ( ) ;
2020-12-03 22:09:47 +01:00
_instance_queue_update ( geom , true , false ) ;
}
}
p_instance - > mirror = p_instance - > transform . basis . determinant ( ) < 0.0 ;
AABB new_aabb ;
new_aabb = p_instance - > transform . xform ( p_instance - > aabb ) ;
p_instance - > transformed_aabb = new_aabb ;
2020-12-23 17:52:58 +01:00
if ( p_instance - > scenario = = nullptr | | ! p_instance - > visible | | Math : : is_zero_approx ( p_instance - > transform . basis . determinant ( ) ) ) {
2020-12-24 16:18:28 +01:00
p_instance - > prev_transformed_aabb = p_instance - > transformed_aabb ;
2020-12-03 22:09:47 +01:00
return ;
}
2020-12-24 16:18:28 +01:00
//quantize to improve moving object performance
AABB bvh_aabb = p_instance - > transformed_aabb ;
if ( p_instance - > indexer_id . is_valid ( ) & & bvh_aabb ! = p_instance - > prev_transformed_aabb ) {
//assume motion, see if bounds need to be quantized
AABB motion_aabb = bvh_aabb . merge ( p_instance - > prev_transformed_aabb ) ;
float motion_longest_axis = motion_aabb . get_longest_axis_size ( ) ;
float longest_axis = p_instance - > transformed_aabb . get_longest_axis_size ( ) ;
if ( motion_longest_axis < longest_axis * 2 ) {
//moved but not a lot, use motion aabb quantizing
float quantize_size = Math : : pow ( 2.0 , Math : : ceil ( Math : : log ( motion_longest_axis ) / Math : : log ( 2.0 ) ) ) * 0.5 ; //one fifth
bvh_aabb . quantize ( quantize_size ) ;
}
}
2020-12-23 17:52:58 +01:00
if ( ! p_instance - > indexer_id . is_valid ( ) ) {
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
2020-12-24 16:18:28 +01:00
p_instance - > indexer_id = p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . insert ( bvh_aabb , p_instance ) ;
2020-12-23 17:52:58 +01:00
} else {
2020-12-24 16:18:28 +01:00
p_instance - > indexer_id = p_instance - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . insert ( bvh_aabb , p_instance ) ;
2020-12-24 11:59:57 +01:00
}
2020-12-26 13:05:36 +01:00
p_instance - > array_index = p_instance - > scenario - > instance_data . size ( ) ;
InstanceData idata ;
idata . instance = p_instance ;
idata . layer_mask = p_instance - > layer_mask ;
idata . flags = p_instance - > base_type ; //changing it means de-indexing, so this never needs to be changed later
idata . base_rid = p_instance - > base ;
switch ( p_instance - > base_type ) {
case RS : : INSTANCE_LIGHT : {
idata . instance_data_rid = static_cast < InstanceLightData * > ( p_instance - > base_data ) - > instance ;
} break ;
case RS : : INSTANCE_REFLECTION_PROBE : {
idata . instance_data_rid = static_cast < InstanceReflectionProbeData * > ( p_instance - > base_data ) - > instance ;
} break ;
case RS : : INSTANCE_DECAL : {
idata . instance_data_rid = static_cast < InstanceDecalData * > ( p_instance - > base_data ) - > instance ;
} break ;
case RS : : INSTANCE_GI_PROBE : {
idata . instance_data_rid = static_cast < InstanceGIProbeData * > ( p_instance - > base_data ) - > probe_instance ;
} break ;
default : {
}
}
if ( p_instance - > base_type = = RS : : INSTANCE_REFLECTION_PROBE ) {
//always dirty when added
idata . flags | = InstanceData : : FLAG_REFLECTION_PROBE_DIRTY ;
}
if ( p_instance - > cast_shadows ! = RS : : SHADOW_CASTING_SETTING_SHADOWS_ONLY ) {
idata . flags | = InstanceData : : FLAG_CAST_SHADOWS ;
}
if ( p_instance - > cast_shadows = = RS : : SHADOW_CASTING_SETTING_SHADOWS_ONLY ) {
idata . flags | = InstanceData : : FLAG_CAST_SHADOWS_ONLY ;
}
if ( p_instance - > redraw_if_visible ) {
idata . flags | = InstanceData : : FLAG_REDRAW_IF_VISIBLE ;
}
// dirty flags should not be set here, since no pairing has happened
if ( p_instance - > baked_light ) {
idata . flags | = InstanceData : : FLAG_USES_BAKED_LIGHT ;
}
if ( p_instance - > mesh_instance . is_valid ( ) ) {
idata . flags | = InstanceData : : FLAG_USES_MESH_INSTANCE ;
}
p_instance - > scenario - > instance_data . push_back ( idata ) ;
p_instance - > scenario - > instance_aabbs . push_back ( InstanceBounds ( p_instance - > transformed_aabb ) ) ;
2020-12-24 11:59:57 +01:00
} else {
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
2020-12-24 16:18:28 +01:00
p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . update ( p_instance - > indexer_id , bvh_aabb ) ;
2020-12-24 11:59:57 +01:00
} else {
2020-12-24 16:18:28 +01:00
p_instance - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . update ( p_instance - > indexer_id , bvh_aabb ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
p_instance - > scenario - > instance_aabbs [ p_instance - > array_index ] = InstanceBounds ( p_instance - > transformed_aabb ) ;
2020-12-23 17:52:58 +01:00
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
//move instance and repair
pair_pass + + ;
PairInstances pair ;
pair . instance = p_instance ;
pair . pair_allocator = & pair_allocator ;
pair . pair_pass = pair_pass ;
pair . pair_mask = 0 ;
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
pair . pair_mask | = 1 < < RS : : INSTANCE_LIGHT ;
pair . pair_mask | = 1 < < RS : : INSTANCE_GI_PROBE ;
pair . pair_mask | = 1 < < RS : : INSTANCE_LIGHTMAP ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
if ( pair_volumes_to_mesh ) {
pair . pair_mask | = 1 < < RS : : INSTANCE_DECAL ;
pair . pair_mask | = 1 < < RS : : INSTANCE_REFLECTION_PROBE ;
}
pair . bvh2 = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] ;
} else if ( p_instance - > base_type = = RS : : INSTANCE_LIGHT ) {
pair . pair_mask | = RS : : INSTANCE_GEOMETRY_MASK ;
pair . bvh = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] ;
if ( RSG : : storage - > light_get_bake_mode ( p_instance - > base ) = = RS : : LIGHT_BAKE_DYNAMIC ) {
pair . pair_mask | = ( 1 < < RS : : INSTANCE_GI_PROBE ) ;
pair . bvh2 = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
} else if ( pair_volumes_to_mesh & & ( p_instance - > base_type = = RS : : INSTANCE_REFLECTION_PROBE | | p_instance - > base_type = = RS : : INSTANCE_DECAL ) ) {
pair . pair_mask = RS : : INSTANCE_GEOMETRY_MASK ;
pair . bvh = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] ;
} else if ( p_instance - > base_type = = RS : : INSTANCE_PARTICLES_COLLISION ) {
pair . pair_mask = ( 1 < < RS : : INSTANCE_PARTICLES ) ;
pair . bvh = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] ;
} else if ( p_instance - > base_type = = RS : : INSTANCE_GI_PROBE ) {
//lights and geometries
pair . pair_mask = RS : : INSTANCE_GEOMETRY_MASK | ( 1 < < RS : : INSTANCE_LIGHT ) ;
pair . bvh = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] ;
pair . bvh2 = & p_instance - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] ;
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
pair . pair ( ) ;
2020-12-24 16:18:28 +01:00
p_instance - > prev_transformed_aabb = p_instance - > transformed_aabb ;
2020-12-23 17:52:58 +01:00
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
void RendererSceneCull : : _unpair_instance ( Instance * p_instance ) {
if ( ! p_instance - > indexer_id . is_valid ( ) ) {
return ; //nothing to do
}
while ( p_instance - > pairs . first ( ) ) {
InstancePair * pair = p_instance - > pairs . first ( ) - > self ( ) ;
Instance * other_instance = p_instance = = pair - > a ? pair - > b : pair - > a ;
_instance_unpair ( p_instance , other_instance ) ;
pair_allocator . free ( pair ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
p_instance - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . remove ( p_instance - > indexer_id ) ;
} else {
p_instance - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . remove ( p_instance - > indexer_id ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
p_instance - > indexer_id = DynamicBVH : : ID ( ) ;
2020-12-26 13:05:36 +01:00
//replace this by last
int32_t swap_with_index = p_instance - > scenario - > instance_data . size ( ) - 1 ;
if ( swap_with_index ! = p_instance - > array_index ) {
p_instance - > scenario - > instance_data [ swap_with_index ] . instance - > array_index = p_instance - > array_index ; //swap
p_instance - > scenario - > instance_data [ p_instance - > array_index ] = p_instance - > scenario - > instance_data [ swap_with_index ] ;
p_instance - > scenario - > instance_aabbs [ p_instance - > array_index ] = p_instance - > scenario - > instance_aabbs [ swap_with_index ] ;
}
// pop last
p_instance - > scenario - > instance_data . pop_back ( ) ;
p_instance - > scenario - > instance_aabbs . pop_back ( ) ;
//uninitialize
p_instance - > array_index = - 1 ;
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
// Clear these now because the InstanceData containing the dirty flags is gone
p_instance - > light_instances . clear ( ) ;
p_instance - > reflection_probe_instances . clear ( ) ;
//p_instance->decal_instances.clear(); will implement later
p_instance - > gi_probe_instances . clear ( ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : _update_instance_aabb ( Instance * p_instance ) {
2020-12-03 22:09:47 +01:00
AABB new_aabb ;
ERR_FAIL_COND ( p_instance - > base_type ! = RS : : INSTANCE_NONE & & ! p_instance - > base . is_valid ( ) ) ;
switch ( p_instance - > base_type ) {
case RenderingServer : : INSTANCE_NONE : {
// do nothing
} break ;
case RenderingServer : : INSTANCE_MESH : {
if ( p_instance - > custom_aabb ) {
new_aabb = * p_instance - > custom_aabb ;
} else {
new_aabb = RSG : : storage - > mesh_get_aabb ( p_instance - > base , p_instance - > skeleton ) ;
}
} break ;
case RenderingServer : : INSTANCE_MULTIMESH : {
if ( p_instance - > custom_aabb ) {
new_aabb = * p_instance - > custom_aabb ;
} else {
new_aabb = RSG : : storage - > multimesh_get_aabb ( p_instance - > base ) ;
}
} break ;
case RenderingServer : : INSTANCE_IMMEDIATE : {
if ( p_instance - > custom_aabb ) {
new_aabb = * p_instance - > custom_aabb ;
} else {
new_aabb = RSG : : storage - > immediate_get_aabb ( p_instance - > base ) ;
}
} break ;
case RenderingServer : : INSTANCE_PARTICLES : {
if ( p_instance - > custom_aabb ) {
new_aabb = * p_instance - > custom_aabb ;
} else {
new_aabb = RSG : : storage - > particles_get_aabb ( p_instance - > base ) ;
}
} break ;
case RenderingServer : : INSTANCE_PARTICLES_COLLISION : {
new_aabb = RSG : : storage - > particles_collision_get_aabb ( p_instance - > base ) ;
} break ;
case RenderingServer : : INSTANCE_LIGHT : {
new_aabb = RSG : : storage - > light_get_aabb ( p_instance - > base ) ;
} break ;
case RenderingServer : : INSTANCE_REFLECTION_PROBE : {
new_aabb = RSG : : storage - > reflection_probe_get_aabb ( p_instance - > base ) ;
} break ;
case RenderingServer : : INSTANCE_DECAL : {
new_aabb = RSG : : storage - > decal_get_aabb ( p_instance - > base ) ;
} break ;
case RenderingServer : : INSTANCE_GI_PROBE : {
new_aabb = RSG : : storage - > gi_probe_get_bounds ( p_instance - > base ) ;
} break ;
case RenderingServer : : INSTANCE_LIGHTMAP : {
new_aabb = RSG : : storage - > lightmap_get_aabb ( p_instance - > base ) ;
} break ;
default : {
}
}
// <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs
if ( p_instance - > extra_margin ) {
new_aabb . grow_by ( p_instance - > extra_margin ) ;
}
p_instance - > aabb = new_aabb ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : _update_instance_lightmap_captures ( Instance * p_instance ) {
2020-12-03 22:09:47 +01:00
bool first_set = p_instance - > lightmap_sh . size ( ) = = 0 ;
p_instance - > lightmap_sh . resize ( 9 ) ; //using SH
p_instance - > lightmap_target_sh . resize ( 9 ) ; //using SH
Color * instance_sh = p_instance - > lightmap_target_sh . ptrw ( ) ;
bool inside = false ;
Color accum_sh [ 9 ] ;
float accum_blend = 0.0 ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( p_instance - > base_data ) ;
2020-12-23 17:52:58 +01:00
for ( Set < Instance * > : : Element * E = geom - > lightmap_captures . front ( ) ; E ; E = E - > next ( ) ) {
2020-12-03 22:09:47 +01:00
Instance * lightmap = E - > get ( ) ;
bool interior = RSG : : storage - > lightmap_is_interior ( lightmap - > base ) ;
if ( inside & & ! interior ) {
continue ; //we are inside, ignore exteriors
}
Transform to_bounds = lightmap - > transform . affine_inverse ( ) ;
Vector3 center = p_instance - > transform . xform ( p_instance - > aabb . position + p_instance - > aabb . size * 0.5 ) ; //use aabb center
Vector3 lm_pos = to_bounds . xform ( center ) ;
AABB bounds = RSG : : storage - > lightmap_get_aabb ( lightmap - > base ) ;
if ( ! bounds . has_point ( lm_pos ) ) {
continue ; //not in this lightmap
}
Color sh [ 9 ] ;
RSG : : storage - > lightmap_tap_sh_light ( lightmap - > base , lm_pos , sh ) ;
//rotate it
Basis rot = lightmap - > transform . basis . orthonormalized ( ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
float csh [ 9 ] ;
for ( int j = 0 ; j < 9 ; j + + ) {
csh [ j ] = sh [ j ] [ i ] ;
}
rot . rotate_sh ( csh ) ;
for ( int j = 0 ; j < 9 ; j + + ) {
sh [ j ] [ i ] = csh [ j ] ;
}
}
Vector3 inner_pos = ( ( lm_pos - bounds . position ) / bounds . size ) * 2.0 - Vector3 ( 1.0 , 1.0 , 1.0 ) ;
float blend = MAX ( inner_pos . x , MAX ( inner_pos . y , inner_pos . z ) ) ;
//make blend more rounded
blend = Math : : lerp ( inner_pos . length ( ) , blend , blend ) ;
blend * = blend ;
blend = MAX ( 0.0 , 1.0 - blend ) ;
if ( interior & & ! inside ) {
//do not blend, just replace
for ( int j = 0 ; j < 9 ; j + + ) {
accum_sh [ j ] = sh [ j ] * blend ;
}
accum_blend = blend ;
inside = true ;
} else {
for ( int j = 0 ; j < 9 ; j + + ) {
accum_sh [ j ] + = sh [ j ] * blend ;
}
accum_blend + = blend ;
}
}
if ( accum_blend > 0.0 ) {
for ( int j = 0 ; j < 9 ; j + + ) {
instance_sh [ j ] = accum_sh [ j ] / accum_blend ;
if ( first_set ) {
p_instance - > lightmap_sh . write [ j ] = instance_sh [ j ] ;
}
}
}
}
2020-12-26 13:05:36 +01:00
void RendererSceneCull : : _light_instance_setup_directional_shadow ( int p_shadow_index , Instance * p_instance , const Transform p_cam_transform , const CameraMatrix & p_cam_projection , bool p_cam_orthogonal , bool p_cam_vaspect ) {
2020-12-03 22:09:47 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( p_instance - > base_data ) ;
Transform light_transform = p_instance - > transform ;
light_transform . orthonormalize ( ) ; //scale does not count on lights
2020-12-26 13:05:36 +01:00
real_t max_distance = p_cam_projection . get_z_far ( ) ;
real_t shadow_max = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_SHADOW_MAX_DISTANCE ) ;
if ( shadow_max > 0 & & ! p_cam_orthogonal ) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera
max_distance = MIN ( shadow_max , max_distance ) ;
}
max_distance = MAX ( max_distance , p_cam_projection . get_z_near ( ) + 0.001 ) ;
real_t min_distance = MIN ( p_cam_projection . get_z_near ( ) , max_distance ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
RS : : LightDirectionalShadowDepthRangeMode depth_range_mode = RSG : : storage - > light_directional_get_shadow_depth_range_mode ( p_instance - > base ) ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
real_t pancake_size = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_SHADOW_PANCAKE_SIZE ) ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
real_t range = max_distance - min_distance ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
int splits = 0 ;
switch ( RSG : : storage - > light_directional_get_shadow_mode ( p_instance - > base ) ) {
case RS : : LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL :
splits = 1 ;
break ;
case RS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS :
splits = 2 ;
break ;
case RS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS :
splits = 4 ;
break ;
}
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
real_t distances [ 5 ] ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
distances [ 0 ] = min_distance ;
for ( int i = 0 ; i < splits ; i + + ) {
distances [ i + 1 ] = min_distance + RSG : : storage - > light_get_param ( p_instance - > base , RS : : LightParam ( RS : : LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i ) ) * range ;
} ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
distances [ splits ] = max_distance ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t texture_size = scene_render - > get_directional_light_shadow_size ( light - > instance ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
bool overlap = RSG : : storage - > light_directional_get_blend_splits ( p_instance - > base ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t first_radius = 0.0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t min_distance_bias_scale = distances [ 1 ] ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
cull . shadow_count = p_shadow_index + 1 ;
cull . shadows [ p_shadow_index ] . cascade_count = splits ;
cull . shadows [ p_shadow_index ] . light_instance = light - > instance ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int i = 0 ; i < splits ; i + + ) {
RENDER_TIMESTAMP ( " Culling Directional Light split " + itos ( i ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
// setup a camera matrix for that range!
CameraMatrix camera_matrix ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t aspect = p_cam_projection . get_aspect ( ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( p_cam_orthogonal ) {
Vector2 vp_he = p_cam_projection . get_viewport_half_extents ( ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
camera_matrix . set_orthogonal ( vp_he . y * 2.0 , aspect , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , false ) ;
} else {
real_t fov = p_cam_projection . get_fov ( ) ; //this is actually yfov, because set aspect tries to keep it
camera_matrix . set_perspective ( fov , aspect , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , true ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//obtain the frustum endpoints
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Vector3 endpoints [ 8 ] ; // frustum plane endpoints
bool res = camera_matrix . get_endpoints ( p_cam_transform , endpoints ) ;
ERR_CONTINUE ( ! res ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
// obtain the light frustum ranges (given endpoints)
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Transform transform = light_transform ; //discard scale and stabilize light
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Vector3 x_vec = transform . basis . get_axis ( Vector3 : : AXIS_X ) . normalized ( ) ;
Vector3 y_vec = transform . basis . get_axis ( Vector3 : : AXIS_Y ) . normalized ( ) ;
Vector3 z_vec = transform . basis . get_axis ( Vector3 : : AXIS_Z ) . normalized ( ) ;
//z_vec points against the camera, like in default opengl
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t x_min = 0.f , x_max = 0.f ;
real_t y_min = 0.f , y_max = 0.f ;
real_t z_min = 0.f , z_max = 0.f ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
// FIXME: z_max_cam is defined, computed, but not used below when setting up
// ortho_camera. Commented out for now to fix warnings but should be investigated.
real_t x_min_cam = 0.f , x_max_cam = 0.f ;
real_t y_min_cam = 0.f , y_max_cam = 0.f ;
real_t z_min_cam = 0.f ;
//real_t z_max_cam = 0.f;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t bias_scale = 1.0 ;
real_t aspect_bias_scale = 1.0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//used for culling
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
real_t d_x = x_vec . dot ( endpoints [ j ] ) ;
real_t d_y = y_vec . dot ( endpoints [ j ] ) ;
real_t d_z = z_vec . dot ( endpoints [ j ] ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( j = = 0 | | d_x < x_min ) {
x_min = d_x ;
}
if ( j = = 0 | | d_x > x_max ) {
x_max = d_x ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( j = = 0 | | d_y < y_min ) {
y_min = d_y ;
}
if ( j = = 0 | | d_y > y_max ) {
y_max = d_y ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( j = = 0 | | d_z < z_min ) {
z_min = d_z ;
}
if ( j = = 0 | | d_z > z_max ) {
z_max = d_z ;
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t radius = 0 ;
real_t soft_shadow_expand = 0 ;
Vector3 center ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
{
//camera viewport stuff
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
center + = endpoints [ j ] ;
}
center / = 8.0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
real_t d = center . distance_to ( endpoints [ j ] ) ;
if ( d > radius ) {
radius = d ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
radius * = texture_size / ( texture_size - 2.0 ) ; //add a texel by each side
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( i = = 0 ) {
first_radius = radius ;
} else {
bias_scale = radius / first_radius ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
z_min_cam = z_vec . dot ( center ) - radius ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
{
float soft_shadow_angle = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_SIZE ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( soft_shadow_angle > 0.0 ) {
float z_range = ( z_vec . dot ( center ) + radius + pancake_size ) - z_min_cam ;
soft_shadow_expand = Math : : tan ( Math : : deg2rad ( soft_shadow_angle ) ) * z_range ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
x_max + = soft_shadow_expand ;
y_max + = soft_shadow_expand ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
x_min - = soft_shadow_expand ;
y_min - = soft_shadow_expand ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
x_max_cam = x_vec . dot ( center ) + radius + soft_shadow_expand ;
x_min_cam = x_vec . dot ( center ) - radius - soft_shadow_expand ;
y_max_cam = y_vec . dot ( center ) + radius + soft_shadow_expand ;
y_min_cam = y_vec . dot ( center ) - radius - soft_shadow_expand ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
if ( depth_range_mode = = RS : : LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE ) {
//this trick here is what stabilizes the shadow (make potential jaggies to not move)
//at the cost of some wasted resolution. Still the quality increase is very well worth it
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
real_t unit = radius * 2.0 / texture_size ;
2020-12-23 17:52:58 +01:00
2020-12-21 19:02:57 +01:00
x_max_cam = Math : : snapped ( x_max_cam , unit ) ;
x_min_cam = Math : : snapped ( x_min_cam , unit ) ;
y_max_cam = Math : : snapped ( y_max_cam , unit ) ;
y_min_cam = Math : : snapped ( y_min_cam , unit ) ;
2020-12-26 13:05:36 +01:00
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//now that we know all ranges, we can proceed to make the light frustum planes, for culling octree
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Vector < Plane > light_frustum_planes ;
light_frustum_planes . resize ( 6 ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//right/left
light_frustum_planes . write [ 0 ] = Plane ( x_vec , x_max ) ;
light_frustum_planes . write [ 1 ] = Plane ( - x_vec , - x_min ) ;
//top/bottom
light_frustum_planes . write [ 2 ] = Plane ( y_vec , y_max ) ;
light_frustum_planes . write [ 3 ] = Plane ( - y_vec , - y_min ) ;
//near/far
light_frustum_planes . write [ 4 ] = Plane ( z_vec , z_max + 1e6 ) ;
light_frustum_planes . write [ 5 ] = Plane ( - z_vec , - z_min ) ; // z_min is ok, since casters further than far-light plane are not needed
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
// a pre pass will need to be needed to determine the actual z-near to be used
2020-12-16 15:07:08 +01:00
2020-12-26 13:05:36 +01:00
if ( pancake_size > 0 ) {
z_max = z_vec . dot ( center ) + radius + pancake_size ;
}
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
if ( aspect ! = 1.0 ) {
// if the aspect is different, then the radius will become larger.
// if this happens, then bias needs to be adjusted too, as depth will increase
// to do this, compare the depth of one that would have resulted from a square frustum
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
CameraMatrix camera_matrix_square ;
if ( p_cam_orthogonal ) {
Vector2 vp_he = camera_matrix . get_viewport_half_extents ( ) ;
if ( p_cam_vaspect ) {
camera_matrix_square . set_orthogonal ( vp_he . x * 2.0 , 1.0 , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , true ) ;
} else {
camera_matrix_square . set_orthogonal ( vp_he . y * 2.0 , 1.0 , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , false ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
} else {
Vector2 vp_he = camera_matrix . get_viewport_half_extents ( ) ;
if ( p_cam_vaspect ) {
camera_matrix_square . set_frustum ( vp_he . x * 2.0 , 1.0 , Vector2 ( ) , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , true ) ;
} else {
camera_matrix_square . set_frustum ( vp_he . y * 2.0 , 1.0 , Vector2 ( ) , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , false ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Vector3 endpoints_square [ 8 ] ; // frustum plane endpoints
res = camera_matrix_square . get_endpoints ( p_cam_transform , endpoints_square ) ;
ERR_CONTINUE ( ! res ) ;
Vector3 center_square ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
center_square + = endpoints_square [ j ] ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
center_square / = 8.0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t radius_square = 0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
real_t d = center_square . distance_to ( endpoints_square [ j ] ) ;
if ( d > radius_square ) {
radius_square = d ;
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
radius_square * = texture_size / ( texture_size - 2.0 ) ; //add a texel by each side
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
float z_max_square = z_vec . dot ( center_square ) + radius_square + pancake_size ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
real_t z_min_cam_square = z_vec . dot ( center_square ) - radius_square ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
aspect_bias_scale = ( z_max - z_min_cam ) / ( z_max_square - z_min_cam_square ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
// this is not entirely perfect, because the cull-adjusted z-max may be different
// but at least it's warranted that it results in a greater bias, so no acne should be present either way.
// pancaking also helps with this.
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
{
CameraMatrix ortho_camera ;
real_t half_x = ( x_max_cam - x_min_cam ) * 0.5 ;
real_t half_y = ( y_max_cam - y_min_cam ) * 0.5 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
ortho_camera . set_orthogonal ( - half_x , half_x , - half_y , half_y , 0 , ( z_max - z_min_cam ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Vector2 uv_scale ( 1.0 / ( x_max_cam - x_min_cam ) , 1.0 / ( y_max_cam - y_min_cam ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Transform ortho_transform ;
ortho_transform . basis = transform . basis ;
ortho_transform . origin = x_vec * ( x_min_cam + half_x ) + y_vec * ( y_min_cam + half_y ) + z_vec * z_max ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
cull . shadows [ p_shadow_index ] . cascades [ i ] . frustum = Frustum ( light_frustum_planes ) ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . projection = ortho_camera ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . transform = ortho_transform ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . zfar = z_max - z_min_cam ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . split = distances [ i + 1 ] ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . shadow_texel_size = radius * 2.0 / texture_size ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . bias_scale = bias_scale * aspect_bias_scale * min_distance_bias_scale ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . range_begin = z_max ;
cull . shadows [ p_shadow_index ] . cascades [ i ] . uv_scale = uv_scale ;
}
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
bool RendererSceneCull : : _light_instance_update_shadow ( Instance * p_instance , const Transform p_cam_transform , const CameraMatrix & p_cam_projection , bool p_cam_orthogonal , bool p_cam_vaspect , RID p_shadow_atlas , Scenario * p_scenario , float p_screen_lod_threshold ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( p_instance - > base_data ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
Transform light_transform = p_instance - > transform ;
light_transform . orthonormalize ( ) ; //scale does not count on lights
2020-12-16 15:07:08 +01:00
2020-12-26 13:05:36 +01:00
bool animated_material_found = false ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
switch ( RSG : : storage - > light_get_type ( p_instance - > base ) ) {
case RS : : LIGHT_DIRECTIONAL : {
2020-12-03 22:09:47 +01:00
} break ;
case RS : : LIGHT_OMNI : {
RS : : LightOmniShadowMode shadow_mode = RSG : : storage - > light_omni_get_shadow_mode ( p_instance - > base ) ;
if ( shadow_mode = = RS : : LIGHT_OMNI_SHADOW_DUAL_PARABOLOID | | ! scene_render - > light_instances_can_render_shadow_cube ( ) ) {
for ( int i = 0 ; i < 2 ; i + + ) {
//using this one ensures that raster deferred will have it
RENDER_TIMESTAMP ( " Culling Shadow Paraboloid " + itos ( i ) ) ;
real_t radius = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_RANGE ) ;
real_t z = i = = 0 ? - 1 : 1 ;
Vector < Plane > planes ;
planes . resize ( 6 ) ;
planes . write [ 0 ] = light_transform . xform ( Plane ( Vector3 ( 0 , 0 , z ) , radius ) ) ;
planes . write [ 1 ] = light_transform . xform ( Plane ( Vector3 ( 1 , 0 , z ) . normalized ( ) , radius ) ) ;
planes . write [ 2 ] = light_transform . xform ( Plane ( Vector3 ( - 1 , 0 , z ) . normalized ( ) , radius ) ) ;
planes . write [ 3 ] = light_transform . xform ( Plane ( Vector3 ( 0 , 1 , z ) . normalized ( ) , radius ) ) ;
planes . write [ 4 ] = light_transform . xform ( Plane ( Vector3 ( 0 , - 1 , z ) . normalized ( ) , radius ) ) ;
planes . write [ 5 ] = light_transform . xform ( Plane ( Vector3 ( 0 , 0 , - z ) , 0 ) ) ;
2020-12-23 17:52:58 +01:00
geometry_instances_to_shadow_render . clear ( ) ;
instance_shadow_cull_result . clear ( ) ;
Vector < Vector3 > points = Geometry3D : : compute_convex_mesh_points ( & planes [ 0 ] , planes . size ( ) ) ;
struct CullConvex {
PagedArray < Instance * > * result ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
result - > push_back ( p_instance ) ;
return false ;
}
} ;
CullConvex cull_convex ;
cull_convex . result = & instance_shadow_cull_result ;
p_scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . convex_query ( planes . ptr ( ) , planes . size ( ) , points . ptr ( ) , points . size ( ) , cull_convex ) ;
2020-12-03 22:09:47 +01:00
Plane near_plane ( light_transform . origin , light_transform . basis . get_axis ( 2 ) * z ) ;
2020-12-23 17:52:58 +01:00
for ( int j = 0 ; j < ( int ) instance_shadow_cull_result . size ( ) ; j + + ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_shadow_cull_result [ j ] ;
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows ) {
2020-12-23 17:52:58 +01:00
continue ;
2020-12-03 22:09:47 +01:00
} else {
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
}
2020-12-16 15:07:08 +01:00
if ( instance - > mesh_instance . is_valid ( ) ) {
RSG : : storage - > mesh_instance_check_for_update ( instance - > mesh_instance ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
geometry_instances_to_shadow_render . push_back ( instance ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-16 15:07:08 +01:00
RSG : : storage - > update_mesh_instances ( ) ;
2020-12-03 22:09:47 +01:00
scene_render - > light_instance_set_shadow_transform ( light - > instance , CameraMatrix ( ) , light_transform , radius , 0 , i , 0 ) ;
2020-12-23 17:52:58 +01:00
scene_render - > render_shadow ( light - > instance , p_shadow_atlas , i , geometry_instances_to_shadow_render ) ;
2020-12-03 22:09:47 +01:00
}
} else { //shadow cube
real_t radius = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_RANGE ) ;
CameraMatrix cm ;
cm . set_perspective ( 90 , 1 , 0.01 , radius ) ;
for ( int i = 0 ; i < 6 ; i + + ) {
RENDER_TIMESTAMP ( " Culling Shadow Cube side " + itos ( i ) ) ;
//using this one ensures that raster deferred will have it
static const Vector3 view_normals [ 6 ] = {
Vector3 ( + 1 , 0 , 0 ) ,
Vector3 ( - 1 , 0 , 0 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , + 1 , 0 ) ,
Vector3 ( 0 , 0 , + 1 ) ,
Vector3 ( 0 , 0 , - 1 )
} ;
static const Vector3 view_up [ 6 ] = {
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , 0 , - 1 ) ,
Vector3 ( 0 , 0 , + 1 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , - 1 , 0 )
} ;
Transform xform = light_transform * Transform ( ) . looking_at ( view_normals [ i ] , view_up [ i ] ) ;
Vector < Plane > planes = cm . get_projection_planes ( xform ) ;
2020-12-23 17:52:58 +01:00
geometry_instances_to_shadow_render . clear ( ) ;
instance_shadow_cull_result . clear ( ) ;
Vector < Vector3 > points = Geometry3D : : compute_convex_mesh_points ( & planes [ 0 ] , planes . size ( ) ) ;
struct CullConvex {
PagedArray < Instance * > * result ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
result - > push_back ( p_instance ) ;
return false ;
}
} ;
CullConvex cull_convex ;
cull_convex . result = & instance_shadow_cull_result ;
p_scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . convex_query ( planes . ptr ( ) , planes . size ( ) , points . ptr ( ) , points . size ( ) , cull_convex ) ;
2020-12-03 22:09:47 +01:00
Plane near_plane ( xform . origin , - xform . basis . get_axis ( 2 ) ) ;
2020-12-23 17:52:58 +01:00
for ( int j = 0 ; j < ( int ) instance_shadow_cull_result . size ( ) ; j + + ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_shadow_cull_result [ j ] ;
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows ) {
2020-12-23 17:52:58 +01:00
continue ;
2020-12-03 22:09:47 +01:00
} else {
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
}
2020-12-16 15:07:08 +01:00
if ( instance - > mesh_instance . is_valid ( ) ) {
RSG : : storage - > mesh_instance_check_for_update ( instance - > mesh_instance ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
geometry_instances_to_shadow_render . push_back ( instance ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-16 15:07:08 +01:00
RSG : : storage - > update_mesh_instances ( ) ;
2020-12-03 22:09:47 +01:00
scene_render - > light_instance_set_shadow_transform ( light - > instance , cm , xform , radius , 0 , i , 0 ) ;
2020-12-23 17:52:58 +01:00
scene_render - > render_shadow ( light - > instance , p_shadow_atlas , i , geometry_instances_to_shadow_render ) ;
2020-12-03 22:09:47 +01:00
}
//restore the regular DP matrix
scene_render - > light_instance_set_shadow_transform ( light - > instance , CameraMatrix ( ) , light_transform , radius , 0 , 0 , 0 ) ;
}
} break ;
case RS : : LIGHT_SPOT : {
RENDER_TIMESTAMP ( " Culling Spot Light " ) ;
real_t radius = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_RANGE ) ;
real_t angle = RSG : : storage - > light_get_param ( p_instance - > base , RS : : LIGHT_PARAM_SPOT_ANGLE ) ;
CameraMatrix cm ;
cm . set_perspective ( angle * 2.0 , 1.0 , 0.01 , radius ) ;
Vector < Plane > planes = cm . get_projection_planes ( light_transform ) ;
2020-12-23 17:52:58 +01:00
geometry_instances_to_shadow_render . clear ( ) ;
instance_shadow_cull_result . clear ( ) ;
Vector < Vector3 > points = Geometry3D : : compute_convex_mesh_points ( & planes [ 0 ] , planes . size ( ) ) ;
struct CullConvex {
PagedArray < Instance * > * result ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
result - > push_back ( p_instance ) ;
return false ;
}
} ;
CullConvex cull_convex ;
cull_convex . result = & instance_shadow_cull_result ;
p_scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . convex_query ( planes . ptr ( ) , planes . size ( ) , points . ptr ( ) , points . size ( ) , cull_convex ) ;
2020-12-03 22:09:47 +01:00
Plane near_plane ( light_transform . origin , - light_transform . basis . get_axis ( 2 ) ) ;
2020-12-23 17:52:58 +01:00
for ( int j = 0 ; j < ( int ) instance_shadow_cull_result . size ( ) ; j + + ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_shadow_cull_result [ j ] ;
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows ) {
2020-12-23 17:52:58 +01:00
continue ;
2020-12-03 22:09:47 +01:00
} else {
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
}
2020-12-16 15:07:08 +01:00
if ( instance - > mesh_instance . is_valid ( ) ) {
RSG : : storage - > mesh_instance_check_for_update ( instance - > mesh_instance ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
geometry_instances_to_shadow_render . push_back ( instance ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-16 15:07:08 +01:00
RSG : : storage - > update_mesh_instances ( ) ;
2020-12-03 22:09:47 +01:00
scene_render - > light_instance_set_shadow_transform ( light - > instance , cm , light_transform , radius , 0 , 0 , 0 ) ;
2020-12-23 17:52:58 +01:00
scene_render - > render_shadow ( light - > instance , p_shadow_atlas , 0 , geometry_instances_to_shadow_render ) ;
2020-12-03 22:09:47 +01:00
} break ;
}
return animated_material_found ;
}
2020-12-17 19:56:59 +01:00
void RendererSceneCull : : render_camera ( RID p_render_buffers , RID p_camera , RID p_scenario , Size2 p_viewport_size , float p_screen_lod_threshold , RID p_shadow_atlas ) {
2020-12-03 22:09:47 +01:00
// render to mono camera
# ifndef _3D_DISABLED
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
/* STEP 1 - SETUP CAMERA */
CameraMatrix camera_matrix ;
bool ortho = false ;
switch ( camera - > type ) {
case Camera : : ORTHOGONAL : {
camera_matrix . set_orthogonal (
camera - > size ,
p_viewport_size . width / ( float ) p_viewport_size . height ,
camera - > znear ,
camera - > zfar ,
camera - > vaspect ) ;
ortho = true ;
} break ;
case Camera : : PERSPECTIVE : {
camera_matrix . set_perspective (
camera - > fov ,
p_viewport_size . width / ( float ) p_viewport_size . height ,
camera - > znear ,
camera - > zfar ,
camera - > vaspect ) ;
ortho = false ;
} break ;
case Camera : : FRUSTUM : {
camera_matrix . set_frustum (
camera - > size ,
p_viewport_size . width / ( float ) p_viewport_size . height ,
camera - > offset ,
camera - > znear ,
camera - > zfar ,
camera - > vaspect ) ;
ortho = false ;
} break ;
}
RID environment = _render_get_environment ( p_camera , p_scenario ) ;
2020-12-17 19:56:59 +01:00
_prepare_scene ( camera - > transform , camera_matrix , ortho , camera - > vaspect , p_render_buffers , environment , camera - > visible_layers , p_scenario , p_shadow_atlas , RID ( ) , p_screen_lod_threshold ) ;
_render_scene ( p_render_buffers , camera - > transform , camera_matrix , ortho , environment , camera - > effects , p_scenario , p_shadow_atlas , RID ( ) , - 1 , p_screen_lod_threshold ) ;
2020-12-03 22:09:47 +01:00
# endif
}
2020-12-17 19:56:59 +01:00
void RendererSceneCull : : render_camera ( RID p_render_buffers , Ref < XRInterface > & p_interface , XRInterface : : Eyes p_eye , RID p_camera , RID p_scenario , Size2 p_viewport_size , float p_screen_lod_threshold , RID p_shadow_atlas ) {
2020-12-03 22:09:47 +01:00
// render for AR/VR interface
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
/* SETUP CAMERA, we are ignoring type and FOV here */
float aspect = p_viewport_size . width / ( float ) p_viewport_size . height ;
CameraMatrix camera_matrix = p_interface - > get_projection_for_eye ( p_eye , aspect , camera - > znear , camera - > zfar ) ;
// We also ignore our camera position, it will have been positioned with a slightly old tracking position.
// Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo!
Transform world_origin = XRServer : : get_singleton ( ) - > get_world_origin ( ) ;
Transform cam_transform = p_interface - > get_transform_for_eye ( p_eye , world_origin ) ;
RID environment = _render_get_environment ( p_camera , p_scenario ) ;
// For stereo render we only prepare for our left eye and then reuse the outcome for our right eye
if ( p_eye = = XRInterface : : EYE_LEFT ) {
// Center our transform, we assume basis is equal.
Transform mono_transform = cam_transform ;
Transform right_transform = p_interface - > get_transform_for_eye ( XRInterface : : EYE_RIGHT , world_origin ) ;
mono_transform . origin + = right_transform . origin ;
mono_transform . origin * = 0.5 ;
// We need to combine our projection frustums for culling.
// Ideally we should use our clipping planes for this and combine them,
// however our shadow map logic uses our projection matrix.
// Note: as our left and right frustums should be mirrored, we don't need our right projection matrix.
// - get some base values we need
float eye_dist = ( mono_transform . origin - cam_transform . origin ) . length ( ) ;
float z_near = camera_matrix . get_z_near ( ) ; // get our near plane
float z_far = camera_matrix . get_z_far ( ) ; // get our far plane
float width = ( 2.0 * z_near ) / camera_matrix . matrix [ 0 ] [ 0 ] ;
float x_shift = width * camera_matrix . matrix [ 2 ] [ 0 ] ;
float height = ( 2.0 * z_near ) / camera_matrix . matrix [ 1 ] [ 1 ] ;
float y_shift = height * camera_matrix . matrix [ 2 ] [ 1 ] ;
// printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift);
// - calculate our near plane size (horizontal only, right_near is mirrored)
float left_near = - eye_dist - ( ( width - x_shift ) * 0.5 ) ;
// - calculate our far plane size (horizontal only, right_far is mirrored)
float left_far = - eye_dist - ( z_far * ( width - x_shift ) * 0.5 / z_near ) ;
float left_far_right_eye = eye_dist - ( z_far * ( width + x_shift ) * 0.5 / z_near ) ;
if ( left_far > left_far_right_eye ) {
// on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes.
left_far = left_far_right_eye ;
}
// - figure out required z-shift
float slope = ( left_far - left_near ) / ( z_far - z_near ) ;
float z_shift = ( left_near / slope ) - z_near ;
// - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift)
float top_near = ( height - y_shift ) * 0.5 ;
top_near + = ( top_near / z_near ) * z_shift ;
float bottom_near = - ( height + y_shift ) * 0.5 ;
bottom_near + = ( bottom_near / z_near ) * z_shift ;
// printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift);
// - generate our frustum
CameraMatrix combined_matrix ;
combined_matrix . set_frustum ( left_near , - left_near , bottom_near , top_near , z_near + z_shift , z_far + z_shift ) ;
// and finally move our camera back
Transform apply_z_shift ;
apply_z_shift . origin = Vector3 ( 0.0 , 0.0 , z_shift ) ; // z negative is forward so this moves it backwards
mono_transform * = apply_z_shift ;
// now prepare our scene with our adjusted transform projection matrix
2020-12-17 19:56:59 +01:00
_prepare_scene ( mono_transform , combined_matrix , false , false , p_render_buffers , environment , camera - > visible_layers , p_scenario , p_shadow_atlas , RID ( ) , p_screen_lod_threshold ) ;
2020-12-03 22:09:47 +01:00
} else if ( p_eye = = XRInterface : : EYE_MONO ) {
// For mono render, prepare as per usual
2020-12-17 19:56:59 +01:00
_prepare_scene ( cam_transform , camera_matrix , false , false , p_render_buffers , environment , camera - > visible_layers , p_scenario , p_shadow_atlas , RID ( ) , p_screen_lod_threshold ) ;
2020-12-03 22:09:47 +01:00
}
// And render our scene...
2020-12-17 19:56:59 +01:00
_render_scene ( p_render_buffers , cam_transform , camera_matrix , false , environment , camera - > effects , p_scenario , p_shadow_atlas , RID ( ) , - 1 , p_screen_lod_threshold ) ;
2020-12-03 22:09:47 +01:00
} ;
2020-12-17 19:56:59 +01:00
void RendererSceneCull : : _prepare_scene ( const Transform p_cam_transform , const CameraMatrix & p_cam_projection , bool p_cam_orthogonal , bool p_cam_vaspect , RID p_render_buffers , RID p_environment , uint32_t p_visible_layers , RID p_scenario , RID p_shadow_atlas , RID p_reflection_probe , float p_screen_lod_threshold , bool p_using_shadows ) {
2020-12-03 22:09:47 +01:00
// Note, in stereo rendering:
// - p_cam_transform will be a transform in the middle of our two eyes
// - p_cam_projection is a wider frustrum that encompasses both eyes
2020-12-26 13:05:36 +01:00
Instance * render_reflection_probe = instance_owner . getornull ( p_reflection_probe ) ; //if null, not rendering to it
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
render_pass + + ;
scene_render - > set_scene_pass ( render_pass ) ;
if ( p_render_buffers . is_valid ( ) ) {
scene_render - > sdfgi_update ( p_render_buffers , p_environment , p_cam_transform . origin ) ; //update conditions for SDFGI (whether its used or not)
}
RENDER_TIMESTAMP ( " Frustum Culling " ) ;
//rasterizer->set_camera(camera->transform, camera_matrix,ortho);
Vector < Plane > planes = p_cam_projection . get_projection_planes ( p_cam_transform ) ;
Plane near_plane ( p_cam_transform . origin , - p_cam_transform . basis . get_axis ( 2 ) . normalized ( ) ) ;
2020-12-26 13:05:36 +01:00
uint64_t frame_number = RSG : : rasterizer - > get_frame_number ( ) ;
float lightmap_probe_update_speed = RSG : : storage - > lightmap_get_probe_capture_update_speed ( ) * RSG : : rasterizer - > get_frame_delta_time ( ) ;
2020-12-03 22:09:47 +01:00
/* STEP 2 - CULL */
2020-12-26 13:05:36 +01:00
cull . frustum = Frustum ( planes ) ;
Vector < RID > directional_lights ;
// directional lights
2020-12-23 17:52:58 +01:00
{
2020-12-26 13:05:36 +01:00
//reset shadows
for ( int i = 0 ; i < RendererSceneRender : : MAX_DIRECTIONAL_LIGHTS ; i + + ) {
for ( int j = 0 ; j < RendererSceneRender : : MAX_DIRECTIONAL_LIGHT_CASCADES ; j + + ) {
cull . shadows [ i ] . cascades [ j ] . cull_result . clear ( ) ;
}
}
cull . shadow_count = 0 ;
Vector < Instance * > lights_with_shadow ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
for ( List < Instance * > : : Element * E = scenario - > directional_lights . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! E - > get ( ) - > visible ) {
continue ;
}
if ( directional_lights . size ( ) > RendererSceneRender : : MAX_DIRECTIONAL_LIGHTS ) {
break ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
//check shadow..
if ( light ) {
if ( p_using_shadows & & p_shadow_atlas . is_valid ( ) & & RSG : : storage - > light_has_shadow ( E - > get ( ) - > base ) & & ! ( RSG : : storage - > light_get_type ( E - > get ( ) - > base ) = = RS : : LIGHT_DIRECTIONAL & & RSG : : storage - > light_directional_is_sky_only ( E - > get ( ) - > base ) ) ) {
lights_with_shadow . push_back ( E - > get ( ) ) ;
}
//add to list
directional_lights . push_back ( light - > instance ) ;
}
}
scene_render - > set_directional_shadow_count ( lights_with_shadow . size ( ) ) ;
for ( int i = 0 ; i < lights_with_shadow . size ( ) ; i + + ) {
_light_instance_setup_directional_shadow ( i , lights_with_shadow [ i ] , p_cam_transform , p_cam_projection , p_cam_orthogonal , p_cam_vaspect ) ;
}
2020-12-23 17:52:58 +01:00
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
{ //sdfgi
cull . sdfgi . region_count = 0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int i = 0 ; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE ; i + + ) {
cull . sdfgi . region_cull_result [ i ] . clear ( ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( int i = 0 ; i < SDFGI_MAX_CASCADES ; i + + ) {
cull . sdfgi . cascade_lights [ i ] . clear ( ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( p_render_buffers . is_valid ( ) ) {
for ( int i = 0 ; i < SDFGI_MAX_CASCADES ; i + + ) {
cull . sdfgi . cascade_lights [ i ] . clear ( ) ;
}
cull . sdfgi . cascade_light_count = 0 ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
uint32_t prev_cascade = 0xFFFFFFFF ;
uint32_t pending_region_count = scene_render - > sdfgi_get_pending_region_count ( p_render_buffers ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( uint32_t i = 0 ; i < pending_region_count ; i + + ) {
cull . sdfgi . region_aabb [ i ] = scene_render - > sdfgi_get_pending_region_bounds ( p_render_buffers , i ) ;
uint32_t region_cascade = scene_render - > sdfgi_get_pending_region_cascade ( p_render_buffers , i ) ;
cull . sdfgi . region_cascade [ i ] = region_cascade ;
if ( region_cascade ! = prev_cascade ) {
cull . sdfgi . cascade_light_index [ cull . sdfgi . cascade_light_count ] = region_cascade ;
cull . sdfgi . cascade_light_count + + ;
prev_cascade = region_cascade ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
cull . sdfgi . region_count = pending_region_count ;
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
{
//pre-clear results
geometry_instances_to_render . clear ( ) ;
light_cull_result . clear ( ) ;
lightmap_cull_result . clear ( ) ;
reflection_probe_instance_cull_result . clear ( ) ;
light_instance_cull_result . clear ( ) ;
gi_probe_instance_cull_result . clear ( ) ;
lightmap_cull_result . clear ( ) ;
decal_instance_cull_result . clear ( ) ;
mesh_instance_cull_result . clear ( ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
{
uint64_t cull_count = scenario - > instance_data . size ( ) ;
uint32_t sdfgi_last_light_index = 0xFFFFFFFF ;
uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF ;
for ( uint64_t i = 0 ; i < cull_count ; i + + ) {
bool mesh_visible = false ;
if ( scenario - > instance_aabbs [ i ] . in_frustum ( cull . frustum ) ) {
InstanceData & idata = scenario - > instance_data [ i ] ;
uint32_t base_type = idata . flags & InstanceData : : FLAG_BASE_TYPE_MASK ;
if ( ( p_visible_layers & idata . layer_mask ) = = 0 ) {
//failure
} else if ( base_type = = RS : : INSTANCE_LIGHT ) {
light_cull_result . push_back ( idata . instance ) ;
light_instance_cull_result . push_back ( idata . instance_data_rid ) ;
if ( p_shadow_atlas . is_valid ( ) & & RSG : : storage - > light_has_shadow ( idata . base_rid ) ) {
scene_render - > light_instance_mark_visible ( idata . instance_data_rid ) ; //mark it visible for shadow allocation later
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
} else if ( base_type = = RS : : INSTANCE_REFLECTION_PROBE ) {
if ( render_reflection_probe ! = idata . instance ) {
//avoid entering The Matrix
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
if ( ( idata . flags & InstanceData : : FLAG_REFLECTION_PROBE_DIRTY ) | | scene_render - > reflection_probe_instance_needs_redraw ( idata . instance_data_rid ) ) {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( idata . instance - > base_data ) ;
cull . lock . lock ( ) ;
if ( ! reflection_probe - > update_list . in_list ( ) ) {
reflection_probe - > render_step = 0 ;
reflection_probe_render_list . add_last ( & reflection_probe - > update_list ) ;
}
cull . lock . unlock ( ) ;
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_REFLECTION_PROBE_DIRTY ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( scene_render - > reflection_probe_instance_has_reflection ( idata . instance_data_rid ) ) {
reflection_probe_instance_cull_result . push_back ( idata . instance_data_rid ) ;
}
}
} else if ( base_type = = RS : : INSTANCE_DECAL ) {
decal_instance_cull_result . push_back ( idata . instance_data_rid ) ;
} else if ( base_type = = RS : : INSTANCE_GI_PROBE ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( idata . instance - > base_data ) ;
cull . lock . lock ( ) ;
if ( ! gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . add ( & gi_probe - > update_element ) ;
}
cull . lock . unlock ( ) ;
gi_probe_instance_cull_result . push_back ( idata . instance_data_rid ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
} else if ( base_type = = RS : : INSTANCE_LIGHTMAP ) {
lightmap_cull_result . push_back ( idata . instance ) ;
} else if ( ( ( 1 < < base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) & & ! ( idata . flags & InstanceData : : FLAG_CAST_SHADOWS_ONLY ) ) {
bool keep = true ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( idata . flags & InstanceData : : FLAG_REDRAW_IF_VISIBLE ) {
RenderingServerDefault : : redraw_request ( ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( base_type = = RS : : INSTANCE_MESH ) {
mesh_visible = true ;
} else if ( base_type = = RS : : INSTANCE_PARTICLES ) {
//particles visible? process them
if ( RSG : : storage - > particles_is_inactive ( idata . base_rid ) ) {
//but if nothing is going on, don't do it.
keep = false ;
} else {
cull . lock . lock ( ) ;
RSG : : storage - > particles_request_process ( idata . base_rid ) ;
cull . lock . unlock ( ) ;
RSG : : storage - > particles_set_view_axis ( idata . base_rid , - p_cam_transform . basis . get_axis ( 2 ) . normalized ( ) ) ;
//particles visible? request redraw
RenderingServerDefault : : redraw_request ( ) ;
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( pair_volumes_to_mesh & & ( idata . flags & InstanceData : : FLAG_GEOM_LIGHTING_DIRTY ) ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( idata . instance - > base_data ) ;
int l = 0 ;
//only called when lights AABB enter/exit this geometry
idata . instance - > light_instances . resize ( geom - > lights . size ( ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( Set < Instance * > : : Element * E = geom - > lights . front ( ) ; E ; E = E - > next ( ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
idata . instance - > light_instances . write [ l + + ] = light - > instance ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_GEOM_LIGHTING_DIRTY ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( pair_volumes_to_mesh & & ( idata . flags & InstanceData : : FLAG_GEOM_REFLECTION_DIRTY ) ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( idata . instance - > base_data ) ;
int l = 0 ;
//only called when reflection probe AABB enter/exit this geometry
idata . instance - > reflection_probe_instances . resize ( geom - > reflection_probes . size ( ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( Set < Instance * > : : Element * E = geom - > reflection_probes . front ( ) ; E ; E = E - > next ( ) ) {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( E - > get ( ) - > base_data ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
idata . instance - > reflection_probe_instances . write [ l + + ] = reflection_probe - > instance ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_GEOM_REFLECTION_DIRTY ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( pair_volumes_to_mesh & & ( idata . flags & InstanceData : : FLAG_GEOM_DECAL_DIRTY ) ) {
//InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
//todo for GLES3
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_GEOM_DECAL_DIRTY ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( idata . flags & InstanceData : : FLAG_GEOM_GI_PROBE_DIRTY ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( idata . instance - > base_data ) ;
int l = 0 ;
//only called when reflection probe AABB enter/exit this geometry
idata . instance - > gi_probe_instances . resize ( geom - > gi_probes . size ( ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
for ( Set < Instance * > : : Element * E = geom - > gi_probes . front ( ) ; E ; E = E - > next ( ) ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( E - > get ( ) - > base_data ) ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
idata . instance - > gi_probe_instances . write [ l + + ] = gi_probe - > probe_instance ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
idata . flags & = ~ uint32_t ( InstanceData : : FLAG_GEOM_GI_PROBE_DIRTY ) ;
}
2020-12-03 22:09:47 +01:00
2020-12-15 13:04:21 +01:00
if ( ( idata . flags & InstanceData : : FLAG_LIGHTMAP_CAPTURE ) & & idata . instance - > last_frame_pass ! = frame_number & & ! idata . instance - > lightmap_target_sh . is_empty ( ) & & ! idata . instance - > lightmap_sh . is_empty ( ) ) {
2020-12-26 13:05:36 +01:00
Color * sh = idata . instance - > lightmap_sh . ptrw ( ) ;
const Color * target_sh = idata . instance - > lightmap_target_sh . ptr ( ) ;
for ( uint32_t j = 0 ; j < 9 ; j + + ) {
sh [ j ] = sh [ j ] . lerp ( target_sh [ j ] , MIN ( 1.0 , lightmap_probe_update_speed ) ) ;
}
idata . instance - > last_frame_pass = frame_number ;
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( keep ) {
geometry_instances_to_render . push_back ( idata . instance ) ;
}
2020-12-03 22:09:47 +01:00
}
}
2020-12-26 13:05:36 +01:00
for ( uint32_t j = 0 ; j < cull . shadow_count ; j + + ) {
for ( uint32_t k = 0 ; k < cull . shadows [ j ] . cascade_count ; k + + ) {
if ( scenario - > instance_aabbs [ i ] . in_frustum ( cull . shadows [ j ] . cascades [ k ] . frustum ) ) {
InstanceData & idata = scenario - > instance_data [ i ] ;
uint32_t base_type = idata . flags & InstanceData : : FLAG_BASE_TYPE_MASK ;
if ( ( ( 1 < < base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) & & idata . flags & InstanceData : : FLAG_CAST_SHADOWS ) {
cull . shadows [ j ] . cascades [ k ] . cull_result . push_back ( idata . instance ) ;
mesh_visible = true ;
}
}
}
2020-12-16 15:07:08 +01:00
}
2020-12-26 13:05:36 +01:00
for ( uint32_t j = 0 ; j < cull . sdfgi . region_count ; j + + ) {
if ( scenario - > instance_aabbs [ i ] . in_aabb ( cull . sdfgi . region_aabb [ j ] ) ) {
InstanceData & idata = scenario - > instance_data [ i ] ;
uint32_t base_type = idata . flags & InstanceData : : FLAG_BASE_TYPE_MASK ;
if ( base_type = = RS : : INSTANCE_LIGHT ) {
InstanceLightData * instance_light = ( InstanceLightData * ) idata . instance - > base_data ;
if ( instance_light - > bake_mode = = RS : : LIGHT_BAKE_STATIC & & cull . sdfgi . region_cascade [ j ] < = instance_light - > max_sdfgi_cascade ) {
if ( sdfgi_last_light_index ! = i | | sdfgi_last_light_cascade ! = cull . sdfgi . region_cascade [ j ] ) {
sdfgi_last_light_index = i ;
sdfgi_last_light_cascade = cull . sdfgi . region_cascade [ j ] ;
cull . sdfgi . cascade_lights [ sdfgi_last_light_cascade ] . push_back ( instance_light - > instance ) ;
}
}
} else if ( ( 1 < < base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
if ( idata . flags & InstanceData : : FLAG_USES_BAKED_LIGHT ) {
cull . sdfgi . region_cull_result [ j ] . push_back ( idata . instance ) ;
mesh_visible = true ;
}
}
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( mesh_visible & & scenario - > instance_data [ i ] . flags & InstanceData : : FLAG_USES_MESH_INSTANCE ) {
mesh_instance_cull_result . push_back ( scenario - > instance_data [ i ] . instance - > mesh_instance ) ;
2020-12-23 17:52:58 +01:00
}
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
if ( mesh_instance_cull_result . size ( ) ) {
for ( uint64_t i = 0 ; i < mesh_instance_cull_result . size ( ) ; i + + ) {
RSG : : storage - > mesh_instance_check_for_update ( mesh_instance_cull_result [ i ] ) ;
}
RSG : : storage - > update_mesh_instances ( ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
//render shadows
2020-12-16 15:07:08 +01:00
2020-12-26 13:05:36 +01:00
for ( uint32_t i = 0 ; i < cull . shadow_count ; i + + ) {
for ( uint32_t j = 0 ; j < cull . shadows [ i ] . cascade_count ; j + + ) {
const Cull : : Shadow : : Cascade & c = cull . shadows [ i ] . cascades [ j ] ;
// print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size()));
scene_render - > light_instance_set_shadow_transform ( cull . shadows [ i ] . light_instance , c . projection , c . transform , c . zfar , c . split , j , c . shadow_texel_size , c . bias_scale , c . range_begin , c . uv_scale ) ;
scene_render - > render_shadow ( cull . shadows [ i ] . light_instance , p_shadow_atlas , j , c . cull_result , near_plane , p_cam_projection . get_lod_multiplier ( ) , p_screen_lod_threshold ) ;
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//render SDFGI
2020-12-03 22:09:47 +01:00
{
2020-12-26 13:05:36 +01:00
if ( cull . sdfgi . region_count > 0 ) {
//update regions
for ( uint32_t i = 0 ; i < cull . sdfgi . region_count ; i + + ) {
scene_render - > render_sdfgi ( p_render_buffers , i , cull . sdfgi . region_cull_result [ i ] ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
//check if static lights were culled
bool static_lights_culled = false ;
for ( uint32_t i = 0 ; i < cull . sdfgi . cascade_light_count ; i + + ) {
if ( cull . sdfgi . cascade_lights [ i ] . size ( ) ) {
static_lights_culled = true ;
break ;
2020-12-03 22:09:47 +01:00
}
}
2020-12-23 17:52:58 +01:00
2020-12-26 13:05:36 +01:00
if ( static_lights_culled ) {
scene_render - > render_sdfgi_static_lights ( p_render_buffers , cull . sdfgi . cascade_light_count , cull . sdfgi . cascade_light_index , cull . sdfgi . cascade_lights ) ;
}
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
if ( p_render_buffers . is_valid ( ) ) {
scene_render - > sdfgi_update_probes ( p_render_buffers , p_environment , directional_lights , scenario - > dynamic_lights . ptr ( ) , scenario - > dynamic_lights . size ( ) ) ;
}
}
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
//light_samplers_culled=0;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
/*
print_line ( " OT: " + rtos ( ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - t ) / 1000.0 ) ) ;
print_line ( " OTO: " + itos ( p_scenario - > octree . get_octant_count ( ) ) ) ;
print_line ( " OTE: " + itos ( p_scenario - > octree . get_elem_count ( ) ) ) ;
print_line ( " OTP: " + itos ( p_scenario - > octree . get_pair_count ( ) ) ) ;
*/
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
/* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */
//removed, will replace with culling
/* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */
/* STEP 5 - PROCESS POSITIONAL LIGHTS */
2020-12-03 22:09:47 +01:00
if ( p_using_shadows ) { //setup shadow maps
//SortArray<Instance*,_InstanceLightsort> sorter;
//sorter.sort(light_cull_result,light_cull_count);
2020-12-23 17:52:58 +01:00
for ( uint32_t i = 0 ; i < ( uint32_t ) light_cull_result . size ( ) ; i + + ) {
2020-12-03 22:09:47 +01:00
Instance * ins = light_cull_result [ i ] ;
if ( ! p_shadow_atlas . is_valid ( ) | | ! RSG : : storage - > light_has_shadow ( ins - > base ) ) {
continue ;
}
InstanceLightData * light = static_cast < InstanceLightData * > ( ins - > base_data ) ;
float coverage = 0.f ;
{ //compute coverage
Transform cam_xf = p_cam_transform ;
float zn = p_cam_projection . get_z_near ( ) ;
Plane p ( cam_xf . origin + cam_xf . basis . get_axis ( 2 ) * - zn , - cam_xf . basis . get_axis ( 2 ) ) ; //camera near plane
// near plane half width and height
Vector2 vp_half_extents = p_cam_projection . get_viewport_half_extents ( ) ;
switch ( RSG : : storage - > light_get_type ( ins - > base ) ) {
case RS : : LIGHT_OMNI : {
float radius = RSG : : storage - > light_get_param ( ins - > base , RS : : LIGHT_PARAM_RANGE ) ;
//get two points parallel to near plane
Vector3 points [ 2 ] = {
ins - > transform . origin ,
ins - > transform . origin + cam_xf . basis . get_axis ( 0 ) * radius
} ;
if ( ! p_cam_orthogonal ) {
//if using perspetive, map them to near plane
for ( int j = 0 ; j < 2 ; j + + ) {
if ( p . distance_to ( points [ j ] ) < 0 ) {
points [ j ] . z = - zn ; //small hack to keep size constant when hitting the screen
}
p . intersects_segment ( cam_xf . origin , points [ j ] , & points [ j ] ) ; //map to plane
}
}
float screen_diameter = points [ 0 ] . distance_to ( points [ 1 ] ) * 2 ;
coverage = screen_diameter / ( vp_half_extents . x + vp_half_extents . y ) ;
} break ;
case RS : : LIGHT_SPOT : {
float radius = RSG : : storage - > light_get_param ( ins - > base , RS : : LIGHT_PARAM_RANGE ) ;
float angle = RSG : : storage - > light_get_param ( ins - > base , RS : : LIGHT_PARAM_SPOT_ANGLE ) ;
float w = radius * Math : : sin ( Math : : deg2rad ( angle ) ) ;
float d = radius * Math : : cos ( Math : : deg2rad ( angle ) ) ;
Vector3 base = ins - > transform . origin - ins - > transform . basis . get_axis ( 2 ) . normalized ( ) * d ;
Vector3 points [ 2 ] = {
base ,
base + cam_xf . basis . get_axis ( 0 ) * w
} ;
if ( ! p_cam_orthogonal ) {
//if using perspetive, map them to near plane
for ( int j = 0 ; j < 2 ; j + + ) {
if ( p . distance_to ( points [ j ] ) < 0 ) {
points [ j ] . z = - zn ; //small hack to keep size constant when hitting the screen
}
p . intersects_segment ( cam_xf . origin , points [ j ] , & points [ j ] ) ; //map to plane
}
}
float screen_diameter = points [ 0 ] . distance_to ( points [ 1 ] ) * 2 ;
coverage = screen_diameter / ( vp_half_extents . x + vp_half_extents . y ) ;
} break ;
default : {
ERR_PRINT ( " Invalid Light Type " ) ;
}
}
}
if ( light - > shadow_dirty ) {
light - > last_version + + ;
light - > shadow_dirty = false ;
}
bool redraw = scene_render - > shadow_atlas_update_light ( p_shadow_atlas , light - > instance , coverage , light - > last_version ) ;
if ( redraw ) {
//must redraw!
RENDER_TIMESTAMP ( " >Rendering Light " + itos ( i ) ) ;
2020-12-17 19:56:59 +01:00
light - > shadow_dirty = _light_instance_update_shadow ( ins , p_cam_transform , p_cam_projection , p_cam_orthogonal , p_cam_vaspect , p_shadow_atlas , scenario , p_screen_lod_threshold ) ;
2020-12-03 22:09:47 +01:00
RENDER_TIMESTAMP ( " <Rendering Light " + itos ( i ) ) ;
}
}
}
2020-12-26 13:05:36 +01:00
//append the directional lights to the lights culled
for ( int i = 0 ; i < directional_lights . size ( ) ; i + + ) {
light_instance_cull_result . push_back ( directional_lights [ i ] ) ;
2020-12-03 22:09:47 +01:00
}
}
2020-12-04 19:26:24 +01:00
RID RendererSceneCull : : _render_get_environment ( RID p_camera , RID p_scenario ) {
2020-12-03 22:09:47 +01:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
if ( camera & & scene_render - > is_environment ( camera - > env ) ) {
return camera - > env ;
}
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
if ( ! scenario ) {
return RID ( ) ;
}
if ( scene_render - > is_environment ( scenario - > environment ) ) {
return scenario - > environment ;
}
if ( scene_render - > is_environment ( scenario - > fallback_environment ) ) {
return scenario - > fallback_environment ;
}
return RID ( ) ;
}
2020-12-17 19:56:59 +01:00
void RendererSceneCull : : _render_scene ( RID p_render_buffers , const Transform p_cam_transform , const CameraMatrix & p_cam_projection , bool p_cam_orthogonal , RID p_environment , RID p_force_camera_effects , RID p_scenario , RID p_shadow_atlas , RID p_reflection_probe , int p_reflection_probe_pass , float p_screen_lod_threshold ) {
2020-12-03 22:09:47 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
RID camera_effects ;
if ( p_force_camera_effects . is_valid ( ) ) {
camera_effects = p_force_camera_effects ;
} else {
camera_effects = scenario - > camera_effects ;
}
/* PROCESS GEOMETRY AND DRAW SCENE */
RENDER_TIMESTAMP ( " Render Scene " ) ;
2020-12-23 17:52:58 +01:00
scene_render - > render_scene ( p_render_buffers , p_cam_transform , p_cam_projection , p_cam_orthogonal , geometry_instances_to_render , light_instance_cull_result , reflection_probe_instance_cull_result , gi_probe_instance_cull_result , decal_instance_cull_result , lightmap_cull_result , p_environment , camera_effects , p_shadow_atlas , p_reflection_probe . is_valid ( ) ? RID ( ) : scenario - > reflection_atlas , p_reflection_probe , p_reflection_probe_pass , p_screen_lod_threshold ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : render_empty_scene ( RID p_render_buffers , RID p_scenario , RID p_shadow_atlas ) {
2020-12-03 22:09:47 +01:00
# ifndef _3D_DISABLED
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
RID environment ;
if ( scenario - > environment . is_valid ( ) ) {
environment = scenario - > environment ;
} else {
environment = scenario - > fallback_environment ;
}
RENDER_TIMESTAMP ( " Render Empty Scene " ) ;
2020-12-23 17:52:58 +01:00
scene_render - > render_scene ( p_render_buffers , Transform ( ) , CameraMatrix ( ) , true , PagedArray < RendererSceneRender : : InstanceBase * > ( ) , PagedArray < RID > ( ) , PagedArray < RID > ( ) , PagedArray < RID > ( ) , PagedArray < RID > ( ) , PagedArray < RendererSceneRender : : InstanceBase * > ( ) , RID ( ) , RID ( ) , p_shadow_atlas , scenario - > reflection_atlas , RID ( ) , 0 , 0 ) ;
2020-12-03 22:09:47 +01:00
# endif
}
2020-12-04 19:26:24 +01:00
bool RendererSceneCull : : _render_reflection_probe_step ( Instance * p_instance , int p_step ) {
2020-12-03 22:09:47 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( p_instance - > base_data ) ;
Scenario * scenario = p_instance - > scenario ;
ERR_FAIL_COND_V ( ! scenario , true ) ;
RenderingServerDefault : : redraw_request ( ) ; //update, so it updates in editor
if ( p_step = = 0 ) {
if ( ! scene_render - > reflection_probe_instance_begin_render ( reflection_probe - > instance , scenario - > reflection_atlas ) ) {
return true ; //all full
}
}
if ( p_step > = 0 & & p_step < 6 ) {
static const Vector3 view_normals [ 6 ] = {
Vector3 ( + 1 , 0 , 0 ) ,
Vector3 ( - 1 , 0 , 0 ) ,
Vector3 ( 0 , + 1 , 0 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , 0 , + 1 ) ,
Vector3 ( 0 , 0 , - 1 )
} ;
static const Vector3 view_up [ 6 ] = {
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , 0 , + 1 ) ,
Vector3 ( 0 , 0 , - 1 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , - 1 , 0 )
} ;
Vector3 extents = RSG : : storage - > reflection_probe_get_extents ( p_instance - > base ) ;
Vector3 origin_offset = RSG : : storage - > reflection_probe_get_origin_offset ( p_instance - > base ) ;
float max_distance = RSG : : storage - > reflection_probe_get_origin_max_distance ( p_instance - > base ) ;
2020-12-17 19:56:59 +01:00
float size = scene_render - > reflection_atlas_get_size ( scenario - > reflection_atlas ) ;
float lod_threshold = RSG : : storage - > reflection_probe_get_lod_threshold ( p_instance - > base ) / size ;
2020-12-03 22:09:47 +01:00
Vector3 edge = view_normals [ p_step ] * extents ;
float distance = ABS ( view_normals [ p_step ] . dot ( edge ) - view_normals [ p_step ] . dot ( origin_offset ) ) ; //distance from origin offset to actual view distance limit
max_distance = MAX ( max_distance , distance ) ;
//render cubemap side
CameraMatrix cm ;
cm . set_perspective ( 90 , 1 , 0.01 , max_distance ) ;
Transform local_view ;
local_view . set_look_at ( origin_offset , origin_offset + view_normals [ p_step ] , view_up [ p_step ] ) ;
Transform xform = p_instance - > transform * local_view ;
RID shadow_atlas ;
bool use_shadows = RSG : : storage - > reflection_probe_renders_shadows ( p_instance - > base ) ;
if ( use_shadows ) {
shadow_atlas = scenario - > reflection_probe_shadow_atlas ;
}
RENDER_TIMESTAMP ( " Render Reflection Probe, Step " + itos ( p_step ) ) ;
2020-12-17 19:56:59 +01:00
_prepare_scene ( xform , cm , false , false , RID ( ) , RID ( ) , RSG : : storage - > reflection_probe_get_cull_mask ( p_instance - > base ) , p_instance - > scenario - > self , shadow_atlas , reflection_probe - > instance , lod_threshold , use_shadows ) ;
_render_scene ( RID ( ) , xform , cm , false , RID ( ) , RID ( ) , p_instance - > scenario - > self , shadow_atlas , reflection_probe - > instance , p_step , lod_threshold ) ;
2020-12-03 22:09:47 +01:00
} else {
//do roughness postprocess step until it believes it's done
RENDER_TIMESTAMP ( " Post-Process Reflection Probe, Step " + itos ( p_step ) ) ;
return scene_render - > reflection_probe_instance_postprocess_step ( reflection_probe - > instance ) ;
}
return false ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : render_probes ( ) {
2020-12-03 22:09:47 +01:00
/* REFLECTION PROBES */
SelfList < InstanceReflectionProbeData > * ref_probe = reflection_probe_render_list . first ( ) ;
bool busy = false ;
while ( ref_probe ) {
SelfList < InstanceReflectionProbeData > * next = ref_probe - > next ( ) ;
RID base = ref_probe - > self ( ) - > owner - > base ;
switch ( RSG : : storage - > reflection_probe_get_update_mode ( base ) ) {
case RS : : REFLECTION_PROBE_UPDATE_ONCE : {
if ( busy ) { //already rendering something
break ;
}
bool done = _render_reflection_probe_step ( ref_probe - > self ( ) - > owner , ref_probe - > self ( ) - > render_step ) ;
if ( done ) {
reflection_probe_render_list . remove ( ref_probe ) ;
} else {
ref_probe - > self ( ) - > render_step + + ;
}
busy = true ; //do not render another one of this kind
} break ;
case RS : : REFLECTION_PROBE_UPDATE_ALWAYS : {
int step = 0 ;
bool done = false ;
while ( ! done ) {
done = _render_reflection_probe_step ( ref_probe - > self ( ) - > owner , step ) ;
step + + ;
}
reflection_probe_render_list . remove ( ref_probe ) ;
} break ;
}
ref_probe = next ;
}
/* GI PROBES */
SelfList < InstanceGIProbeData > * gi_probe = gi_probe_update_list . first ( ) ;
if ( gi_probe ) {
RENDER_TIMESTAMP ( " Render GI Probes " ) ;
}
while ( gi_probe ) {
SelfList < InstanceGIProbeData > * next = gi_probe - > next ( ) ;
InstanceGIProbeData * probe = gi_probe - > self ( ) ;
//Instance *instance_probe = probe->owner;
//check if probe must be setup, but don't do if on the lighting thread
bool cache_dirty = false ;
int cache_count = 0 ;
{
int light_cache_size = probe - > light_cache . size ( ) ;
const InstanceGIProbeData : : LightCache * caches = probe - > light_cache . ptr ( ) ;
const RID * instance_caches = probe - > light_instances . ptr ( ) ;
int idx = 0 ; //must count visible lights
for ( Set < Instance * > : : Element * E = probe - > lights . front ( ) ; E ; E = E - > next ( ) ) {
Instance * instance = E - > get ( ) ;
InstanceLightData * instance_light = ( InstanceLightData * ) instance - > base_data ;
if ( ! instance - > visible ) {
continue ;
}
if ( cache_dirty ) {
//do nothing, since idx must count all visible lights anyway
} else if ( idx > = light_cache_size ) {
cache_dirty = true ;
} else {
const InstanceGIProbeData : : LightCache * cache = & caches [ idx ] ;
if (
instance_caches [ idx ] ! = instance_light - > instance | |
cache - > has_shadow ! = RSG : : storage - > light_has_shadow ( instance - > base ) | |
cache - > type ! = RSG : : storage - > light_get_type ( instance - > base ) | |
cache - > transform ! = instance - > transform | |
cache - > color ! = RSG : : storage - > light_get_color ( instance - > base ) | |
cache - > energy ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ENERGY ) | |
cache - > bake_energy ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_INDIRECT_ENERGY ) | |
cache - > radius ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_RANGE ) | |
cache - > attenuation ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ATTENUATION ) | |
cache - > spot_angle ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ANGLE ) | |
cache - > spot_attenuation ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ATTENUATION ) ) {
cache_dirty = true ;
}
}
idx + + ;
}
for ( List < Instance * > : : Element * E = probe - > owner - > scenario - > directional_lights . front ( ) ; E ; E = E - > next ( ) ) {
Instance * instance = E - > get ( ) ;
InstanceLightData * instance_light = ( InstanceLightData * ) instance - > base_data ;
if ( ! instance - > visible ) {
continue ;
}
if ( cache_dirty ) {
//do nothing, since idx must count all visible lights anyway
} else if ( idx > = light_cache_size ) {
cache_dirty = true ;
} else {
const InstanceGIProbeData : : LightCache * cache = & caches [ idx ] ;
if (
instance_caches [ idx ] ! = instance_light - > instance | |
cache - > has_shadow ! = RSG : : storage - > light_has_shadow ( instance - > base ) | |
cache - > type ! = RSG : : storage - > light_get_type ( instance - > base ) | |
cache - > transform ! = instance - > transform | |
cache - > color ! = RSG : : storage - > light_get_color ( instance - > base ) | |
cache - > energy ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ENERGY ) | |
cache - > bake_energy ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_INDIRECT_ENERGY ) | |
cache - > radius ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_RANGE ) | |
cache - > attenuation ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ATTENUATION ) | |
cache - > spot_angle ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ANGLE ) | |
cache - > spot_attenuation ! = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ATTENUATION ) | |
cache - > sky_only ! = RSG : : storage - > light_directional_is_sky_only ( instance - > base ) ) {
cache_dirty = true ;
}
}
idx + + ;
}
if ( idx ! = light_cache_size ) {
cache_dirty = true ;
}
cache_count = idx ;
}
bool update_lights = scene_render - > gi_probe_needs_update ( probe - > probe_instance ) ;
if ( cache_dirty ) {
probe - > light_cache . resize ( cache_count ) ;
probe - > light_instances . resize ( cache_count ) ;
if ( cache_count ) {
InstanceGIProbeData : : LightCache * caches = probe - > light_cache . ptrw ( ) ;
RID * instance_caches = probe - > light_instances . ptrw ( ) ;
int idx = 0 ; //must count visible lights
for ( Set < Instance * > : : Element * E = probe - > lights . front ( ) ; E ; E = E - > next ( ) ) {
Instance * instance = E - > get ( ) ;
InstanceLightData * instance_light = ( InstanceLightData * ) instance - > base_data ;
if ( ! instance - > visible ) {
continue ;
}
InstanceGIProbeData : : LightCache * cache = & caches [ idx ] ;
instance_caches [ idx ] = instance_light - > instance ;
cache - > has_shadow = RSG : : storage - > light_has_shadow ( instance - > base ) ;
cache - > type = RSG : : storage - > light_get_type ( instance - > base ) ;
cache - > transform = instance - > transform ;
cache - > color = RSG : : storage - > light_get_color ( instance - > base ) ;
cache - > energy = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ENERGY ) ;
cache - > bake_energy = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_INDIRECT_ENERGY ) ;
cache - > radius = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_RANGE ) ;
cache - > attenuation = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ATTENUATION ) ;
cache - > spot_angle = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ANGLE ) ;
cache - > spot_attenuation = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ATTENUATION ) ;
idx + + ;
}
for ( List < Instance * > : : Element * E = probe - > owner - > scenario - > directional_lights . front ( ) ; E ; E = E - > next ( ) ) {
Instance * instance = E - > get ( ) ;
InstanceLightData * instance_light = ( InstanceLightData * ) instance - > base_data ;
if ( ! instance - > visible ) {
continue ;
}
InstanceGIProbeData : : LightCache * cache = & caches [ idx ] ;
instance_caches [ idx ] = instance_light - > instance ;
cache - > has_shadow = RSG : : storage - > light_has_shadow ( instance - > base ) ;
cache - > type = RSG : : storage - > light_get_type ( instance - > base ) ;
cache - > transform = instance - > transform ;
cache - > color = RSG : : storage - > light_get_color ( instance - > base ) ;
cache - > energy = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ENERGY ) ;
cache - > bake_energy = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_INDIRECT_ENERGY ) ;
cache - > radius = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_RANGE ) ;
cache - > attenuation = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_ATTENUATION ) ;
cache - > spot_angle = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ANGLE ) ;
cache - > spot_attenuation = RSG : : storage - > light_get_param ( instance - > base , RS : : LIGHT_PARAM_SPOT_ATTENUATION ) ;
cache - > sky_only = RSG : : storage - > light_directional_is_sky_only ( instance - > base ) ;
idx + + ;
}
}
update_lights = true ;
}
2020-12-23 17:52:58 +01:00
geometry_instances_to_render . clear ( ) ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
for ( Set < Instance * > : : Element * E = probe - > dynamic_geometries . front ( ) ; E ; E = E - > next ( ) ) {
Instance * ins = E - > get ( ) ;
if ( ! ins - > visible ) {
continue ;
}
InstanceGeometryData * geom = ( InstanceGeometryData * ) ins - > base_data ;
2020-12-03 22:09:47 +01:00
2020-12-26 13:05:36 +01:00
if ( ins - > scenario & & ins - > array_index > = 0 & & ( ins - > scenario - > instance_data [ ins - > array_index ] . flags & InstanceData : : FLAG_GEOM_GI_PROBE_DIRTY ) ) {
2020-12-23 17:52:58 +01:00
//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 ( ) ) ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
for ( Set < Instance * > : : Element * F = geom - > gi_probes . front ( ) ; F ; F = F - > next ( ) ) {
InstanceGIProbeData * gi_probe2 = static_cast < InstanceGIProbeData * > ( F - > get ( ) - > base_data ) ;
2020-12-03 22:09:47 +01:00
2020-12-23 17:52:58 +01:00
ins - > gi_probe_instances . write [ l + + ] = gi_probe2 - > probe_instance ;
2020-12-03 22:09:47 +01:00
}
2020-12-26 13:05:36 +01:00
ins - > scenario - > instance_data [ ins - > array_index ] . flags & = ~ uint32_t ( InstanceData : : FLAG_GEOM_GI_PROBE_DIRTY ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
geometry_instances_to_render . push_back ( E - > get ( ) ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
scene_render - > gi_probe_update ( probe - > probe_instance , update_lights , probe - > light_instances , geometry_instances_to_render ) ;
2020-12-03 22:09:47 +01:00
gi_probe_update_list . remove ( gi_probe ) ;
gi_probe = next ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : render_particle_colliders ( ) {
2020-12-03 22:09:47 +01:00
while ( heightfield_particle_colliders_update_list . front ( ) ) {
Instance * hfpc = heightfield_particle_colliders_update_list . front ( ) - > get ( ) ;
if ( hfpc - > scenario & & hfpc - > base_type = = RS : : INSTANCE_PARTICLES_COLLISION & & RSG : : storage - > particles_collision_is_heightfield ( hfpc - > base ) ) {
//update heightfield
2020-12-23 17:52:58 +01:00
instance_cull_result . clear ( ) ;
geometry_instances_to_render . clear ( ) ;
struct CullAABB {
PagedArray < Instance * > * result ;
_FORCE_INLINE_ bool operator ( ) ( void * p_data ) {
Instance * p_instance = ( Instance * ) p_data ;
result - > push_back ( p_instance ) ;
return false ;
}
} ;
CullAABB cull_aabb ;
cull_aabb . result = & instance_cull_result ;
hfpc - > scenario - > indexers [ Scenario : : INDEXER_GEOMETRY ] . aabb_query ( hfpc - > transformed_aabb , cull_aabb ) ;
hfpc - > scenario - > indexers [ Scenario : : INDEXER_VOLUMES ] . aabb_query ( hfpc - > transformed_aabb , cull_aabb ) ;
for ( int i = 0 ; i < ( int ) instance_cull_result . size ( ) ; i + + ) {
2020-12-03 22:09:47 +01:00
Instance * instance = instance_cull_result [ i ] ;
2020-12-23 17:52:58 +01:00
if ( ! instance | | ! ( ( 1 < < instance - > base_type ) & ( RS : : INSTANCE_GEOMETRY_MASK & ( ~ ( 1 < < RS : : INSTANCE_PARTICLES ) ) ) ) ) { //all but particles to avoid self collision
continue ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
geometry_instances_to_render . push_back ( instance ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-23 17:52:58 +01:00
scene_render - > render_particle_collider_heightfield ( hfpc - > base , hfpc - > transform , geometry_instances_to_render ) ;
2020-12-03 22:09:47 +01:00
}
heightfield_particle_colliders_update_list . erase ( heightfield_particle_colliders_update_list . front ( ) ) ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : _update_instance_shader_parameters_from_material ( Map < StringName , RendererSceneRender : : InstanceBase : : InstanceShaderParameter > & isparams , const Map < StringName , RendererSceneRender : : InstanceBase : : InstanceShaderParameter > & existing_isparams , RID p_material ) {
List < RendererStorage : : InstanceShaderParam > plist ;
2020-12-03 22:09:47 +01:00
RSG : : storage - > material_get_instance_shader_parameters ( p_material , & plist ) ;
2020-12-04 19:26:24 +01:00
for ( List < RendererStorage : : InstanceShaderParam > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
2020-12-03 22:09:47 +01:00
StringName name = E - > get ( ) . info . name ;
if ( isparams . has ( name ) ) {
if ( isparams [ name ] . info . type ! = E - > get ( ) . info . type ) {
WARN_PRINT ( " More than one material in instance export the same instance shader uniform ' " + E - > get ( ) . info . name + " ', but they do it with different data types. Only the first one (in order) will display correctly. " ) ;
}
if ( isparams [ name ] . index ! = E - > get ( ) . index ) {
WARN_PRINT ( " More than one material in instance export the same instance shader uniform ' " + E - > get ( ) . info . name + " ', but they do it with different indices. Only the first one (in order) will display correctly. " ) ;
}
continue ; //first one found always has priority
}
2020-12-04 19:26:24 +01:00
RendererSceneRender : : InstanceBase : : InstanceShaderParameter isp ;
2020-12-03 22:09:47 +01:00
isp . index = E - > get ( ) . index ;
isp . info = E - > get ( ) . info ;
isp . default_value = E - > get ( ) . default_value ;
if ( existing_isparams . has ( name ) ) {
isp . value = existing_isparams [ name ] . value ;
} else {
isp . value = E - > get ( ) . default_value ;
}
isparams [ name ] = isp ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : _update_dirty_instance ( Instance * p_instance ) {
2020-12-03 22:09:47 +01:00
if ( p_instance - > update_aabb ) {
_update_instance_aabb ( p_instance ) ;
}
if ( p_instance - > update_dependencies ) {
p_instance - > instance_increase_version ( ) ;
if ( p_instance - > base . is_valid ( ) ) {
RSG : : storage - > base_update_dependency ( p_instance - > base , p_instance ) ;
}
if ( p_instance - > material_override . is_valid ( ) ) {
RSG : : storage - > material_update_dependency ( p_instance - > material_override , p_instance ) ;
}
if ( p_instance - > base_type = = RS : : INSTANCE_MESH ) {
//remove materials no longer used and un-own them
int new_mat_count = RSG : : storage - > mesh_get_surface_count ( p_instance - > base ) ;
p_instance - > materials . resize ( new_mat_count ) ;
2020-12-16 15:07:08 +01:00
_instance_update_mesh_instance ( p_instance ) ;
2020-12-03 22:09:47 +01:00
}
if ( ( 1 < < p_instance - > base_type ) & RS : : INSTANCE_GEOMETRY_MASK ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( p_instance - > base_data ) ;
bool can_cast_shadows = true ;
bool is_animated = false ;
2020-12-04 19:26:24 +01:00
Map < StringName , RendererSceneRender : : InstanceBase : : InstanceShaderParameter > isparams ;
2020-12-03 22:09:47 +01:00
if ( p_instance - > cast_shadows = = RS : : SHADOW_CASTING_SETTING_OFF ) {
can_cast_shadows = false ;
}
if ( p_instance - > material_override . is_valid ( ) ) {
if ( ! RSG : : storage - > material_casts_shadows ( p_instance - > material_override ) ) {
can_cast_shadows = false ;
}
is_animated = RSG : : storage - > material_is_animated ( p_instance - > material_override ) ;
_update_instance_shader_parameters_from_material ( isparams , p_instance - > instance_shader_parameters , p_instance - > material_override ) ;
} else {
if ( p_instance - > base_type = = RS : : INSTANCE_MESH ) {
RID mesh = p_instance - > base ;
if ( mesh . is_valid ( ) ) {
bool cast_shadows = false ;
for ( int i = 0 ; i < p_instance - > materials . size ( ) ; i + + ) {
RID mat = p_instance - > materials [ i ] . is_valid ( ) ? p_instance - > materials [ i ] : RSG : : storage - > mesh_surface_get_material ( mesh , i ) ;
if ( ! mat . is_valid ( ) ) {
cast_shadows = true ;
} else {
if ( RSG : : storage - > material_casts_shadows ( mat ) ) {
cast_shadows = true ;
}
if ( RSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
_update_instance_shader_parameters_from_material ( isparams , p_instance - > instance_shader_parameters , mat ) ;
RSG : : storage - > material_update_dependency ( mat , p_instance ) ;
}
}
if ( ! cast_shadows ) {
can_cast_shadows = false ;
}
}
} else if ( p_instance - > base_type = = RS : : INSTANCE_MULTIMESH ) {
RID mesh = RSG : : storage - > multimesh_get_mesh ( p_instance - > base ) ;
if ( mesh . is_valid ( ) ) {
bool cast_shadows = false ;
int sc = RSG : : storage - > mesh_get_surface_count ( mesh ) ;
for ( int i = 0 ; i < sc ; i + + ) {
RID mat = RSG : : storage - > mesh_surface_get_material ( mesh , i ) ;
if ( ! mat . is_valid ( ) ) {
cast_shadows = true ;
} else {
if ( RSG : : storage - > material_casts_shadows ( mat ) ) {
cast_shadows = true ;
}
if ( RSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
_update_instance_shader_parameters_from_material ( isparams , p_instance - > instance_shader_parameters , mat ) ;
RSG : : storage - > material_update_dependency ( mat , p_instance ) ;
}
}
if ( ! cast_shadows ) {
can_cast_shadows = false ;
}
RSG : : storage - > base_update_dependency ( mesh , p_instance ) ;
}
} else if ( p_instance - > base_type = = RS : : INSTANCE_IMMEDIATE ) {
RID mat = RSG : : storage - > immediate_get_material ( p_instance - > base ) ;
if ( ! ( ! mat . is_valid ( ) | | RSG : : storage - > material_casts_shadows ( mat ) ) ) {
can_cast_shadows = false ;
}
if ( mat . is_valid ( ) & & RSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
if ( mat . is_valid ( ) ) {
_update_instance_shader_parameters_from_material ( isparams , p_instance - > instance_shader_parameters , mat ) ;
}
if ( mat . is_valid ( ) ) {
RSG : : storage - > material_update_dependency ( mat , p_instance ) ;
}
} else if ( p_instance - > base_type = = RS : : INSTANCE_PARTICLES ) {
bool cast_shadows = false ;
int dp = RSG : : storage - > particles_get_draw_passes ( p_instance - > base ) ;
for ( int i = 0 ; i < dp ; i + + ) {
RID mesh = RSG : : storage - > particles_get_draw_pass_mesh ( p_instance - > base , i ) ;
if ( ! mesh . is_valid ( ) ) {
continue ;
}
int sc = RSG : : storage - > mesh_get_surface_count ( mesh ) ;
for ( int j = 0 ; j < sc ; j + + ) {
RID mat = RSG : : storage - > mesh_surface_get_material ( mesh , j ) ;
if ( ! mat . is_valid ( ) ) {
cast_shadows = true ;
} else {
if ( RSG : : storage - > material_casts_shadows ( mat ) ) {
cast_shadows = true ;
}
if ( RSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
_update_instance_shader_parameters_from_material ( isparams , p_instance - > instance_shader_parameters , mat ) ;
RSG : : storage - > material_update_dependency ( mat , p_instance ) ;
}
}
}
if ( ! cast_shadows ) {
can_cast_shadows = false ;
}
}
}
if ( can_cast_shadows ! = geom - > can_cast_shadows ) {
//ability to cast shadows change, let lights now
2020-12-23 17:52:58 +01:00
for ( Set < Instance * > : : Element * E = geom - > lights . front ( ) ; E ; E = E - > next ( ) ) {
2020-12-03 22:09:47 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
light - > shadow_dirty = true ;
}
geom - > can_cast_shadows = can_cast_shadows ;
}
geom - > material_is_animated = is_animated ;
p_instance - > instance_shader_parameters = isparams ;
if ( p_instance - > instance_allocated_shader_parameters ! = ( p_instance - > instance_shader_parameters . size ( ) > 0 ) ) {
p_instance - > instance_allocated_shader_parameters = ( p_instance - > instance_shader_parameters . size ( ) > 0 ) ;
if ( p_instance - > instance_allocated_shader_parameters ) {
p_instance - > instance_allocated_shader_parameters_offset = RSG : : storage - > global_variables_instance_allocate ( p_instance - > self ) ;
2020-12-04 19:26:24 +01:00
for ( Map < StringName , RendererSceneRender : : InstanceBase : : InstanceShaderParameter > : : Element * E = p_instance - > instance_shader_parameters . front ( ) ; E ; E = E - > next ( ) ) {
2020-12-03 22:09:47 +01:00
if ( E - > get ( ) . value . get_type ( ) ! = Variant : : NIL ) {
RSG : : storage - > global_variables_instance_update ( p_instance - > self , E - > get ( ) . index , E - > get ( ) . value ) ;
}
}
} else {
RSG : : storage - > global_variables_instance_free ( p_instance - > self ) ;
p_instance - > instance_allocated_shader_parameters_offset = - 1 ;
}
}
}
if ( p_instance - > skeleton . is_valid ( ) ) {
RSG : : storage - > skeleton_update_dependency ( p_instance - > skeleton , p_instance ) ;
}
p_instance - > clean_up_dependencies ( ) ;
}
_instance_update_list . remove ( & p_instance - > update_item ) ;
_update_instance ( p_instance ) ;
p_instance - > update_aabb = false ;
p_instance - > update_dependencies = false ;
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : update_dirty_instances ( ) {
2020-12-03 22:09:47 +01:00
RSG : : storage - > update_dirty_resources ( ) ;
while ( _instance_update_list . first ( ) ) {
_update_dirty_instance ( _instance_update_list . first ( ) - > self ( ) ) ;
}
}
2020-12-04 19:26:24 +01:00
void RendererSceneCull : : update ( ) {
2020-12-23 17:52:58 +01:00
//optimize bvhs
for ( uint32_t i = 0 ; i < scenario_owner . get_rid_count ( ) ; i + + ) {
Scenario * s = scenario_owner . get_ptr_by_index ( i ) ;
s - > indexers [ Scenario : : INDEXER_GEOMETRY ] . optimize_incremental ( indexer_update_iterations ) ;
s - > indexers [ Scenario : : INDEXER_VOLUMES ] . optimize_incremental ( indexer_update_iterations ) ;
}
2020-12-03 22:09:47 +01:00
scene_render - > update ( ) ;
update_dirty_instances ( ) ;
render_particle_colliders ( ) ;
}
2020-12-04 19:26:24 +01:00
bool RendererSceneCull : : free ( RID p_rid ) {
2020-12-03 22:09:47 +01:00
if ( scene_render - > free ( p_rid ) ) {
return true ;
}
if ( camera_owner . owns ( p_rid ) ) {
Camera * camera = camera_owner . getornull ( p_rid ) ;
camera_owner . free ( p_rid ) ;
memdelete ( camera ) ;
} else if ( scenario_owner . owns ( p_rid ) ) {
Scenario * scenario = scenario_owner . getornull ( p_rid ) ;
while ( scenario - > instances . first ( ) ) {
instance_set_scenario ( scenario - > instances . first ( ) - > self ( ) - > self , RID ( ) ) ;
}
2020-12-26 13:05:36 +01:00
scenario - > instance_aabbs . reset ( ) ;
scenario - > instance_data . reset ( ) ;
2020-12-03 22:09:47 +01:00
scene_render - > free ( scenario - > reflection_probe_shadow_atlas ) ;
scene_render - > free ( scenario - > reflection_atlas ) ;
scenario_owner . free ( p_rid ) ;
memdelete ( scenario ) ;
} else if ( instance_owner . owns ( p_rid ) ) {
// delete the instance
update_dirty_instances ( ) ;
Instance * instance = instance_owner . getornull ( p_rid ) ;
instance_geometry_set_lightmap ( p_rid , RID ( ) , Rect2 ( ) , 0 ) ;
instance_set_scenario ( p_rid , RID ( ) ) ;
instance_set_base ( p_rid , RID ( ) ) ;
instance_geometry_set_material_override ( p_rid , RID ( ) ) ;
instance_attach_skeleton ( p_rid , RID ( ) ) ;
if ( instance - > instance_allocated_shader_parameters ) {
//free the used shader parameters
RSG : : storage - > global_variables_instance_free ( instance - > self ) ;
}
update_dirty_instances ( ) ; //in case something changed this
instance_owner . free ( p_rid ) ;
memdelete ( instance ) ;
} else {
return false ;
}
return true ;
}
2020-12-04 19:26:24 +01:00
TypedArray < Image > RendererSceneCull : : bake_render_uv2 ( RID p_base , const Vector < RID > & p_material_overrides , const Size2i & p_image_size ) {
2020-12-03 22:09:47 +01:00
return scene_render - > bake_render_uv2 ( p_base , p_material_overrides , p_image_size ) ;
}
/*******************************/
/* Passthrough to Scene Render */
/*******************************/
/* ENVIRONMENT API */
2020-12-04 19:26:24 +01:00
RendererSceneCull * RendererSceneCull : : singleton = nullptr ;
2020-12-03 22:09:47 +01:00
2020-12-04 19:26:24 +01:00
RendererSceneCull : : RendererSceneCull ( ) {
2020-12-03 22:09:47 +01:00
render_pass = 1 ;
singleton = this ;
2020-12-23 17:52:58 +01:00
pair_volumes_to_mesh = false ;
instance_cull_result . set_page_pool ( & instance_cull_page_pool ) ;
2020-12-26 13:05:36 +01:00
mesh_instance_cull_result . set_page_pool ( & rid_cull_page_pool ) ;
2020-12-23 17:52:58 +01:00
instance_shadow_cull_result . set_page_pool ( & instance_cull_page_pool ) ;
instance_sdfgi_cull_result . set_page_pool ( & instance_cull_page_pool ) ;
light_cull_result . set_page_pool ( & instance_cull_page_pool ) ;
geometry_instances_to_render . set_page_pool ( & base_instance_cull_page_pool ) ;
geometry_instances_to_shadow_render . set_page_pool ( & base_instance_cull_page_pool ) ;
lightmap_cull_result . set_page_pool ( & base_instance_cull_page_pool ) ;
reflection_probe_instance_cull_result . set_page_pool ( & rid_cull_page_pool ) ;
light_instance_cull_result . set_page_pool ( & rid_cull_page_pool ) ;
gi_probe_instance_cull_result . set_page_pool ( & rid_cull_page_pool ) ;
decal_instance_cull_result . set_page_pool ( & rid_cull_page_pool ) ;
2020-12-26 13:05:36 +01:00
for ( int i = 0 ; i < RendererSceneRender : : MAX_DIRECTIONAL_LIGHTS ; i + + ) {
for ( int j = 0 ; j < RendererSceneRender : : MAX_DIRECTIONAL_LIGHT_CASCADES ; j + + ) {
cull . shadows [ i ] . cascades [ j ] . cull_result . set_page_pool ( & base_instance_cull_page_pool ) ;
}
}
for ( int i = 0 ; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE ; i + + ) {
cull . sdfgi . region_cull_result [ i ] . set_page_pool ( & base_instance_cull_page_pool ) ;
}
2020-12-23 17:52:58 +01:00
for ( int i = 0 ; i < SDFGI_MAX_CASCADES ; i + + ) {
2020-12-26 13:05:36 +01:00
cull . sdfgi . cascade_lights [ i ] . set_page_pool ( & rid_cull_page_pool ) ;
2020-12-23 17:52:58 +01:00
}
indexer_update_iterations = GLOBAL_GET ( " rendering/spatial_indexer/update_iterations_per_frame " ) ;
2020-12-03 22:09:47 +01:00
}
2020-12-04 19:26:24 +01:00
RendererSceneCull : : ~ RendererSceneCull ( ) {
2020-12-23 17:52:58 +01:00
instance_cull_result . reset ( ) ;
2020-12-26 13:05:36 +01:00
mesh_instance_cull_result . reset ( ) ;
2020-12-23 17:52:58 +01:00
instance_shadow_cull_result . reset ( ) ;
instance_sdfgi_cull_result . reset ( ) ;
light_cull_result . reset ( ) ;
geometry_instances_to_render . reset ( ) ;
geometry_instances_to_shadow_render . reset ( ) ;
lightmap_cull_result . reset ( ) ;
reflection_probe_instance_cull_result . reset ( ) ;
light_instance_cull_result . reset ( ) ;
gi_probe_instance_cull_result . reset ( ) ;
decal_instance_cull_result . reset ( ) ;
2020-12-26 13:05:36 +01:00
for ( int i = 0 ; i < RendererSceneRender : : MAX_DIRECTIONAL_LIGHTS ; i + + ) {
for ( int j = 0 ; j < RendererSceneRender : : MAX_DIRECTIONAL_LIGHT_CASCADES ; j + + ) {
cull . shadows [ i ] . cascades [ j ] . cull_result . reset ( ) ;
}
}
for ( int i = 0 ; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE ; i + + ) {
cull . sdfgi . region_cull_result [ i ] . reset ( ) ;
}
2020-12-23 17:52:58 +01:00
for ( int i = 0 ; i < SDFGI_MAX_CASCADES ; i + + ) {
2020-12-26 13:05:36 +01:00
cull . sdfgi . cascade_lights [ i ] . reset ( ) ;
2020-12-23 17:52:58 +01:00
}
2020-12-03 22:09:47 +01:00
}