2023-01-10 15:26:54 +01:00
/**************************************************************************/
/* visual_server_scene.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2016-10-19 16:14:41 +02:00
# include "visual_server_scene.h"
2020-01-21 21:32:27 +01:00
2021-09-15 13:30:45 +02:00
# include "core/math/transform_interpolator.h"
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
2019-02-12 14:23:35 +01:00
# include "visual_server_globals.h"
2019-11-02 21:00:24 +01:00
# include "visual_server_light_culler.h"
2017-04-07 04:36:37 +02:00
# include "visual_server_raster.h"
2020-01-21 21:32:27 +01:00
2019-01-25 12:06:44 +01:00
# include <new>
2020-01-21 21:32:27 +01:00
2016-10-19 16:14:41 +02:00
/* CAMERA API */
RID VisualServerScene : : camera_create ( ) {
2017-03-05 16:44:50 +01:00
Camera * camera = memnew ( Camera ) ;
return camera_owner . make_rid ( camera ) ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : camera_set_perspective ( RID p_camera , float p_fovy_degrees , float p_z_near , float p_z_far ) {
Camera * camera = camera_owner . get ( p_camera ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! camera ) ;
2017-03-05 16:44:50 +01:00
camera - > type = Camera : : PERSPECTIVE ;
camera - > fov = p_fovy_degrees ;
camera - > znear = p_z_near ;
camera - > zfar = p_z_far ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : camera_set_orthogonal ( RID p_camera , float p_size , float p_z_near , float p_z_far ) {
Camera * camera = camera_owner . get ( p_camera ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! camera ) ;
2017-03-05 16:44:50 +01:00
camera - > type = Camera : : ORTHOGONAL ;
camera - > size = p_size ;
camera - > znear = p_z_near ;
camera - > zfar = p_z_far ;
2016-10-19 16:14:41 +02:00
}
2019-02-19 17:17:02 +01:00
void VisualServerScene : : camera_set_frustum ( RID p_camera , float p_size , Vector2 p_offset , float p_z_near , float p_z_far ) {
Camera * camera = camera_owner . get ( 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 ;
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : camera_set_transform ( RID p_camera , const Transform & p_transform ) {
Camera * camera = camera_owner . get ( p_camera ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! camera ) ;
2021-09-15 13:30:45 +02:00
2017-03-05 16:44:50 +01:00
camera - > transform = p_transform . orthonormalized ( ) ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : camera_set_cull_mask ( RID p_camera , uint32_t p_layers ) {
Camera * camera = camera_owner . get ( p_camera ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! camera ) ;
2017-03-05 16:44:50 +01:00
camera - > visible_layers = p_layers ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : camera_set_environment ( RID p_camera , RID p_env ) {
Camera * camera = camera_owner . get ( p_camera ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! camera ) ;
2017-03-05 16:44:50 +01:00
camera - > env = p_env ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : camera_set_use_vertical_aspect ( RID p_camera , bool p_enable ) {
Camera * camera = camera_owner . get ( p_camera ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! camera ) ;
2017-03-05 16:44:50 +01:00
camera - > vaspect = p_enable ;
2016-10-19 16:14:41 +02:00
}
2020-10-21 14:13:20 +02:00
/* SPATIAL PARTITIONING */
2021-05-18 21:36:25 +02:00
VisualServerScene : : SpatialPartitioningScene_BVH : : SpatialPartitioningScene_BVH ( ) {
_bvh . params_set_thread_safe ( GLOBAL_GET ( " rendering/threads/thread_safe_bvh " ) ) ;
2021-11-18 15:32:33 +01:00
_bvh . params_set_pairing_expansion ( GLOBAL_GET ( " rendering/quality/spatial_partitioning/bvh_collision_margin " ) ) ;
2021-12-03 12:36:39 +01:00
_dummy_cull_object = memnew ( Instance ) ;
}
VisualServerScene : : SpatialPartitioningScene_BVH : : ~ SpatialPartitioningScene_BVH ( ) {
if ( _dummy_cull_object ) {
memdelete ( _dummy_cull_object ) ;
_dummy_cull_object = nullptr ;
}
2021-05-18 21:36:25 +02:00
}
2020-10-21 14:13:20 +02:00
VisualServerScene : : SpatialPartitionID VisualServerScene : : SpatialPartitioningScene_BVH : : create ( Instance * p_userdata , const AABB & p_aabb , int p_subindex , bool p_pairable , uint32_t p_pairable_type , uint32_t p_pairable_mask ) {
2021-01-29 18:47:40 +01:00
# if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
// we are relying on this instance to be valid in order to pass
// the visible flag to the bvh.
2021-02-04 11:43:08 +01:00
DEV_ASSERT ( p_userdata ) ;
2021-01-29 18:47:40 +01:00
# endif
2021-12-03 12:36:39 +01:00
// cache the pairable mask and pairable type on the instance as it is needed for user callbacks from the BVH, and this is
// too complex to calculate each callback...
p_userdata - > bvh_pairable_mask = p_pairable_mask ;
p_userdata - > bvh_pairable_type = p_pairable_type ;
2023-02-01 13:37:52 +01:00
uint32_t tree_collision_mask = 0 ;
uint32_t tree_id = find_tree_id_and_collision_mask ( p_pairable , tree_collision_mask ) ;
2021-12-03 12:36:39 +01:00
return _bvh . create ( p_userdata , p_userdata - > visible , tree_id , tree_collision_mask , p_aabb , p_subindex ) + 1 ;
2020-10-21 14:13:20 +02:00
}
void VisualServerScene : : SpatialPartitioningScene_BVH : : erase ( SpatialPartitionID p_handle ) {
_bvh . erase ( p_handle - 1 ) ;
}
void VisualServerScene : : SpatialPartitioningScene_BVH : : move ( SpatialPartitionID p_handle , const AABB & p_aabb ) {
_bvh . move ( p_handle - 1 , p_aabb ) ;
}
2021-01-29 18:47:40 +01:00
void VisualServerScene : : SpatialPartitioningScene_BVH : : activate ( SpatialPartitionID p_handle , const AABB & p_aabb ) {
// be very careful here, we are deferring the collision check, expecting a set_pairable to be called
// immediately after.
// see the notes in the BVH function.
_bvh . activate ( p_handle - 1 , p_aabb , true ) ;
}
void VisualServerScene : : SpatialPartitioningScene_BVH : : deactivate ( SpatialPartitionID p_handle ) {
_bvh . deactivate ( p_handle - 1 ) ;
}
2021-02-13 19:53:32 +01:00
void VisualServerScene : : SpatialPartitioningScene_BVH : : force_collision_check ( SpatialPartitionID p_handle ) {
_bvh . force_collision_check ( p_handle - 1 ) ;
}
2020-10-21 14:13:20 +02:00
void VisualServerScene : : SpatialPartitioningScene_BVH : : update ( ) {
_bvh . update ( ) ;
}
2021-01-19 12:18:55 +01:00
void VisualServerScene : : SpatialPartitioningScene_BVH : : update_collisions ( ) {
_bvh . update_collisions ( ) ;
}
2021-12-03 12:36:39 +01:00
void VisualServerScene : : SpatialPartitioningScene_BVH : : set_pairable ( Instance * p_instance , bool p_pairable , uint32_t p_pairable_type , uint32_t p_pairable_mask ) {
SpatialPartitionID handle = p_instance - > spatial_partition_id ;
p_instance - > bvh_pairable_mask = p_pairable_mask ;
p_instance - > bvh_pairable_type = p_pairable_type ;
2023-02-01 13:37:52 +01:00
uint32_t tree_collision_mask = 0 ;
uint32_t tree_id = find_tree_id_and_collision_mask ( p_pairable , tree_collision_mask ) ;
2021-12-03 12:36:39 +01:00
_bvh . set_tree ( handle - 1 , tree_id , tree_collision_mask ) ;
2020-10-21 14:13:20 +02:00
}
int VisualServerScene : : SpatialPartitioningScene_BVH : : cull_convex ( const Vector < Plane > & p_convex , Instance * * p_result_array , int p_result_max , uint32_t p_mask ) {
2021-12-03 12:36:39 +01:00
_dummy_cull_object - > bvh_pairable_mask = p_mask ;
_dummy_cull_object - > bvh_pairable_type = 0 ;
return _bvh . cull_convex ( p_convex , p_result_array , p_result_max , _dummy_cull_object ) ;
2020-10-21 14:13:20 +02:00
}
int VisualServerScene : : SpatialPartitioningScene_BVH : : cull_aabb ( const AABB & p_aabb , Instance * * p_result_array , int p_result_max , int * p_subindex_array , uint32_t p_mask ) {
2021-12-03 12:36:39 +01:00
_dummy_cull_object - > bvh_pairable_mask = p_mask ;
_dummy_cull_object - > bvh_pairable_type = 0 ;
return _bvh . cull_aabb ( p_aabb , p_result_array , p_result_max , _dummy_cull_object , 0xFFFFFFFF , p_subindex_array ) ;
2020-10-21 14:13:20 +02:00
}
int VisualServerScene : : SpatialPartitioningScene_BVH : : cull_segment ( const Vector3 & p_from , const Vector3 & p_to , Instance * * p_result_array , int p_result_max , int * p_subindex_array , uint32_t p_mask ) {
2021-12-03 12:36:39 +01:00
_dummy_cull_object - > bvh_pairable_mask = p_mask ;
_dummy_cull_object - > bvh_pairable_type = 0 ;
return _bvh . cull_segment ( p_from , p_to , p_result_array , p_result_max , _dummy_cull_object , 0xFFFFFFFF , p_subindex_array ) ;
2020-10-21 14:13:20 +02:00
}
void VisualServerScene : : SpatialPartitioningScene_BVH : : set_pair_callback ( PairCallback p_callback , void * p_userdata ) {
_bvh . set_pair_callback ( p_callback , p_userdata ) ;
}
void VisualServerScene : : SpatialPartitioningScene_BVH : : set_unpair_callback ( UnpairCallback p_callback , void * p_userdata ) {
_bvh . set_unpair_callback ( p_callback , p_userdata ) ;
}
///////////////////////
VisualServerScene : : SpatialPartitionID VisualServerScene : : SpatialPartitioningScene_Octree : : create ( Instance * p_userdata , const AABB & p_aabb , int p_subindex , bool p_pairable , uint32_t p_pairable_type , uint32_t p_pairable_mask ) {
return _octree . create ( p_userdata , p_aabb , p_subindex , p_pairable , p_pairable_type , p_pairable_mask ) ;
}
void VisualServerScene : : SpatialPartitioningScene_Octree : : erase ( SpatialPartitionID p_handle ) {
_octree . erase ( p_handle ) ;
}
void VisualServerScene : : SpatialPartitioningScene_Octree : : move ( SpatialPartitionID p_handle , const AABB & p_aabb ) {
_octree . move ( p_handle , p_aabb ) ;
}
2021-12-03 12:36:39 +01:00
void VisualServerScene : : SpatialPartitioningScene_Octree : : set_pairable ( Instance * p_instance , bool p_pairable , uint32_t p_pairable_type , uint32_t p_pairable_mask ) {
SpatialPartitionID handle = p_instance - > spatial_partition_id ;
_octree . set_pairable ( handle , p_pairable , p_pairable_type , p_pairable_mask ) ;
2020-10-21 14:13:20 +02:00
}
int VisualServerScene : : SpatialPartitioningScene_Octree : : cull_convex ( const Vector < Plane > & p_convex , Instance * * p_result_array , int p_result_max , uint32_t p_mask ) {
return _octree . cull_convex ( p_convex , p_result_array , p_result_max , p_mask ) ;
}
int VisualServerScene : : SpatialPartitioningScene_Octree : : cull_aabb ( const AABB & p_aabb , Instance * * p_result_array , int p_result_max , int * p_subindex_array , uint32_t p_mask ) {
return _octree . cull_aabb ( p_aabb , p_result_array , p_result_max , p_subindex_array , p_mask ) ;
}
int VisualServerScene : : SpatialPartitioningScene_Octree : : cull_segment ( const Vector3 & p_from , const Vector3 & p_to , Instance * * p_result_array , int p_result_max , int * p_subindex_array , uint32_t p_mask ) {
return _octree . cull_segment ( p_from , p_to , p_result_array , p_result_max , p_subindex_array , p_mask ) ;
}
void VisualServerScene : : SpatialPartitioningScene_Octree : : set_pair_callback ( PairCallback p_callback , void * p_userdata ) {
_octree . set_pair_callback ( p_callback , p_userdata ) ;
}
void VisualServerScene : : SpatialPartitioningScene_Octree : : set_unpair_callback ( UnpairCallback p_callback , void * p_userdata ) {
_octree . set_unpair_callback ( p_callback , p_userdata ) ;
}
void VisualServerScene : : SpatialPartitioningScene_Octree : : set_balance ( float p_balance ) {
_octree . set_balance ( p_balance ) ;
}
2016-10-19 16:14:41 +02:00
/* SCENARIO API */
2020-10-21 14:13:20 +02:00
VisualServerScene : : Scenario : : Scenario ( ) {
debug = VS : : SCENARIO_DEBUG_DISABLED ;
2021-01-19 12:18:55 +01:00
bool use_bvh_or_octree = GLOBAL_GET ( " rendering/quality/spatial_partitioning/use_bvh " ) ;
2020-10-21 14:13:20 +02:00
if ( use_bvh_or_octree ) {
sps = memnew ( SpatialPartitioningScene_BVH ) ;
} else {
sps = memnew ( SpatialPartitioningScene_Octree ) ;
}
}
void * VisualServerScene : : _instance_pair ( void * p_self , SpatialPartitionID , Instance * p_A , int , SpatialPartitionID , Instance * p_B , int ) {
2017-01-14 12:26:56 +01:00
//VisualServerScene *self = (VisualServerScene*)p_self;
2016-10-19 16:14:41 +02: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 ) {
2017-03-05 16:44:50 +01:00
SWAP ( A , B ) ; //lesser always first
2016-10-19 16:14:41 +02:00
}
2017-09-07 21:48:50 +02:00
if ( B - > base_type = = VS : : INSTANCE_LIGHT & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2016-10-19 16:14:41 +02:00
InstanceLightData : : PairInfo pinfo ;
2017-03-05 16:44:50 +01:00
pinfo . geometry = A ;
2016-10-19 16:14:41 +02:00
pinfo . L = geom - > lighting . push_back ( B ) ;
List < InstanceLightData : : PairInfo > : : Element * E = light - > geometries . push_back ( pinfo ) ;
2016-11-10 03:55:06 +01:00
if ( geom - > can_cast_shadows ) {
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
geom - > lighting_dirty = true ;
2016-10-19 16:14:41 +02:00
2016-11-19 17:23:37 +01:00
return E ; //this element should make freeing faster
2017-09-07 21:48:50 +02:00
} else if ( B - > base_type = = VS : : INSTANCE_REFLECTION_PROBE & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2016-11-19 17:23:37 +01:00
InstanceReflectionProbeData : : PairInfo pinfo ;
2017-03-05 16:44:50 +01:00
pinfo . geometry = A ;
2016-11-19 17:23:37 +01:00
pinfo . L = geom - > reflection_probes . push_back ( B ) ;
List < InstanceReflectionProbeData : : PairInfo > : : Element * E = reflection_probe - > geometries . push_back ( pinfo ) ;
2017-03-05 16:44:50 +01:00
geom - > reflection_dirty = true ;
2016-11-19 17:23:37 +01:00
2017-12-14 12:59:46 +01:00
return E ; //this element should make freeing faster
} else if ( B - > base_type = = VS : : INSTANCE_LIGHTMAP_CAPTURE & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceLightmapCaptureData * lightmap_capture = static_cast < InstanceLightmapCaptureData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
InstanceLightmapCaptureData : : PairInfo pinfo ;
pinfo . geometry = A ;
pinfo . L = geom - > lightmap_captures . push_back ( B ) ;
List < InstanceLightmapCaptureData : : PairInfo > : : Element * E = lightmap_capture - > geometries . push_back ( pinfo ) ;
( ( VisualServerScene * ) p_self ) - > _instance_queue_update ( A , false , false ) ; //need to update capture
2016-10-19 16:14:41 +02:00
return E ; //this element should make freeing faster
2017-09-07 21:48:50 +02:00
} else if ( B - > base_type = = VS : : INSTANCE_GI_PROBE & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2016-12-20 04:21:07 +01:00
InstanceGIProbeData : : PairInfo pinfo ;
2017-03-05 16:44:50 +01:00
pinfo . geometry = A ;
2016-12-20 04:21:07 +01:00
pinfo . L = geom - > gi_probes . push_back ( B ) ;
List < InstanceGIProbeData : : PairInfo > : : Element * E = gi_probe - > geometries . push_back ( pinfo ) ;
2017-03-05 16:44:50 +01:00
geom - > gi_probes_dirty = true ;
2016-12-20 04:21:07 +01:00
return E ; //this element should make freeing faster
2017-03-05 16:44:50 +01:00
} else if ( B - > base_type = = VS : : INSTANCE_GI_PROBE & & A - > base_type = = VS : : INSTANCE_LIGHT ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
2016-12-20 04:21:07 +01:00
return gi_probe - > lights . insert ( A ) ;
2016-10-19 16:14:41 +02:00
}
2021-05-04 16:00:45 +02:00
return nullptr ;
2016-10-19 16:14:41 +02:00
}
2020-10-21 14:13:20 +02:00
void VisualServerScene : : _instance_unpair ( void * p_self , SpatialPartitionID , Instance * p_A , int , SpatialPartitionID , Instance * p_B , int , void * udata ) {
2017-01-14 12:26:56 +01:00
//VisualServerScene *self = (VisualServerScene*)p_self;
2016-10-19 16:14:41 +02: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 ) {
2017-03-05 16:44:50 +01:00
SWAP ( A , B ) ; //lesser always first
2016-10-19 16:14:41 +02:00
}
2017-09-07 21:48:50 +02:00
if ( B - > base_type = = VS : : INSTANCE_LIGHT & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
List < InstanceLightData : : PairInfo > : : Element * E = reinterpret_cast < List < InstanceLightData : : PairInfo > : : Element * > ( udata ) ;
2016-10-19 16:14:41 +02:00
geom - > lighting . erase ( E - > get ( ) . L ) ;
light - > geometries . erase ( E ) ;
2016-11-10 03:55:06 +01:00
if ( geom - > can_cast_shadows ) {
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
geom - > lighting_dirty = true ;
2016-10-19 16:14:41 +02:00
2017-09-07 21:48:50 +02:00
} else if ( B - > base_type = = VS : : INSTANCE_REFLECTION_PROBE & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2016-11-19 17:23:37 +01:00
2017-03-05 16:44:50 +01:00
List < InstanceReflectionProbeData : : PairInfo > : : Element * E = reinterpret_cast < List < InstanceReflectionProbeData : : PairInfo > : : Element * > ( udata ) ;
2016-11-19 17:23:37 +01:00
geom - > reflection_probes . erase ( E - > get ( ) . L ) ;
reflection_probe - > geometries . erase ( E ) ;
2017-03-05 16:44:50 +01:00
geom - > reflection_dirty = true ;
2017-12-14 12:59:46 +01:00
} else if ( B - > base_type = = VS : : INSTANCE_LIGHTMAP_CAPTURE & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
InstanceLightmapCaptureData * lightmap_capture = static_cast < InstanceLightmapCaptureData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
List < InstanceLightmapCaptureData : : PairInfo > : : Element * E = reinterpret_cast < List < InstanceLightmapCaptureData : : PairInfo > : : Element * > ( udata ) ;
geom - > lightmap_captures . erase ( E - > get ( ) . L ) ;
lightmap_capture - > geometries . erase ( E ) ;
( ( VisualServerScene * ) p_self ) - > _instance_queue_update ( A , false , false ) ; //need to update capture
2016-11-19 17:23:37 +01:00
2017-09-07 21:48:50 +02:00
} else if ( B - > base_type = = VS : : INSTANCE_GI_PROBE & & ( ( 1 < < A - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) ) {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( A - > base_data ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
List < InstanceGIProbeData : : PairInfo > : : Element * E = reinterpret_cast < List < InstanceGIProbeData : : PairInfo > : : Element * > ( udata ) ;
2016-12-20 04:21:07 +01:00
geom - > gi_probes . erase ( E - > get ( ) . L ) ;
gi_probe - > geometries . erase ( E ) ;
2017-03-05 16:44:50 +01:00
geom - > gi_probes_dirty = true ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
} else if ( B - > base_type = = VS : : INSTANCE_GI_PROBE & & A - > base_type = = VS : : INSTANCE_LIGHT ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( B - > base_data ) ;
Set < Instance * > : : Element * E = reinterpret_cast < Set < Instance * > : : Element * > ( udata ) ;
2016-12-20 04:21:07 +01:00
gi_probe - > lights . erase ( E ) ;
2016-10-19 16:14:41 +02:00
}
}
RID VisualServerScene : : scenario_create ( ) {
2017-03-05 16:44:50 +01:00
Scenario * scenario = memnew ( Scenario ) ;
ERR_FAIL_COND_V ( ! scenario , RID ( ) ) ;
RID scenario_rid = scenario_owner . make_rid ( scenario ) ;
scenario - > self = scenario_rid ;
2020-10-21 14:13:20 +02:00
scenario - > sps - > set_balance ( GLOBAL_GET ( " rendering/quality/spatial_partitioning/render_tree_balance " ) ) ;
scenario - > sps - > set_pair_callback ( _instance_pair , this ) ;
scenario - > sps - > set_unpair_callback ( _instance_unpair , this ) ;
2017-03-05 16:44:50 +01:00
scenario - > reflection_probe_shadow_atlas = VSG : : scene_render - > shadow_atlas_create ( ) ;
VSG : : scene_render - > shadow_atlas_set_size ( scenario - > reflection_probe_shadow_atlas , 1024 ) ; //make enough shadows for close distance, don't bother with rest
VSG : : scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 0 , 4 ) ;
VSG : : scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 1 , 4 ) ;
VSG : : scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 2 , 4 ) ;
VSG : : scene_render - > shadow_atlas_set_quadrant_subdivision ( scenario - > reflection_probe_shadow_atlas , 3 , 8 ) ;
scenario - > reflection_atlas = VSG : : scene_render - > reflection_atlas_create ( ) ;
2016-10-19 16:14:41 +02:00
return scenario_rid ;
}
2022-04-04 16:18:44 +02:00
void VisualServerScene : : set_physics_interpolation_enabled ( bool p_enabled ) {
_interpolation_data . interpolation_enabled = p_enabled ;
2021-09-15 13:30:45 +02:00
}
2022-04-04 16:18:44 +02:00
void VisualServerScene : : tick ( ) {
if ( _interpolation_data . interpolation_enabled ) {
update_interpolation_tick ( true ) ;
2021-09-15 13:30:45 +02:00
}
}
2022-04-04 16:18:44 +02:00
void VisualServerScene : : pre_draw ( bool p_will_draw ) {
2021-09-15 13:30:45 +02:00
// even when running and not drawing scenes, we still need to clear intermediate per frame
// interpolation data .. hence the p_will_draw flag (so we can reduce the processing if the frame
// will not be drawn)
2022-04-04 16:18:44 +02:00
if ( _interpolation_data . interpolation_enabled ) {
update_interpolation_frame ( p_will_draw ) ;
2021-09-15 13:30:45 +02:00
}
2019-11-02 21:00:24 +01:00
// Opportunity to cheaply get any project settings that have changed.
if ( ProjectSettings : : get_singleton ( ) - > has_changes ( ) ) {
light_culler - > set_caster_culling_active ( GLOBAL_GET ( " rendering/quality/shadows/caster_culling " ) ) ;
light_culler - > set_light_culling_active ( GLOBAL_GET ( " rendering/quality/shadows/light_culling " ) ) ;
}
2021-09-15 13:30:45 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : scenario_set_debug ( RID p_scenario , VS : : ScenarioDebugMode p_debug_mode ) {
2016-10-19 16:14:41 +02:00
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2017-03-05 16:44:50 +01:00
scenario - > debug = p_debug_mode ;
2016-10-19 16:14:41 +02:00
}
void VisualServerScene : : scenario_set_environment ( RID p_scenario , RID p_environment ) {
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2017-03-05 16:44:50 +01:00
scenario - > environment = p_environment ;
2016-10-19 16:14:41 +02:00
}
void VisualServerScene : : scenario_set_fallback_environment ( RID p_scenario , RID p_environment ) {
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2017-03-05 16:44:50 +01:00
scenario - > fallback_environment = p_environment ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : scenario_set_reflection_atlas_size ( RID p_scenario , int p_size , int p_subdiv ) {
2016-11-19 17:23:37 +01:00
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2017-03-05 16:44:50 +01:00
VSG : : scene_render - > reflection_atlas_set_size ( scenario - > reflection_atlas , p_size ) ;
VSG : : scene_render - > reflection_atlas_set_subdivision ( scenario - > reflection_atlas , p_subdiv ) ;
2016-11-19 17:23:37 +01:00
}
2016-10-19 16:14:41 +02:00
/* INSTANCING API */
2017-03-05 16:44:50 +01:00
void VisualServerScene : : _instance_queue_update ( Instance * p_instance , bool p_update_aabb , bool p_update_materials ) {
2021-05-05 12:44:11 +02:00
if ( p_update_aabb ) {
2017-03-05 16:44:50 +01:00
p_instance - > update_aabb = true ;
2021-05-05 12:44:11 +02:00
}
if ( p_update_materials ) {
2017-03-05 16:44:50 +01:00
p_instance - > update_materials = true ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
2021-05-05 12:44:11 +02:00
if ( p_instance - > update_item . in_list ( ) ) {
2016-10-19 16:14:41 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
_instance_update_list . add ( & p_instance - > update_item ) ;
}
2017-03-05 16:44:50 +01:00
RID VisualServerScene : : instance_create ( ) {
Instance * instance = memnew ( Instance ) ;
ERR_FAIL_COND_V ( ! instance , RID ( ) ) ;
2016-10-19 16:14:41 +02:00
RID instance_rid = instance_owner . make_rid ( instance ) ;
2017-03-05 16:44:50 +01:00
instance - > self = instance_rid ;
2016-10-19 16:14:41 +02:00
return instance_rid ;
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_base ( RID p_instance , RID p_base ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
Scenario * scenario = instance - > scenario ;
2017-03-05 16:44:50 +01:00
if ( instance - > base_type ! = VS : : INSTANCE_NONE ) {
2016-10-19 16:14:41 +02:00
//free anything related to that base
2017-03-05 16:44:50 +01:00
VSG : : storage - > instance_remove_dependency ( instance - > base , instance ) ;
2016-10-19 16:14:41 +02:00
2017-12-06 20:41:19 +01:00
if ( instance - > base_type = = VS : : INSTANCE_GI_PROBE ) {
//if gi probe is baking, wait until done baking, else race condition may happen when removing it
//from octree
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
2017-12-06 22:06:34 +01:00
//make sure probes are done baking
while ( ! probe_bake_list . empty ( ) ) {
OS : : get_singleton ( ) - > delay_usec ( 1 ) ;
}
//make sure this one is done baking
2017-12-06 20:41:19 +01:00
while ( gi_probe - > dynamic . updating_stage = = GI_UPDATE_STAGE_LIGHTING ) {
//wait until bake is done if it's baking
OS : : get_singleton ( ) - > delay_usec ( 1 ) ;
}
}
2020-10-21 14:13:20 +02:00
if ( scenario & & instance - > spatial_partition_id ) {
scenario - > sps - > erase ( instance - > spatial_partition_id ) ;
instance - > spatial_partition_id = 0 ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
switch ( instance - > base_type ) {
2016-10-19 16:14:41 +02:00
case VS : : INSTANCE_LIGHT : {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( instance - > base_data ) ;
2016-10-19 16:14:41 +02:00
if ( instance - > scenario & & light - > D ) {
2017-03-05 16:44:50 +01:00
instance - > scenario - > directional_lights . erase ( light - > D ) ;
2021-05-04 16:00:45 +02:00
light - > D = nullptr ;
2016-10-19 16:14:41 +02:00
}
VSG : : scene_render - > free ( light - > instance ) ;
2016-10-27 16:50:26 +02:00
} break ;
2016-11-19 17:23:37 +01:00
case VS : : INSTANCE_REFLECTION_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( instance - > base_data ) ;
2016-11-19 17:23:37 +01:00
VSG : : scene_render - > free ( reflection_probe - > instance ) ;
if ( reflection_probe - > update_list . in_list ( ) ) {
reflection_probe_render_list . remove ( & reflection_probe - > update_list ) ;
}
} break ;
2017-12-14 12:59:46 +01:00
case VS : : INSTANCE_LIGHTMAP_CAPTURE : {
InstanceLightmapCaptureData * lightmap_capture = static_cast < InstanceLightmapCaptureData * > ( instance - > base_data ) ;
//erase dependencies, since no longer a lightmap
while ( lightmap_capture - > users . front ( ) ) {
2020-12-19 18:17:22 +01:00
instance_set_use_lightmap ( lightmap_capture - > users . front ( ) - > get ( ) - > self , RID ( ) , RID ( ) , - 1 , Rect2 ( 0 , 0 , 1 , 1 ) ) ;
2017-12-14 12:59:46 +01:00
}
} break ;
2016-12-20 04:21:07 +01:00
case VS : : INSTANCE_GI_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
2016-12-20 04:21:07 +01:00
if ( gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . remove ( & gi_probe - > update_element ) ;
}
if ( gi_probe - > dynamic . probe_data . is_valid ( ) ) {
VSG : : storage - > free ( gi_probe - > dynamic . probe_data ) ;
}
2017-12-14 12:59:46 +01:00
if ( instance - > lightmap_capture ) {
Instance * capture = ( Instance * ) instance - > lightmap_capture ;
InstanceLightmapCaptureData * lightmap_capture = static_cast < InstanceLightmapCaptureData * > ( capture - > base_data ) ;
lightmap_capture - > users . erase ( instance ) ;
2021-05-04 16:00:45 +02:00
instance - > lightmap_capture = nullptr ;
2017-12-14 12:59:46 +01:00
instance - > lightmap = RID ( ) ;
}
2016-12-20 04:21:07 +01:00
VSG : : scene_render - > free ( gi_probe - > probe_instance ) ;
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-19 16:14:41 +02:00
}
if ( instance - > base_data ) {
2017-03-05 16:44:50 +01:00
memdelete ( instance - > base_data ) ;
2021-05-04 16:00:45 +02:00
instance - > base_data = nullptr ;
2016-10-19 16:14:41 +02:00
}
2021-05-13 16:16:17 +02:00
instance - > blend_values = PoolRealArray ( ) ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < instance - > materials . size ( ) ; i + + ) {
2016-11-10 03:55:06 +01:00
if ( instance - > materials [ i ] . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
VSG : : storage - > material_remove_instance_owner ( instance - > materials [ i ] , instance ) ;
2016-11-10 03:55:06 +01:00
}
}
2016-10-19 16:14:41 +02:00
instance - > materials . clear ( ) ;
}
2017-03-05 16:44:50 +01:00
instance - > base_type = VS : : INSTANCE_NONE ;
instance - > base = RID ( ) ;
2016-10-19 16:14:41 +02:00
if ( p_base . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
instance - > base_type = VSG : : storage - > get_base_type ( p_base ) ;
ERR_FAIL_COND ( instance - > base_type = = VS : : INSTANCE_NONE ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
switch ( instance - > base_type ) {
2016-10-19 16:14:41 +02:00
case VS : : INSTANCE_LIGHT : {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = memnew ( InstanceLightData ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
if ( scenario & & VSG : : storage - > light_get_type ( p_base ) = = VS : : LIGHT_DIRECTIONAL ) {
2016-10-19 16:14:41 +02:00
light - > D = scenario - > directional_lights . push_back ( instance ) ;
}
light - > instance = VSG : : scene_render - > light_instance_create ( p_base ) ;
2017-03-05 16:44:50 +01:00
instance - > base_data = light ;
2016-10-27 16:50:26 +02:00
} break ;
2016-11-23 11:04:55 +01:00
case VS : : INSTANCE_MESH :
case VS : : INSTANCE_MULTIMESH :
2017-04-07 04:36:37 +02:00
case VS : : INSTANCE_IMMEDIATE :
case VS : : INSTANCE_PARTICLES : {
2017-03-05 16:44:50 +01:00
InstanceGeometryData * geom = memnew ( InstanceGeometryData ) ;
instance - > base_data = geom ;
2019-03-01 20:01:21 +01:00
if ( instance - > base_type = = VS : : INSTANCE_MESH ) {
instance - > blend_values . resize ( VSG : : storage - > mesh_get_blend_shape_count ( p_base ) ) ;
}
2016-11-22 05:26:56 +01:00
} break ;
2016-11-19 17:23:37 +01:00
case VS : : INSTANCE_REFLECTION_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = memnew ( InstanceReflectionProbeData ) ;
reflection_probe - > owner = instance ;
instance - > base_data = reflection_probe ;
2016-11-19 17:23:37 +01:00
2017-03-05 16:44:50 +01:00
reflection_probe - > instance = VSG : : scene_render - > reflection_probe_instance_create ( p_base ) ;
2016-11-19 17:23:37 +01:00
} break ;
2017-12-14 12:59:46 +01:00
case VS : : INSTANCE_LIGHTMAP_CAPTURE : {
InstanceLightmapCaptureData * lightmap_capture = memnew ( InstanceLightmapCaptureData ) ;
instance - > base_data = lightmap_capture ;
//lightmap_capture->instance = VSG::scene_render->lightmap_capture_instance_create(p_base);
} break ;
2016-12-20 04:21:07 +01:00
case VS : : INSTANCE_GI_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * gi_probe = memnew ( InstanceGIProbeData ) ;
instance - > base_data = gi_probe ;
gi_probe - > owner = instance ;
2016-12-20 04:21:07 +01:00
if ( scenario & & ! gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . add ( & gi_probe - > update_element ) ;
}
2017-03-05 16:44:50 +01:00
gi_probe - > probe_instance = VSG : : scene_render - > gi_probe_instance_create ( ) ;
2016-12-20 04:21:07 +01:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
VSG : : storage - > instance_add_dependency ( p_base , instance ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
instance - > base = p_base ;
2016-10-19 16:14:41 +02:00
2021-05-05 12:44:11 +02:00
if ( scenario ) {
2017-03-05 16:44:50 +01:00
_instance_queue_update ( instance , true , true ) ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
}
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_scenario ( RID p_instance , RID p_scenario ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
if ( instance - > scenario ) {
2017-03-05 16:44:50 +01:00
instance - > scenario - > instances . remove ( & instance - > scenario_item ) ;
2016-10-19 16:14:41 +02:00
2020-10-21 14:13:20 +02:00
if ( instance - > spatial_partition_id ) {
instance - > scenario - > sps - > erase ( instance - > spatial_partition_id ) ;
instance - > spatial_partition_id = 0 ;
2016-10-19 16:14:41 +02:00
}
2021-02-04 11:43:08 +01:00
// handle occlusion changes
if ( instance - > occlusion_handle ) {
_instance_destroy_occlusion_rep ( instance ) ;
}
2021-09-15 13:30:45 +02:00
// remove any interpolation data associated with the instance in this scenario
2022-04-04 16:18:44 +02:00
_interpolation_data . notify_free_instance ( p_instance , * instance ) ;
2021-09-15 13:30:45 +02:00
2017-03-05 16:44:50 +01:00
switch ( instance - > base_type ) {
2016-10-19 16:14:41 +02:00
case VS : : INSTANCE_LIGHT : {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( instance - > base_data ) ;
2016-10-19 16:14:41 +02:00
if ( light - > D ) {
2017-03-05 16:44:50 +01:00
instance - > scenario - > directional_lights . erase ( light - > D ) ;
2021-05-04 16:00:45 +02:00
light - > D = nullptr ;
2016-10-19 16:14:41 +02:00
}
2016-10-27 16:50:26 +02:00
} break ;
2016-11-19 17:23:37 +01:00
case VS : : INSTANCE_REFLECTION_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( instance - > base_data ) ;
2016-11-19 17:23:37 +01:00
VSG : : scene_render - > reflection_probe_release_atlas_index ( reflection_probe - > instance ) ;
} break ;
2016-12-20 04:21:07 +01:00
case VS : : INSTANCE_GI_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
2016-12-20 04:21:07 +01:00
if ( gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . remove ( & gi_probe - > update_element ) ;
}
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-19 16:14:41 +02:00
}
2021-05-04 16:00:45 +02:00
instance - > scenario = nullptr ;
2016-10-19 16:14:41 +02:00
}
if ( p_scenario . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
2016-10-19 16:14:41 +02:00
ERR_FAIL_COND ( ! scenario ) ;
2017-03-05 16:44:50 +01:00
instance - > scenario = scenario ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
scenario - > instances . add ( & instance - > scenario_item ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
switch ( instance - > base_type ) {
2016-10-19 16:14:41 +02:00
case VS : : INSTANCE_LIGHT : {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( instance - > base_data ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
if ( VSG : : storage - > light_get_type ( instance - > base ) = = VS : : LIGHT_DIRECTIONAL ) {
2016-10-19 16:14:41 +02:00
light - > D = scenario - > directional_lights . push_back ( instance ) ;
}
2016-10-27 16:50:26 +02:00
} break ;
2016-12-20 04:21:07 +01:00
case VS : : INSTANCE_GI_PROBE : {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( instance - > base_data ) ;
2016-12-20 04:21:07 +01:00
if ( ! gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . add ( & gi_probe - > update_element ) ;
}
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-19 16:14:41 +02:00
}
2021-02-04 11:43:08 +01:00
// handle occlusion changes if necessary
_instance_create_occlusion_rep ( instance ) ;
2017-03-05 16:44:50 +01:00
_instance_queue_update ( instance , true , true ) ;
2016-10-19 16:14:41 +02:00
}
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_layer_mask ( RID p_instance , uint32_t p_mask ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
2022-06-09 09:02:43 +02:00
if ( instance - > layer_mask = = p_mask ) {
return ;
}
2017-03-05 16:44:50 +01:00
instance - > layer_mask = p_mask ;
2022-06-09 09:02:43 +02:00
// update lights to show / hide shadows according to the new mask
if ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( instance - > base_data ) ;
if ( geom - > can_cast_shadows ) {
for ( List < Instance * > : : Element * E = geom - > lighting . front ( ) ; E ; E = E - > next ( ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2022-06-09 09:02:43 +02:00
}
}
}
2016-10-19 16:14:41 +02:00
}
2021-09-15 13:30:45 +02:00
2022-07-13 20:06:25 +02:00
void VisualServerScene : : instance_set_pivot_data ( RID p_instance , float p_sorting_offset , bool p_use_aabb_center ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > sorting_offset = p_sorting_offset ;
instance - > use_aabb_center = p_use_aabb_center ;
}
2021-09-15 13:30:45 +02:00
void VisualServerScene : : instance_reset_physics_interpolation ( RID p_instance ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2022-04-04 16:18:44 +02:00
if ( _interpolation_data . interpolation_enabled & & instance - > interpolated ) {
2024-06-05 08:45:03 +02:00
instance - > transform_prev = instance - > transform_curr ;
instance - > transform_checksum_prev = instance - > transform_checksum_curr ;
# ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
print_line ( " instance_reset_physics_interpolation .. tick " + itos ( Engine : : get_singleton ( ) - > get_physics_frames ( ) ) ) ;
print_line ( " \t prev " + rtos ( instance - > transform_prev . origin . x ) + " , curr " + rtos ( instance - > transform_curr . origin . x ) ) ;
# endif
2021-09-15 13:30:45 +02:00
}
}
void VisualServerScene : : instance_set_interpolated ( RID p_instance , bool p_interpolated ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > interpolated = p_interpolated ;
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_transform ( RID p_instance , const Transform & p_transform ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
2024-06-05 08:45:03 +02:00
# ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
print_line ( " instance_set_transform " + rtos ( p_transform . origin . x ) + " .. tick " + itos ( Engine : : get_singleton ( ) - > get_physics_frames ( ) ) ) ;
# endif
2022-04-04 16:18:44 +02:00
if ( ! ( _interpolation_data . interpolation_enabled & & instance - > interpolated ) | | ! instance - > scenario ) {
2021-09-15 13:30:45 +02:00
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 ) ;
2022-04-26 13:59:53 +02:00
# if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
if ( ( _interpolation_data . interpolation_enabled & & ! instance - > interpolated ) & & ( Engine : : get_singleton ( ) - > is_in_physics_frame ( ) ) ) {
2024-06-05 08:45:03 +02:00
PHYSICS_INTERPOLATION_NODE_WARNING ( instance - > object_id , " Non-interpolated triggered from physics process " ) ;
2022-04-26 13:59:53 +02:00
}
# endif
2021-09-15 13:30:45 +02:00
return ;
}
float new_checksum = TransformInterpolator : : checksum_transform ( p_transform ) ;
bool checksums_match = ( instance - > transform_checksum_curr = = new_checksum ) & & ( instance - > transform_checksum_prev = = new_checksum ) ;
// we can't entirely reject no changes because we need the interpolation
// system to keep on stewing
// Optimized check. First checks the checksums. If they pass it does the slow check at the end.
// Alternatively we can do this non-optimized and ignore the checksum...
// if no change
if ( checksums_match & & ( instance - > transform_curr = = p_transform ) & & ( instance - > transform_prev = = p_transform ) ) {
return ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
2019-01-26 23:09:48 +01:00
# 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
2021-09-15 13:30:45 +02:00
instance - > transform_curr = p_transform ;
2024-06-05 08:45:03 +02:00
# ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
print_line ( " \t prev " + rtos ( instance - > transform_prev . origin . x ) + " , curr " + rtos ( instance - > transform_curr . origin . x ) ) ;
# endif
2021-09-15 13:30:45 +02:00
// keep checksums up to date
instance - > transform_checksum_curr = new_checksum ;
if ( ! instance - > on_interpolate_transform_list ) {
2022-04-04 16:18:44 +02:00
_interpolation_data . instance_transform_update_list_curr - > push_back ( p_instance ) ;
2021-09-15 13:30:45 +02:00
instance - > on_interpolate_transform_list = true ;
} else {
2022-04-04 16:18:44 +02:00
DEV_ASSERT ( _interpolation_data . instance_transform_update_list_curr - > size ( ) ) ;
2021-09-15 13:30:45 +02:00
}
2022-05-10 09:54:56 +02:00
// If the instance is invisible, then we are simply updating the data flow, there is no need to calculate the interpolated
// transform or anything else.
// Ideally we would not even call the VisualServer::set_transform() when invisible but that would entail having logic
// to keep track of the previous transform on the SceneTree side. The "early out" below is less efficient but a lot cleaner codewise.
if ( ! instance - > visible ) {
return ;
}
// decide on the interpolation method .. slerp if possible
instance - > interpolation_method = TransformInterpolator : : find_method ( instance - > transform_prev . basis , instance - > transform_curr . basis ) ;
2021-09-15 13:30:45 +02:00
if ( ! instance - > on_interpolate_list ) {
2022-04-04 16:18:44 +02:00
_interpolation_data . instance_interpolate_update_list . push_back ( p_instance ) ;
2021-09-15 13:30:45 +02:00
instance - > on_interpolate_list = true ;
} else {
2022-04-04 16:18:44 +02:00
DEV_ASSERT ( _interpolation_data . instance_interpolate_update_list . size ( ) ) ;
2021-09-15 13:30:45 +02:00
}
2017-03-05 16:44:50 +01:00
_instance_queue_update ( instance , true ) ;
2022-04-26 13:59:53 +02:00
# if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
if ( ! Engine : : get_singleton ( ) - > is_in_physics_frame ( ) ) {
2024-06-05 08:45:03 +02:00
PHYSICS_INTERPOLATION_NODE_WARNING ( instance - > object_id , " Interpolated triggered from outside physics process " ) ;
2022-04-26 13:59:53 +02:00
}
# endif
2016-10-19 16:14:41 +02:00
}
2021-09-15 13:30:45 +02:00
2022-04-04 16:18:44 +02:00
void VisualServerScene : : InterpolationData : : notify_free_instance ( RID p_rid , Instance & r_instance ) {
2021-09-15 13:30:45 +02:00
r_instance . on_interpolate_list = false ;
r_instance . on_interpolate_transform_list = false ;
if ( ! interpolation_enabled ) {
return ;
}
// if the instance was on any of the lists, remove
instance_interpolate_update_list . erase_multiple_unordered ( p_rid ) ;
instance_transform_update_list_curr - > erase_multiple_unordered ( p_rid ) ;
instance_transform_update_list_prev - > erase_multiple_unordered ( p_rid ) ;
}
2022-04-04 16:18:44 +02:00
void VisualServerScene : : update_interpolation_tick ( bool p_process ) {
2024-06-05 08:45:03 +02:00
# ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
print_line ( " update_interpolation_tick " + itos ( Engine : : get_singleton ( ) - > get_physics_frames ( ) ) ) ;
# endif
2021-09-15 13:30:45 +02:00
// update interpolation in storage
VSG : : storage - > update_interpolation_tick ( p_process ) ;
// detect any that were on the previous transform list that are no longer active,
// we should remove them from the interpolate list
2022-04-04 16:18:44 +02:00
for ( unsigned int n = 0 ; n < _interpolation_data . instance_transform_update_list_prev - > size ( ) ; n + + ) {
const RID & rid = ( * _interpolation_data . instance_transform_update_list_prev ) [ n ] ;
2021-09-15 13:30:45 +02:00
Instance * instance = instance_owner . getornull ( rid ) ;
bool active = true ;
// no longer active? (either the instance deleted or no longer being transformed)
if ( instance & & ! instance - > on_interpolate_transform_list ) {
active = false ;
instance - > on_interpolate_list = false ;
// make sure the most recent transform is set
instance - > transform = instance - > transform_curr ;
// and that both prev and current are the same, just in case of any interpolations
instance - > transform_prev = instance - > transform_curr ;
// make sure are updated one more time to ensure the AABBs are correct
_instance_queue_update ( instance , true ) ;
}
if ( ! instance ) {
active = false ;
}
if ( ! active ) {
2022-04-04 16:18:44 +02:00
_interpolation_data . instance_interpolate_update_list . erase ( rid ) ;
2021-09-15 13:30:45 +02:00
}
}
// and now for any in the transform list (being actively interpolated), keep the previous transform
// value up to date ready for the next tick
if ( p_process ) {
2022-04-04 16:18:44 +02:00
for ( unsigned int n = 0 ; n < _interpolation_data . instance_transform_update_list_curr - > size ( ) ; n + + ) {
const RID & rid = ( * _interpolation_data . instance_transform_update_list_curr ) [ n ] ;
2021-09-15 13:30:45 +02:00
Instance * instance = instance_owner . getornull ( rid ) ;
if ( instance ) {
instance - > transform_prev = instance - > transform_curr ;
instance - > transform_checksum_prev = instance - > transform_checksum_curr ;
instance - > on_interpolate_transform_list = false ;
}
}
}
// we maintain a mirror list for the transform updates, so we can detect when an instance
// is no longer being transformed, and remove it from the interpolate list
2022-04-04 16:18:44 +02:00
SWAP ( _interpolation_data . instance_transform_update_list_curr , _interpolation_data . instance_transform_update_list_prev ) ;
2021-09-15 13:30:45 +02:00
// prepare for the next iteration
2022-04-04 16:18:44 +02:00
_interpolation_data . instance_transform_update_list_curr - > clear ( ) ;
2021-09-15 13:30:45 +02:00
}
2022-04-04 16:18:44 +02:00
void VisualServerScene : : update_interpolation_frame ( bool p_process ) {
2021-09-15 13:30:45 +02:00
// update interpolation in storage
VSG : : storage - > update_interpolation_frame ( p_process ) ;
if ( p_process ) {
real_t f = Engine : : get_singleton ( ) - > get_physics_interpolation_fraction ( ) ;
2022-04-04 16:18:44 +02:00
for ( unsigned int i = 0 ; i < _interpolation_data . instance_interpolate_update_list . size ( ) ; i + + ) {
const RID & rid = _interpolation_data . instance_interpolate_update_list [ i ] ;
2021-09-15 13:30:45 +02:00
Instance * instance = instance_owner . getornull ( rid ) ;
if ( instance ) {
TransformInterpolator : : interpolate_transform_via_method ( instance - > transform_prev , instance - > transform_curr , instance - > transform , f , instance - > interpolation_method ) ;
2024-06-05 08:45:03 +02:00
# ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
print_line ( " \t \t interpolated: " + rtos ( instance - > transform . origin . x ) + " \t ( prev " + rtos ( instance - > transform_prev . origin . x ) + " , curr " + rtos ( instance - > transform_curr . origin . x ) + " ) on tick " + itos ( Engine : : get_singleton ( ) - > get_physics_frames ( ) ) ) ;
# endif
2021-09-15 13:30:45 +02:00
// make sure AABBs are constantly up to date through the interpolation
_instance_queue_update ( instance , true ) ;
}
} // for n
}
}
2019-05-09 11:21:49 +02:00
void VisualServerScene : : instance_attach_object_instance_id ( RID p_instance , ObjectID p_id ) {
2017-03-05 16:44:50 +01:00
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
2019-05-09 11:21:49 +02:00
instance - > object_id = p_id ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_blend_shape_weight ( RID p_instance , int p_shape , float p_weight ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-11-25 00:46:55 +01:00
if ( instance - > update_item . in_list ( ) ) {
_update_dirty_instance ( instance ) ;
}
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_shape , instance - > blend_values . size ( ) ) ;
2021-05-13 16:16:17 +02:00
instance - > blend_values . write ( ) . ptr ( ) [ p_shape ] = p_weight ;
VSG : : storage - > mesh_set_blend_shape_values ( instance - > base , instance - > blend_values ) ;
2016-10-19 16:14:41 +02:00
}
2016-11-25 00:46:55 +01:00
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_surface_material ( RID p_instance , int p_surface , RID p_material ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
2018-11-08 19:58:52 +01:00
if ( instance - > base_type = = VS : : INSTANCE_MESH ) {
//may not have been updated yet
instance - > materials . resize ( VSG : : storage - > mesh_get_surface_count ( instance - > base ) ) ;
2016-11-25 00:46:55 +01:00
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_surface , instance - > materials . size ( ) ) ;
2016-10-19 16:14:41 +02:00
2016-11-10 03:55:06 +01:00
if ( instance - > materials [ p_surface ] . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
VSG : : storage - > material_remove_instance_owner ( instance - > materials [ p_surface ] , instance ) ;
2016-11-10 03:55:06 +01:00
}
2018-07-25 03:11:03 +02:00
instance - > materials . write [ p_surface ] = p_material ;
2018-11-14 13:32:39 +01:00
instance - > base_changed ( false , true ) ;
2016-11-10 03:55:06 +01:00
if ( instance - > materials [ p_surface ] . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
VSG : : storage - > material_add_instance_owner ( instance - > materials [ p_surface ] , instance ) ;
2016-11-10 03:55:06 +01:00
}
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_visible ( RID p_instance , bool p_visible ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2017-01-04 05:16:14 +01:00
2021-05-05 12:44:11 +02:00
if ( instance - > visible = = p_visible ) {
2017-01-04 05:16:14 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2017-01-04 05:16:14 +01:00
2017-03-05 16:44:50 +01:00
instance - > visible = p_visible ;
2017-01-04 05:16:14 +01:00
2022-06-14 11:19:44 +02:00
// Special case for physics interpolation, we want to ensure the interpolated data is up to date
if ( _interpolation_data . interpolation_enabled & & p_visible & & instance - > interpolated & & instance - > scenario & & ! instance - > on_interpolate_list ) {
// Do all the extra work we normally do on instance_set_transform(), because this is optimized out for hidden instances.
// This prevents a glitch of stale interpolation transform data when unhiding before the next physics tick.
instance - > interpolation_method = TransformInterpolator : : find_method ( instance - > transform_prev . basis , instance - > transform_curr . basis ) ;
_interpolation_data . instance_interpolate_update_list . push_back ( p_instance ) ;
instance - > on_interpolate_list = true ;
_instance_queue_update ( instance , true ) ;
2022-06-19 12:26:13 +02:00
// We must also place on the transform update list for a tick, so the system
// can auto-detect if the instance is no longer moving, and remove from the interpolate lists again.
// If this step is ignored, an unmoving instance could remain on the interpolate lists indefinitely
// (or rather until the object is deleted) and cause unnecessary updates and drawcalls.
if ( ! instance - > on_interpolate_transform_list ) {
_interpolation_data . instance_transform_update_list_curr - > push_back ( p_instance ) ;
instance - > on_interpolate_transform_list = true ;
}
2022-06-14 11:19:44 +02:00
}
2021-05-20 12:47:34 +02:00
// give the opportunity for the spatial partitioning scene to use a special implementation of visibility
2021-01-29 18:47:40 +01:00
// for efficiency (supported in BVH but not octree)
2021-02-13 19:53:32 +01:00
// slightly bug prone optimization here - we want to avoid doing a collision check twice
// once when activating, and once when calling set_pairable. We do this by deferring the collision check.
// However, in some cases (notably meshes), set_pairable never gets called. So we want to catch this case
// and force a collision check (see later in this function).
// This is only done in two stages to maintain compatibility with the octree.
if ( instance - > spatial_partition_id & & instance - > scenario ) {
2021-01-29 18:47:40 +01:00
if ( p_visible ) {
instance - > scenario - > sps - > activate ( instance - > spatial_partition_id , instance - > transformed_aabb ) ;
} else {
instance - > scenario - > sps - > deactivate ( instance - > spatial_partition_id ) ;
}
}
2019-10-01 20:09:03 +02:00
// when showing or hiding geometry, lights must be kept up to date to show / hide shadows
if ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( instance - > base_data ) ;
if ( geom - > can_cast_shadows ) {
for ( List < Instance * > : : Element * E = geom - > lighting . front ( ) ; E ; E = E - > next ( ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2019-10-01 20:09:03 +02:00
}
}
}
2017-03-05 16:44:50 +01:00
switch ( instance - > base_type ) {
2017-01-04 05:16:14 +01:00
case VS : : INSTANCE_LIGHT : {
2020-10-21 14:13:20 +02:00
if ( VSG : : storage - > light_get_type ( instance - > base ) ! = VS : : LIGHT_DIRECTIONAL & & instance - > spatial_partition_id & & instance - > scenario ) {
2021-12-03 12:36:39 +01:00
instance - > scenario - > sps - > set_pairable ( instance , p_visible , 1 < < VS : : INSTANCE_LIGHT , p_visible ? VS : : INSTANCE_GEOMETRY_MASK : 0 ) ;
2017-01-04 05:16:14 +01:00
}
} break ;
case VS : : INSTANCE_REFLECTION_PROBE : {
2020-10-21 14:13:20 +02:00
if ( instance - > spatial_partition_id & & instance - > scenario ) {
2021-12-03 12:36:39 +01:00
instance - > scenario - > sps - > set_pairable ( instance , p_visible , 1 < < VS : : INSTANCE_REFLECTION_PROBE , p_visible ? VS : : INSTANCE_GEOMETRY_MASK : 0 ) ;
2017-01-04 05:16:14 +01:00
}
2017-12-14 12:59:46 +01:00
} break ;
case VS : : INSTANCE_LIGHTMAP_CAPTURE : {
2020-10-21 14:13:20 +02:00
if ( instance - > spatial_partition_id & & instance - > scenario ) {
2021-12-03 12:36:39 +01:00
instance - > scenario - > sps - > set_pairable ( instance , p_visible , 1 < < VS : : INSTANCE_LIGHTMAP_CAPTURE , p_visible ? VS : : INSTANCE_GEOMETRY_MASK : 0 ) ;
2017-12-14 12:59:46 +01:00
}
2017-01-04 05:16:14 +01:00
} break ;
case VS : : INSTANCE_GI_PROBE : {
2020-10-21 14:13:20 +02:00
if ( instance - > spatial_partition_id & & instance - > scenario ) {
2021-12-03 12:36:39 +01:00
instance - > scenario - > sps - > set_pairable ( instance , p_visible , 1 < < VS : : INSTANCE_GI_PROBE , p_visible ? ( VS : : INSTANCE_GEOMETRY_MASK | ( 1 < < VS : : INSTANCE_LIGHT ) ) : 0 ) ;
2017-01-04 05:16:14 +01:00
}
} break ;
2019-04-09 17:08:36 +02:00
default : {
2021-02-13 19:53:32 +01:00
// if we haven't called set_pairable, we STILL need to do a collision check
// for activated items because we deferred it earlier in the call to activate.
if ( instance - > spatial_partition_id & & instance - > scenario & & p_visible ) {
instance - > scenario - > sps - > force_collision_check ( instance - > spatial_partition_id ) ;
}
2019-04-09 17:08:36 +02:00
}
2017-01-04 05:16:14 +01:00
}
}
2017-11-20 20:54:26 +01:00
inline bool is_geometry_instance ( VisualServer : : InstanceType p_type ) {
return p_type = = VS : : INSTANCE_MESH | | p_type = = VS : : INSTANCE_MULTIMESH | | p_type = = VS : : INSTANCE_PARTICLES | | p_type = = VS : : INSTANCE_IMMEDIATE ;
}
2020-12-19 18:17:22 +01:00
void VisualServerScene : : instance_set_use_lightmap ( RID p_instance , RID p_lightmap_instance , RID p_lightmap , int p_lightmap_slice , const Rect2 & p_lightmap_uv_rect ) {
2017-12-14 12:59:46 +01:00
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2021-03-02 12:29:16 +01:00
instance - > lightmap = RID ( ) ;
instance - > lightmap_slice = - 1 ;
instance - > lightmap_uv_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
instance - > baked_light = false ;
2017-12-14 12:59:46 +01:00
if ( instance - > lightmap_capture ) {
InstanceLightmapCaptureData * lightmap_capture = static_cast < InstanceLightmapCaptureData * > ( ( ( Instance * ) instance - > lightmap_capture ) - > base_data ) ;
lightmap_capture - > users . erase ( instance ) ;
2021-05-04 16:00:45 +02:00
instance - > lightmap_capture = nullptr ;
2017-12-14 12:59:46 +01:00
}
if ( p_lightmap_instance . is_valid ( ) ) {
Instance * lightmap_instance = instance_owner . get ( p_lightmap_instance ) ;
ERR_FAIL_COND ( ! lightmap_instance ) ;
ERR_FAIL_COND ( lightmap_instance - > base_type ! = VS : : INSTANCE_LIGHTMAP_CAPTURE ) ;
instance - > lightmap_capture = lightmap_instance ;
InstanceLightmapCaptureData * lightmap_capture = static_cast < InstanceLightmapCaptureData * > ( ( ( Instance * ) instance - > lightmap_capture ) - > base_data ) ;
lightmap_capture - > users . insert ( instance ) ;
instance - > lightmap = p_lightmap ;
2020-12-19 18:17:22 +01:00
instance - > lightmap_slice = p_lightmap_slice ;
instance - > lightmap_uv_rect = p_lightmap_uv_rect ;
2021-03-02 12:29:16 +01:00
instance - > baked_light = true ;
2017-12-14 12:59:46 +01:00
}
}
2017-11-20 20:54:26 +01:00
void VisualServerScene : : instance_set_custom_aabb ( RID p_instance , AABB p_aabb ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
ERR_FAIL_COND ( ! is_geometry_instance ( instance - > base_type ) ) ;
2017-11-25 04:07:54 +01:00
if ( p_aabb ! = AABB ( ) ) {
2017-11-20 20:54:26 +01:00
// Set custom AABB
2021-05-05 12:44:11 +02:00
if ( instance - > custom_aabb = = nullptr ) {
2017-11-20 20:54:26 +01:00
instance - > custom_aabb = memnew ( AABB ) ;
2021-05-05 12:44:11 +02:00
}
2017-11-20 20:54:26 +01:00
* instance - > custom_aabb = p_aabb ;
} else {
// Clear custom AABB
2021-05-04 16:00:45 +02:00
if ( instance - > custom_aabb ! = nullptr ) {
2017-11-20 20:54:26 +01:00
memdelete ( instance - > custom_aabb ) ;
2021-05-04 16:00:45 +02:00
instance - > custom_aabb = nullptr ;
2017-11-20 20:54:26 +01:00
}
}
2021-05-05 12:44:11 +02:00
if ( instance - > scenario ) {
2017-11-20 20:54:26 +01:00
_instance_queue_update ( instance , true , false ) ;
2021-05-05 12:44:11 +02:00
}
2017-11-20 20:54:26 +01:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_attach_skeleton ( RID p_instance , RID p_skeleton ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-19 16:14:41 +02:00
2021-05-05 12:44:11 +02:00
if ( instance - > skeleton = = p_skeleton ) {
2016-11-22 05:26:56 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-11-22 05:26:56 +01:00
if ( instance - > skeleton . is_valid ( ) ) {
2017-08-08 03:18:12 +02:00
VSG : : storage - > instance_remove_skeleton ( instance - > skeleton , instance ) ;
2016-11-22 05:26:56 +01:00
}
2017-03-05 16:44:50 +01:00
instance - > skeleton = p_skeleton ;
2016-10-19 16:14:41 +02:00
2016-11-22 05:26:56 +01:00
if ( instance - > skeleton . is_valid ( ) ) {
2017-08-08 03:18:12 +02:00
VSG : : storage - > instance_add_skeleton ( instance - > skeleton , instance ) ;
2016-11-22 05:26:56 +01:00
}
2017-03-05 16:44:50 +01:00
_instance_queue_update ( instance , true ) ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_exterior ( RID p_instance , bool p_enabled ) {
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_set_extra_visibility_margin ( RID p_instance , real_t p_margin ) {
2018-03-04 14:20:59 +01:00
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > extra_margin = p_margin ;
_instance_queue_update ( instance , true , false ) ;
2016-10-19 16:14:41 +02:00
}
2021-02-04 11:43:08 +01:00
// Portals
void VisualServerScene : : instance_set_portal_mode ( RID p_instance , VisualServer : : InstancePortalMode p_mode ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
// no change?
if ( instance - > portal_mode = = p_mode ) {
return ;
}
// should this happen?
if ( ! instance - > scenario ) {
instance - > portal_mode = p_mode ;
return ;
}
// destroy previous occlusion instance?
_instance_destroy_occlusion_rep ( instance ) ;
instance - > portal_mode = p_mode ;
_instance_create_occlusion_rep ( instance ) ;
}
void VisualServerScene : : _instance_create_occlusion_rep ( Instance * p_instance ) {
ERR_FAIL_COND ( ! p_instance ) ;
ERR_FAIL_COND ( ! p_instance - > scenario ) ;
switch ( p_instance - > portal_mode ) {
default : {
p_instance - > occlusion_handle = 0 ;
} break ;
case VisualServer : : InstancePortalMode : : INSTANCE_PORTAL_MODE_ROAMING : {
p_instance - > occlusion_handle = p_instance - > scenario - > _portal_renderer . instance_moving_create ( p_instance , p_instance - > self , false , p_instance - > transformed_aabb ) ;
} break ;
case VisualServer : : InstancePortalMode : : INSTANCE_PORTAL_MODE_GLOBAL : {
p_instance - > occlusion_handle = p_instance - > scenario - > _portal_renderer . instance_moving_create ( p_instance , p_instance - > self , true , p_instance - > transformed_aabb ) ;
} break ;
}
}
void VisualServerScene : : _instance_destroy_occlusion_rep ( Instance * p_instance ) {
ERR_FAIL_COND ( ! p_instance ) ;
ERR_FAIL_COND ( ! p_instance - > scenario ) ;
// not an error, can occur
if ( ! p_instance - > occlusion_handle ) {
return ;
}
p_instance - > scenario - > _portal_renderer . instance_moving_destroy ( p_instance - > occlusion_handle ) ;
// unset
p_instance - > occlusion_handle = 0 ;
}
void * VisualServerScene : : _instance_get_from_rid ( RID p_instance ) {
Instance * instance = instance_owner . get ( p_instance ) ;
return instance ;
}
bool VisualServerScene : : _instance_get_transformed_aabb ( RID p_instance , AABB & r_aabb ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_NULL_V ( instance , false ) ;
r_aabb = instance - > transformed_aabb ;
return true ;
}
// the portal has to be associated with a scenario, this is assumed to be
// the same scenario as the portal node
RID VisualServerScene : : portal_create ( ) {
Portal * portal = memnew ( Portal ) ;
ERR_FAIL_COND_V ( ! portal , RID ( ) ) ;
RID portal_rid = portal_owner . make_rid ( portal ) ;
return portal_rid ;
}
// should not be called multiple times, different scenarios etc, but just in case, we will support this
void VisualServerScene : : portal_set_scenario ( RID p_portal , RID p_scenario ) {
Portal * portal = portal_owner . getornull ( p_portal ) ;
ERR_FAIL_COND ( ! portal ) ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
// noop?
if ( portal - > scenario = = scenario ) {
return ;
}
// if the portal is in a scenario already, remove it
if ( portal - > scenario ) {
portal - > scenario - > _portal_renderer . portal_destroy ( portal - > scenario_portal_id ) ;
portal - > scenario = nullptr ;
portal - > scenario_portal_id = 0 ;
}
// create when entering the world
if ( scenario ) {
portal - > scenario = scenario ;
// defer the actual creation to here
portal - > scenario_portal_id = scenario - > _portal_renderer . portal_create ( ) ;
}
}
2021-07-29 12:57:32 +02:00
void VisualServerScene : : portal_set_geometry ( RID p_portal , const Vector < Vector3 > & p_points , real_t p_margin ) {
2021-02-04 11:43:08 +01:00
Portal * portal = portal_owner . getornull ( p_portal ) ;
ERR_FAIL_COND ( ! portal ) ;
ERR_FAIL_COND ( ! portal - > scenario ) ;
2021-07-29 12:57:32 +02:00
portal - > scenario - > _portal_renderer . portal_set_geometry ( portal - > scenario_portal_id , p_points , p_margin ) ;
2021-02-04 11:43:08 +01:00
}
void VisualServerScene : : portal_link ( RID p_portal , RID p_room_from , RID p_room_to , bool p_two_way ) {
Portal * portal = portal_owner . getornull ( p_portal ) ;
ERR_FAIL_COND ( ! portal ) ;
ERR_FAIL_COND ( ! portal - > scenario ) ;
Room * room_from = room_owner . getornull ( p_room_from ) ;
ERR_FAIL_COND ( ! room_from ) ;
Room * room_to = room_owner . getornull ( p_room_to ) ;
ERR_FAIL_COND ( ! room_to ) ;
portal - > scenario - > _portal_renderer . portal_link ( portal - > scenario_portal_id , room_from - > scenario_room_id , room_to - > scenario_room_id , p_two_way ) ;
}
void VisualServerScene : : portal_set_active ( RID p_portal , bool p_active ) {
Portal * portal = portal_owner . getornull ( p_portal ) ;
ERR_FAIL_COND ( ! portal ) ;
ERR_FAIL_COND ( ! portal - > scenario ) ;
portal - > scenario - > _portal_renderer . portal_set_active ( portal - > scenario_portal_id , p_active ) ;
}
RID VisualServerScene : : ghost_create ( ) {
Ghost * ci = memnew ( Ghost ) ;
ERR_FAIL_COND_V ( ! ci , RID ( ) ) ;
RID ci_rid = ghost_owner . make_rid ( ci ) ;
return ci_rid ;
}
void VisualServerScene : : ghost_set_scenario ( RID p_ghost , RID p_scenario , ObjectID p_id , const AABB & p_aabb ) {
Ghost * ci = ghost_owner . getornull ( p_ghost ) ;
ERR_FAIL_COND ( ! ci ) ;
ci - > aabb = p_aabb ;
ci - > object_id = p_id ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
// noop?
if ( ci - > scenario = = scenario ) {
return ;
}
// if the portal is in a scenario already, remove it
if ( ci - > scenario ) {
_ghost_destroy_occlusion_rep ( ci ) ;
ci - > scenario = nullptr ;
}
// create when entering the world
if ( scenario ) {
ci - > scenario = scenario ;
// defer the actual creation to here
_ghost_create_occlusion_rep ( ci ) ;
}
}
void VisualServerScene : : ghost_update ( RID p_ghost , const AABB & p_aabb ) {
Ghost * ci = ghost_owner . getornull ( p_ghost ) ;
ERR_FAIL_COND ( ! ci ) ;
ERR_FAIL_COND ( ! ci - > scenario ) ;
ci - > aabb = p_aabb ;
if ( ci - > rghost_handle ) {
ci - > scenario - > _portal_renderer . rghost_update ( ci - > rghost_handle , p_aabb ) ;
}
}
void VisualServerScene : : _ghost_create_occlusion_rep ( Ghost * p_ghost ) {
ERR_FAIL_COND ( ! p_ghost ) ;
ERR_FAIL_COND ( ! p_ghost - > scenario ) ;
if ( ! p_ghost - > rghost_handle ) {
p_ghost - > rghost_handle = p_ghost - > scenario - > _portal_renderer . rghost_create ( p_ghost - > object_id , p_ghost - > aabb ) ;
}
}
void VisualServerScene : : _ghost_destroy_occlusion_rep ( Ghost * p_ghost ) {
ERR_FAIL_COND ( ! p_ghost ) ;
ERR_FAIL_COND ( ! p_ghost - > scenario ) ;
// not an error, can occur
if ( ! p_ghost - > rghost_handle ) {
return ;
}
p_ghost - > scenario - > _portal_renderer . rghost_destroy ( p_ghost - > rghost_handle ) ;
p_ghost - > rghost_handle = 0 ;
}
RID VisualServerScene : : roomgroup_create ( ) {
RoomGroup * rg = memnew ( RoomGroup ) ;
ERR_FAIL_COND_V ( ! rg , RID ( ) ) ;
RID roomgroup_rid = roomgroup_owner . make_rid ( rg ) ;
return roomgroup_rid ;
}
void VisualServerScene : : roomgroup_prepare ( RID p_roomgroup , ObjectID p_roomgroup_object_id ) {
RoomGroup * roomgroup = roomgroup_owner . getornull ( p_roomgroup ) ;
ERR_FAIL_COND ( ! roomgroup ) ;
ERR_FAIL_COND ( ! roomgroup - > scenario ) ;
roomgroup - > scenario - > _portal_renderer . roomgroup_prepare ( roomgroup - > scenario_roomgroup_id , p_roomgroup_object_id ) ;
}
void VisualServerScene : : roomgroup_set_scenario ( RID p_roomgroup , RID p_scenario ) {
RoomGroup * rg = roomgroup_owner . getornull ( p_roomgroup ) ;
ERR_FAIL_COND ( ! rg ) ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
// noop?
if ( rg - > scenario = = scenario ) {
return ;
}
// if the portal is in a scenario already, remove it
if ( rg - > scenario ) {
rg - > scenario - > _portal_renderer . roomgroup_destroy ( rg - > scenario_roomgroup_id ) ;
rg - > scenario = nullptr ;
rg - > scenario_roomgroup_id = 0 ;
}
// create when entering the world
if ( scenario ) {
rg - > scenario = scenario ;
// defer the actual creation to here
rg - > scenario_roomgroup_id = scenario - > _portal_renderer . roomgroup_create ( ) ;
}
}
void VisualServerScene : : roomgroup_add_room ( RID p_roomgroup , RID p_room ) {
RoomGroup * roomgroup = roomgroup_owner . getornull ( p_roomgroup ) ;
ERR_FAIL_COND ( ! roomgroup ) ;
ERR_FAIL_COND ( ! roomgroup - > scenario ) ;
Room * room = room_owner . getornull ( p_room ) ;
ERR_FAIL_COND ( ! room ) ;
ERR_FAIL_COND ( ! room - > scenario ) ;
ERR_FAIL_COND ( roomgroup - > scenario ! = room - > scenario ) ;
roomgroup - > scenario - > _portal_renderer . roomgroup_add_room ( roomgroup - > scenario_roomgroup_id , room - > scenario_room_id ) ;
}
2021-08-05 16:44:43 +02:00
// Occluders
2022-02-11 15:36:02 +01:00
RID VisualServerScene : : occluder_instance_create ( ) {
OccluderInstance * ro = memnew ( OccluderInstance ) ;
2021-08-05 16:44:43 +02:00
ERR_FAIL_COND_V ( ! ro , RID ( ) ) ;
2022-02-11 15:36:02 +01:00
RID occluder_rid = occluder_instance_owner . make_rid ( ro ) ;
2021-08-05 16:44:43 +02:00
return occluder_rid ;
}
2022-02-11 15:36:02 +01:00
void VisualServerScene : : occluder_instance_link_resource ( RID p_occluder_instance , RID p_occluder_resource ) {
OccluderInstance * oi = occluder_instance_owner . getornull ( p_occluder_instance ) ;
ERR_FAIL_COND ( ! oi ) ;
ERR_FAIL_COND ( ! oi - > scenario ) ;
OccluderResource * res = occluder_resource_owner . getornull ( p_occluder_resource ) ;
ERR_FAIL_COND ( ! res ) ;
oi - > scenario - > _portal_renderer . occluder_instance_link ( oi - > scenario_occluder_id , res - > occluder_resource_id ) ;
}
void VisualServerScene : : occluder_instance_set_scenario ( RID p_occluder_instance , RID p_scenario ) {
OccluderInstance * oi = occluder_instance_owner . getornull ( p_occluder_instance ) ;
ERR_FAIL_COND ( ! oi ) ;
2021-08-05 16:44:43 +02:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
// noop?
2022-02-11 15:36:02 +01:00
if ( oi - > scenario = = scenario ) {
2021-08-05 16:44:43 +02:00
return ;
}
// if the portal is in a scenario already, remove it
2022-02-11 15:36:02 +01:00
if ( oi - > scenario ) {
oi - > scenario - > _portal_renderer . occluder_instance_destroy ( oi - > scenario_occluder_id ) ;
oi - > scenario = nullptr ;
oi - > scenario_occluder_id = 0 ;
2021-08-05 16:44:43 +02:00
}
// create when entering the world
if ( scenario ) {
2022-02-11 15:36:02 +01:00
oi - > scenario = scenario ;
oi - > scenario_occluder_id = scenario - > _portal_renderer . occluder_instance_create ( ) ;
2021-08-05 16:44:43 +02:00
}
}
2022-02-11 15:36:02 +01:00
void VisualServerScene : : occluder_instance_set_active ( RID p_occluder_instance , bool p_active ) {
OccluderInstance * oi = occluder_instance_owner . getornull ( p_occluder_instance ) ;
ERR_FAIL_COND ( ! oi ) ;
ERR_FAIL_COND ( ! oi - > scenario ) ;
oi - > scenario - > _portal_renderer . occluder_instance_set_active ( oi - > scenario_occluder_id , p_active ) ;
}
void VisualServerScene : : occluder_instance_set_transform ( RID p_occluder_instance , const Transform & p_xform ) {
OccluderInstance * oi = occluder_instance_owner . getornull ( p_occluder_instance ) ;
ERR_FAIL_COND ( ! oi ) ;
ERR_FAIL_COND ( ! oi - > scenario ) ;
oi - > scenario - > _portal_renderer . occluder_instance_set_transform ( oi - > scenario_occluder_id , p_xform ) ;
}
RID VisualServerScene : : occluder_resource_create ( ) {
OccluderResource * res = memnew ( OccluderResource ) ;
ERR_FAIL_COND_V ( ! res , RID ( ) ) ;
res - > occluder_resource_id = _portal_resources . occluder_resource_create ( ) ;
RID occluder_resource_rid = occluder_resource_owner . make_rid ( res ) ;
return occluder_resource_rid ;
2021-08-05 16:44:43 +02:00
}
2022-02-11 15:36:02 +01:00
void VisualServerScene : : occluder_resource_prepare ( RID p_occluder_resource , VisualServer : : OccluderType p_type ) {
OccluderResource * res = occluder_resource_owner . getornull ( p_occluder_resource ) ;
ERR_FAIL_COND ( ! res ) ;
_portal_resources . occluder_resource_prepare ( res - > occluder_resource_id , ( VSOccluder_Instance : : Type ) p_type ) ;
2021-08-05 16:44:43 +02:00
}
2022-02-11 15:36:02 +01:00
void VisualServerScene : : occluder_resource_spheres_update ( RID p_occluder_resource , const Vector < Plane > & p_spheres ) {
OccluderResource * res = occluder_resource_owner . getornull ( p_occluder_resource ) ;
ERR_FAIL_COND ( ! res ) ;
_portal_resources . occluder_resource_update_spheres ( res - > occluder_resource_id , p_spheres ) ;
2021-08-05 16:44:43 +02:00
}
2022-02-11 15:36:02 +01:00
void VisualServerScene : : occluder_resource_mesh_update ( RID p_occluder_resource , const Geometry : : OccluderMeshData & p_mesh_data ) {
OccluderResource * res = occluder_resource_owner . getornull ( p_occluder_resource ) ;
ERR_FAIL_COND ( ! res ) ;
_portal_resources . occluder_resource_update_mesh ( res - > occluder_resource_id , p_mesh_data ) ;
2021-08-17 14:40:39 +02:00
}
2021-08-05 16:44:43 +02:00
void VisualServerScene : : set_use_occlusion_culling ( bool p_enable ) {
// this is not scenario specific, and is global
// (mainly for debugging)
PortalRenderer : : use_occlusion_culling = p_enable ;
}
2021-08-17 14:40:39 +02:00
Geometry : : MeshData VisualServerScene : : occlusion_debug_get_current_polys ( RID p_scenario ) const {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
if ( ! scenario ) {
return Geometry : : MeshData ( ) ;
}
return scenario - > _portal_renderer . occlusion_debug_get_current_polys ( ) ;
}
2021-02-04 11:43:08 +01:00
// Rooms
void VisualServerScene : : callbacks_register ( VisualServerCallbacks * p_callbacks ) {
_visual_server_callbacks = p_callbacks ;
}
// the room has to be associated with a scenario, this is assumed to be
// the same scenario as the room node
RID VisualServerScene : : room_create ( ) {
Room * room = memnew ( Room ) ;
ERR_FAIL_COND_V ( ! room , RID ( ) ) ;
RID room_rid = room_owner . make_rid ( room ) ;
return room_rid ;
}
// should not be called multiple times, different scenarios etc, but just in case, we will support this
void VisualServerScene : : room_set_scenario ( RID p_room , RID p_scenario ) {
Room * room = room_owner . getornull ( p_room ) ;
ERR_FAIL_COND ( ! room ) ;
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
// no change?
if ( room - > scenario = = scenario ) {
return ;
}
// if the room has an existing scenario, remove from it
if ( room - > scenario ) {
room - > scenario - > _portal_renderer . room_destroy ( room - > scenario_room_id ) ;
room - > scenario = nullptr ;
room - > scenario_room_id = 0 ;
}
// create when entering the world
if ( scenario ) {
room - > scenario = scenario ;
// defer the actual creation to here
room - > scenario_room_id = scenario - > _portal_renderer . room_create ( ) ;
}
}
void VisualServerScene : : room_add_ghost ( RID p_room , ObjectID p_object_id , const AABB & p_aabb ) {
Room * room = room_owner . getornull ( p_room ) ;
ERR_FAIL_COND ( ! room ) ;
ERR_FAIL_COND ( ! room - > scenario ) ;
room - > scenario - > _portal_renderer . room_add_ghost ( room - > scenario_room_id , p_object_id , p_aabb ) ;
}
void VisualServerScene : : room_add_instance ( RID p_room , RID p_instance , const AABB & p_aabb , const Vector < Vector3 > & p_object_pts ) {
Room * room = room_owner . getornull ( p_room ) ;
ERR_FAIL_COND ( ! room ) ;
ERR_FAIL_COND ( ! room - > scenario ) ;
Instance * instance = instance_owner . getornull ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
AABB bb = p_aabb ;
// the aabb passed from the client takes no account of the extra cull margin,
// so we need to add this manually.
// It is assumed it is in world space.
if ( instance - > extra_margin ! = 0.0 ) {
bb . grow_by ( instance - > extra_margin ) ;
}
bool dynamic = false ;
// don't add if portal mode is not static or dynamic
switch ( instance - > portal_mode ) {
default : {
return ; // this should be taken care of by the calling function, but just in case
} break ;
case VisualServer : : InstancePortalMode : : INSTANCE_PORTAL_MODE_DYNAMIC : {
dynamic = true ;
} break ;
case VisualServer : : InstancePortalMode : : INSTANCE_PORTAL_MODE_STATIC : {
dynamic = false ;
} break ;
}
instance - > occlusion_handle = room - > scenario - > _portal_renderer . room_add_instance ( room - > scenario_room_id , p_instance , bb , dynamic , p_object_pts ) ;
}
void VisualServerScene : : room_prepare ( RID p_room , int32_t p_priority ) {
Room * room = room_owner . getornull ( p_room ) ;
ERR_FAIL_COND ( ! room ) ;
ERR_FAIL_COND ( ! room - > scenario ) ;
room - > scenario - > _portal_renderer . room_prepare ( room - > scenario_room_id , p_priority ) ;
}
void VisualServerScene : : room_set_bound ( RID p_room , ObjectID p_room_object_id , const Vector < Plane > & p_convex , const AABB & p_aabb , const Vector < Vector3 > & p_verts ) {
Room * room = room_owner . getornull ( p_room ) ;
ERR_FAIL_COND ( ! room ) ;
ERR_FAIL_COND ( ! room - > scenario ) ;
room - > scenario - > _portal_renderer . room_set_bound ( room - > scenario_room_id , p_room_object_id , p_convex , p_aabb , p_verts ) ;
}
2021-09-24 15:00:24 +02:00
void VisualServerScene : : rooms_unload ( RID p_scenario , String p_reason ) {
2021-02-04 11:43:08 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2021-09-24 15:00:24 +02:00
scenario - > _portal_renderer . rooms_unload ( p_reason ) ;
2021-02-04 11:43:08 +01:00
}
void VisualServerScene : : rooms_and_portals_clear ( RID p_scenario ) {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > _portal_renderer . rooms_and_portals_clear ( ) ;
}
2021-08-08 20:31:02 +02:00
void VisualServerScene : : rooms_finalize ( RID p_scenario , bool p_generate_pvs , bool p_cull_using_pvs , bool p_use_secondary_pvs , bool p_use_signals , String p_pvs_filename , bool p_use_simple_pvs , bool p_log_pvs_generation ) {
2021-02-04 11:43:08 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2021-08-08 20:31:02 +02:00
scenario - > _portal_renderer . rooms_finalize ( p_generate_pvs , p_cull_using_pvs , p_use_secondary_pvs , p_use_signals , p_pvs_filename , p_use_simple_pvs , p_log_pvs_generation ) ;
2021-02-04 11:43:08 +01:00
}
void VisualServerScene : : rooms_override_camera ( RID p_scenario , bool p_override , const Vector3 & p_point , const Vector < Plane > * p_convex ) {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > _portal_renderer . rooms_override_camera ( p_override , p_point , p_convex ) ;
}
void VisualServerScene : : rooms_set_active ( RID p_scenario , bool p_active ) {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > _portal_renderer . rooms_set_active ( p_active ) ;
}
2021-11-12 16:32:23 +01:00
void VisualServerScene : : rooms_set_params ( RID p_scenario , int p_portal_depth_limit , real_t p_roaming_expansion_margin ) {
2021-02-04 11:43:08 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
2021-11-12 16:32:23 +01:00
scenario - > _portal_renderer . rooms_set_params ( p_portal_depth_limit , p_roaming_expansion_margin ) ;
2021-02-04 11:43:08 +01:00
}
void VisualServerScene : : rooms_set_debug_feature ( RID p_scenario , VisualServer : : RoomsDebugFeature p_feature , bool p_active ) {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
switch ( p_feature ) {
default : {
} break ;
case VisualServer : : ROOMS_DEBUG_SPRAWL : {
scenario - > _portal_renderer . set_debug_sprawl ( p_active ) ;
} break ;
}
}
void VisualServerScene : : rooms_update_gameplay_monitor ( RID p_scenario , const Vector < Vector3 > & p_camera_positions ) {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND ( ! scenario ) ;
scenario - > _portal_renderer . rooms_update_gameplay_monitor ( p_camera_positions ) ;
}
2021-08-01 09:56:26 +02:00
bool VisualServerScene : : rooms_is_loaded ( RID p_scenario ) const {
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , false ) ;
return scenario - > _portal_renderer . rooms_is_loaded ( ) ;
}
2017-11-17 03:09:00 +01:00
Vector < ObjectID > VisualServerScene : : instances_cull_aabb ( const AABB & p_aabb , RID p_scenario ) const {
2016-10-30 01:48:09 +02:00
Vector < ObjectID > instances ;
2017-03-05 16:44:50 +01:00
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , instances ) ;
2016-10-30 01:48:09 +02:00
2017-03-05 16:44:50 +01:00
const_cast < VisualServerScene * > ( this ) - > update_dirty_instances ( ) ; // check dirty instances before culling
2016-10-30 01:48:09 +02:00
2017-03-05 16:44:50 +01:00
int culled = 0 ;
2016-10-30 01:48:09 +02:00
Instance * cull [ 1024 ] ;
2020-10-21 14:13:20 +02:00
culled = scenario - > sps - > cull_aabb ( p_aabb , cull , 1024 ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < culled ; i + + ) {
Instance * instance = cull [ i ] ;
2016-10-30 01:48:09 +02:00
ERR_CONTINUE ( ! instance ) ;
2021-05-05 12:44:11 +02:00
if ( instance - > object_id = = 0 ) {
2016-10-30 01:48:09 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-10-30 01:48:09 +02:00
2019-05-09 11:21:49 +02:00
instances . push_back ( instance - > object_id ) ;
2016-10-30 01:48:09 +02:00
}
return instances ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
Vector < ObjectID > VisualServerScene : : instances_cull_ray ( const Vector3 & p_from , const Vector3 & p_to , RID p_scenario ) const {
2016-10-30 01:48:09 +02:00
Vector < ObjectID > instances ;
2017-03-05 16:44:50 +01:00
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , instances ) ;
const_cast < VisualServerScene * > ( this ) - > update_dirty_instances ( ) ; // check dirty instances before culling
2016-10-30 01:48:09 +02:00
2017-03-05 16:44:50 +01:00
int culled = 0 ;
2016-10-30 01:48:09 +02:00
Instance * cull [ 1024 ] ;
2020-10-21 14:13:20 +02:00
culled = scenario - > sps - > cull_segment ( p_from , p_from + p_to * 10000 , cull , 1024 ) ;
2016-10-30 01:48:09 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < culled ; i + + ) {
Instance * instance = cull [ i ] ;
2016-10-30 01:48:09 +02:00
ERR_CONTINUE ( ! instance ) ;
2021-05-05 12:44:11 +02:00
if ( instance - > object_id = = 0 ) {
2016-10-30 01:48:09 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-10-30 01:48:09 +02:00
2019-05-09 11:21:49 +02:00
instances . push_back ( instance - > object_id ) ;
2016-10-30 01:48:09 +02:00
}
return instances ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
Vector < ObjectID > VisualServerScene : : instances_cull_convex ( const Vector < Plane > & p_convex , RID p_scenario ) const {
2016-10-30 01:48:09 +02:00
Vector < ObjectID > instances ;
2017-03-05 16:44:50 +01:00
Scenario * scenario = scenario_owner . get ( p_scenario ) ;
ERR_FAIL_COND_V ( ! scenario , instances ) ;
const_cast < VisualServerScene * > ( this ) - > update_dirty_instances ( ) ; // check dirty instances before culling
2016-10-30 01:48:09 +02:00
2017-03-05 16:44:50 +01:00
int culled = 0 ;
2016-10-30 01:48:09 +02:00
Instance * cull [ 1024 ] ;
2020-10-21 14:13:20 +02:00
culled = scenario - > sps - > cull_convex ( p_convex , cull , 1024 ) ;
2016-10-30 01:48:09 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < culled ; i + + ) {
Instance * instance = cull [ i ] ;
2016-10-30 01:48:09 +02:00
ERR_CONTINUE ( ! instance ) ;
2021-05-05 12:44:11 +02:00
if ( instance - > object_id = = 0 ) {
2016-10-30 01:48:09 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-10-30 01:48:09 +02:00
2019-05-09 11:21:49 +02:00
instances . push_back ( instance - > object_id ) ;
2016-10-30 01:48:09 +02:00
}
return instances ;
}
2016-10-19 16:14:41 +02:00
2021-02-04 11:43:08 +01:00
// thin wrapper to allow rooms / portals to take over culling if active
2021-08-17 14:40:39 +02:00
int VisualServerScene : : _cull_convex_from_point ( Scenario * p_scenario , const Transform & p_cam_transform , const CameraMatrix & p_cam_projection , const Vector < Plane > & p_convex , Instance * * p_result_array , int p_result_max , int32_t & r_previous_room_id_hint , uint32_t p_mask ) {
2021-02-04 11:43:08 +01:00
int res = - 1 ;
if ( p_scenario - > _portal_renderer . is_active ( ) ) {
// Note that the portal renderer ASSUMES that the planes exactly match the convention in
// CameraMatrix of enum Planes (6 planes, in order, near, far etc)
// If this is not the case, it should not be used.
2021-08-17 14:40:39 +02:00
res = p_scenario - > _portal_renderer . cull_convex ( p_cam_transform , p_cam_projection , p_convex , ( VSInstance * * ) p_result_array , p_result_max , p_mask , r_previous_room_id_hint ) ;
2021-02-04 11:43:08 +01:00
}
// fallback to BVH / octree if portals not active
if ( res = = - 1 ) {
res = p_scenario - > sps - > cull_convex ( p_convex , p_result_array , p_result_max , p_mask ) ;
2021-08-05 16:44:43 +02:00
// Opportunity for occlusion culling on the main scene. This will be a noop if no occluders.
2021-08-17 14:40:39 +02:00
if ( p_scenario - > _portal_renderer . occlusion_is_active ( ) ) {
res = p_scenario - > _portal_renderer . occlusion_cull ( p_cam_transform , p_cam_projection , p_convex , ( VSInstance * * ) p_result_array , res ) ;
}
2021-02-04 11:43:08 +01:00
}
return res ;
}
void VisualServerScene : : _rooms_instance_update ( Instance * p_instance , const AABB & p_aabb ) {
// magic number for instances in the room / portal system, but not requiring an update
// (due to being a STATIC or DYNAMIC object within a room)
// Must match the value in PortalRenderer in VisualServer
const uint32_t OCCLUSION_HANDLE_ROOM_BIT = 1 < < 31 ;
// if the instance is a moving object in the room / portal system, update it
// Note that if rooms and portals is not in use, occlusion_handle should be zero in all cases unless the portal_mode
// has been set to global or roaming. (which is unlikely as the default is static).
// The exception is editor user interface elements.
// These are always set to global and will always keep their aabb up to date in the portal renderer unnecessarily.
// There is no easy way around this, but it should be very cheap, and have no impact outside the editor.
if ( p_instance - > occlusion_handle & & ( p_instance - > occlusion_handle ! = OCCLUSION_HANDLE_ROOM_BIT ) ) {
p_instance - > scenario - > _portal_renderer . instance_moving_update ( p_instance - > occlusion_handle , p_aabb ) ;
}
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_geometry_set_flag ( RID p_instance , VS : : InstanceFlags p_flags , bool p_enabled ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-27 16:50:26 +02:00
2017-03-05 16:44:50 +01:00
switch ( p_flags ) {
2017-07-16 04:24:37 +02:00
case VS : : INSTANCE_FLAG_USE_BAKED_LIGHT : {
instance - > baked_light = p_enabled ;
} break ;
2018-07-27 13:58:56 +02:00
case VS : : INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE : {
2018-07-23 17:28:15 +02:00
instance - > redraw_if_visible = p_enabled ;
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-27 16:50:26 +02:00
}
2016-10-19 16:14:41 +02:00
}
void VisualServerScene : : instance_geometry_set_cast_shadows_setting ( RID p_instance , VS : : ShadowCastingSetting p_shadow_casting_setting ) {
2017-08-20 01:06:40 +02:00
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
instance - > cast_shadows = p_shadow_casting_setting ;
2018-11-14 13:32:39 +01:00
instance - > base_changed ( false , true ) ; // to actually compute if shadows are visible or not
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : instance_geometry_set_material_override ( RID p_instance , RID p_material ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
2016-10-27 16:50:26 +02:00
2016-11-10 03:55:06 +01:00
if ( instance - > material_override . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
VSG : : storage - > material_remove_instance_owner ( instance - > material_override , instance ) ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
instance - > material_override = p_material ;
2018-11-14 13:32:39 +01:00
instance - > base_changed ( false , true ) ;
2016-10-27 16:50:26 +02:00
2016-11-10 03:55:06 +01:00
if ( instance - > material_override . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
VSG : : storage - > material_add_instance_owner ( instance - > material_override , instance ) ;
2016-11-10 03:55:06 +01:00
}
2016-10-19 16:14:41 +02:00
}
2021-07-24 22:45:51 +02:00
void VisualServerScene : : instance_geometry_set_material_overlay ( RID p_instance , RID p_material ) {
Instance * instance = instance_owner . get ( p_instance ) ;
ERR_FAIL_COND ( ! instance ) ;
if ( instance - > material_overlay . is_valid ( ) ) {
VSG : : storage - > material_remove_instance_owner ( instance - > material_overlay , instance ) ;
}
instance - > material_overlay = p_material ;
instance - > base_changed ( false , true ) ;
if ( instance - > material_overlay . is_valid ( ) ) {
VSG : : storage - > material_add_instance_owner ( instance - > material_overlay , instance ) ;
}
}
2016-10-19 16:14:41 +02:00
void VisualServerScene : : _update_instance ( Instance * p_instance ) {
p_instance - > version + + ;
2021-09-15 13:30:45 +02:00
// when not using interpolation the transform is used straight
const Transform * instance_xform = & p_instance - > transform ;
// Can possibly use the most up to date current transform here when using physics interpolation ..
// uncomment the next line for this..
// if (p_instance->is_currently_interpolated()) {
// instance_xform = &p_instance->transform_curr;
// }
// However it does seem that using the interpolated transform (transform) works for keeping AABBs
// up to date to avoid culling errors.
2016-10-19 16:14:41 +02:00
if ( p_instance - > base_type = = VS : : INSTANCE_LIGHT ) {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( p_instance - > base_data ) ;
2016-10-19 16:14:41 +02:00
2021-09-15 13:30:45 +02:00
VSG : : scene_render - > light_instance_set_transform ( light - > instance , * instance_xform ) ;
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2016-10-19 16:14:41 +02:00
}
2016-11-19 17:23:37 +01:00
if ( p_instance - > base_type = = VS : : INSTANCE_REFLECTION_PROBE ) {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( p_instance - > base_data ) ;
2016-11-19 17:23:37 +01:00
2021-09-15 13:30:45 +02:00
VSG : : scene_render - > reflection_probe_instance_set_transform ( reflection_probe - > instance , * instance_xform ) ;
2017-03-05 16:44:50 +01:00
reflection_probe - > reflection_dirty = true ;
2016-11-19 17:23:37 +01:00
}
2017-04-07 04:36:37 +02:00
if ( p_instance - > base_type = = VS : : INSTANCE_PARTICLES ) {
2021-09-15 13:30:45 +02:00
VSG : : storage - > particles_set_emission_transform ( p_instance - > base , * instance_xform ) ;
2017-04-07 04:36:37 +02:00
}
2021-03-11 13:34:57 +01:00
if ( p_instance - > base_type = = VS : : INSTANCE_LIGHTMAP_CAPTURE ) {
InstanceLightmapCaptureData * capture = static_cast < InstanceLightmapCaptureData * > ( p_instance - > base_data ) ;
for ( List < InstanceLightmapCaptureData : : PairInfo > : : Element * E = capture - > geometries . front ( ) ; E ; E = E - > next ( ) ) {
_instance_queue_update ( E - > get ( ) . geometry , false , true ) ;
}
}
2017-08-19 19:54:04 +02:00
if ( p_instance - > aabb . has_no_surface ( ) ) {
2016-10-19 16:14:41 +02:00
return ;
2017-08-18 20:11:16 +02:00
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
if ( ( 1 < < p_instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( p_instance - > base_data ) ;
2016-11-10 03:55:06 +01:00
//make sure lights are updated if it casts shadow
2016-10-19 16:14:41 +02:00
2016-11-10 03:55:06 +01:00
if ( geom - > can_cast_shadows ) {
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = geom - > lighting . front ( ) ; E ; E = E - > next ( ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2016-11-10 03:55:06 +01:00
}
2016-10-19 16:14:41 +02:00
}
2017-12-14 12:59:46 +01:00
if ( ! p_instance - > lightmap_capture & & geom - > lightmap_captures . size ( ) ) {
//affected by lightmap captures, must update capture info!
_update_instance_lightmap_captures ( p_instance ) ;
} else {
if ( ! p_instance - > lightmap_capture_data . empty ( ) ) {
2018-09-27 12:07:59 +02:00
p_instance - > lightmap_capture_data . resize ( 0 ) ; //not in use, clear capture data
2017-12-14 12:59:46 +01:00
}
}
2016-10-19 16:14:41 +02:00
}
2021-09-15 13:30:45 +02:00
p_instance - > mirror = instance_xform - > basis . determinant ( ) < 0.0 ;
2016-10-19 16:14:41 +02:00
2017-11-17 03:09:00 +01:00
AABB new_aabb ;
2016-10-19 16:14:41 +02:00
2021-09-15 13:30:45 +02:00
new_aabb = instance_xform - > xform ( p_instance - > aabb ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
p_instance - > transformed_aabb = new_aabb ;
2016-10-19 16:14:41 +02:00
if ( ! p_instance - > scenario ) {
return ;
}
2020-10-21 14:13:20 +02:00
if ( p_instance - > spatial_partition_id = = 0 ) {
2017-03-05 16:44:50 +01:00
uint32_t base_type = 1 < < p_instance - > base_type ;
uint32_t pairable_mask = 0 ;
bool pairable = false ;
2016-10-19 16:14:41 +02:00
2017-12-14 12:59:46 +01:00
if ( p_instance - > base_type = = VS : : INSTANCE_LIGHT | | p_instance - > base_type = = VS : : INSTANCE_REFLECTION_PROBE | | p_instance - > base_type = = VS : : INSTANCE_LIGHTMAP_CAPTURE ) {
2017-03-05 16:44:50 +01:00
pairable_mask = p_instance - > visible ? VS : : INSTANCE_GEOMETRY_MASK : 0 ;
pairable = true ;
2016-10-19 16:14:41 +02:00
}
2016-12-20 04:21:07 +01:00
if ( p_instance - > base_type = = VS : : INSTANCE_GI_PROBE ) {
//lights and geometries
2017-03-05 16:44:50 +01:00
pairable_mask = p_instance - > visible ? VS : : INSTANCE_GEOMETRY_MASK | ( 1 < < VS : : INSTANCE_LIGHT ) : 0 ;
pairable = true ;
2016-12-20 04:21:07 +01:00
}
2016-10-19 16:14:41 +02:00
// not inside octree
2020-10-21 14:13:20 +02:00
p_instance - > spatial_partition_id = p_instance - > scenario - > sps - > create ( p_instance , new_aabb , 0 , pairable , base_type , pairable_mask ) ;
2016-10-19 16:14:41 +02:00
} else {
2017-01-14 12:26:56 +01:00
/*
if ( new_aabb = = p_instance - > data . transformed_aabb )
return ;
*/
2016-10-19 16:14:41 +02:00
2020-10-21 14:13:20 +02:00
p_instance - > scenario - > sps - > move ( p_instance - > spatial_partition_id , new_aabb ) ;
2016-10-19 16:14:41 +02:00
}
2021-02-04 11:43:08 +01:00
// keep rooms and portals instance up to date if present
_rooms_instance_update ( p_instance , new_aabb ) ;
2016-10-19 16:14:41 +02:00
}
void VisualServerScene : : _update_instance_aabb ( Instance * p_instance ) {
2017-11-17 03:09:00 +01:00
AABB new_aabb ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_instance - > base_type ! = VS : : INSTANCE_NONE & & ! p_instance - > base . is_valid ( ) ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
switch ( p_instance - > base_type ) {
2016-10-19 16:14:41 +02:00
case VisualServer : : INSTANCE_NONE : {
// do nothing
} break ;
case VisualServer : : INSTANCE_MESH : {
2021-05-05 12:44:11 +02:00
if ( p_instance - > custom_aabb ) {
2017-11-20 20:54:26 +01:00
new_aabb = * p_instance - > custom_aabb ;
2021-05-05 12:44:11 +02:00
} else {
2017-11-20 20:54:26 +01:00
new_aabb = VSG : : storage - > mesh_get_aabb ( p_instance - > base , p_instance - > skeleton ) ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
} break ;
2016-11-22 05:26:56 +01:00
2016-10-19 16:14:41 +02:00
case VisualServer : : INSTANCE_MULTIMESH : {
2021-05-05 12:44:11 +02:00
if ( p_instance - > custom_aabb ) {
2017-11-20 20:54:26 +01:00
new_aabb = * p_instance - > custom_aabb ;
2021-05-05 12:44:11 +02:00
} else {
2017-11-20 20:54:26 +01:00
new_aabb = VSG : : storage - > multimesh_get_aabb ( p_instance - > base ) ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
} break ;
case VisualServer : : INSTANCE_IMMEDIATE : {
2021-05-05 12:44:11 +02:00
if ( p_instance - > custom_aabb ) {
2017-11-20 20:54:26 +01:00
new_aabb = * p_instance - > custom_aabb ;
2021-05-05 12:44:11 +02:00
} else {
2017-11-20 20:54:26 +01:00
new_aabb = VSG : : storage - > immediate_get_aabb ( p_instance - > base ) ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
} break ;
2017-04-07 04:36:37 +02:00
case VisualServer : : INSTANCE_PARTICLES : {
2021-05-05 12:44:11 +02:00
if ( p_instance - > custom_aabb ) {
2017-11-20 20:54:26 +01:00
new_aabb = * p_instance - > custom_aabb ;
2021-05-05 12:44:11 +02:00
} else {
2017-11-20 20:54:26 +01:00
new_aabb = VSG : : storage - > particles_get_aabb ( p_instance - > base ) ;
2021-05-05 12:44:11 +02:00
}
2017-04-07 04:36:37 +02:00
} break ;
2016-10-19 16:14:41 +02:00
case VisualServer : : INSTANCE_LIGHT : {
new_aabb = VSG : : storage - > light_get_aabb ( p_instance - > base ) ;
} break ;
2016-11-19 17:23:37 +01:00
case VisualServer : : INSTANCE_REFLECTION_PROBE : {
new_aabb = VSG : : storage - > reflection_probe_get_aabb ( p_instance - > base ) ;
} break ;
2016-12-20 04:21:07 +01:00
case VisualServer : : INSTANCE_GI_PROBE : {
new_aabb = VSG : : storage - > gi_probe_get_bounds ( p_instance - > base ) ;
2017-12-14 12:59:46 +01:00
} break ;
case VisualServer : : INSTANCE_LIGHTMAP_CAPTURE : {
new_aabb = VSG : : storage - > lightmap_capture_get_bounds ( p_instance - > base ) ;
2016-12-20 04:21:07 +01:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-19 16:14:41 +02:00
}
2017-11-20 20:54:26 +01:00
// <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs
2021-05-05 12:44:11 +02:00
if ( p_instance - > extra_margin ) {
2016-10-19 16:14:41 +02:00
new_aabb . grow_by ( p_instance - > extra_margin ) ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
p_instance - > aabb = new_aabb ;
2016-10-19 16:14:41 +02:00
}
2017-12-14 12:59:46 +01:00
_FORCE_INLINE_ static void _light_capture_sample_octree ( const RasterizerStorage : : LightmapCaptureOctree * p_octree , int p_cell_subdiv , const Vector3 & p_pos , const Vector3 & p_dir , float p_level , Vector3 & r_color , float & r_alpha ) {
static const Vector3 aniso_normal [ 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 )
} ;
int size = 1 < < ( p_cell_subdiv - 1 ) ;
int clamp_v = size - 1 ;
//first of all, clamp
Vector3 pos ;
pos . x = CLAMP ( p_pos . x , 0 , clamp_v ) ;
pos . y = CLAMP ( p_pos . y , 0 , clamp_v ) ;
pos . z = CLAMP ( p_pos . z , 0 , clamp_v ) ;
float level = ( p_cell_subdiv - 1 ) - p_level ;
int target_level ;
float level_filter ;
if ( level < = 0.0 ) {
level_filter = 0 ;
target_level = 0 ;
} else {
target_level = Math : : ceil ( level ) ;
level_filter = target_level - level ;
}
Vector3 color [ 2 ] [ 8 ] ;
float alpha [ 2 ] [ 8 ] ;
2021-04-29 12:34:11 +02:00
memset ( alpha , 0 , sizeof ( float ) * 2 * 8 ) ;
2017-12-14 12:59:46 +01:00
//find cell at given level first
for ( int c = 0 ; c < 2 ; c + + ) {
int current_level = MAX ( 0 , target_level - c ) ;
int level_cell_size = ( 1 < < ( p_cell_subdiv - 1 ) ) > > current_level ;
for ( int n = 0 ; n < 8 ; n + + ) {
int x = int ( pos . x ) ;
int y = int ( pos . y ) ;
int z = int ( pos . z ) ;
2021-05-05 12:44:11 +02:00
if ( n & 1 ) {
2017-12-14 12:59:46 +01:00
x + = level_cell_size ;
2021-05-05 12:44:11 +02:00
}
if ( n & 2 ) {
2017-12-14 12:59:46 +01:00
y + = level_cell_size ;
2021-05-05 12:44:11 +02:00
}
if ( n & 4 ) {
2017-12-14 12:59:46 +01:00
z + = level_cell_size ;
2021-05-05 12:44:11 +02:00
}
2017-12-14 12:59:46 +01:00
int ofs_x = 0 ;
int ofs_y = 0 ;
int ofs_z = 0 ;
x = CLAMP ( x , 0 , clamp_v ) ;
y = CLAMP ( y , 0 , clamp_v ) ;
z = CLAMP ( z , 0 , clamp_v ) ;
int half = size / 2 ;
uint32_t cell = 0 ;
for ( int i = 0 ; i < current_level ; i + + ) {
const RasterizerStorage : : LightmapCaptureOctree * bc = & p_octree [ cell ] ;
int child = 0 ;
if ( x > = ofs_x + half ) {
child | = 1 ;
ofs_x + = half ;
}
if ( y > = ofs_y + half ) {
child | = 2 ;
ofs_y + = half ;
}
if ( z > = ofs_z + half ) {
child | = 4 ;
ofs_z + = half ;
}
cell = bc - > children [ child ] ;
2021-05-05 12:44:11 +02:00
if ( cell = = RasterizerStorage : : LightmapCaptureOctree : : CHILD_EMPTY ) {
2017-12-14 12:59:46 +01:00
break ;
2021-05-05 12:44:11 +02:00
}
2017-12-14 12:59:46 +01:00
half > > = 1 ;
}
2023-08-19 19:28:20 +02:00
if ( cell ! = RasterizerStorage : : LightmapCaptureOctree : : CHILD_EMPTY ) {
2017-12-14 12:59:46 +01:00
alpha [ c ] [ n ] = p_octree [ cell ] . alpha ;
for ( int i = 0 ; i < 6 ; i + + ) {
//anisotropic read light
float amount = p_dir . dot ( aniso_normal [ i ] ) ;
2023-08-19 19:28:20 +02:00
if ( amount > 0 ) {
constexpr float ONE_1024TH = 1.0 / 1024.0 ;
color [ c ] [ n ] . x + = p_octree [ cell ] . light [ i ] [ 0 ] * ONE_1024TH * amount ;
color [ c ] [ n ] . y + = p_octree [ cell ] . light [ i ] [ 1 ] * ONE_1024TH * amount ;
color [ c ] [ n ] . z + = p_octree [ cell ] . light [ i ] [ 2 ] * ONE_1024TH * amount ;
2021-05-05 12:44:11 +02:00
}
2017-12-14 12:59:46 +01:00
}
}
//print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]);
}
}
float target_level_size = size > > target_level ;
Vector3 pos_fract [ 2 ] ;
2023-08-19 19:28:20 +02:00
float target_level_size_inv = 1.0f / target_level_size ;
real_t res ;
res = pos . x * target_level_size_inv ;
pos_fract [ 0 ] . x = res - ( int ) res ;
res = pos . y * target_level_size_inv ;
pos_fract [ 0 ] . y = res - ( int ) res ;
res = pos . z * target_level_size_inv ;
pos_fract [ 0 ] . z = res - ( int ) res ;
2017-12-14 12:59:46 +01:00
target_level_size = size > > MAX ( 0 , target_level - 1 ) ;
2023-08-19 19:28:20 +02:00
target_level_size_inv = 1.0f / target_level_size ;
res = pos . x * target_level_size_inv ;
pos_fract [ 1 ] . x = res - ( int ) res ;
res = pos . y * target_level_size_inv ;
pos_fract [ 1 ] . y = res - ( int ) res ;
res = pos . z * target_level_size_inv ;
pos_fract [ 1 ] . z = res - ( int ) res ;
2017-12-14 12:59:46 +01:00
float alpha_interp [ 2 ] ;
Vector3 color_interp [ 2 ] ;
for ( int i = 0 ; i < 2 ; i + + ) {
Vector3 color_x00 = color [ i ] [ 0 ] . linear_interpolate ( color [ i ] [ 1 ] , pos_fract [ i ] . x ) ;
Vector3 color_xy0 = color [ i ] [ 2 ] . linear_interpolate ( color [ i ] [ 3 ] , pos_fract [ i ] . x ) ;
Vector3 blend_z0 = color_x00 . linear_interpolate ( color_xy0 , pos_fract [ i ] . y ) ;
Vector3 color_x0z = color [ i ] [ 4 ] . linear_interpolate ( color [ i ] [ 5 ] , pos_fract [ i ] . x ) ;
Vector3 color_xyz = color [ i ] [ 6 ] . linear_interpolate ( color [ i ] [ 7 ] , pos_fract [ i ] . x ) ;
Vector3 blend_z1 = color_x0z . linear_interpolate ( color_xyz , pos_fract [ i ] . y ) ;
color_interp [ i ] = blend_z0 . linear_interpolate ( blend_z1 , pos_fract [ i ] . z ) ;
float alpha_x00 = Math : : lerp ( alpha [ i ] [ 0 ] , alpha [ i ] [ 1 ] , pos_fract [ i ] . x ) ;
float alpha_xy0 = Math : : lerp ( alpha [ i ] [ 2 ] , alpha [ i ] [ 3 ] , pos_fract [ i ] . x ) ;
float alpha_z0 = Math : : lerp ( alpha_x00 , alpha_xy0 , pos_fract [ i ] . y ) ;
float alpha_x0z = Math : : lerp ( alpha [ i ] [ 4 ] , alpha [ i ] [ 5 ] , pos_fract [ i ] . x ) ;
float alpha_xyz = Math : : lerp ( alpha [ i ] [ 6 ] , alpha [ i ] [ 7 ] , pos_fract [ i ] . x ) ;
float alpha_z1 = Math : : lerp ( alpha_x0z , alpha_xyz , pos_fract [ i ] . y ) ;
alpha_interp [ i ] = Math : : lerp ( alpha_z0 , alpha_z1 , pos_fract [ i ] . z ) ;
}
r_color = color_interp [ 0 ] . linear_interpolate ( color_interp [ 1 ] , level_filter ) ;
r_alpha = Math : : lerp ( alpha_interp [ 0 ] , alpha_interp [ 1 ] , level_filter ) ;
2018-08-24 09:35:07 +02:00
//print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha));
2017-12-14 12:59:46 +01:00
}
_FORCE_INLINE_ static Color _light_capture_voxel_cone_trace ( const RasterizerStorage : : LightmapCaptureOctree * p_octree , const Vector3 & p_pos , const Vector3 & p_dir , float p_aperture , int p_cell_subdiv ) {
float bias = 0.0 ; //no need for bias here
float max_distance = ( Vector3 ( 1 , 1 , 1 ) * ( 1 < < ( p_cell_subdiv - 1 ) ) ) . length ( ) ;
float dist = bias ;
float alpha = 0.0 ;
Vector3 color ;
Vector3 scolor ;
float salpha ;
while ( dist < max_distance & & alpha < 0.95 ) {
float diameter = MAX ( 1.0 , 2.0 * p_aperture * dist ) ;
_light_capture_sample_octree ( p_octree , p_cell_subdiv , p_pos + dist * p_dir , p_dir , log2 ( diameter ) , scolor , salpha ) ;
float a = ( 1.0 - alpha ) ;
color + = scolor * a ;
alpha + = a * salpha ;
dist + = diameter * 0.5 ;
}
return Color ( color . x , color . y , color . z , alpha ) ;
}
void VisualServerScene : : _update_instance_lightmap_captures ( Instance * p_instance ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( p_instance - > base_data ) ;
static const Vector3 cone_traces [ 12 ] = {
Vector3 ( 0 , 0 , 1 ) ,
Vector3 ( 0.866025 , 0 , 0.5 ) ,
Vector3 ( 0.267617 , 0.823639 , 0.5 ) ,
Vector3 ( - 0.700629 , 0.509037 , 0.5 ) ,
Vector3 ( - 0.700629 , - 0.509037 , 0.5 ) ,
Vector3 ( 0.267617 , - 0.823639 , 0.5 ) ,
Vector3 ( 0 , 0 , - 1 ) ,
Vector3 ( 0.866025 , 0 , - 0.5 ) ,
Vector3 ( 0.267617 , 0.823639 , - 0.5 ) ,
Vector3 ( - 0.700629 , 0.509037 , - 0.5 ) ,
Vector3 ( - 0.700629 , - 0.509037 , - 0.5 ) ,
Vector3 ( 0.267617 , - 0.823639 , - 0.5 )
} ;
float cone_aperture = 0.577 ; // tan(angle) 60 degrees
if ( p_instance - > lightmap_capture_data . empty ( ) ) {
p_instance - > lightmap_capture_data . resize ( 12 ) ;
}
//print_line("update captures for pos: " + p_instance->transform.origin);
2021-05-05 12:44:11 +02:00
for ( int i = 0 ; i < 12 ; i + + ) {
2019-01-25 12:06:44 +01:00
new ( & p_instance - > lightmap_capture_data . ptrw ( ) [ i ] ) Color ;
2021-05-05 12:44:11 +02:00
}
2019-01-25 12:06:44 +01:00
2021-03-11 13:34:57 +01:00
bool interior = true ;
2017-12-14 12:59:46 +01:00
//this could use some sort of blending..
for ( List < Instance * > : : Element * E = geom - > lightmap_captures . front ( ) ; E ; E = E - > next ( ) ) {
const PoolVector < RasterizerStorage : : LightmapCaptureOctree > * octree = VSG : : storage - > lightmap_capture_get_octree_ptr ( E - > get ( ) - > base ) ;
//print_line("octree size: " + itos(octree->size()));
2021-05-05 12:44:11 +02:00
if ( octree - > size ( ) = = 0 ) {
2017-12-14 12:59:46 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2017-12-14 12:59:46 +01:00
Transform to_cell_xform = VSG : : storage - > lightmap_capture_get_octree_cell_transform ( E - > get ( ) - > base ) ;
int cell_subdiv = VSG : : storage - > lightmap_capture_get_octree_cell_subdiv ( E - > get ( ) - > base ) ;
to_cell_xform = to_cell_xform * E - > get ( ) - > transform . affine_inverse ( ) ;
PoolVector < RasterizerStorage : : LightmapCaptureOctree > : : Read octree_r = octree - > read ( ) ;
Vector3 pos = to_cell_xform . xform ( p_instance - > transform . origin ) ;
2020-12-17 16:02:08 +01:00
const float capture_energy = VSG : : storage - > lightmap_capture_get_energy ( E - > get ( ) - > base ) ;
2021-03-11 13:34:57 +01:00
interior = interior & & VSG : : storage - > lightmap_capture_is_interior ( E - > get ( ) - > base ) ;
2020-12-17 16:02:08 +01:00
2017-12-14 12:59:46 +01:00
for ( int i = 0 ; i < 12 ; i + + ) {
Vector3 dir = to_cell_xform . basis . xform ( cone_traces [ i ] ) . normalized ( ) ;
Color capture = _light_capture_voxel_cone_trace ( octree_r . ptr ( ) , pos , dir , cone_aperture , cell_subdiv ) ;
2020-12-17 16:02:08 +01:00
capture . r * = capture_energy ;
capture . g * = capture_energy ;
capture . b * = capture_energy ;
2018-07-25 03:11:03 +02:00
p_instance - > lightmap_capture_data . write [ i ] + = capture ;
2017-12-14 12:59:46 +01:00
}
}
2021-03-11 13:34:57 +01:00
p_instance - > lightmap_capture_data . write [ 0 ] . a = interior ? 0.0f : 1.0f ;
2017-12-14 12:59:46 +01:00
}
2022-06-09 09:02:43 +02:00
bool VisualServerScene : : _light_instance_update_shadow ( Instance * p_instance , const Transform p_cam_transform , const CameraMatrix & p_cam_projection , bool p_cam_orthogonal , RID p_shadow_atlas , Scenario * p_scenario , uint32_t p_visible_layers ) {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( p_instance - > base_data ) ;
2016-10-19 16:14:41 +02:00
2018-07-03 13:34:06 +02:00
Transform light_transform = p_instance - > transform ;
light_transform . orthonormalize ( ) ; //scale does not count on lights
2018-11-14 13:32:39 +01:00
bool animated_material_found = false ;
2017-03-05 16:44:50 +01:00
switch ( VSG : : storage - > light_get_type ( p_instance - > base ) ) {
2016-11-10 03:55:06 +01:00
case VS : : LIGHT_DIRECTIONAL : {
2019-11-02 21:00:24 +01:00
// Directional light always needs preparing as it takes a different path to other lights.
light_culler - > prepare_light ( * p_instance ) ;
// Directional lights can always do a tighter cull.
// This should occur because shadow_dirty_count is never decremented for directional lights.
# ifdef DEV_ENABLED
DEV_CHECK_ONCE ( ! light - > is_shadow_update_full ( ) ) ;
# endif
2017-03-05 16:44:50 +01:00
float max_distance = p_cam_projection . get_z_far ( ) ;
float shadow_max = VSG : : storage - > light_get_param ( p_instance - > base , VS : : LIGHT_PARAM_SHADOW_MAX_DISTANCE ) ;
2017-09-07 23:00:47 +02:00
if ( shadow_max > 0 & & ! p_cam_orthogonal ) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera
2017-03-05 16:44:50 +01:00
max_distance = MIN ( shadow_max , max_distance ) ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
max_distance = MAX ( max_distance , p_cam_projection . get_z_near ( ) + 0.001 ) ;
2017-09-07 21:48:50 +02:00
float min_distance = MIN ( p_cam_projection . get_z_near ( ) , max_distance ) ;
2016-11-10 03:55:06 +01:00
2017-09-07 23:00:47 +02:00
VS : : LightDirectionalShadowDepthRangeMode depth_range_mode = VSG : : storage - > light_directional_get_shadow_depth_range_mode ( p_instance - > base ) ;
2017-09-07 21:48:50 +02:00
if ( depth_range_mode = = VS : : LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED ) {
2017-09-07 23:00:47 +02:00
//optimize min/max
Vector < Plane > planes = p_cam_projection . get_projection_planes ( p_cam_transform ) ;
2020-10-21 14:13:20 +02:00
int cull_count = p_scenario - > sps - > cull_convex ( planes , instance_shadow_cull_result , MAX_INSTANCE_CULL , VS : : INSTANCE_GEOMETRY_MASK ) ;
2017-09-07 21:48:50 +02:00
Plane base ( p_cam_transform . origin , - p_cam_transform . basis . get_axis ( 2 ) ) ;
2017-09-07 23:00:47 +02:00
//check distance max and min
2017-09-07 21:48:50 +02:00
bool found_items = false ;
float z_max = - 1e20 ;
float z_min = 1e20 ;
2017-09-07 23:00:47 +02:00
2017-09-07 21:48:50 +02:00
for ( int i = 0 ; i < cull_count ; i + + ) {
2017-09-07 23:00:47 +02:00
Instance * instance = instance_shadow_cull_result [ i ] ;
2022-06-09 09:02:43 +02:00
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows | | ! ( p_visible_layers & instance - > layer_mask ) ) {
2017-09-07 23:00:47 +02:00
continue ;
}
2018-11-14 13:32:39 +01:00
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
}
2017-09-07 21:48:50 +02:00
float max , min ;
2017-09-07 23:00:47 +02:00
instance - > transformed_aabb . project_range_in_plane ( base , min , max ) ;
2017-09-07 21:48:50 +02:00
if ( max > z_max ) {
z_max = max ;
2017-09-07 23:00:47 +02:00
}
2017-09-07 21:48:50 +02:00
if ( min < z_min ) {
z_min = min ;
2017-09-07 23:00:47 +02:00
}
2017-09-07 21:48:50 +02:00
found_items = true ;
2017-09-07 23:00:47 +02:00
}
if ( found_items ) {
2017-09-07 21:48:50 +02:00
min_distance = MAX ( min_distance , z_min ) ;
max_distance = MIN ( max_distance , z_max ) ;
2017-09-07 23:00:47 +02:00
}
}
float range = max_distance - min_distance ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
int splits = 0 ;
switch ( VSG : : storage - > light_directional_get_shadow_mode ( p_instance - > base ) ) {
2021-05-04 14:35:44 +02:00
case VS : : LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL :
splits = 1 ;
break ;
case VS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS :
splits = 2 ;
break ;
2023-03-29 12:56:41 +02:00
case VS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS :
splits = 3 ;
break ;
2021-05-04 14:35:44 +02:00
case VS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS :
splits = 4 ;
break ;
2016-11-10 03:55:06 +01:00
}
float distances [ 5 ] ;
2017-09-07 23:00:47 +02:00
distances [ 0 ] = min_distance ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < splits ; i + + ) {
2017-09-07 23:00:47 +02:00
distances [ i + 1 ] = min_distance + VSG : : storage - > light_get_param ( p_instance - > base , VS : : LightParam ( VS : : LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i ) ) * range ;
2016-11-10 03:55:06 +01:00
} ;
2017-03-05 16:44:50 +01:00
distances [ splits ] = max_distance ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
float texture_size = VSG : : scene_render - > get_directional_light_shadow_size ( light - > instance ) ;
2016-11-10 03:55:06 +01:00
2016-11-11 16:27:52 +01:00
bool overlap = VSG : : storage - > light_directional_get_blend_splits ( p_instance - > base ) ;
2016-11-10 03:55:06 +01:00
2017-06-14 21:56:47 +02:00
float first_radius = 0.0 ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < splits ; i + + ) {
2016-11-10 03:55:06 +01:00
// setup a camera matrix for that range!
CameraMatrix camera_matrix ;
2016-11-19 17:23:37 +01:00
float aspect = p_cam_projection . get_aspect ( ) ;
2016-11-10 03:55:06 +01:00
2016-11-19 17:23:37 +01:00
if ( p_cam_orthogonal ) {
2020-01-21 19:39:16 +01:00
Vector2 vp_he = p_cam_projection . get_viewport_half_extents ( ) ;
camera_matrix . set_orthogonal ( vp_he . y * 2.0 , aspect , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , false ) ;
2016-11-19 17:23:37 +01:00
} else {
float fov = p_cam_projection . get_fov ( ) ;
2017-03-05 16:44:50 +01:00
camera_matrix . set_perspective ( fov , aspect , distances [ ( i = = 0 | | ! overlap ) ? i : i - 1 ] , distances [ i + 1 ] , false ) ;
2016-11-10 03:55:06 +01:00
}
//obtain the frustum endpoints
Vector3 endpoints [ 8 ] ; // frustum plane endpoints
2017-03-05 16:44:50 +01:00
bool res = camera_matrix . get_endpoints ( p_cam_transform , endpoints ) ;
2016-11-10 03:55:06 +01:00
ERR_CONTINUE ( ! res ) ;
// obtain the light frustm ranges (given endpoints)
2018-07-03 13:34:06 +02:00
Transform transform = light_transform ; //discard scale and stabilize light
2017-06-14 21:56:47 +02: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 ( ) ;
2016-11-10 03:55:06 +01:00
//z_vec points agsint the camera, like in default opengl
2017-09-01 22:33:39 +02:00
float x_min = 0.f , x_max = 0.f ;
float y_min = 0.f , y_max = 0.f ;
float z_min = 0.f , z_max = 0.f ;
2016-11-10 03:55:06 +01:00
2018-09-27 12:07:59 +02: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.
2017-09-01 22:33:39 +02:00
float x_min_cam = 0.f , x_max_cam = 0.f ;
float y_min_cam = 0.f , y_max_cam = 0.f ;
2018-09-27 12:07:59 +02:00
float z_min_cam = 0.f ;
//float z_max_cam = 0.f;
2016-11-10 03:55:06 +01:00
2017-06-14 21:56:47 +02:00
float bias_scale = 1.0 ;
2016-11-10 03:55:06 +01:00
//used for culling
2017-06-14 21:56:47 +02:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
float d_x = x_vec . dot ( endpoints [ j ] ) ;
float d_y = y_vec . dot ( endpoints [ j ] ) ;
float d_z = z_vec . dot ( endpoints [ j ] ) ;
2021-05-05 12:44:11 +02:00
if ( j = = 0 | | d_x < x_min ) {
2017-03-05 16:44:50 +01:00
x_min = d_x ;
2021-05-05 12:44:11 +02:00
}
if ( j = = 0 | | d_x > x_max ) {
2017-03-05 16:44:50 +01:00
x_max = d_x ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
2021-05-05 12:44:11 +02:00
if ( j = = 0 | | d_y < y_min ) {
2017-03-05 16:44:50 +01:00
y_min = d_y ;
2021-05-05 12:44:11 +02:00
}
if ( j = = 0 | | d_y > y_max ) {
2017-03-05 16:44:50 +01:00
y_max = d_y ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
2021-05-05 12:44:11 +02:00
if ( j = = 0 | | d_z < z_min ) {
2017-03-05 16:44:50 +01:00
z_min = d_z ;
2021-05-05 12:44:11 +02:00
}
if ( j = = 0 | | d_z > z_max ) {
2017-03-05 16:44:50 +01:00
z_max = d_z ;
2021-05-05 12:44:11 +02:00
}
2016-11-10 03:55:06 +01:00
}
{
//camera viewport stuff
Vector3 center ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
center + = endpoints [ j ] ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
center / = 8.0 ;
2016-11-10 03:55:06 +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;
2017-03-05 16:44:50 +01:00
float radius = 0 ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < 8 ; j + + ) {
2016-11-10 03:55:06 +01:00
float d = center . distance_to ( endpoints [ j ] ) ;
2021-05-05 12:44:11 +02:00
if ( d > radius ) {
2017-03-05 16:44:50 +01:00
radius = d ;
2021-05-05 12:44:11 +02:00
}
2016-11-10 03:55:06 +01:00
}
2017-09-07 23:00:47 +02:00
radius * = texture_size / ( texture_size - 2.0 ) ; //add a texel by each side
2016-11-10 03:55:06 +01:00
2017-06-14 21:56:47 +02:00
if ( i = = 0 ) {
first_radius = radius ;
} else {
bias_scale = radius / first_radius ;
}
2017-03-05 16:44:50 +01:00
x_max_cam = x_vec . dot ( center ) + radius ;
x_min_cam = x_vec . dot ( center ) - radius ;
y_max_cam = y_vec . dot ( center ) + radius ;
y_min_cam = y_vec . dot ( center ) - radius ;
2018-09-27 12:07:59 +02:00
//z_max_cam = z_vec.dot(center) + radius;
2017-03-05 16:44:50 +01:00
z_min_cam = z_vec . dot ( center ) - radius ;
2016-11-10 03:55:06 +01:00
2017-09-07 21:48:50 +02:00
if ( depth_range_mode = = VS : : LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE ) {
2017-09-07 23:00:47 +02:00
//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
float unit = radius * 2.0 / texture_size ;
x_max_cam = Math : : stepify ( x_max_cam , unit ) ;
x_min_cam = Math : : stepify ( x_min_cam , unit ) ;
y_max_cam = Math : : stepify ( y_max_cam , unit ) ;
y_min_cam = Math : : stepify ( y_min_cam , unit ) ;
}
2016-11-10 03:55:06 +01:00
}
//now that we now all ranges, we can proceed to make the light frustum planes, for culling octree
Vector < Plane > light_frustum_planes ;
light_frustum_planes . resize ( 6 ) ;
//right/left
2018-07-25 03:11:03 +02:00
light_frustum_planes . write [ 0 ] = Plane ( x_vec , x_max ) ;
light_frustum_planes . write [ 1 ] = Plane ( - x_vec , - x_min ) ;
2016-11-10 03:55:06 +01:00
//top/bottom
2018-07-25 03:11:03 +02:00
light_frustum_planes . write [ 2 ] = Plane ( y_vec , y_max ) ;
light_frustum_planes . write [ 3 ] = Plane ( - y_vec , - y_min ) ;
2016-11-10 03:55:06 +01:00
//near/far
2018-07-25 03:11:03 +02:00
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
2016-11-10 03:55:06 +01:00
2020-10-21 14:13:20 +02:00
int cull_count = p_scenario - > sps - > cull_convex ( light_frustum_planes , instance_shadow_cull_result , MAX_INSTANCE_CULL , VS : : INSTANCE_GEOMETRY_MASK ) ;
2016-11-10 03:55:06 +01:00
// a pre pass will need to be needed to determine the actual z-near to be used
2018-07-03 13:34:06 +02:00
Plane near_plane ( light_transform . origin , - light_transform . basis . get_axis ( 2 ) ) ;
2017-07-15 06:23:10 +02:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < cull_count ; j + + ) {
float min , max ;
2016-11-10 03:55:06 +01:00
Instance * instance = instance_shadow_cull_result [ j ] ;
2022-06-09 09:02:43 +02:00
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows | | ! ( p_visible_layers & instance - > layer_mask ) ) {
2016-11-10 03:55:06 +01:00
cull_count - - ;
2017-03-05 16:44:50 +01:00
SWAP ( instance_shadow_cull_result [ j ] , instance_shadow_cull_result [ cull_count ] ) ;
2016-11-10 03:55:06 +01:00
j - - ;
2017-02-16 12:55:11 +01:00
continue ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
instance - > transformed_aabb . project_range_in_plane ( Plane ( z_vec , 0 ) , min , max ) ;
2017-07-15 06:23:10 +02:00
instance - > depth = near_plane . distance_to ( instance - > transform . origin ) ;
instance - > depth_layer = 0 ;
2021-05-05 12:44:11 +02:00
if ( max > z_max ) {
2017-03-05 16:44:50 +01:00
z_max = max ;
2021-05-05 12:44:11 +02:00
}
2016-11-10 03:55:06 +01:00
}
{
CameraMatrix ortho_camera ;
2017-03-05 16:44:50 +01:00
real_t half_x = ( x_max_cam - x_min_cam ) * 0.5 ;
real_t half_y = ( y_max_cam - y_min_cam ) * 0.5 ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
ortho_camera . set_orthogonal ( - half_x , half_x , - half_y , half_y , 0 , ( z_max - z_min_cam ) ) ;
2016-11-10 03:55:06 +01:00
Transform ortho_transform ;
2017-06-14 21:56:47 +02:00
ortho_transform . basis = transform . basis ;
2017-03-05 16:44:50 +01:00
ortho_transform . origin = x_vec * ( x_min_cam + half_x ) + y_vec * ( y_min_cam + half_y ) + z_vec * z_max ;
2016-11-10 03:55:06 +01:00
2017-06-14 21:56:47 +02:00
VSG : : scene_render - > light_instance_set_shadow_transform ( light - > instance , ortho_camera , ortho_transform , 0 , distances [ i + 1 ] , i , bias_scale ) ;
2016-11-10 03:55:06 +01:00
}
2019-11-02 21:00:24 +01:00
// Do a secondary cull to remove casters that don't intersect with the camera frustum.
// Note this could possibly be done in a more efficient place if we can share the cull results for each split.
cull_count = light_culler - > cull ( cull_count , instance_shadow_cull_result ) ;
2017-03-05 16:44:50 +01:00
VSG : : scene_render - > render_shadow ( light - > instance , p_shadow_atlas , i , ( RasterizerScene : : InstanceBase * * ) instance_shadow_cull_result , cull_count ) ;
2016-11-10 03:55:06 +01:00
}
} break ;
case VS : : LIGHT_OMNI : {
VS : : LightOmniShadowMode shadow_mode = VSG : : storage - > light_omni_get_shadow_mode ( p_instance - > base ) ;
2019-01-22 14:04:25 +01:00
if ( shadow_mode = = VS : : LIGHT_OMNI_SHADOW_DUAL_PARABOLOID | | ! VSG : : 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
2016-11-10 03:55:06 +01:00
2019-01-22 14:04:25 +01:00
float radius = VSG : : storage - > light_get_param ( p_instance - > base , VS : : LIGHT_PARAM_RANGE ) ;
2016-11-10 03:55:06 +01:00
2019-01-22 14:04:25 +01:00
float z = i = = 0 ? - 1 : 1 ;
Vector < Plane > planes ;
2020-04-29 02:13:36 +02:00
planes . resize ( 6 ) ;
2019-01-22 14:04:25 +01:00
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 ) ) ;
2020-04-29 02:13:36 +02:00
planes . write [ 5 ] = light_transform . xform ( Plane ( Vector3 ( 0 , 0 , - z ) , 0 ) ) ;
2019-01-22 14:04:25 +01:00
2020-10-21 14:13:20 +02:00
int cull_count = p_scenario - > sps - > cull_convex ( planes , instance_shadow_cull_result , MAX_INSTANCE_CULL , VS : : INSTANCE_GEOMETRY_MASK ) ;
2019-11-02 21:00:24 +01:00
// Do a secondary cull to remove casters that don't intersect with the camera frustum.
if ( ! light - > is_shadow_update_full ( ) ) {
cull_count = light_culler - > cull ( cull_count , instance_shadow_cull_result ) ;
}
2019-01-22 14:04:25 +01:00
Plane near_plane ( light_transform . origin , light_transform . basis . get_axis ( 2 ) * z ) ;
for ( int j = 0 ; j < cull_count ; j + + ) {
Instance * instance = instance_shadow_cull_result [ j ] ;
2022-06-09 09:02:43 +02:00
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows | | ! ( p_visible_layers & instance - > layer_mask ) ) {
2019-01-22 14:04:25 +01:00
cull_count - - ;
SWAP ( instance_shadow_cull_result [ j ] , instance_shadow_cull_result [ cull_count ] ) ;
j - - ;
} else {
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
}
2016-11-10 03:55:06 +01:00
2019-01-22 14:04:25 +01:00
instance - > depth = near_plane . distance_to ( instance - > transform . origin ) ;
instance - > depth_layer = 0 ;
}
}
2016-11-10 03:55:06 +01:00
2019-01-22 14:04:25 +01:00
VSG : : scene_render - > light_instance_set_shadow_transform ( light - > instance , CameraMatrix ( ) , light_transform , radius , 0 , i ) ;
VSG : : scene_render - > render_shadow ( light - > instance , p_shadow_atlas , i , ( RasterizerScene : : InstanceBase * * ) instance_shadow_cull_result , cull_count ) ;
}
} else { //shadow cube
2016-11-10 03:55:06 +01:00
2019-01-22 14:04:25 +01:00
float radius = VSG : : storage - > light_get_param ( p_instance - > base , VS : : LIGHT_PARAM_RANGE ) ;
CameraMatrix cm ;
cm . set_perspective ( 90 , 1 , 0.01 , radius ) ;
2018-11-14 13:32:39 +01:00
2019-01-22 14:04:25 +01:00
for ( int i = 0 ; i < 6 ; 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 ) ;
2021-08-17 14:40:39 +02:00
int cull_count = _cull_convex_from_point ( p_scenario , light_transform , cm , planes , instance_shadow_cull_result , MAX_INSTANCE_CULL , light - > previous_room_id_hint , VS : : INSTANCE_GEOMETRY_MASK ) ;
2019-01-22 14:04:25 +01:00
2019-11-02 21:00:24 +01:00
// Do a secondary cull to remove casters that don't intersect with the camera frustum.
if ( ! light - > is_shadow_update_full ( ) ) {
cull_count = light_culler - > cull ( cull_count , instance_shadow_cull_result ) ;
}
2019-01-22 14:04:25 +01:00
Plane near_plane ( xform . origin , - xform . basis . get_axis ( 2 ) ) ;
for ( int j = 0 ; j < cull_count ; j + + ) {
Instance * instance = instance_shadow_cull_result [ j ] ;
2022-06-09 09:02:43 +02:00
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows | | ! ( p_visible_layers & instance - > layer_mask ) ) {
2019-01-22 14:04:25 +01:00
cull_count - - ;
SWAP ( instance_shadow_cull_result [ j ] , instance_shadow_cull_result [ cull_count ] ) ;
j - - ;
} else {
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
2016-11-10 03:55:06 +01:00
}
2019-01-22 14:04:25 +01:00
instance - > depth = near_plane . distance_to ( instance - > transform . origin ) ;
instance - > depth_layer = 0 ;
2016-11-10 03:55:06 +01:00
}
}
2019-01-22 14:04:25 +01:00
VSG : : scene_render - > light_instance_set_shadow_transform ( light - > instance , cm , xform , radius , 0 , i ) ;
VSG : : scene_render - > render_shadow ( light - > instance , p_shadow_atlas , i , ( RasterizerScene : : InstanceBase * * ) instance_shadow_cull_result , cull_count ) ;
}
2016-11-10 03:55:06 +01:00
2019-01-22 14:04:25 +01:00
//restore the regular DP matrix
VSG : : scene_render - > light_instance_set_shadow_transform ( light - > instance , CameraMatrix ( ) , light_transform , radius , 0 , 0 ) ;
2016-11-10 03:55:06 +01:00
}
} break ;
case VS : : LIGHT_SPOT : {
2017-03-05 16:44:50 +01:00
float radius = VSG : : storage - > light_get_param ( p_instance - > base , VS : : LIGHT_PARAM_RANGE ) ;
float angle = VSG : : storage - > light_get_param ( p_instance - > base , VS : : LIGHT_PARAM_SPOT_ANGLE ) ;
2016-11-10 03:55:06 +01:00
CameraMatrix cm ;
2017-03-05 16:44:50 +01:00
cm . set_perspective ( angle * 2.0 , 1.0 , 0.01 , radius ) ;
2016-11-10 03:55:06 +01:00
2018-07-03 13:34:06 +02:00
Vector < Plane > planes = cm . get_projection_planes ( light_transform ) ;
2021-08-17 14:40:39 +02:00
int cull_count = _cull_convex_from_point ( p_scenario , light_transform , cm , planes , instance_shadow_cull_result , MAX_INSTANCE_CULL , light - > previous_room_id_hint , VS : : INSTANCE_GEOMETRY_MASK ) ;
2016-11-10 03:55:06 +01:00
2019-11-02 21:00:24 +01:00
// Do a secondary cull to remove casters that don't intersect with the camera frustum.
if ( ! light - > is_shadow_update_full ( ) ) {
cull_count = light_culler - > cull ( cull_count , instance_shadow_cull_result ) ;
}
2018-07-03 13:34:06 +02:00
Plane near_plane ( light_transform . origin , - light_transform . basis . get_axis ( 2 ) ) ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < cull_count ; j + + ) {
2016-11-10 03:55:06 +01:00
Instance * instance = instance_shadow_cull_result [ j ] ;
2022-06-09 09:02:43 +02:00
if ( ! instance - > visible | | ! ( ( 1 < < instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) | | ! static_cast < InstanceGeometryData * > ( instance - > base_data ) - > can_cast_shadows | | ! ( p_visible_layers & instance - > layer_mask ) ) {
2016-11-10 03:55:06 +01:00
cull_count - - ;
2017-03-05 16:44:50 +01:00
SWAP ( instance_shadow_cull_result [ j ] , instance_shadow_cull_result [ cull_count ] ) ;
2016-11-10 03:55:06 +01:00
j - - ;
2017-07-15 06:23:10 +02:00
} else {
2018-11-14 13:32:39 +01:00
if ( static_cast < InstanceGeometryData * > ( instance - > base_data ) - > material_is_animated ) {
animated_material_found = true ;
}
2017-07-15 06:23:10 +02:00
instance - > depth = near_plane . distance_to ( instance - > transform . origin ) ;
instance - > depth_layer = 0 ;
2016-11-10 03:55:06 +01:00
}
}
2018-07-03 13:34:06 +02:00
VSG : : scene_render - > light_instance_set_shadow_transform ( light - > instance , cm , light_transform , radius , 0 , 0 ) ;
2017-03-05 16:44:50 +01:00
VSG : : scene_render - > render_shadow ( light - > instance , p_shadow_atlas , 0 , ( RasterizerScene : : InstanceBase * * ) instance_shadow_cull_result , cull_count ) ;
2016-11-10 03:55:06 +01:00
} break ;
}
2018-11-14 13:32:39 +01:00
return animated_material_found ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : render_camera ( RID p_camera , RID p_scenario , Size2 p_viewport_size , RID p_shadow_atlas ) {
2018-07-21 22:26:14 +02:00
// render to mono camera
# ifndef _3D_DISABLED
2016-11-10 03:55:06 +01:00
2016-10-19 16:14:41 +02:00
Camera * camera = camera_owner . getornull ( p_camera ) ;
ERR_FAIL_COND ( ! camera ) ;
/* STEP 1 - SETUP CAMERA */
CameraMatrix camera_matrix ;
2017-03-05 16:44:50 +01:00
bool ortho = false ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
switch ( camera - > type ) {
2016-10-19 16:14:41 +02:00
case Camera : : ORTHOGONAL : {
camera_matrix . set_orthogonal (
2017-03-05 16:44:50 +01:00
camera - > size ,
p_viewport_size . width / ( float ) p_viewport_size . height ,
camera - > znear ,
camera - > zfar ,
2017-12-06 21:36:34 +01:00
camera - > vaspect ) ;
2017-03-05 16:44:50 +01:00
ortho = true ;
2016-10-19 16:14:41 +02:00
} break ;
case Camera : : PERSPECTIVE : {
camera_matrix . set_perspective (
2017-03-05 16:44:50 +01:00
camera - > fov ,
p_viewport_size . width / ( float ) p_viewport_size . height ,
camera - > znear ,
camera - > zfar ,
2017-12-06 21:36:34 +01:00
camera - > vaspect ) ;
2017-03-05 16:44:50 +01:00
ortho = false ;
2016-10-19 16:14:41 +02:00
} break ;
2019-02-19 17:17:02 +01:00
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 ;
2016-10-19 16:14:41 +02:00
}
2024-06-05 08:45:03 +02:00
_prepare_scene ( camera - > transform , camera_matrix , ortho , camera - > env , camera - > visible_layers , p_scenario , p_shadow_atlas , RID ( ) , camera - > previous_room_id_hint ) ;
_render_scene ( camera - > transform , camera_matrix , 0 , ortho , camera - > env , p_scenario , p_shadow_atlas , RID ( ) , - 1 ) ;
2018-07-21 22:26:14 +02:00
# endif
2016-11-19 17:23:37 +01:00
}
2017-04-23 14:10:41 +02:00
void VisualServerScene : : render_camera ( Ref < ARVRInterface > & p_interface , ARVRInterface : : Eyes p_eye , RID p_camera , RID p_scenario , Size2 p_viewport_size , RID p_shadow_atlas ) {
// 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 = ARVRServer : : get_singleton ( ) - > get_world_origin ( ) ;
Transform cam_transform = p_interface - > get_transform_for_eye ( p_eye , world_origin ) ;
2018-06-11 13:51:30 +02:00
// For stereo render we only prepare for our left eye and then reuse the outcome for our right eye
if ( p_eye = = ARVRInterface : : EYE_LEFT ) {
///@TODO possibly move responsibility for this into our ARVRServer or ARVRInterface?
// Center our transform, we assume basis is equal.
Transform mono_transform = cam_transform ;
Transform right_transform = p_interface - > get_transform_for_eye ( ARVRInterface : : 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 ] ;
2018-06-23 14:22:57 +02:00
float y_shift = height * camera_matrix . matrix [ 2 ] [ 1 ] ;
2018-06-11 13:51:30 +02:00
// 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)
2018-06-23 14:22:57 +02:00
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 ;
2018-06-11 13:51:30 +02:00
// 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
2021-02-04 11:43:08 +01:00
_prepare_scene ( mono_transform , combined_matrix , false , camera - > env , camera - > visible_layers , p_scenario , p_shadow_atlas , RID ( ) , camera - > previous_room_id_hint ) ;
2018-06-11 13:51:30 +02:00
} else if ( p_eye = = ARVRInterface : : EYE_MONO ) {
// For mono render, prepare as per usual
2021-02-04 11:43:08 +01:00
_prepare_scene ( cam_transform , camera_matrix , false , camera - > env , camera - > visible_layers , p_scenario , p_shadow_atlas , RID ( ) , camera - > previous_room_id_hint ) ;
2018-06-11 13:51:30 +02:00
}
// And render our scene...
2021-04-19 05:32:23 +02:00
_render_scene ( cam_transform , camera_matrix , p_eye , false , camera - > env , p_scenario , p_shadow_atlas , RID ( ) , - 1 ) ;
2017-04-23 14:10:41 +02:00
} ;
2021-02-04 11:43:08 +01:00
void VisualServerScene : : _prepare_scene ( const Transform p_cam_transform , const CameraMatrix & p_cam_projection , bool p_cam_orthogonal , RID p_force_environment , uint32_t p_visible_layers , RID p_scenario , RID p_shadow_atlas , RID p_reflection_probe , int32_t & r_previous_room_id_hint ) {
2019-11-02 21:00:24 +01:00
// Prepare the light - camera volume culling system.
light_culler - > prepare_camera ( p_cam_transform , p_cam_projection ) ;
2018-06-11 13:51:30 +02: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
2016-11-19 17:23:37 +01:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
render_pass + + ;
2017-03-05 16:44:50 +01:00
uint32_t camera_layer_mask = p_visible_layers ;
2016-11-19 17:23:37 +01:00
VSG : : scene_render - > set_scene_pass ( render_pass ) ;
2017-01-14 12:26:56 +01:00
//rasterizer->set_camera(camera->transform, camera_matrix,ortho);
2016-10-19 16:14:41 +02:00
2016-11-19 17:23:37 +01:00
Vector < Plane > planes = p_cam_projection . get_projection_planes ( p_cam_transform ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
Plane near_plane ( p_cam_transform . origin , - p_cam_transform . basis . get_axis ( 2 ) . normalized ( ) ) ;
2016-11-19 17:23:37 +01:00
float z_far = p_cam_projection . get_z_far ( ) ;
2016-10-19 16:14:41 +02:00
/* STEP 2 - CULL */
2021-08-17 14:40:39 +02:00
instance_cull_count = _cull_convex_from_point ( scenario , p_cam_transform , p_cam_projection , planes , instance_cull_result , MAX_INSTANCE_CULL , r_previous_room_id_hint ) ;
2017-03-05 16:44:50 +01:00
light_cull_count = 0 ;
2016-11-19 17:23:37 +01:00
2017-03-05 16:44:50 +01:00
reflection_probe_cull_count = 0 ;
2016-11-19 17:23:37 +01:00
2017-08-26 05:40:45 +02:00
//light_samplers_culled=0;
2016-10-19 16:14:41 +02:00
2018-08-24 09:35:07 +02:00
/*
print_line ( " OT: " + rtos ( ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - t ) / 1000.0 ) ) ;
2016-10-19 16:14:41 +02:00
print_line ( " OTO: " + itos ( p_scenario - > octree . get_octant_count ( ) ) ) ;
2018-08-24 09:35:07 +02:00
print_line ( " OTE: " + itos ( p_scenario - > octree . get_elem_count ( ) ) ) ;
2016-10-19 16:14:41 +02:00
print_line ( " OTP: " + itos ( p_scenario - > octree . get_pair_count ( ) ) ) ;
2018-08-24 09:35:07 +02:00
*/
2016-10-19 16:14:41 +02:00
2017-08-26 05:40:45 +02:00
/* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */
//removed, will replace with culling
2016-10-19 16:14:41 +02:00
/* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */
2018-06-11 13:51:30 +02:00
for ( int i = 0 ; i < instance_cull_count ; i + + ) {
2016-10-19 16:14:41 +02:00
Instance * ins = instance_cull_result [ i ] ;
2017-03-05 16:44:50 +01:00
bool keep = false ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
if ( ( camera_layer_mask & ins - > layer_mask ) = = 0 ) {
2016-10-19 16:14:41 +02:00
//failure
2017-03-05 16:44:50 +01:00
} else if ( ins - > base_type = = VS : : INSTANCE_LIGHT & & ins - > visible ) {
2019-04-08 11:03:37 +02:00
if ( light_cull_count < MAX_LIGHTS_CULLED ) {
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( ins - > base_data ) ;
2016-10-19 16:14:41 +02:00
if ( ! light - > geometries . empty ( ) ) {
//do not add this light if no geometry is affected by it..
2017-03-05 16:44:50 +01:00
light_cull_result [ light_cull_count ] = ins ;
light_instance_cull_result [ light_cull_count ] = light - > instance ;
2016-11-10 03:55:06 +01:00
if ( p_shadow_atlas . is_valid ( ) & & VSG : : storage - > light_has_shadow ( ins - > base ) ) {
VSG : : scene_render - > light_instance_mark_visible ( light - > instance ) ; //mark it visible for shadow allocation later
}
2016-10-19 16:14:41 +02:00
light_cull_count + + ;
}
}
2017-03-05 16:44:50 +01:00
} else if ( ins - > base_type = = VS : : INSTANCE_REFLECTION_PROBE & & ins - > visible ) {
2019-04-08 11:03:37 +02:00
if ( reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED ) {
2017-03-05 16:44:50 +01:00
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( ins - > base_data ) ;
2016-11-19 17:23:37 +01:00
2017-03-05 16:44:50 +01:00
if ( p_reflection_probe ! = reflection_probe - > instance ) {
2016-11-19 17:23:37 +01:00
//avoid entering The Matrix
if ( ! reflection_probe - > geometries . empty ( ) ) {
//do not add this light if no geometry is affected by it..
if ( reflection_probe - > reflection_dirty | | VSG : : scene_render - > reflection_probe_instance_needs_redraw ( reflection_probe - > instance ) ) {
if ( ! reflection_probe - > update_list . in_list ( ) ) {
2017-03-05 16:44:50 +01:00
reflection_probe - > render_step = 0 ;
2017-07-15 23:40:47 +02:00
reflection_probe_render_list . add_last ( & reflection_probe - > update_list ) ;
2016-11-19 17:23:37 +01:00
}
2017-03-05 16:44:50 +01:00
reflection_probe - > reflection_dirty = false ;
2016-11-19 17:23:37 +01:00
}
if ( VSG : : scene_render - > reflection_probe_instance_has_reflection ( reflection_probe - > instance ) ) {
2017-03-05 16:44:50 +01:00
reflection_probe_instance_cull_result [ reflection_probe_cull_count ] = reflection_probe - > instance ;
2016-11-19 17:23:37 +01:00
reflection_probe_cull_count + + ;
}
}
}
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
} else if ( ins - > base_type = = VS : : INSTANCE_GI_PROBE & & ins - > visible ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( ins - > base_data ) ;
2016-12-20 04:21:07 +01:00
if ( ! gi_probe - > update_element . in_list ( ) ) {
gi_probe_update_list . add ( & gi_probe - > update_element ) ;
}
2017-09-07 21:48:50 +02:00
} else if ( ( ( 1 < < ins - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) & & ins - > visible & & ins - > cast_shadows ! = VS : : SHADOW_CASTING_SETTING_SHADOWS_ONLY ) {
2017-03-05 16:44:50 +01:00
keep = true ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( ins - > base_data ) ;
2016-11-19 17:23:37 +01:00
2018-07-23 17:28:15 +02:00
if ( ins - > redraw_if_visible ) {
2021-10-05 20:05:57 +02:00
VisualServerRaster : : redraw_request ( false ) ;
2018-07-23 17:28:15 +02:00
}
2017-04-07 04:36:37 +02:00
if ( ins - > base_type = = VS : : INSTANCE_PARTICLES ) {
2018-07-17 16:52:13 +02:00
//particles visible? process them
2018-11-20 00:34:29 +01:00
if ( VSG : : storage - > particles_is_inactive ( ins - > base ) ) {
//but if nothing is going on, don't do it.
keep = false ;
} else {
2021-10-05 20:05:57 +02:00
if ( OS : : get_singleton ( ) - > is_update_pending ( true ) ) {
VSG : : storage - > particles_request_process ( ins - > base ) ;
//particles visible? request redraw
VisualServerRaster : : redraw_request ( false ) ;
}
2018-11-20 00:34:29 +01:00
}
2017-04-07 04:36:37 +02:00
}
2016-10-19 16:14:41 +02:00
if ( geom - > lighting_dirty ) {
2017-03-05 16:44:50 +01:00
int l = 0 ;
2016-10-19 16:14:41 +02:00
//only called when lights AABB enter/exit this geometry
ins - > light_instances . resize ( geom - > lighting . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = geom - > lighting . front ( ) ; E ; E = E - > next ( ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2016-10-19 16:14:41 +02:00
2018-07-25 03:11:03 +02:00
ins - > light_instances . write [ l + + ] = light - > instance ;
2016-10-19 16:14:41 +02:00
}
2017-03-05 16:44:50 +01:00
geom - > lighting_dirty = false ;
2016-10-19 16:14:41 +02:00
}
2016-11-19 17:23:37 +01:00
if ( geom - > reflection_dirty ) {
2017-03-05 16:44:50 +01:00
int l = 0 ;
2016-11-19 17:23:37 +01:00
//only called when reflection probe AABB enter/exit this geometry
ins - > reflection_probe_instances . resize ( geom - > reflection_probes . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = geom - > reflection_probes . front ( ) ; E ; E = E - > next ( ) ) {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( E - > get ( ) - > base_data ) ;
2016-11-19 17:23:37 +01:00
2018-07-25 03:11:03 +02:00
ins - > reflection_probe_instances . write [ l + + ] = reflection_probe - > instance ;
2016-11-19 17:23:37 +01:00
}
2017-03-05 16:44:50 +01:00
geom - > reflection_dirty = false ;
2016-11-19 17:23:37 +01:00
}
2016-12-20 04:21:07 +01:00
if ( geom - > gi_probes_dirty ) {
2017-03-05 16:44:50 +01:00
int l = 0 ;
2016-12-20 04:21:07 +01:00
//only called when reflection probe AABB enter/exit this geometry
ins - > gi_probe_instances . resize ( geom - > gi_probes . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = geom - > gi_probes . front ( ) ; E ; E = E - > next ( ) ) {
InstanceGIProbeData * gi_probe = static_cast < InstanceGIProbeData * > ( E - > get ( ) - > base_data ) ;
2016-12-20 04:21:07 +01:00
2018-07-25 03:11:03 +02:00
ins - > gi_probe_instances . write [ l + + ] = gi_probe - > probe_instance ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
geom - > gi_probes_dirty = false ;
2016-12-20 04:21:07 +01:00
}
2016-10-19 16:14:41 +02:00
}
if ( ! keep ) {
// remove, no reason to keep
2018-06-11 13:51:30 +02:00
instance_cull_count - - ;
SWAP ( instance_cull_result [ i ] , instance_cull_result [ instance_cull_count ] ) ;
2016-10-19 16:14:41 +02:00
i - - ;
2017-03-05 16:44:50 +01:00
ins - > last_render_pass = 0 ; // make invalid
2016-10-19 16:14:41 +02:00
} else {
2017-03-05 16:44:50 +01:00
ins - > last_render_pass = render_pass ;
2016-10-19 16:14:41 +02:00
}
}
/* STEP 5 - PROCESS LIGHTS */
2017-03-05 16:44:50 +01:00
RID * directional_light_ptr = & light_instance_cull_result [ light_cull_count ] ;
2018-06-11 13:51:30 +02:00
directional_light_count = 0 ;
2016-10-19 16:14:41 +02:00
// directional lights
{
2017-03-05 16:44:50 +01:00
Instance * * lights_with_shadow = ( Instance * * ) alloca ( sizeof ( Instance * ) * scenario - > directional_lights . size ( ) ) ;
int directional_shadow_count = 0 ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = scenario - > directional_lights . front ( ) ; E ; E = E - > next ( ) ) {
if ( light_cull_count + directional_light_count > = MAX_LIGHTS_CULLED ) {
2016-10-19 16:14:41 +02:00
break ;
}
2021-05-05 12:44:11 +02:00
if ( ! E - > get ( ) - > visible ) {
2016-10-19 16:14:41 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2016-10-19 16:14:41 +02:00
//check shadow..
2017-08-29 13:31:27 +02:00
if ( light ) {
if ( p_shadow_atlas . is_valid ( ) & & VSG : : storage - > light_has_shadow ( E - > get ( ) - > base ) ) {
lights_with_shadow [ directional_shadow_count + + ] = E - > get ( ) ;
}
2017-08-25 17:14:33 +02:00
//add to list
directional_light_ptr [ directional_light_count + + ] = light - > instance ;
}
2016-11-10 03:55:06 +01:00
}
VSG : : scene_render - > set_directional_shadow_count ( directional_shadow_count ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < directional_shadow_count ; i + + ) {
2022-06-09 09:02:43 +02:00
_light_instance_update_shadow ( lights_with_shadow [ i ] , p_cam_transform , p_cam_projection , p_cam_orthogonal , p_shadow_atlas , scenario , p_visible_layers ) ;
2016-10-19 16:14:41 +02:00
}
}
2016-11-10 03:55:06 +01:00
{ //setup shadow maps
//SortArray<Instance*,_InstanceLightsort> sorter;
//sorter.sort(light_cull_result,light_cull_count);
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < light_cull_count ; i + + ) {
2016-10-19 16:14:41 +02:00
Instance * ins = light_cull_result [ i ] ;
2021-05-05 12:44:11 +02:00
if ( ! p_shadow_atlas . is_valid ( ) | | ! VSG : : storage - > light_has_shadow ( ins - > base ) ) {
2016-10-19 16:14:41 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
InstanceLightData * light = static_cast < InstanceLightData * > ( ins - > base_data ) ;
2016-11-10 03:55:06 +01:00
2017-09-01 22:33:39 +02:00
float coverage = 0.f ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
{ //compute coverage
2016-11-10 03:55:06 +01:00
2016-11-19 17:23:37 +01:00
Transform cam_xf = p_cam_transform ;
float zn = p_cam_projection . get_z_near ( ) ;
2017-03-05 16:44:50 +01:00
Plane p ( cam_xf . origin + cam_xf . basis . get_axis ( 2 ) * - zn , - cam_xf . basis . get_axis ( 2 ) ) ; //camera near plane
2016-11-10 03:55:06 +01:00
2020-01-21 19:39:16 +01:00
// near plane half width and height
Vector2 vp_half_extents = p_cam_projection . get_viewport_half_extents ( ) ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
switch ( VSG : : storage - > light_get_type ( ins - > base ) ) {
2016-11-10 03:55:06 +01:00
case VS : : LIGHT_OMNI : {
2017-03-05 16:44:50 +01:00
float radius = VSG : : storage - > light_get_param ( ins - > base , VS : : LIGHT_PARAM_RANGE ) ;
2016-11-10 03:55:06 +01:00
//get two points parallel to near plane
2017-03-05 16:44:50 +01:00
Vector3 points [ 2 ] = {
2016-11-10 03:55:06 +01:00
ins - > transform . origin ,
2017-03-05 16:44:50 +01:00
ins - > transform . origin + cam_xf . basis . get_axis ( 0 ) * radius
2016-11-10 03:55:06 +01:00
} ;
2016-11-19 17:23:37 +01:00
if ( ! p_cam_orthogonal ) {
2016-11-10 03:55:06 +01:00
//if using perspetive, map them to near plane
2017-03-05 16:44:50 +01:00
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
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
p . intersects_segment ( cam_xf . origin , points [ j ] , & points [ j ] ) ; //map to plane
2016-11-10 03:55:06 +01:00
}
}
2017-03-05 16:44:50 +01:00
float screen_diameter = points [ 0 ] . distance_to ( points [ 1 ] ) * 2 ;
2020-01-21 19:39:16 +01:00
coverage = screen_diameter / ( vp_half_extents . x + vp_half_extents . y ) ;
2016-11-10 03:55:06 +01:00
} break ;
case VS : : LIGHT_SPOT : {
2017-03-05 16:44:50 +01:00
float radius = VSG : : storage - > light_get_param ( ins - > base , VS : : LIGHT_PARAM_RANGE ) ;
float angle = VSG : : storage - > light_get_param ( ins - > base , VS : : LIGHT_PARAM_SPOT_ANGLE ) ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
float w = radius * Math : : sin ( Math : : deg2rad ( angle ) ) ;
float d = radius * Math : : cos ( Math : : deg2rad ( angle ) ) ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
Vector3 base = ins - > transform . origin - ins - > transform . basis . get_axis ( 2 ) . normalized ( ) * d ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
Vector3 points [ 2 ] = {
2016-11-10 03:55:06 +01:00
base ,
2017-03-05 16:44:50 +01:00
base + cam_xf . basis . get_axis ( 0 ) * w
2016-11-10 03:55:06 +01:00
} ;
2016-11-19 17:23:37 +01:00
if ( ! p_cam_orthogonal ) {
2016-11-10 03:55:06 +01:00
//if using perspetive, map them to near plane
2017-03-05 16:44:50 +01:00
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
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
p . intersects_segment ( cam_xf . origin , points [ j ] , & points [ j ] ) ; //map to plane
2016-11-10 03:55:06 +01:00
}
}
2017-03-05 16:44:50 +01:00
float screen_diameter = points [ 0 ] . distance_to ( points [ 1 ] ) * 2 ;
2020-01-21 19:39:16 +01:00
coverage = screen_diameter / ( vp_half_extents . x + vp_half_extents . y ) ;
2016-11-10 03:55:06 +01:00
} break ;
default : {
ERR_PRINT ( " Invalid Light Type " ) ;
}
}
}
2019-11-02 21:00:24 +01:00
// We can detect whether multiple cameras are hitting this light, whether or not the shadow is dirty,
// so that we can turn off tighter caster culling.
light - > detect_light_intersects_multiple_cameras ( Engine : : get_singleton ( ) - > get_frames_drawn ( ) ) ;
if ( light - > is_shadow_dirty ( ) ) {
// Dirty shadows have no need to be drawn if
// the light volume doesn't intersect the camera frustum.
// Returns false if the entire light can be culled.
bool allow_redraw = light_culler - > prepare_light ( * ins ) ;
// Directional lights aren't handled here, _light_instance_update_shadow is called from elsewhere.
// Checking for this in case this changes, as this is assumed.
DEV_CHECK_ONCE ( VSG : : storage - > light_get_type ( ins - > base ) ! = VS : : LIGHT_DIRECTIONAL ) ;
// Tighter caster culling to the camera frustum should work correctly with multiple viewports + cameras.
// The first camera will cull tightly, but if the light is present on more than 1 camera, the second will
// do a full render, and mark the light as non-dirty.
// There is however a cost to tighter shadow culling in this situation (2 shadow updates in 1 frame),
// so we should detect this and switch off tighter caster culling automatically.
// This is done in the logic for `decrement_shadow_dirty()`.
if ( allow_redraw ) {
light - > last_version + + ;
light - > decrement_shadow_dirty ( ) ;
}
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
bool redraw = VSG : : scene_render - > shadow_atlas_update_light ( p_shadow_atlas , light - > instance , coverage , light - > last_version ) ;
2016-11-10 03:55:06 +01:00
if ( redraw ) {
//must redraw!
2019-11-02 21:00:24 +01:00
if ( _light_instance_update_shadow ( ins , p_cam_transform , p_cam_projection , p_cam_orthogonal , p_shadow_atlas , scenario , p_visible_layers ) ) {
// If the light requests another update (animated material?)...
light - > make_shadow_dirty ( ) ;
}
2016-11-10 03:55:06 +01:00
}
2016-10-19 16:14:41 +02:00
}
}
2021-07-22 01:41:31 +02:00
// Calculate instance->depth from the camera, after shadow calculation has stopped overwriting instance->depth
for ( int i = 0 ; i < instance_cull_count ; i + + ) {
Instance * ins = instance_cull_result [ i ] ;
if ( ( ( 1 < < ins - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) & & ins - > visible & & ins - > cast_shadows ! = VS : : SHADOW_CASTING_SETTING_SHADOWS_ONLY ) {
2022-07-13 20:06:25 +02:00
Vector3 center = ins - > transform . origin ;
if ( ins - > use_aabb_center ) {
center = ins - > transformed_aabb . position + ( ins - > transformed_aabb . size * 0.5 ) ;
}
2022-04-19 23:54:51 +02:00
if ( p_cam_orthogonal ) {
2022-07-13 20:06:25 +02:00
ins - > depth = near_plane . distance_to ( center ) - ins - > sorting_offset ;
2022-04-19 23:54:51 +02:00
} else {
2022-07-13 20:06:25 +02:00
ins - > depth = p_cam_transform . origin . distance_to ( center ) - ins - > sorting_offset ;
2022-04-19 23:54:51 +02:00
}
2021-07-22 01:41:31 +02:00
ins - > depth_layer = CLAMP ( int ( ins - > depth * 16 / z_far ) , 0 , 15 ) ;
}
}
2018-06-11 13:51:30 +02:00
}
2021-04-19 05:32:23 +02:00
void VisualServerScene : : _render_scene ( const Transform p_cam_transform , const CameraMatrix & p_cam_projection , const int p_eye , bool p_cam_orthogonal , RID p_force_environment , RID p_scenario , RID p_shadow_atlas , RID p_reflection_probe , int p_reflection_probe_pass ) {
2018-06-11 13:51:30 +02:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
2016-11-10 03:55:06 +01:00
2016-10-19 16:14:41 +02:00
/* ENVIRONMENT */
RID environment ;
2021-05-05 12:44:11 +02:00
if ( p_force_environment . is_valid ( ) ) { //camera has more environment priority
2017-03-05 16:44:50 +01:00
environment = p_force_environment ;
2021-05-05 12:44:11 +02:00
} else if ( scenario - > environment . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
environment = scenario - > environment ;
2021-05-05 12:44:11 +02:00
} else {
2017-03-05 16:44:50 +01:00
environment = scenario - > fallback_environment ;
2021-05-05 12:44:11 +02:00
}
2016-10-19 16:14:41 +02:00
2018-06-11 13:51:30 +02:00
/* PROCESS GEOMETRY AND DRAW SCENE */
2016-10-19 16:14:41 +02:00
2021-04-19 05:32:23 +02:00
VSG : : scene_render - > render_scene ( p_cam_transform , p_cam_projection , p_eye , p_cam_orthogonal , ( RasterizerScene : : InstanceBase * * ) instance_cull_result , instance_cull_count , light_instance_cull_result , light_cull_count + directional_light_count , reflection_probe_instance_cull_result , reflection_probe_cull_count , environment , p_shadow_atlas , scenario - > reflection_atlas , p_reflection_probe , p_reflection_probe_pass ) ;
2016-11-19 17:23:37 +01:00
}
2016-10-19 16:14:41 +02:00
2017-06-24 13:58:27 +02:00
void VisualServerScene : : render_empty_scene ( RID p_scenario , RID p_shadow_atlas ) {
2018-07-21 22:26:14 +02:00
# ifndef _3D_DISABLED
2017-06-24 13:58:27 +02:00
Scenario * scenario = scenario_owner . getornull ( p_scenario ) ;
RID environment ;
2021-05-05 12:44:11 +02:00
if ( scenario - > environment . is_valid ( ) ) {
2017-06-24 13:58:27 +02:00
environment = scenario - > environment ;
2021-05-05 12:44:11 +02:00
} else {
2017-06-24 13:58:27 +02:00
environment = scenario - > fallback_environment ;
2021-05-05 12:44:11 +02:00
}
2021-04-19 05:32:23 +02:00
VSG : : scene_render - > render_scene ( Transform ( ) , CameraMatrix ( ) , 0 , true , nullptr , 0 , nullptr , 0 , nullptr , 0 , environment , p_shadow_atlas , scenario - > reflection_atlas , RID ( ) , 0 ) ;
2018-07-21 22:26:14 +02:00
# endif
2017-06-24 13:58:27 +02:00
}
2017-03-05 16:44:50 +01:00
bool VisualServerScene : : _render_reflection_probe_step ( Instance * p_instance , int p_step ) {
InstanceReflectionProbeData * reflection_probe = static_cast < InstanceReflectionProbeData * > ( p_instance - > base_data ) ;
2016-11-19 17:23:37 +01:00
Scenario * scenario = p_instance - > scenario ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! scenario , true ) ;
2016-10-19 16:14:41 +02:00
2022-06-12 07:44:59 +02:00
VisualServerRaster : : redraw_request ( false ) ; //update, so it updates in editor
2018-09-28 21:40:20 +02:00
2017-03-05 16:44:50 +01:00
if ( p_step = = 0 ) {
if ( ! VSG : : scene_render - > reflection_probe_instance_begin_render ( reflection_probe - > instance , scenario - > reflection_atlas ) ) {
2016-11-19 17:23:37 +01:00
return true ; //sorry, all full :(
2016-10-19 16:14:41 +02:00
}
2016-11-19 17:23:37 +01:00
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
if ( p_step > = 0 & & p_step < 6 ) {
static const Vector3 view_normals [ 6 ] = {
2016-11-19 17:23:37 +01:00
Vector3 ( - 1 , 0 , 0 ) ,
Vector3 ( + 1 , 0 , 0 ) ,
2017-03-05 16:44:50 +01:00
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , + 1 , 0 ) ,
Vector3 ( 0 , 0 , - 1 ) ,
Vector3 ( 0 , 0 , + 1 )
2016-11-19 17:23:37 +01:00
} ;
Vector3 extents = VSG : : storage - > reflection_probe_get_extents ( p_instance - > base ) ;
Vector3 origin_offset = VSG : : storage - > reflection_probe_get_origin_offset ( p_instance - > base ) ;
float max_distance = VSG : : storage - > reflection_probe_get_origin_max_distance ( p_instance - > base ) ;
2017-03-05 16:44:50 +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
2016-11-19 17:23:37 +01:00
2017-03-05 16:44:50 +01:00
max_distance = MAX ( max_distance , distance ) ;
2016-11-19 17:23:37 +01:00
//render cubemap side
CameraMatrix cm ;
2017-03-05 16:44:50 +01:00
cm . set_perspective ( 90 , 1 , 0.01 , max_distance ) ;
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 )
2016-11-19 17:23:37 +01:00
} ;
Transform local_view ;
2017-03-05 16:44:50 +01:00
local_view . set_look_at ( origin_offset , origin_offset + view_normals [ p_step ] , view_up [ p_step ] ) ;
2016-11-19 17:23:37 +01:00
Transform xform = p_instance - > transform * local_view ;
RID shadow_atlas ;
if ( VSG : : storage - > reflection_probe_renders_shadows ( p_instance - > base ) ) {
2017-03-05 16:44:50 +01:00
shadow_atlas = scenario - > reflection_probe_shadow_atlas ;
2016-10-19 16:14:41 +02:00
}
2016-11-19 17:23:37 +01:00
2021-02-04 11:43:08 +01:00
_prepare_scene ( xform , cm , false , RID ( ) , VSG : : storage - > reflection_probe_get_cull_mask ( p_instance - > base ) , p_instance - > scenario - > self , shadow_atlas , reflection_probe - > instance , reflection_probe - > previous_room_id_hint ) ;
2021-09-26 21:31:17 +02:00
bool async_forbidden_backup = VSG : : storage - > is_shader_async_hidden_forbidden ( ) ;
VSG : : storage - > set_shader_async_hidden_forbidden ( true ) ;
2021-04-19 05:32:23 +02:00
_render_scene ( xform , cm , 0 , false , RID ( ) , p_instance - > scenario - > self , shadow_atlas , reflection_probe - > instance , p_step ) ;
2021-09-26 21:31:17 +02:00
VSG : : storage - > set_shader_async_hidden_forbidden ( async_forbidden_backup ) ;
2016-11-19 17:23:37 +01:00
} else {
2018-01-18 21:37:17 +01:00
//do roughness postprocess step until it believes it's done
2016-11-19 17:23:37 +01:00
return VSG : : scene_render - > reflection_probe_instance_postprocess_step ( reflection_probe - > instance ) ;
2016-10-19 16:14:41 +02:00
}
2016-11-19 17:23:37 +01:00
return false ;
}
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
void VisualServerScene : : _gi_probe_fill_local_data ( int p_idx , int p_level , int p_x , int p_y , int p_z , const GIProbeDataCell * p_cell , const GIProbeDataHeader * p_header , InstanceGIProbeData : : LocalData * p_local_data , Vector < uint32_t > * prev_cell ) {
2017-08-31 23:30:35 +02:00
if ( ( uint32_t ) p_level = = p_header - > cell_subdiv - 1 ) {
2016-12-20 04:21:07 +01:00
Vector3 emission ;
2017-03-05 16:44:50 +01:00
emission . x = ( p_cell [ p_idx ] . emission > > 24 ) / 255.0 ;
emission . y = ( ( p_cell [ p_idx ] . emission > > 16 ) & 0xFF ) / 255.0 ;
emission . z = ( ( p_cell [ p_idx ] . emission > > 8 ) & 0xFF ) / 255.0 ;
float l = ( p_cell [ p_idx ] . emission & 0xFF ) / 255.0 ;
l * = 8.0 ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
emission * = l ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
p_local_data [ p_idx ] . energy [ 0 ] = uint16_t ( emission . x * 1024 ) ; //go from 0 to 1024 for light
p_local_data [ p_idx ] . energy [ 1 ] = uint16_t ( emission . y * 1024 ) ; //go from 0 to 1024 for light
p_local_data [ p_idx ] . energy [ 2 ] = uint16_t ( emission . z * 1024 ) ; //go from 0 to 1024 for light
2016-12-20 04:21:07 +01:00
} else {
2017-03-05 16:44:50 +01:00
p_local_data [ p_idx ] . energy [ 0 ] = 0 ;
p_local_data [ p_idx ] . energy [ 1 ] = 0 ;
p_local_data [ p_idx ] . energy [ 2 ] = 0 ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
int half = ( 1 < < ( p_header - > cell_subdiv - 1 ) ) > > ( p_level + 1 ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 8 ; i + + ) {
2016-12-20 04:21:07 +01:00
uint32_t child = p_cell [ p_idx ] . children [ i ] ;
2021-05-05 12:44:11 +02:00
if ( child = = 0xFFFFFFFF ) {
2016-12-20 04:21:07 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-12-20 04:21:07 +01:00
int x = p_x ;
int y = p_y ;
int z = p_z ;
2021-05-05 12:44:11 +02:00
if ( i & 1 ) {
2017-03-05 16:44:50 +01:00
x + = half ;
2021-05-05 12:44:11 +02:00
}
if ( i & 2 ) {
2017-03-05 16:44:50 +01:00
y + = half ;
2021-05-05 12:44:11 +02:00
}
if ( i & 4 ) {
2017-03-05 16:44:50 +01:00
z + = half ;
2021-05-05 12:44:11 +02:00
}
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
_gi_probe_fill_local_data ( child , p_level + 1 , x , y , z , p_cell , p_header , p_local_data , prev_cell ) ;
2016-12-20 04:21:07 +01:00
}
}
//position for each part of the mipmaped texture
2017-03-05 16:44:50 +01:00
p_local_data [ p_idx ] . pos [ 0 ] = p_x > > ( p_header - > cell_subdiv - p_level - 1 ) ;
p_local_data [ p_idx ] . pos [ 1 ] = p_y > > ( p_header - > cell_subdiv - p_level - 1 ) ;
p_local_data [ p_idx ] . pos [ 2 ] = p_z > > ( p_header - > cell_subdiv - p_level - 1 ) ;
2016-12-20 04:21:07 +01:00
prev_cell [ p_level ] . push_back ( p_idx ) ;
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : _gi_probe_bake_threads ( void * self ) {
VisualServerScene * vss = ( VisualServerScene * ) self ;
2016-12-20 04:21:07 +01:00
vss - > _gi_probe_bake_thread ( ) ;
}
void VisualServerScene : : _setup_gi_probe ( Instance * p_instance ) {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * probe = static_cast < InstanceGIProbeData * > ( p_instance - > base_data ) ;
2016-12-20 04:21:07 +01:00
if ( probe - > dynamic . probe_data . is_valid ( ) ) {
VSG : : storage - > free ( probe - > dynamic . probe_data ) ;
2017-03-05 16:44:50 +01:00
probe - > dynamic . probe_data = RID ( ) ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
probe - > dynamic . light_data = VSG : : storage - > gi_probe_get_dynamic_data ( p_instance - > base ) ;
2016-12-20 04:21:07 +01:00
2021-05-05 12:44:11 +02:00
if ( probe - > dynamic . light_data . size ( ) = = 0 ) {
2016-12-30 12:35:54 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-12-23 04:37:38 +01:00
//using dynamic data
2017-03-05 16:44:50 +01:00
PoolVector < int > : : Read r = probe - > dynamic . light_data . read ( ) ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
const GIProbeDataHeader * header = ( GIProbeDataHeader * ) r . ptr ( ) ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
probe - > dynamic . local_data . resize ( header - > cell_count ) ;
2016-12-20 04:21:07 +01:00
2016-12-30 12:35:54 +01:00
int cell_count = probe - > dynamic . local_data . size ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < InstanceGIProbeData : : LocalData > : : Write ldw = probe - > dynamic . local_data . write ( ) ;
2017-03-05 16:44:50 +01:00
const GIProbeDataCell * cells = ( GIProbeDataCell * ) & r [ 16 ] ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
probe - > dynamic . level_cell_lists . resize ( header - > cell_subdiv ) ;
2016-12-20 04:21:07 +01:00
2017-11-25 04:07:54 +01:00
_gi_probe_fill_local_data ( 0 , 0 , 0 , 0 , 0 , cells , header , ldw . ptr ( ) , probe - > dynamic . level_cell_lists . ptrw ( ) ) ;
2016-12-20 04:21:07 +01:00
2020-08-23 16:18:33 +02:00
probe - > dynamic . compression = RasterizerStorage : : GI_PROBE_UNCOMPRESSED ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
probe - > dynamic . probe_data = VSG : : storage - > gi_probe_dynamic_data_create ( header - > width , header - > height , header - > depth , probe - > dynamic . compression ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
probe - > dynamic . bake_dynamic_range = VSG : : storage - > gi_probe_get_dynamic_range ( p_instance - > base ) ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
probe - > dynamic . mipmaps_3d . clear ( ) ;
2017-03-05 16:44:50 +01:00
probe - > dynamic . propagate = VSG : : storage - > gi_probe_get_propagation ( p_instance - > base ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
probe - > dynamic . grid_size [ 0 ] = header - > width ;
probe - > dynamic . grid_size [ 1 ] = header - > height ;
probe - > dynamic . grid_size [ 2 ] = header - > depth ;
2016-12-20 04:21:07 +01:00
2016-12-30 12:35:54 +01:00
int size_limit = 1 ;
int size_divisor = 1 ;
2017-03-05 16:44:50 +01:00
if ( probe - > dynamic . compression = = RasterizerStorage : : GI_PROBE_S3TC ) {
size_limit = 4 ;
size_divisor = 4 ;
2016-12-30 12:35:54 +01:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ( int ) header - > cell_subdiv ; i + + ) {
2017-08-31 23:30:35 +02:00
int x = header - > width > > i ;
int y = header - > height > > i ;
int z = header - > depth > > i ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
//create and clear mipmap
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > mipmap ;
2017-03-05 16:44:50 +01:00
int size = x * y * z * 4 ;
size / = size_divisor ;
2016-12-30 12:35:54 +01:00
mipmap . resize ( size ) ;
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > : : Write w = mipmap . write ( ) ;
2021-04-29 12:34:11 +02:00
memset ( w . ptr ( ) , 0 , size ) ;
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
probe - > dynamic . mipmaps_3d . push_back ( mipmap ) ;
2016-12-20 04:21:07 +01:00
2021-05-05 12:44:11 +02:00
if ( x < = size_limit | | y < = size_limit | | z < = size_limit ) {
2016-12-23 04:37:38 +01:00
break ;
2021-05-05 12:44:11 +02:00
}
2016-12-23 04:37:38 +01:00
}
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
probe - > dynamic . updating_stage = GI_UPDATE_STAGE_CHECK ;
probe - > invalid = false ;
probe - > dynamic . enabled = true ;
2016-12-20 04:21:07 +01:00
2016-12-23 04:37:38 +01:00
Transform cell_to_xform = VSG : : storage - > gi_probe_get_to_cell_xform ( p_instance - > base ) ;
2017-11-17 03:09:00 +01:00
AABB bounds = VSG : : storage - > gi_probe_get_bounds ( p_instance - > base ) ;
2016-12-23 04:37:38 +01:00
float cell_size = VSG : : storage - > gi_probe_get_cell_size ( p_instance - > base ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
probe - > dynamic . light_to_cell_xform = cell_to_xform * p_instance - > transform . affine_inverse ( ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
VSG : : scene_render - > gi_probe_instance_set_light_data ( probe - > probe_instance , p_instance - > base , probe - > dynamic . probe_data ) ;
VSG : : scene_render - > gi_probe_instance_set_transform_to_data ( probe - > probe_instance , probe - > dynamic . light_to_cell_xform ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
VSG : : scene_render - > gi_probe_instance_set_bounds ( probe - > probe_instance , bounds . size / cell_size ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
probe - > base_version = VSG : : storage - > gi_probe_get_version ( p_instance - > base ) ;
2016-12-20 04:21:07 +01:00
2016-12-30 12:35:54 +01:00
//if compression is S3TC, fill it up
2017-03-05 16:44:50 +01:00
if ( probe - > dynamic . compression = = RasterizerStorage : : GI_PROBE_S3TC ) {
2016-12-30 12:35:54 +01:00
//create all blocks
2021-05-04 14:20:36 +02:00
Vector < Map < uint32_t , InstanceGIProbeData : : CompBlockS3TC > > comp_blocks ;
2016-12-30 12:35:54 +01:00
int mipmap_count = probe - > dynamic . mipmaps_3d . size ( ) ;
comp_blocks . resize ( mipmap_count ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < cell_count ; i + + ) {
2016-12-30 12:35:54 +01:00
const GIProbeDataCell & c = cells [ i ] ;
const InstanceGIProbeData : : LocalData & ld = ldw [ i ] ;
2017-03-05 16:44:50 +01:00
int level = c . level_alpha > > 16 ;
int mipmap = header - > cell_subdiv - level - 1 ;
2021-05-05 12:44:11 +02:00
if ( mipmap > = mipmap_count ) {
2017-03-05 16:44:50 +01:00
continue ; //uninteresting
2021-05-05 12:44:11 +02:00
}
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
int blockx = ( ld . pos [ 0 ] > > 2 ) ;
int blocky = ( ld . pos [ 1 ] > > 2 ) ;
2016-12-30 12:35:54 +01:00
int blockz = ( ld . pos [ 2 ] ) ; //compression is x/y only
int blockw = ( header - > width > > mipmap ) > > 2 ;
int blockh = ( header - > height > > mipmap ) > > 2 ;
//print_line("cell "+itos(i)+" level "+itos(level)+"mipmap: "+itos(mipmap)+" pos: "+Vector3(blockx,blocky,blockz)+" size "+Vector2(blockw,blockh));
2017-03-05 16:44:50 +01:00
uint32_t key = blockz * blockw * blockh + blocky * blockw + blockx ;
2016-12-30 12:35:54 +01:00
2018-07-25 03:11:03 +02:00
Map < uint32_t , InstanceGIProbeData : : CompBlockS3TC > & cmap = comp_blocks . write [ mipmap ] ;
2016-12-30 12:35:54 +01:00
if ( ! cmap . has ( key ) ) {
InstanceGIProbeData : : CompBlockS3TC k ;
2017-03-05 16:44:50 +01:00
k . offset = key ; //use offset as counter first
k . source_count = 0 ;
cmap [ key ] = k ;
2016-12-30 12:35:54 +01:00
}
2017-03-05 16:44:50 +01:00
InstanceGIProbeData : : CompBlockS3TC & k = cmap [ key ] ;
ERR_CONTINUE ( k . source_count = = 16 ) ;
k . sources [ k . source_count + + ] = i ;
2016-12-30 12:35:54 +01:00
}
//fix the blocks, precomputing what is needed
probe - > dynamic . mipmaps_s3tc . resize ( mipmap_count ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < mipmap_count ; i + + ) {
2018-08-24 09:35:07 +02:00
//print_line("S3TC level: " + itos(i) + " blocks: " + itos(comp_blocks[i].size()));
2018-07-25 03:11:03 +02:00
probe - > dynamic . mipmaps_s3tc . write [ i ] . resize ( comp_blocks [ i ] . size ( ) ) ;
PoolVector < InstanceGIProbeData : : CompBlockS3TC > : : Write w = probe - > dynamic . mipmaps_s3tc . write [ i ] . write ( ) ;
2017-03-05 16:44:50 +01:00
int block_idx = 0 ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
for ( Map < uint32_t , InstanceGIProbeData : : CompBlockS3TC > : : Element * E = comp_blocks [ i ] . front ( ) ; E ; E = E - > next ( ) ) {
2016-12-30 12:35:54 +01:00
InstanceGIProbeData : : CompBlockS3TC k = E - > get ( ) ;
//PRECOMPUTE ALPHA
2017-03-05 16:44:50 +01:00
int max_alpha = - 100000 ;
int min_alpha = k . source_count = = 16 ? 100000 : 0 ; //if the block is not completely full, minimum is always 0, (and those blocks will map to 1, which will be zero)
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
uint8_t alpha_block [ 4 ] [ 4 ] = { { 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 } } ;
2016-12-30 12:35:54 +01:00
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < k . source_count ; j + + ) {
2017-03-05 16:44:50 +01:00
int alpha = ( cells [ k . sources [ j ] ] . level_alpha > > 8 ) & 0xFF ;
2021-05-05 12:44:11 +02:00
if ( alpha < min_alpha ) {
2017-03-05 16:44:50 +01:00
min_alpha = alpha ;
2021-05-05 12:44:11 +02:00
}
if ( alpha > max_alpha ) {
2017-03-05 16:44:50 +01:00
max_alpha = alpha ;
2021-05-05 12:44:11 +02:00
}
2016-12-30 12:35:54 +01:00
//fill up alpha block
2017-03-05 16:44:50 +01:00
alpha_block [ ldw [ k . sources [ j ] ] . pos [ 0 ] % 4 ] [ ldw [ k . sources [ j ] ] . pos [ 1 ] % 4 ] = alpha ;
2016-12-30 12:35:54 +01:00
}
//use the first mode (8 adjustable levels)
2017-03-05 16:44:50 +01:00
k . alpha [ 0 ] = max_alpha ;
k . alpha [ 1 ] = min_alpha ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
uint64_t alpha_bits = 0 ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
if ( max_alpha ! = min_alpha ) {
int idx = 0 ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
for ( int y = 0 ; y < 4 ; y + + ) {
for ( int x = 0 ; x < 4 ; x + + ) {
2017-03-24 21:45:31 +01:00
//subtract minimum
2017-03-05 16:44:50 +01:00
uint32_t a = uint32_t ( alpha_block [ x ] [ y ] ) - min_alpha ;
2016-12-30 12:35:54 +01:00
//convert range to 3 bits
2017-03-05 16:44:50 +01:00
a = int ( ( a * 7.0 / ( max_alpha - min_alpha ) ) + 0.5 ) ;
2019-02-23 12:07:48 +01:00
a = MIN ( a , 7 ) ; //just to be sure
2017-03-05 16:44:50 +01:00
a = 7 - a ; //because range is inverted in this mode
if ( a = = 0 ) {
2016-12-30 12:35:54 +01:00
//do none, remain
2017-03-05 16:44:50 +01:00
} else if ( a = = 7 ) {
a = 1 ;
2016-12-30 12:35:54 +01:00
} else {
2017-03-05 16:44:50 +01:00
a = a + 1 ;
2016-12-30 12:35:54 +01:00
}
2017-03-05 16:44:50 +01:00
alpha_bits | = uint64_t ( a ) < < ( idx * 3 ) ;
2016-12-30 12:35:54 +01:00
idx + + ;
}
}
}
2017-03-05 16:44:50 +01:00
k . alpha [ 2 ] = ( alpha_bits > > 0 ) & 0xFF ;
k . alpha [ 3 ] = ( alpha_bits > > 8 ) & 0xFF ;
k . alpha [ 4 ] = ( alpha_bits > > 16 ) & 0xFF ;
k . alpha [ 5 ] = ( alpha_bits > > 24 ) & 0xFF ;
k . alpha [ 6 ] = ( alpha_bits > > 32 ) & 0xFF ;
k . alpha [ 7 ] = ( alpha_bits > > 40 ) & 0xFF ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
w [ block_idx + + ] = k ;
2016-12-30 12:35:54 +01:00
}
}
}
2016-12-20 04:21:07 +01:00
}
void VisualServerScene : : _gi_probe_bake_thread ( ) {
2017-03-05 16:44:50 +01:00
while ( true ) {
2021-01-27 13:41:10 +01:00
probe_bake_sem . wait ( ) ;
2016-12-20 04:21:07 +01:00
if ( probe_bake_thread_exit ) {
break ;
}
2021-05-04 16:00:45 +02:00
Instance * to_bake = nullptr ;
2016-12-20 04:21:07 +01:00
2021-01-27 10:43:02 +01:00
probe_bake_mutex . lock ( ) ;
2016-12-20 04:21:07 +01:00
if ( ! probe_bake_list . empty ( ) ) {
2017-03-05 16:44:50 +01:00
to_bake = probe_bake_list . front ( ) - > get ( ) ;
2016-12-20 04:21:07 +01:00
probe_bake_list . pop_front ( ) ;
}
2021-01-27 10:43:02 +01:00
probe_bake_mutex . unlock ( ) ;
2016-12-20 04:21:07 +01:00
2021-05-05 12:44:11 +02:00
if ( ! to_bake ) {
2016-12-20 04:21:07 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-12-20 04:21:07 +01:00
_bake_gi_probe ( to_bake ) ;
}
}
2017-03-05 16:44:50 +01:00
uint32_t VisualServerScene : : _gi_bake_find_cell ( const GIProbeDataCell * cells , int x , int y , int z , int p_cell_subdiv ) {
uint32_t cell = 0 ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
int ofs_x = 0 ;
int ofs_y = 0 ;
int ofs_z = 0 ;
int size = 1 < < ( p_cell_subdiv - 1 ) ;
int half = size / 2 ;
2016-12-20 04:21:07 +01:00
2021-05-05 12:44:11 +02:00
if ( x < 0 | | x > = size ) {
2016-12-20 04:21:07 +01:00
return - 1 ;
2021-05-05 12:44:11 +02:00
}
if ( y < 0 | | y > = size ) {
2016-12-20 04:21:07 +01:00
return - 1 ;
2021-05-05 12:44:11 +02:00
}
if ( z < 0 | | z > = size ) {
2016-12-20 04:21:07 +01:00
return - 1 ;
2021-05-05 12:44:11 +02:00
}
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_cell_subdiv - 1 ; i + + ) {
2016-12-20 04:21:07 +01:00
const GIProbeDataCell * bc = & cells [ cell ] ;
int child = 0 ;
if ( x > = ofs_x + half ) {
2017-03-05 16:44:50 +01:00
child | = 1 ;
ofs_x + = half ;
2016-12-20 04:21:07 +01:00
}
if ( y > = ofs_y + half ) {
2017-03-05 16:44:50 +01:00
child | = 2 ;
ofs_y + = half ;
2016-12-20 04:21:07 +01:00
}
if ( z > = ofs_z + half ) {
2017-03-05 16:44:50 +01:00
child | = 4 ;
ofs_z + = half ;
2016-12-20 04:21:07 +01:00
}
cell = bc - > children [ child ] ;
2021-05-05 12:44:11 +02:00
if ( cell = = 0xFFFFFFFF ) {
2016-12-20 04:21:07 +01:00
return 0xFFFFFFFF ;
2021-05-05 12:44:11 +02:00
}
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
half > > = 1 ;
2016-12-20 04:21:07 +01:00
}
return cell ;
}
2017-03-05 16:44:50 +01:00
static float _get_normal_advance ( const Vector3 & p_normal ) {
2016-12-22 14:00:15 +01:00
Vector3 normal = p_normal ;
Vector3 unorm = normal . abs ( ) ;
2017-03-05 16:44:50 +01:00
if ( ( unorm . x > = unorm . y ) & & ( unorm . x > = unorm . z ) ) {
// x code
unorm = normal . x > 0.0 ? Vector3 ( 1.0 , 0.0 , 0.0 ) : Vector3 ( - 1.0 , 0.0 , 0.0 ) ;
} else if ( ( unorm . y > unorm . x ) & & ( unorm . y > = unorm . z ) ) {
// y code
unorm = normal . y > 0.0 ? Vector3 ( 0.0 , 1.0 , 0.0 ) : Vector3 ( 0.0 , - 1.0 , 0.0 ) ;
} else if ( ( unorm . z > unorm . x ) & & ( unorm . z > unorm . y ) ) {
// z code
unorm = normal . z > 0.0 ? Vector3 ( 0.0 , 0.0 , 1.0 ) : Vector3 ( 0.0 , 0.0 , - 1.0 ) ;
2016-12-22 14:00:15 +01:00
} else {
2017-03-05 16:44:50 +01:00
// oh-no we messed up code
// has to be
unorm = Vector3 ( 1.0 , 0.0 , 0.0 ) ;
2016-12-22 14:00:15 +01:00
}
2017-03-05 16:44:50 +01:00
return 1.0 / normal . dot ( unorm ) ;
2016-12-22 14:00:15 +01:00
}
2017-08-11 21:10:05 +02:00
void VisualServerScene : : _bake_gi_probe_light ( const GIProbeDataHeader * header , const GIProbeDataCell * cells , InstanceGIProbeData : : LocalData * local_data , const uint32_t * leaves , int p_leaf_count , const InstanceGIProbeData : : LightCache & light_cache , int p_sign ) {
int light_r = int ( light_cache . color . r * light_cache . energy * 1024.0 ) * p_sign ;
int light_g = int ( light_cache . color . g * light_cache . energy * 1024.0 ) * p_sign ;
int light_b = int ( light_cache . color . b * light_cache . energy * 1024.0 ) * p_sign ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
float limits [ 3 ] = { float ( header - > width ) , float ( header - > height ) , float ( header - > depth ) } ;
2016-12-22 14:00:15 +01:00
Plane clip [ 3 ] ;
2017-03-05 16:44:50 +01:00
int clip_planes = 0 ;
2016-12-22 14:00:15 +01:00
2017-03-05 16:44:50 +01:00
switch ( light_cache . type ) {
2016-12-20 04:21:07 +01:00
case VS : : LIGHT_DIRECTIONAL : {
2017-03-05 16:44:50 +01:00
float max_len = Vector3 ( limits [ 0 ] , limits [ 1 ] , limits [ 2 ] ) . length ( ) * 1.1 ;
2016-12-20 04:21:07 +01:00
Vector3 light_axis = - light_cache . transform . basis . get_axis ( 2 ) . normalized ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 3 ; i + + ) {
2021-05-05 12:44:11 +02:00
if ( Math : : is_zero_approx ( light_axis [ i ] ) ) {
2016-12-20 04:21:07 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
clip [ clip_planes ] . normal [ i ] = 1.0 ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
if ( light_axis [ i ] < 0 ) {
clip [ clip_planes ] . d = limits [ i ] + 1 ;
2016-12-20 04:21:07 +01:00
} else {
2017-03-05 16:44:50 +01:00
clip [ clip_planes ] . d - = 1.0 ;
2016-12-20 04:21:07 +01:00
}
clip_planes + + ;
}
2016-12-22 14:00:15 +01:00
float distance_adv = _get_normal_advance ( light_axis ) ;
2016-12-20 04:21:07 +01:00
2017-08-11 21:10:05 +02:00
for ( int i = 0 ; i < p_leaf_count ; i + + ) {
2016-12-20 04:21:07 +01:00
uint32_t idx = leaves [ i ] ;
const GIProbeDataCell * cell = & cells [ idx ] ;
InstanceGIProbeData : : LocalData * light = & local_data [ idx ] ;
2017-03-05 16:44:50 +01:00
Vector3 to ( light - > pos [ 0 ] + 0.5 , light - > pos [ 1 ] + 0.5 , light - > pos [ 2 ] + 0.5 ) ;
2017-12-14 12:59:46 +01:00
to + = - light_axis . sign ( ) * 0.47 ; //make it more likely to receive a ray
2017-03-05 16:44:50 +01:00
Vector3 norm (
( ( ( cells [ idx ] . normal > > 16 ) & 0xFF ) / 255.0 ) * 2.0 - 1.0 ,
( ( ( cells [ idx ] . normal > > 8 ) & 0xFF ) / 255.0 ) * 2.0 - 1.0 ,
( ( ( cells [ idx ] . normal > > 0 ) & 0xFF ) / 255.0 ) * 2.0 - 1.0 ) ;
2016-12-20 04:21:07 +01:00
2016-12-22 14:00:15 +01:00
float att = norm . dot ( - light_axis ) ;
2017-03-05 16:44:50 +01:00
if ( att < 0.001 ) {
2016-12-22 14:00:15 +01:00
//not lighting towards this
continue ;
}
2016-12-20 04:21:07 +01:00
Vector3 from = to - max_len * light_axis ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < clip_planes ; j + + ) {
clip [ j ] . intersects_segment ( from , to , & from ) ;
2016-12-20 04:21:07 +01:00
}
float distance = ( to - from ) . length ( ) ;
2017-03-05 16:44:50 +01:00
distance + = distance_adv - Math : : fmod ( distance , distance_adv ) ; //make it reach the center of the box always
2016-12-20 04:21:07 +01:00
from = to - light_axis * distance ;
2017-03-05 16:44:50 +01:00
uint32_t result = 0xFFFFFFFF ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
while ( distance > - distance_adv ) { //use this to avoid precision errors
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
result = _gi_bake_find_cell ( cells , int ( floor ( from . x ) ) , int ( floor ( from . y ) ) , int ( floor ( from . z ) ) , header - > cell_subdiv ) ;
if ( result ! = 0xFFFFFFFF ) {
2016-12-20 04:21:07 +01:00
break ;
}
2017-03-05 16:44:50 +01:00
from + = light_axis * distance_adv ;
distance - = distance_adv ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
if ( result = = idx ) {
2016-12-20 04:21:07 +01:00
//cell hit itself! hooray!
2017-03-05 16:44:50 +01:00
light - > energy [ 0 ] + = int32_t ( light_r * att * ( ( cell - > albedo > > 16 ) & 0xFF ) / 255.0 ) ;
light - > energy [ 1 ] + = int32_t ( light_g * att * ( ( cell - > albedo > > 8 ) & 0xFF ) / 255.0 ) ;
light - > energy [ 2 ] + = int32_t ( light_b * att * ( ( cell - > albedo ) & 0xFF ) / 255.0 ) ;
2016-12-20 04:21:07 +01:00
}
}
2016-12-22 14:00:15 +01:00
} break ;
case VS : : LIGHT_OMNI :
case VS : : LIGHT_SPOT : {
Vector3 light_pos = light_cache . transform . origin ;
Vector3 spot_axis = - light_cache . transform . basis . get_axis ( 2 ) . normalized ( ) ;
float local_radius = light_cache . radius * light_cache . transform . basis . get_axis ( 2 ) . length ( ) ;
2017-08-11 21:10:05 +02:00
for ( int i = 0 ; i < p_leaf_count ; i + + ) {
2016-12-22 14:00:15 +01:00
uint32_t idx = leaves [ i ] ;
const GIProbeDataCell * cell = & cells [ idx ] ;
InstanceGIProbeData : : LocalData * light = & local_data [ idx ] ;
2017-03-05 16:44:50 +01:00
Vector3 to ( light - > pos [ 0 ] + 0.5 , light - > pos [ 1 ] + 0.5 , light - > pos [ 2 ] + 0.5 ) ;
2017-12-14 12:59:46 +01:00
to + = ( light_pos - to ) . sign ( ) * 0.47 ; //make it more likely to receive a ray
2017-03-05 16:44:50 +01:00
Vector3 norm (
( ( ( cells [ idx ] . normal > > 16 ) & 0xFF ) / 255.0 ) * 2.0 - 1.0 ,
( ( ( cells [ idx ] . normal > > 8 ) & 0xFF ) / 255.0 ) * 2.0 - 1.0 ,
( ( ( cells [ idx ] . normal > > 0 ) & 0xFF ) / 255.0 ) * 2.0 - 1.0 ) ;
2016-12-22 14:00:15 +01:00
Vector3 light_axis = ( to - light_pos ) . normalized ( ) ;
float distance_adv = _get_normal_advance ( light_axis ) ;
float att = norm . dot ( - light_axis ) ;
2017-03-05 16:44:50 +01:00
if ( att < 0.001 ) {
2016-12-22 14:00:15 +01:00
//not lighting towards this
continue ;
}
{
float d = light_pos . distance_to ( to ) ;
2021-05-05 12:44:11 +02:00
if ( d + distance_adv > local_radius ) {
2016-12-22 14:00:15 +01:00
continue ; // too far away
2021-05-05 12:44:11 +02:00
}
2016-12-22 14:00:15 +01:00
2017-03-05 16:44:50 +01:00
float dt = CLAMP ( ( d + distance_adv ) / local_radius , 0 , 1 ) ;
att * = powf ( 1.0 - dt , light_cache . attenuation ) ;
2016-12-22 14:00:15 +01:00
}
2017-03-05 16:44:50 +01:00
if ( light_cache . type = = VS : : LIGHT_SPOT ) {
2016-12-22 14:00:15 +01:00
float angle = Math : : rad2deg ( acos ( light_axis . dot ( spot_axis ) ) ) ;
2021-05-05 12:44:11 +02:00
if ( angle > light_cache . spot_angle ) {
2016-12-22 14:00:15 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-12-22 14:00:15 +01:00
2017-12-09 20:57:28 +01:00
float d = CLAMP ( angle / light_cache . spot_angle , 0 , 1 ) ;
2017-03-05 16:44:50 +01:00
att * = powf ( 1.0 - d , light_cache . spot_attenuation ) ;
2016-12-22 14:00:15 +01:00
}
2017-03-05 16:44:50 +01:00
clip_planes = 0 ;
2016-12-22 14:00:15 +01:00
2017-03-05 16:44:50 +01:00
for ( int c = 0 ; c < 3 ; c + + ) {
2021-05-05 12:44:11 +02:00
if ( Math : : is_zero_approx ( light_axis [ c ] ) ) {
2016-12-22 14:00:15 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
clip [ clip_planes ] . normal [ c ] = 1.0 ;
2016-12-22 14:00:15 +01:00
2017-03-05 16:44:50 +01:00
if ( light_axis [ c ] < 0 ) {
clip [ clip_planes ] . d = limits [ c ] + 1 ;
2016-12-22 14:00:15 +01:00
} else {
2017-03-05 16:44:50 +01:00
clip [ clip_planes ] . d - = 1.0 ;
2016-12-22 14:00:15 +01:00
}
clip_planes + + ;
}
Vector3 from = light_pos ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < clip_planes ; j + + ) {
clip [ j ] . intersects_segment ( from , to , & from ) ;
2016-12-22 14:00:15 +01:00
}
float distance = ( to - from ) . length ( ) ;
2017-03-05 16:44:50 +01:00
distance - = Math : : fmod ( distance , distance_adv ) ; //make it reach the center of the box always, but this tame make it closer
2016-12-22 14:00:15 +01:00
from = to - light_axis * distance ;
2017-03-05 16:44:50 +01:00
uint32_t result = 0xFFFFFFFF ;
2016-12-22 14:00:15 +01:00
2017-03-05 16:44:50 +01:00
while ( distance > - distance_adv ) { //use this to avoid precision errors
2016-12-22 14:00:15 +01:00
2017-03-05 16:44:50 +01:00
result = _gi_bake_find_cell ( cells , int ( floor ( from . x ) ) , int ( floor ( from . y ) ) , int ( floor ( from . z ) ) , header - > cell_subdiv ) ;
if ( result ! = 0xFFFFFFFF ) {
2016-12-22 14:00:15 +01:00
break ;
}
2017-03-05 16:44:50 +01:00
from + = light_axis * distance_adv ;
distance - = distance_adv ;
2016-12-22 14:00:15 +01:00
}
2017-03-05 16:44:50 +01:00
if ( result = = idx ) {
2016-12-22 14:00:15 +01:00
//cell hit itself! hooray!
2017-03-05 16:44:50 +01:00
light - > energy [ 0 ] + = int32_t ( light_r * att * ( ( cell - > albedo > > 16 ) & 0xFF ) / 255.0 ) ;
light - > energy [ 1 ] + = int32_t ( light_g * att * ( ( cell - > albedo > > 8 ) & 0xFF ) / 255.0 ) ;
light - > energy [ 2 ] + = int32_t ( light_b * att * ( ( cell - > albedo ) & 0xFF ) / 255.0 ) ;
2016-12-22 14:00:15 +01:00
}
}
2016-12-20 04:21:07 +01:00
} break ;
}
}
2017-03-05 16:44:50 +01:00
void VisualServerScene : : _bake_gi_downscale_light ( int p_idx , int p_level , const GIProbeDataCell * p_cells , const GIProbeDataHeader * p_header , InstanceGIProbeData : : LocalData * p_local_data , float p_propagate ) {
2016-12-20 04:21:07 +01:00
//average light to upper level
2017-03-05 16:44:50 +01:00
float divisor = 0 ;
float sum [ 3 ] = { 0.0 , 0.0 , 0.0 } ;
2017-01-02 18:09:42 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 8 ; i + + ) {
2016-12-20 04:21:07 +01:00
uint32_t child = p_cells [ p_idx ] . children [ i ] ;
2021-05-05 12:44:11 +02:00
if ( child = = 0xFFFFFFFF ) {
2016-12-20 04:21:07 +01:00
continue ;
2021-05-05 12:44:11 +02:00
}
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
if ( p_level + 1 < ( int ) p_header - > cell_subdiv - 1 ) {
_bake_gi_downscale_light ( child , p_level + 1 , p_cells , p_header , p_local_data , p_propagate ) ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
sum [ 0 ] + = p_local_data [ child ] . energy [ 0 ] ;
sum [ 1 ] + = p_local_data [ child ] . energy [ 1 ] ;
sum [ 2 ] + = p_local_data [ child ] . energy [ 2 ] ;
divisor + = 1.0 ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
divisor = Math : : lerp ( ( float ) 8.0 , divisor , p_propagate ) ;
sum [ 0 ] / = divisor ;
sum [ 1 ] / = divisor ;
sum [ 2 ] / = divisor ;
2017-02-06 09:12:15 +01:00
2016-12-20 04:21:07 +01:00
//divide by eight for average
2017-03-05 16:44:50 +01:00
p_local_data [ p_idx ] . energy [ 0 ] = Math : : fast_ftoi ( sum [ 0 ] ) ;
p_local_data [ p_idx ] . energy [ 1 ] = Math : : fast_ftoi ( sum [ 1 ] ) ;
p_local_data [ p_idx ] . energy [ 2 ] = Math : : fast_ftoi ( sum [ 2 ] ) ;
2016-12-20 04:21:07 +01:00
}
void VisualServerScene : : _bake_gi_probe ( Instance * p_gi_probe ) {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * probe_data = static_cast < InstanceGIProbeData * > ( p_gi_probe - > base_data ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
PoolVector < int > : : Read r = probe_data - > dynamic . light_data . read ( ) ;
2016-12-20 04:21:07 +01:00
const GIProbeDataHeader * header = ( const GIProbeDataHeader * ) r . ptr ( ) ;
2017-03-05 16:44:50 +01:00
const GIProbeDataCell * cells = ( const GIProbeDataCell * ) & r [ 16 ] ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
int leaf_count = probe_data - > dynamic . level_cell_lists [ header - > cell_subdiv - 1 ] . size ( ) ;
const uint32_t * leaves = probe_data - > dynamic . level_cell_lists [ header - > cell_subdiv - 1 ] . ptr ( ) ;
2016-12-20 04:21:07 +01:00
2017-01-07 22:25:37 +01:00
PoolVector < InstanceGIProbeData : : LocalData > : : Write ldw = probe_data - > dynamic . local_data . write ( ) ;
2016-12-20 04:21:07 +01:00
InstanceGIProbeData : : LocalData * local_data = ldw . ptr ( ) ;
//remove what must be removed
2017-03-05 16:44:50 +01:00
for ( Map < RID , InstanceGIProbeData : : LightCache > : : Element * E = probe_data - > dynamic . light_cache . front ( ) ; E ; E = E - > next ( ) ) {
2016-12-20 04:21:07 +01:00
RID rid = E - > key ( ) ;
2017-03-05 16:44:50 +01:00
const InstanceGIProbeData : : LightCache & lc = E - > get ( ) ;
2016-12-20 04:21:07 +01:00
2018-10-06 22:20:41 +02:00
if ( ( ! probe_data - > dynamic . light_cache_changes . has ( rid ) | | probe_data - > dynamic . light_cache_changes [ rid ] ! = lc ) & & lc . visible ) {
2016-12-20 04:21:07 +01:00
//erase light data
2017-03-05 16:44:50 +01:00
_bake_gi_probe_light ( header , cells , local_data , leaves , leaf_count , lc , - 1 ) ;
2016-12-20 04:21:07 +01:00
}
}
//add what must be added
2017-03-05 16:44:50 +01:00
for ( Map < RID , InstanceGIProbeData : : LightCache > : : Element * E = probe_data - > dynamic . light_cache_changes . front ( ) ; E ; E = E - > next ( ) ) {
2016-12-20 04:21:07 +01:00
RID rid = E - > key ( ) ;
2017-03-05 16:44:50 +01:00
const InstanceGIProbeData : : LightCache & lc = E - > get ( ) ;
2016-12-20 04:21:07 +01:00
2018-10-06 22:20:41 +02:00
if ( ( ! probe_data - > dynamic . light_cache . has ( rid ) | | probe_data - > dynamic . light_cache [ rid ] ! = lc ) & & lc . visible ) {
2016-12-20 04:21:07 +01:00
//add light data
2017-03-05 16:44:50 +01:00
_bake_gi_probe_light ( header , cells , local_data , leaves , leaf_count , lc , 1 ) ;
2016-12-20 04:21:07 +01:00
}
}
2017-03-05 16:44:50 +01:00
SWAP ( probe_data - > dynamic . light_cache_changes , probe_data - > dynamic . light_cache ) ;
2016-12-20 04:21:07 +01:00
//downscale to lower res levels
2017-03-05 16:44:50 +01:00
_bake_gi_downscale_light ( 0 , 0 , cells , header , local_data , probe_data - > dynamic . propagate ) ;
2016-12-20 04:21:07 +01:00
//plot result to 3D texture!
2017-03-05 16:44:50 +01:00
if ( probe_data - > dynamic . compression = = RasterizerStorage : : GI_PROBE_UNCOMPRESSED ) {
for ( int i = 0 ; i < ( int ) header - > cell_subdiv ; i + + ) {
int stage = header - > cell_subdiv - i - 1 ;
2016-12-30 12:35:54 +01:00
2021-05-05 12:44:11 +02:00
if ( stage > = probe_data - > dynamic . mipmaps_3d . size ( ) ) {
2016-12-30 12:35:54 +01:00
continue ; //no mipmap for this one
2021-05-05 12:44:11 +02:00
}
2016-12-30 12:35:54 +01:00
2017-07-29 05:03:54 +02:00
//print_line("generating mipmap stage: " + itos(stage));
2017-03-05 16:44:50 +01:00
int level_cell_count = probe_data - > dynamic . level_cell_lists [ i ] . size ( ) ;
const uint32_t * level_cells = probe_data - > dynamic . level_cell_lists [ i ] . ptr ( ) ;
2016-12-20 04:21:07 +01:00
2018-07-25 03:11:03 +02:00
PoolVector < uint8_t > : : Write lw = probe_data - > dynamic . mipmaps_3d . write [ stage ] . write ( ) ;
2016-12-30 12:35:54 +01:00
uint8_t * mipmapw = lw . ptr ( ) ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
uint32_t sizes [ 3 ] = { header - > width > > stage , header - > height > > stage , header - > depth > > stage } ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < level_cell_count ; j + + ) {
2016-12-30 12:35:54 +01:00
uint32_t idx = level_cells [ j ] ;
2016-12-20 04:21:07 +01:00
2019-02-12 21:10:08 +01:00
uint32_t r2 = ( uint32_t ( local_data [ idx ] . energy [ 0 ] ) / probe_data - > dynamic . bake_dynamic_range ) > > 2 ;
2017-03-05 16:44:50 +01:00
uint32_t g = ( uint32_t ( local_data [ idx ] . energy [ 1 ] ) / probe_data - > dynamic . bake_dynamic_range ) > > 2 ;
uint32_t b = ( uint32_t ( local_data [ idx ] . energy [ 2 ] ) / probe_data - > dynamic . bake_dynamic_range ) > > 2 ;
uint32_t a = ( cells [ idx ] . level_alpha > > 8 ) & 0xFF ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
uint32_t mm_ofs = sizes [ 0 ] * sizes [ 1 ] * ( local_data [ idx ] . pos [ 2 ] ) + sizes [ 0 ] * ( local_data [ idx ] . pos [ 1 ] ) + ( local_data [ idx ] . pos [ 0 ] ) ;
mm_ofs * = 4 ; //for RGBA (4 bytes)
2016-12-20 04:21:07 +01:00
2019-02-23 12:07:48 +01:00
mipmapw [ mm_ofs + 0 ] = uint8_t ( MIN ( r2 , 255 ) ) ;
mipmapw [ mm_ofs + 1 ] = uint8_t ( MIN ( g , 255 ) ) ;
mipmapw [ mm_ofs + 2 ] = uint8_t ( MIN ( b , 255 ) ) ;
mipmapw [ mm_ofs + 3 ] = uint8_t ( MIN ( a , 255 ) ) ;
2016-12-30 12:35:54 +01:00
}
}
2017-03-05 16:44:50 +01:00
} else if ( probe_data - > dynamic . compression = = RasterizerStorage : : GI_PROBE_S3TC ) {
2016-12-30 12:35:54 +01:00
int mipmap_count = probe_data - > dynamic . mipmaps_3d . size ( ) ;
2017-03-05 16:44:50 +01:00
for ( int mmi = 0 ; mmi < mipmap_count ; mmi + + ) {
2018-07-25 03:11:03 +02:00
PoolVector < uint8_t > : : Write mmw = probe_data - > dynamic . mipmaps_3d . write [ mmi ] . write ( ) ;
2016-12-30 12:35:54 +01:00
int block_count = probe_data - > dynamic . mipmaps_s3tc [ mmi ] . size ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < InstanceGIProbeData : : CompBlockS3TC > : : Read mmr = probe_data - > dynamic . mipmaps_s3tc [ mmi ] . read ( ) ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < block_count ; i + + ) {
const InstanceGIProbeData : : CompBlockS3TC & b = mmr [ i ] ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
uint8_t * blockptr = & mmw [ b . offset * 16 ] ;
2021-04-29 12:34:11 +02:00
memcpy ( blockptr , b . alpha , 8 ) ; //copy alpha part, which is precomputed
2016-12-30 12:35:54 +01:00
Vector3 colors [ 16 ] ;
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
2017-03-05 16:44:50 +01:00
colors [ j ] . x = ( local_data [ b . sources [ j ] ] . energy [ 0 ] / float ( probe_data - > dynamic . bake_dynamic_range ) ) / 1024.0 ;
colors [ j ] . y = ( local_data [ b . sources [ j ] ] . energy [ 1 ] / float ( probe_data - > dynamic . bake_dynamic_range ) ) / 1024.0 ;
colors [ j ] . z = ( local_data [ b . sources [ j ] ] . energy [ 2 ] / float ( probe_data - > dynamic . bake_dynamic_range ) ) / 1024.0 ;
2016-12-30 12:35:54 +01:00
}
//super quick and dirty compression
2017-03-24 21:45:31 +01:00
//find 2 most further apart
2017-03-05 16:44:50 +01:00
float distance = 0 ;
Vector3 from , to ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
if ( b . source_count = = 16 ) {
2016-12-30 12:35:54 +01:00
//all cells are used so, find minmax between them
2017-03-05 16:44:50 +01:00
int further_apart [ 2 ] = { 0 , 0 } ;
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
for ( uint32_t k = j + 1 ; k < b . source_count ; k + + ) {
2016-12-30 12:35:54 +01:00
float d = colors [ j ] . distance_squared_to ( colors [ k ] ) ;
2017-03-05 16:44:50 +01:00
if ( d > distance ) {
distance = d ;
further_apart [ 0 ] = j ;
further_apart [ 1 ] = k ;
2016-12-30 12:35:54 +01:00
}
}
}
from = colors [ further_apart [ 0 ] ] ;
to = colors [ further_apart [ 1 ] ] ;
} else {
//if a block is missing, the priority is that this block remains black,
//otherwise the geometry will appear deformed
//correct shape wins over correct color in this case
//average all colors first
Vector3 average ;
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
2017-03-05 16:44:50 +01:00
average + = colors [ j ] ;
2016-12-30 12:35:54 +01:00
}
average . normalize ( ) ;
//find max distance in normal from average
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
2016-12-30 12:35:54 +01:00
float d = average . dot ( colors [ j ] ) ;
2017-03-05 16:44:50 +01:00
distance = MAX ( d , distance ) ;
2016-12-30 12:35:54 +01:00
}
from = Vector3 ( ) ; //from black
to = average * distance ;
//find max distance
}
int indices [ 16 ] ;
2017-03-05 16:44:50 +01:00
uint16_t color_0 = 0 ;
color_0 = CLAMP ( int ( from . x * 31 ) , 0 , 31 ) < < 11 ;
color_0 | = CLAMP ( int ( from . y * 63 ) , 0 , 63 ) < < 5 ;
color_0 | = CLAMP ( int ( from . z * 31 ) , 0 , 31 ) ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
uint16_t color_1 = 0 ;
color_1 = CLAMP ( int ( to . x * 31 ) , 0 , 31 ) < < 11 ;
color_1 | = CLAMP ( int ( to . y * 63 ) , 0 , 63 ) < < 5 ;
color_1 | = CLAMP ( int ( to . z * 31 ) , 0 , 31 ) ;
2016-12-30 12:35:54 +01:00
2016-12-31 14:53:29 +01:00
if ( color_1 > color_0 ) {
2017-03-05 16:44:50 +01:00
SWAP ( color_1 , color_0 ) ;
SWAP ( from , to ) ;
2016-12-31 14:53:29 +01:00
}
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
if ( distance > 0 ) {
Vector3 dir = ( to - from ) . normalized ( ) ;
2016-12-30 12:35:54 +01:00
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
2017-03-05 16:44:50 +01:00
float d = ( colors [ j ] - from ) . dot ( dir ) / distance ;
indices [ j ] = int ( d * 3 + 0.5 ) ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
static const int index_swap [ 4 ] = { 0 , 3 , 1 , 2 } ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
indices [ j ] = index_swap [ CLAMP ( indices [ j ] , 0 , 3 ) ] ;
2016-12-30 12:35:54 +01:00
}
} else {
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
2017-03-05 16:44:50 +01:00
indices [ j ] = 0 ;
2016-12-30 12:35:54 +01:00
}
}
2017-03-24 21:45:31 +01:00
//by default, 1 is black, otherwise it will be overridden by source
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
uint32_t index_block [ 16 ] = { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 } ;
2016-12-30 12:35:54 +01:00
2017-08-31 23:30:35 +02:00
for ( uint32_t j = 0 ; j < b . source_count ; j + + ) {
2017-03-05 16:44:50 +01:00
int x = local_data [ b . sources [ j ] ] . pos [ 0 ] % 4 ;
int y = local_data [ b . sources [ j ] ] . pos [ 1 ] % 4 ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
index_block [ y * 4 + x ] = indices [ j ] ;
2016-12-30 12:35:54 +01:00
}
2017-03-05 16:44:50 +01:00
uint32_t encode = 0 ;
2016-12-30 12:35:54 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < 16 ; j + + ) {
encode | = index_block [ j ] < < ( j * 2 ) ;
2016-12-30 12:35:54 +01:00
}
2017-03-05 16:44:50 +01:00
blockptr [ 8 ] = color_0 & 0xFF ;
blockptr [ 9 ] = ( color_0 > > 8 ) & 0xFF ;
blockptr [ 10 ] = color_1 & 0xFF ;
blockptr [ 11 ] = ( color_1 > > 8 ) & 0xFF ;
blockptr [ 12 ] = encode & 0xFF ;
blockptr [ 13 ] = ( encode > > 8 ) & 0xFF ;
blockptr [ 14 ] = ( encode > > 16 ) & 0xFF ;
blockptr [ 15 ] = ( encode > > 24 ) & 0xFF ;
2016-12-30 12:35:54 +01:00
}
2016-12-20 04:21:07 +01:00
}
}
//send back to main thread to update un little chunks
2021-01-27 10:43:02 +01:00
probe_bake_mutex . lock ( ) ;
2017-03-05 16:44:50 +01:00
probe_data - > dynamic . updating_stage = GI_UPDATE_STAGE_UPLOADING ;
2021-01-27 10:43:02 +01:00
probe_bake_mutex . unlock ( ) ;
2016-12-20 04:21:07 +01:00
}
bool VisualServerScene : : _check_gi_probe ( Instance * p_gi_probe ) {
2017-03-05 16:44:50 +01:00
InstanceGIProbeData * probe_data = static_cast < InstanceGIProbeData * > ( p_gi_probe - > base_data ) ;
2016-12-20 04:21:07 +01:00
probe_data - > dynamic . light_cache_changes . clear ( ) ;
2017-03-05 16:44:50 +01:00
bool all_equal = true ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = p_gi_probe - > scenario - > directional_lights . front ( ) ; E ; E = E - > next ( ) ) {
2021-05-05 12:44:11 +02:00
if ( VSG : : storage - > light_get_bake_mode ( E - > get ( ) - > base ) = = VS : : LightBakeMode : : LIGHT_BAKE_DISABLED ) {
2019-04-23 11:36:36 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2019-04-23 11:36:36 +02:00
2016-12-20 04:21:07 +01:00
InstanceGIProbeData : : LightCache lc ;
2017-03-05 16:44:50 +01:00
lc . type = VSG : : storage - > light_get_type ( E - > get ( ) - > base ) ;
lc . color = VSG : : storage - > light_get_color ( E - > get ( ) - > base ) ;
2017-11-20 01:45:42 +01:00
lc . energy = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_ENERGY ) * VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_INDIRECT_ENERGY ) ;
2017-03-05 16:44:50 +01:00
lc . radius = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_RANGE ) ;
lc . attenuation = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_ATTENUATION ) ;
lc . spot_angle = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_SPOT_ANGLE ) ;
lc . spot_attenuation = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_SPOT_ATTENUATION ) ;
2016-12-20 04:21:07 +01:00
lc . transform = probe_data - > dynamic . light_to_cell_xform * E - > get ( ) - > transform ;
2017-10-04 10:55:57 +02:00
lc . visible = E - > get ( ) - > visible ;
2016-12-20 04:21:07 +01:00
2018-10-06 22:20:41 +02:00
if ( ! probe_data - > dynamic . light_cache . has ( E - > get ( ) - > self ) | | probe_data - > dynamic . light_cache [ E - > get ( ) - > self ] ! = lc ) {
2017-03-05 16:44:50 +01:00
all_equal = false ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
probe_data - > dynamic . light_cache_changes [ E - > get ( ) - > self ] = lc ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
for ( Set < Instance * > : : Element * E = probe_data - > lights . front ( ) ; E ; E = E - > next ( ) ) {
2021-05-05 12:44:11 +02:00
if ( VSG : : storage - > light_get_bake_mode ( E - > get ( ) - > base ) = = VS : : LightBakeMode : : LIGHT_BAKE_DISABLED ) {
2019-04-23 11:36:36 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2019-04-23 11:36:36 +02:00
2016-12-20 04:21:07 +01:00
InstanceGIProbeData : : LightCache lc ;
2017-03-05 16:44:50 +01:00
lc . type = VSG : : storage - > light_get_type ( E - > get ( ) - > base ) ;
lc . color = VSG : : storage - > light_get_color ( E - > get ( ) - > base ) ;
2017-11-20 01:45:42 +01:00
lc . energy = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_ENERGY ) * VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_INDIRECT_ENERGY ) ;
2017-03-05 16:44:50 +01:00
lc . radius = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_RANGE ) ;
lc . attenuation = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_ATTENUATION ) ;
lc . spot_angle = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_SPOT_ANGLE ) ;
lc . spot_attenuation = VSG : : storage - > light_get_param ( E - > get ( ) - > base , VS : : LIGHT_PARAM_SPOT_ATTENUATION ) ;
2016-12-20 04:21:07 +01:00
lc . transform = probe_data - > dynamic . light_to_cell_xform * E - > get ( ) - > transform ;
2017-10-04 10:55:57 +02:00
lc . visible = E - > get ( ) - > visible ;
2016-12-20 04:21:07 +01:00
2018-10-06 22:20:41 +02:00
if ( ! probe_data - > dynamic . light_cache . has ( E - > get ( ) - > self ) | | probe_data - > dynamic . light_cache [ E - > get ( ) - > self ] ! = lc ) {
2017-03-05 16:44:50 +01:00
all_equal = false ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
probe_data - > dynamic . light_cache_changes [ E - > get ( ) - > self ] = lc ;
2016-12-20 04:21:07 +01:00
}
//lighting changed from after to before, must do some updating
2017-03-05 16:44:50 +01:00
return ! all_equal | | probe_data - > dynamic . light_cache_changes . size ( ) ! = probe_data - > dynamic . light_cache . size ( ) ;
2016-12-20 04:21:07 +01:00
}
2016-10-31 12:47:46 +01:00
2016-11-19 17:23:37 +01:00
void VisualServerScene : : render_probes ( ) {
2016-12-20 04:21:07 +01:00
/* REFLECTION PROBES */
2016-10-19 16:14:41 +02:00
2016-12-20 04:21:07 +01:00
SelfList < InstanceReflectionProbeData > * ref_probe = reflection_probe_render_list . first ( ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
bool busy = false ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
while ( ref_probe ) {
SelfList < InstanceReflectionProbeData > * next = ref_probe - > next ( ) ;
2016-12-20 04:21:07 +01:00
RID base = ref_probe - > self ( ) - > owner - > base ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
switch ( VSG : : storage - > reflection_probe_get_update_mode ( base ) ) {
2016-11-19 17:23:37 +01:00
case VS : : REFLECTION_PROBE_UPDATE_ONCE : {
2021-05-05 12:44:11 +02:00
if ( busy ) { //already rendering something
2016-11-19 17:23:37 +01:00
break ;
2021-05-05 12:44:11 +02:00
}
2016-11-19 17:23:37 +01:00
2017-03-05 16:44:50 +01:00
bool done = _render_reflection_probe_step ( ref_probe - > self ( ) - > owner , ref_probe - > self ( ) - > render_step ) ;
2016-11-19 17:23:37 +01:00
if ( done ) {
2016-12-20 04:21:07 +01:00
reflection_probe_render_list . remove ( ref_probe ) ;
2016-11-19 17:23:37 +01:00
} else {
2016-12-20 04:21:07 +01:00
ref_probe - > self ( ) - > render_step + + ;
2016-11-19 17:23:37 +01:00
}
2017-03-05 16:44:50 +01:00
busy = true ; //do not render another one of this kind
2016-11-19 17:23:37 +01:00
} break ;
case VS : : REFLECTION_PROBE_UPDATE_ALWAYS : {
2017-03-05 16:44:50 +01:00
int step = 0 ;
bool done = false ;
while ( ! done ) {
done = _render_reflection_probe_step ( ref_probe - > self ( ) - > owner , step ) ;
2016-11-19 17:23:37 +01:00
step + + ;
}
2016-12-20 04:21:07 +01:00
reflection_probe_render_list . remove ( ref_probe ) ;
2016-11-19 17:23:37 +01:00
} break ;
}
2017-03-05 16:44:50 +01:00
ref_probe = next ;
2016-11-19 17:23:37 +01:00
}
2016-12-20 04:21:07 +01:00
/* GI PROBES */
SelfList < InstanceGIProbeData > * gi_probe = gi_probe_update_list . first ( ) ;
2017-03-05 16:44:50 +01:00
while ( gi_probe ) {
SelfList < InstanceGIProbeData > * next = gi_probe - > next ( ) ;
2016-12-20 04:21:07 +01:00
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
2017-03-05 16:44:50 +01:00
bool force_lighting = false ;
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
if ( probe - > invalid | | ( probe - > dynamic . updating_stage = = GI_UPDATE_STAGE_CHECK & & probe - > base_version ! = VSG : : storage - > gi_probe_get_version ( instance_probe - > base ) ) ) {
2016-12-20 04:21:07 +01:00
_setup_gi_probe ( instance_probe ) ;
2017-03-05 16:44:50 +01:00
force_lighting = true ;
2016-12-20 04:21:07 +01:00
}
2017-02-06 09:12:15 +01:00
float propagate = VSG : : storage - > gi_probe_get_propagation ( instance_probe - > base ) ;
2017-03-05 16:44:50 +01:00
if ( probe - > dynamic . propagate ! = propagate ) {
probe - > dynamic . propagate = propagate ;
force_lighting = true ;
2017-02-06 09:12:15 +01:00
}
2018-10-06 22:20:41 +02:00
if ( ! probe - > invalid & & probe - > dynamic . enabled ) {
2017-03-05 16:44:50 +01:00
switch ( probe - > dynamic . updating_stage ) {
2016-12-20 04:21:07 +01:00
case GI_UPDATE_STAGE_CHECK : {
2017-12-06 21:36:34 +01:00
if ( _check_gi_probe ( instance_probe ) | | force_lighting ) { //send to lighting thread
2016-12-20 04:21:07 +01:00
# ifndef NO_THREADS
2021-01-27 10:43:02 +01:00
probe_bake_mutex . lock ( ) ;
2017-12-06 22:06:34 +01:00
probe - > dynamic . updating_stage = GI_UPDATE_STAGE_LIGHTING ;
2016-12-20 04:21:07 +01:00
probe_bake_list . push_back ( instance_probe ) ;
2021-01-27 10:43:02 +01:00
probe_bake_mutex . unlock ( ) ;
2021-01-27 13:41:10 +01:00
probe_bake_sem . post ( ) ;
2016-12-20 04:21:07 +01:00
# else
_bake_gi_probe ( instance_probe ) ;
# endif
}
} break ;
case GI_UPDATE_STAGE_LIGHTING : {
//do none, wait til done!
} break ;
case GI_UPDATE_STAGE_UPLOADING : {
2018-08-24 09:35:07 +02:00
//uint64_t us = OS::get_singleton()->get_ticks_usec();
2016-12-20 04:21:07 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ( int ) probe - > dynamic . mipmaps_3d . size ( ) ; i + + ) {
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > : : Read r = probe - > dynamic . mipmaps_3d [ i ] . read ( ) ;
2017-03-05 16:44:50 +01:00
VSG : : storage - > gi_probe_dynamic_data_update ( probe - > dynamic . probe_data , 0 , probe - > dynamic . grid_size [ 2 ] > > i , i , r . ptr ( ) ) ;
2016-12-20 04:21:07 +01:00
}
2017-03-05 16:44:50 +01:00
probe - > dynamic . updating_stage = GI_UPDATE_STAGE_CHECK ;
2016-12-20 04:21:07 +01:00
2018-08-24 09:35:07 +02:00
//print_line("UPLOAD TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
2016-12-20 04:21:07 +01:00
} break ;
}
}
//_update_gi_probe(gi_probe->self()->owner);
2017-03-05 16:44:50 +01:00
gi_probe = next ;
2016-12-20 04:21:07 +01:00
}
2016-11-19 17:23:37 +01:00
}
void VisualServerScene : : _update_dirty_instance ( Instance * p_instance ) {
2017-08-18 20:11:16 +02:00
if ( p_instance - > update_aabb ) {
2016-10-19 16:14:41 +02:00
_update_instance_aabb ( p_instance ) ;
2017-08-18 20:11:16 +02:00
}
2016-10-19 16:14:41 +02:00
if ( p_instance - > update_materials ) {
2017-03-05 16:44:50 +01:00
if ( p_instance - > base_type = = VS : : INSTANCE_MESH ) {
2016-11-10 03:55:06 +01:00
//remove materials no longer used and un-own them
int new_mat_count = VSG : : storage - > mesh_get_surface_count ( p_instance - > base ) ;
2017-03-05 16:44:50 +01:00
for ( int i = p_instance - > materials . size ( ) - 1 ; i > = new_mat_count ; i - - ) {
2016-11-10 03:55:06 +01:00
if ( p_instance - > materials [ i ] . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
VSG : : storage - > material_remove_instance_owner ( p_instance - > materials [ i ] , p_instance ) ;
2016-11-10 03:55:06 +01:00
}
}
p_instance - > materials . resize ( new_mat_count ) ;
2016-11-25 00:46:55 +01:00
2017-01-12 12:34:00 +01:00
int new_blend_shape_count = VSG : : storage - > mesh_get_blend_shape_count ( p_instance - > base ) ;
2017-03-05 16:44:50 +01:00
if ( new_blend_shape_count ! = p_instance - > blend_values . size ( ) ) {
2017-01-12 12:34:00 +01:00
p_instance - > blend_values . resize ( new_blend_shape_count ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < new_blend_shape_count ; i + + ) {
2021-05-13 16:16:17 +02:00
p_instance - > blend_values . write ( ) . ptr ( ) [ i ] = 0 ;
2016-11-25 00:46:55 +01:00
}
}
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
if ( ( 1 < < p_instance - > base_type ) & VS : : INSTANCE_GEOMETRY_MASK ) {
InstanceGeometryData * geom = static_cast < InstanceGeometryData * > ( p_instance - > base_data ) ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
bool can_cast_shadows = true ;
2018-11-14 13:32:39 +01:00
bool is_animated = false ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
if ( p_instance - > cast_shadows = = VS : : SHADOW_CASTING_SETTING_OFF ) {
can_cast_shadows = false ;
2016-11-10 03:55:06 +01:00
} else if ( p_instance - > material_override . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
can_cast_shadows = VSG : : storage - > material_casts_shadows ( p_instance - > material_override ) ;
2018-11-14 13:32:39 +01:00
is_animated = VSG : : storage - > material_is_animated ( p_instance - > material_override ) ;
2016-11-10 03:55:06 +01:00
} else {
2017-03-05 16:44:50 +01:00
if ( p_instance - > base_type = = VS : : INSTANCE_MESH ) {
RID mesh = p_instance - > base ;
2016-11-10 03:55:06 +01:00
2016-11-22 05:26:56 +01:00
if ( mesh . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
bool cast_shadows = false ;
2016-11-10 03:55:06 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_instance - > materials . size ( ) ; i + + ) {
RID mat = p_instance - > materials [ i ] . is_valid ( ) ? p_instance - > materials [ i ] : VSG : : storage - > mesh_surface_get_material ( mesh , i ) ;
2016-11-10 03:55:06 +01:00
2016-11-22 05:26:56 +01:00
if ( ! mat . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
cast_shadows = true ;
2018-11-14 13:32:39 +01:00
} else {
if ( VSG : : storage - > material_casts_shadows ( mat ) ) {
cast_shadows = true ;
}
if ( VSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
2016-11-22 05:26:56 +01:00
}
2016-11-10 03:55:06 +01:00
}
2016-11-22 05:26:56 +01:00
if ( ! cast_shadows ) {
2017-03-05 16:44:50 +01:00
can_cast_shadows = false ;
2016-11-10 03:55:06 +01:00
}
}
2017-03-05 16:44:50 +01:00
} else if ( p_instance - > base_type = = VS : : INSTANCE_MULTIMESH ) {
2016-11-22 05:26:56 +01:00
RID mesh = VSG : : storage - > multimesh_get_mesh ( p_instance - > base ) ;
if ( mesh . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
bool cast_shadows = false ;
2016-11-22 05:26:56 +01:00
int sc = VSG : : storage - > mesh_get_surface_count ( mesh ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < sc ; i + + ) {
RID mat = VSG : : storage - > mesh_surface_get_material ( mesh , i ) ;
2016-11-22 05:26:56 +01:00
if ( ! mat . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
cast_shadows = true ;
2016-11-22 05:26:56 +01:00
2018-11-14 13:32:39 +01:00
} else {
if ( VSG : : storage - > material_casts_shadows ( mat ) ) {
cast_shadows = true ;
}
if ( VSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
2016-11-22 05:26:56 +01:00
}
}
if ( ! cast_shadows ) {
2017-03-05 16:44:50 +01:00
can_cast_shadows = false ;
2016-11-22 05:26:56 +01:00
}
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
} else if ( p_instance - > base_type = = VS : : INSTANCE_IMMEDIATE ) {
2016-11-23 11:04:55 +01:00
RID mat = VSG : : storage - > immediate_get_material ( p_instance - > base ) ;
2019-06-26 15:08:25 +02:00
can_cast_shadows = ! mat . is_valid ( ) | | VSG : : storage - > material_casts_shadows ( mat ) ;
2018-11-14 13:32:39 +01:00
if ( mat . is_valid ( ) & & VSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
2017-06-17 12:32:49 +02:00
} else if ( p_instance - > base_type = = VS : : INSTANCE_PARTICLES ) {
bool cast_shadows = false ;
int dp = VSG : : storage - > particles_get_draw_passes ( p_instance - > base ) ;
for ( int i = 0 ; i < dp ; i + + ) {
RID mesh = VSG : : storage - > particles_get_draw_pass_mesh ( p_instance - > base , i ) ;
2021-05-05 12:44:11 +02:00
if ( ! mesh . is_valid ( ) ) {
2017-07-15 06:23:10 +02:00
continue ;
2021-05-05 12:44:11 +02:00
}
2017-06-17 12:32:49 +02:00
int sc = VSG : : storage - > mesh_get_surface_count ( mesh ) ;
for ( int j = 0 ; j < sc ; j + + ) {
RID mat = VSG : : storage - > mesh_surface_get_material ( mesh , j ) ;
if ( ! mat . is_valid ( ) ) {
cast_shadows = true ;
2018-11-14 13:32:39 +01:00
} else {
if ( VSG : : storage - > material_casts_shadows ( mat ) ) {
cast_shadows = true ;
}
if ( VSG : : storage - > material_is_animated ( mat ) ) {
is_animated = true ;
}
2017-06-17 12:32:49 +02:00
}
}
}
if ( ! cast_shadows ) {
can_cast_shadows = false ;
}
2016-11-10 03:55:06 +01:00
}
}
2021-07-24 22:45:51 +02:00
if ( p_instance - > material_overlay . is_valid ( ) ) {
can_cast_shadows = can_cast_shadows | | VSG : : storage - > material_casts_shadows ( p_instance - > material_overlay ) ;
is_animated = is_animated | | VSG : : storage - > material_is_animated ( p_instance - > material_overlay ) ;
}
2017-03-05 16:44:50 +01:00
if ( can_cast_shadows ! = geom - > can_cast_shadows ) {
2016-11-10 03:55:06 +01:00
//ability to cast shadows change, let lights now
2017-03-05 16:44:50 +01:00
for ( List < Instance * > : : Element * E = geom - > lighting . front ( ) ; E ; E = E - > next ( ) ) {
InstanceLightData * light = static_cast < InstanceLightData * > ( E - > get ( ) - > base_data ) ;
2019-11-02 21:00:24 +01:00
light - > make_shadow_dirty ( ) ;
2016-11-10 03:55:06 +01:00
}
2017-03-05 16:44:50 +01:00
geom - > can_cast_shadows = can_cast_shadows ;
2016-11-10 03:55:06 +01:00
}
2018-11-14 13:32:39 +01:00
geom - > material_is_animated = is_animated ;
2016-10-19 16:14:41 +02:00
}
}
2017-12-14 12:59:46 +01:00
_instance_update_list . remove ( & p_instance - > update_item ) ;
2016-10-19 16:14:41 +02:00
_update_instance ( p_instance ) ;
2017-03-05 16:44:50 +01:00
p_instance - > update_aabb = false ;
p_instance - > update_materials = false ;
2016-10-19 16:14:41 +02:00
}
void VisualServerScene : : update_dirty_instances ( ) {
2017-02-16 12:55:11 +01:00
VSG : : storage - > update_dirty_resources ( ) ;
2020-10-21 14:13:20 +02:00
// this is just to get access to scenario so we can update the spatial partitioning scheme
Scenario * scenario = nullptr ;
if ( _instance_update_list . first ( ) ) {
scenario = _instance_update_list . first ( ) - > self ( ) - > scenario ;
}
2017-03-05 16:44:50 +01:00
while ( _instance_update_list . first ( ) ) {
_update_dirty_instance ( _instance_update_list . first ( ) - > self ( ) ) ;
2016-10-19 16:14:41 +02:00
}
2020-10-21 14:13:20 +02:00
if ( scenario ) {
2021-01-20 20:15:07 +01:00
scenario - > sps - > update ( ) ;
2020-10-21 14:13:20 +02:00
}
2016-10-19 16:14:41 +02:00
}
bool VisualServerScene : : free ( RID p_rid ) {
if ( camera_owner . owns ( p_rid ) ) {
2017-03-05 16:44:50 +01:00
Camera * camera = camera_owner . get ( p_rid ) ;
2016-10-19 16:14:41 +02:00
camera_owner . free ( p_rid ) ;
memdelete ( camera ) ;
} else if ( scenario_owner . owns ( p_rid ) ) {
2017-03-05 16:44:50 +01:00
Scenario * scenario = scenario_owner . get ( p_rid ) ;
2016-10-19 16:14:41 +02:00
2017-03-05 16:44:50 +01:00
while ( scenario - > instances . first ( ) ) {
instance_set_scenario ( scenario - > instances . first ( ) - > self ( ) - > self , RID ( ) ) ;
2016-10-19 16:14:41 +02:00
}
2016-11-19 17:23:37 +01:00
VSG : : scene_render - > free ( scenario - > reflection_probe_shadow_atlas ) ;
VSG : : scene_render - > free ( scenario - > reflection_atlas ) ;
2016-10-19 16:14:41 +02:00
scenario_owner . free ( p_rid ) ;
memdelete ( scenario ) ;
} else if ( instance_owner . owns ( p_rid ) ) {
// delete the instance
update_dirty_instances ( ) ;
Instance * instance = instance_owner . get ( p_rid ) ;
2022-04-04 16:18:44 +02:00
_interpolation_data . notify_free_instance ( p_rid , * instance ) ;
2021-09-15 13:30:45 +02:00
2020-12-19 18:17:22 +01:00
instance_set_use_lightmap ( p_rid , RID ( ) , RID ( ) , - 1 , Rect2 ( 0 , 0 , 1 , 1 ) ) ;
2017-03-05 16:44:50 +01:00
instance_set_scenario ( p_rid , RID ( ) ) ;
instance_set_base ( p_rid , RID ( ) ) ;
instance_geometry_set_material_override ( p_rid , RID ( ) ) ;
2021-07-24 22:45:51 +02:00
instance_geometry_set_material_overlay ( p_rid , RID ( ) ) ;
2017-03-05 16:44:50 +01:00
instance_attach_skeleton ( p_rid , RID ( ) ) ;
2016-10-19 16:14:41 +02:00
2016-11-22 05:26:56 +01:00
update_dirty_instances ( ) ; //in case something changed this
2016-10-19 16:14:41 +02:00
instance_owner . free ( p_rid ) ;
memdelete ( instance ) ;
2021-09-15 13:30:45 +02:00
2021-02-04 11:43:08 +01:00
} else if ( room_owner . owns ( p_rid ) ) {
Room * room = room_owner . get ( p_rid ) ;
room_owner . free ( p_rid ) ;
memdelete ( room ) ;
} else if ( portal_owner . owns ( p_rid ) ) {
Portal * portal = portal_owner . get ( p_rid ) ;
portal_owner . free ( p_rid ) ;
memdelete ( portal ) ;
} else if ( ghost_owner . owns ( p_rid ) ) {
Ghost * ghost = ghost_owner . get ( p_rid ) ;
ghost_owner . free ( p_rid ) ;
memdelete ( ghost ) ;
} else if ( roomgroup_owner . owns ( p_rid ) ) {
RoomGroup * roomgroup = roomgroup_owner . get ( p_rid ) ;
roomgroup_owner . free ( p_rid ) ;
memdelete ( roomgroup ) ;
2022-02-11 15:36:02 +01:00
} else if ( occluder_instance_owner . owns ( p_rid ) ) {
OccluderInstance * occ_inst = occluder_instance_owner . get ( p_rid ) ;
occluder_instance_owner . free ( p_rid ) ;
memdelete ( occ_inst ) ;
} else if ( occluder_resource_owner . owns ( p_rid ) ) {
OccluderResource * occ_res = occluder_resource_owner . get ( p_rid ) ;
occ_res - > destroy ( _portal_resources ) ;
occluder_resource_owner . free ( p_rid ) ;
memdelete ( occ_res ) ;
2016-10-19 16:14:41 +02:00
} else {
return false ;
}
return true ;
}
2021-05-04 16:00:45 +02:00
VisualServerScene * VisualServerScene : : singleton = nullptr ;
2016-12-20 04:21:07 +01:00
2016-10-19 16:14:41 +02:00
VisualServerScene : : VisualServerScene ( ) {
2021-01-27 20:10:10 +01:00
probe_bake_thread . start ( _gi_probe_bake_threads , this ) ;
2017-03-05 16:44:50 +01:00
probe_bake_thread_exit = false ;
2016-12-20 04:21:07 +01:00
2019-11-02 21:00:24 +01:00
light_culler = memnew ( VisualServerLightCuller ) ;
2017-03-05 16:44:50 +01:00
render_pass = 1 ;
singleton = this ;
2021-01-19 12:18:55 +01:00
_use_bvh = GLOBAL_DEF ( " rendering/quality/spatial_partitioning/use_bvh " , true ) ;
2021-11-18 15:32:33 +01:00
GLOBAL_DEF ( " rendering/quality/spatial_partitioning/bvh_collision_margin " , 0.1 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " rendering/quality/spatial_partitioning/bvh_collision_margin " , PropertyInfo ( Variant : : REAL , " rendering/quality/spatial_partitioning/bvh_collision_margin " , PROPERTY_HINT_RANGE , " 0.0,2.0,0.01 " ) ) ;
2019-11-02 21:00:24 +01:00
light_culler - > set_caster_culling_active ( GLOBAL_DEF ( " rendering/quality/shadows/caster_culling " , true ) ) ;
light_culler - > set_light_culling_active ( GLOBAL_DEF ( " rendering/quality/shadows/light_culling " , true ) ) ;
2021-02-04 11:43:08 +01:00
_visual_server_callbacks = nullptr ;
2016-10-19 16:14:41 +02:00
}
2016-12-20 04:21:07 +01:00
VisualServerScene : : ~ VisualServerScene ( ) {
2017-03-05 16:44:50 +01:00
probe_bake_thread_exit = true ;
2021-01-27 13:41:10 +01:00
probe_bake_sem . post ( ) ;
2021-01-27 20:10:10 +01:00
probe_bake_thread . wait_to_finish ( ) ;
2019-11-02 21:00:24 +01:00
if ( light_culler ) {
memdelete ( light_culler ) ;
light_culler = nullptr ;
}
2016-12-20 04:21:07 +01:00
}