2022-04-09 19:34:31 +10:00
/**************************************************************************/
/* light_storage.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. */
/**************************************************************************/
# ifdef GLES3_ENABLED
# include "light_storage.h"
2023-05-25 20:04:00 -07:00
# include "../rasterizer_gles3.h"
# include "../rasterizer_scene_gles3.h"
2023-10-11 22:02:38 +11:00
# include "core/config/project_settings.h"
2022-04-28 12:01:23 -07:00
# include "texture_storage.h"
2022-04-09 19:34:31 +10:00
using namespace GLES3 ;
LightStorage * LightStorage : : singleton = nullptr ;
LightStorage * LightStorage : : get_singleton ( ) {
return singleton ;
}
LightStorage : : LightStorage ( ) {
singleton = this ;
2023-10-11 22:02:38 +11:00
directional_shadow . size = GLOBAL_GET ( " rendering/lights_and_shadows/directional_shadow/size " ) ;
directional_shadow . use_16_bits = GLOBAL_GET ( " rendering/lights_and_shadows/directional_shadow/16_bits " ) ;
// lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed");
2022-04-09 19:34:31 +10:00
}
LightStorage : : ~ LightStorage ( ) {
singleton = nullptr ;
}
/* Light API */
2022-04-28 12:01:23 -07:00
void LightStorage : : _light_initialize ( RID p_light , RS : : LightType p_type ) {
Light light ;
light . type = p_type ;
light . param [ RS : : LIGHT_PARAM_ENERGY ] = 1.0 ;
light . param [ RS : : LIGHT_PARAM_INDIRECT_ENERGY ] = 1.0 ;
2021-07-09 10:28:33 +02:00
light . param [ RS : : LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY ] = 1.0 ;
2022-04-28 12:01:23 -07:00
light . param [ RS : : LIGHT_PARAM_SPECULAR ] = 0.5 ;
light . param [ RS : : LIGHT_PARAM_RANGE ] = 1.0 ;
light . param [ RS : : LIGHT_PARAM_SIZE ] = 0.0 ;
light . param [ RS : : LIGHT_PARAM_ATTENUATION ] = 1.0 ;
light . param [ RS : : LIGHT_PARAM_SPOT_ANGLE ] = 45 ;
light . param [ RS : : LIGHT_PARAM_SPOT_ATTENUATION ] = 1.0 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_MAX_DISTANCE ] = 0 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET ] = 0.1 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET ] = 0.3 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET ] = 0.6 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_FADE_START ] = 0.8 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_NORMAL_BIAS ] = 1.0 ;
2022-06-10 12:47:06 +02:00
light . param [ RS : : LIGHT_PARAM_SHADOW_OPACITY ] = 1.0 ;
2022-04-28 12:01:23 -07:00
light . param [ RS : : LIGHT_PARAM_SHADOW_BIAS ] = 0.02 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_BLUR ] = 0 ;
light . param [ RS : : LIGHT_PARAM_SHADOW_PANCAKE_SIZE ] = 20.0 ;
light . param [ RS : : LIGHT_PARAM_TRANSMITTANCE_BIAS ] = 0.05 ;
2023-05-11 09:46:46 -07:00
light . param [ RS : : LIGHT_PARAM_INTENSITY ] = p_type = = RS : : LIGHT_DIRECTIONAL ? 100000.0 : 1000.0 ;
2022-04-28 12:01:23 -07:00
light_owner . initialize_rid ( p_light , light ) ;
}
2022-04-09 19:34:31 +10:00
RID LightStorage : : directional_light_allocate ( ) {
2022-04-28 12:01:23 -07:00
return light_owner . allocate_rid ( ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : directional_light_initialize ( RID p_rid ) {
2022-04-28 12:01:23 -07:00
_light_initialize ( p_rid , RS : : LIGHT_DIRECTIONAL ) ;
2022-04-09 19:34:31 +10:00
}
RID LightStorage : : omni_light_allocate ( ) {
2022-04-28 12:01:23 -07:00
return light_owner . allocate_rid ( ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : omni_light_initialize ( RID p_rid ) {
2022-04-28 12:01:23 -07:00
_light_initialize ( p_rid , RS : : LIGHT_OMNI ) ;
2022-04-09 19:34:31 +10:00
}
RID LightStorage : : spot_light_allocate ( ) {
2022-04-28 12:01:23 -07:00
return light_owner . allocate_rid ( ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : spot_light_initialize ( RID p_rid ) {
2022-04-28 12:01:23 -07:00
_light_initialize ( p_rid , RS : : LIGHT_SPOT ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_free ( RID p_rid ) {
2022-04-28 12:01:23 -07:00
light_set_projector ( p_rid , RID ( ) ) ; //clear projector
// delete the texture
Light * light = light_owner . get_or_null ( p_rid ) ;
light - > dependency . deleted_notify ( p_rid ) ;
light_owner . free ( p_rid ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_color ( RID p_light , const Color & p_color ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > color = p_color ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_param ( RID p_light , RS : : LightParam p_param , float p_value ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
ERR_FAIL_INDEX ( p_param , RS : : LIGHT_PARAM_MAX ) ;
if ( light - > param [ p_param ] = = p_value ) {
return ;
}
switch ( p_param ) {
case RS : : LIGHT_PARAM_RANGE :
case RS : : LIGHT_PARAM_SPOT_ANGLE :
case RS : : LIGHT_PARAM_SHADOW_MAX_DISTANCE :
case RS : : LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET :
case RS : : LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET :
case RS : : LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET :
case RS : : LIGHT_PARAM_SHADOW_NORMAL_BIAS :
case RS : : LIGHT_PARAM_SHADOW_PANCAKE_SIZE :
case RS : : LIGHT_PARAM_SHADOW_BIAS : {
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-28 12:01:23 -07:00
} break ;
case RS : : LIGHT_PARAM_SIZE : {
if ( ( light - > param [ p_param ] > CMP_EPSILON ) ! = ( p_value > CMP_EPSILON ) ) {
//changing from no size to size and the opposite
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR ) ;
2022-04-28 12:01:23 -07:00
}
} break ;
default : {
}
}
light - > param [ p_param ] = p_value ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_shadow ( RID p_light , bool p_enabled ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > shadow = p_enabled ;
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_projector ( RID p_light , RID p_texture ) {
2022-04-28 12:01:23 -07:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
if ( light - > projector = = p_texture ) {
return ;
}
if ( light - > type ! = RS : : LIGHT_DIRECTIONAL & & light - > projector . is_valid ( ) ) {
texture_storage - > texture_remove_from_decal_atlas ( light - > projector , light - > type = = RS : : LIGHT_OMNI ) ;
}
light - > projector = p_texture ;
if ( light - > type ! = RS : : LIGHT_DIRECTIONAL ) {
if ( light - > projector . is_valid ( ) ) {
texture_storage - > texture_add_to_decal_atlas ( light - > projector , light - > type = = RS : : LIGHT_OMNI ) ;
}
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR ) ;
2022-04-28 12:01:23 -07:00
}
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_negative ( RID p_light , bool p_enable ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > negative = p_enable ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_cull_mask ( RID p_light , uint32_t p_mask ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > cull_mask = p_mask ;
light - > version + + ;
2025-02-03 23:02:20 -08:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_CULL_MASK ) ;
2022-04-09 19:34:31 +10:00
}
2024-08-12 00:17:11 +01:00
void LightStorage : : light_set_shadow_caster_mask ( RID p_light , uint32_t p_caster_mask ) {
Light * light = light_owner . get_or_null ( p_light ) ;
ERR_FAIL_NULL ( light ) ;
light - > shadow_caster_mask = p_caster_mask ;
light - > version + + ;
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
}
uint32_t LightStorage : : light_get_shadow_caster_mask ( RID p_light ) const {
Light * light = light_owner . get_or_null ( p_light ) ;
ERR_FAIL_NULL_V ( light , 0 ) ;
return light - > shadow_caster_mask ;
}
2022-04-09 19:34:31 +10:00
void LightStorage : : light_set_distance_fade ( RID p_light , bool p_enabled , float p_begin , float p_shadow , float p_length ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > distance_fade = p_enabled ;
light - > distance_fade_begin = p_begin ;
light - > distance_fade_shadow = p_shadow ;
light - > distance_fade_length = p_length ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_reverse_cull_face_mode ( RID p_light , bool p_enabled ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > reverse_cull = p_enabled ;
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_set_bake_mode ( RID p_light , RS : : LightBakeMode p_bake_mode ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
light - > bake_mode = p_bake_mode ;
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : light_omni_set_shadow_mode ( RID p_light , RS : : LightOmniShadowMode p_mode ) {
2022-04-28 12:01:23 -07:00
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
light - > omni_shadow_mode = p_mode ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
RS : : LightOmniShadowMode LightStorage : : light_omni_get_shadow_mode ( RID p_light ) {
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , RS : : LIGHT_OMNI_SHADOW_CUBE ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
return light - > omni_shadow_mode ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
void LightStorage : : light_directional_set_shadow_mode ( RID p_light , RS : : LightDirectionalShadowMode p_mode ) {
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
light - > directional_shadow_mode = p_mode ;
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
void LightStorage : : light_directional_set_blend_splits ( RID p_light , bool p_enable ) {
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
light - > directional_blend_splits = p_enable ;
light - > version + + ;
2022-06-21 10:08:33 +10:00
light - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_LIGHT ) ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
bool LightStorage : : light_directional_get_blend_splits ( RID p_light ) const {
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , false ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
return light - > directional_blend_splits ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
void LightStorage : : light_directional_set_sky_mode ( RID p_light , RS : : LightDirectionalSkyMode p_mode ) {
Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light ) ;
2022-04-28 12:01:23 -07:00
light - > directional_sky_mode = p_mode ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
RS : : LightDirectionalSkyMode LightStorage : : light_directional_get_sky_mode ( RID p_light ) const {
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , RS : : LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY ) ;
2022-04-28 12:01:23 -07:00
return light - > directional_sky_mode ;
2022-04-09 19:34:31 +10:00
}
2022-04-28 12:01:23 -07:00
RS : : LightDirectionalShadowMode LightStorage : : light_directional_get_shadow_mode ( RID p_light ) {
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , RS : : LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ) ;
2022-04-28 12:01:23 -07:00
return light - > directional_shadow_mode ;
2022-04-09 19:34:31 +10:00
}
RS : : LightBakeMode LightStorage : : light_get_bake_mode ( RID p_light ) {
2022-04-28 12:01:23 -07:00
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , RS : : LIGHT_BAKE_DISABLED ) ;
2022-04-09 19:34:31 +10:00
2022-04-28 12:01:23 -07:00
return light - > bake_mode ;
2022-04-09 19:34:31 +10:00
}
uint64_t LightStorage : : light_get_version ( RID p_light ) const {
2022-04-28 12:01:23 -07:00
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , 0 ) ;
2022-04-28 12:01:23 -07:00
return light - > version ;
}
2023-02-06 12:12:47 -08:00
uint32_t LightStorage : : light_get_cull_mask ( RID p_light ) const {
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , 0 ) ;
2023-02-06 12:12:47 -08:00
return light - > cull_mask ;
}
2022-04-28 12:01:23 -07:00
AABB LightStorage : : light_get_aabb ( RID p_light ) const {
const Light * light = light_owner . get_or_null ( p_light ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL_V ( light , AABB ( ) ) ;
2022-04-28 12:01:23 -07:00
switch ( light - > type ) {
case RS : : LIGHT_SPOT : {
float len = light - > param [ RS : : LIGHT_PARAM_RANGE ] ;
2025-09-24 22:37:28 -07:00
float angle = Math : : deg_to_rad ( light - > param [ RS : : LIGHT_PARAM_SPOT_ANGLE ] ) ;
if ( angle > Math : : PI * 0.5 ) {
// Light casts backwards as well.
return AABB ( Vector3 ( - 1 , - 1 , - 1 ) * len , Vector3 ( 2 , 2 , 2 ) * len ) ;
}
float size = Math : : sin ( angle ) * len ;
2022-04-28 12:01:23 -07:00
return AABB ( Vector3 ( - size , - size , - len ) , Vector3 ( size * 2 , size * 2 , len ) ) ;
} ;
case RS : : LIGHT_OMNI : {
float r = light - > param [ RS : : LIGHT_PARAM_RANGE ] ;
return AABB ( - Vector3 ( r , r , r ) , Vector3 ( r , r , r ) * 2 ) ;
} ;
case RS : : LIGHT_DIRECTIONAL : {
return AABB ( ) ;
} ;
}
ERR_FAIL_V ( AABB ( ) ) ;
2022-04-09 19:34:31 +10:00
}
2022-09-12 19:44:48 +10:00
/* LIGHT INSTANCE API */
RID LightStorage : : light_instance_create ( RID p_light ) {
RID li = light_instance_owner . make_rid ( LightInstance ( ) ) ;
LightInstance * light_instance = light_instance_owner . get_or_null ( li ) ;
light_instance - > self = li ;
light_instance - > light = p_light ;
light_instance - > light_type = light_get_type ( p_light ) ;
return li ;
}
void LightStorage : : light_instance_free ( RID p_light_instance ) {
LightInstance * light_instance = light_instance_owner . get_or_null ( p_light_instance ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light_instance ) ;
2023-05-25 20:04:00 -07:00
// Remove from shadow atlases.
for ( const RID & E : light_instance - > shadow_atlases ) {
ShadowAtlas * shadow_atlas = shadow_atlas_owner . get_or_null ( E ) ;
ERR_CONTINUE ( ! shadow_atlas - > shadow_owners . has ( p_light_instance ) ) ;
uint32_t key = shadow_atlas - > shadow_owners [ p_light_instance ] ;
uint32_t q = ( key > > QUADRANT_SHIFT ) & 0x3 ;
uint32_t s = key & SHADOW_INDEX_MASK ;
shadow_atlas - > quadrants [ q ] . shadows . write [ s ] . owner = RID ( ) ;
shadow_atlas - > shadow_owners . erase ( p_light_instance ) ;
}
2022-09-12 19:44:48 +10:00
light_instance_owner . free ( p_light_instance ) ;
}
void LightStorage : : light_instance_set_transform ( RID p_light_instance , const Transform3D & p_transform ) {
LightInstance * light_instance = light_instance_owner . get_or_null ( p_light_instance ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light_instance ) ;
2022-09-12 19:44:48 +10:00
light_instance - > transform = p_transform ;
}
void LightStorage : : light_instance_set_aabb ( RID p_light_instance , const AABB & p_aabb ) {
LightInstance * light_instance = light_instance_owner . get_or_null ( p_light_instance ) ;
2023-09-09 17:46:44 +02:00
ERR_FAIL_NULL ( light_instance ) ;
2022-09-12 19:44:48 +10:00
light_instance - > aabb = p_aabb ;
}
void LightStorage : : light_instance_set_shadow_transform ( RID p_light_instance , const Projection & p_projection , const Transform3D & p_transform , float p_far , float p_split , int p_pass , float p_shadow_texel_size , float p_bias_scale , float p_range_begin , const Vector2 & p_uv_scale ) {
2023-05-25 20:04:00 -07:00
LightInstance * light_instance = light_instance_owner . get_or_null ( p_light_instance ) ;
ERR_FAIL_NULL ( light_instance ) ;
ERR_FAIL_INDEX ( p_pass , 6 ) ;
light_instance - > shadow_transform [ p_pass ] . camera = p_projection ;
light_instance - > shadow_transform [ p_pass ] . transform = p_transform ;
light_instance - > shadow_transform [ p_pass ] . farplane = p_far ;
light_instance - > shadow_transform [ p_pass ] . split = p_split ;
light_instance - > shadow_transform [ p_pass ] . bias_scale = p_bias_scale ;
light_instance - > shadow_transform [ p_pass ] . range_begin = p_range_begin ;
light_instance - > shadow_transform [ p_pass ] . shadow_texel_size = p_shadow_texel_size ;
light_instance - > shadow_transform [ p_pass ] . uv_scale = p_uv_scale ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : light_instance_mark_visible ( RID p_light_instance ) {
2023-05-25 20:04:00 -07:00
LightInstance * light_instance = light_instance_owner . get_or_null ( p_light_instance ) ;
ERR_FAIL_NULL ( light_instance ) ;
light_instance - > last_scene_pass = RasterizerSceneGLES3 : : get_singleton ( ) - > get_scene_pass ( ) ;
2022-09-12 19:44:48 +10:00
}
2022-04-09 19:34:31 +10:00
/* PROBE API */
RID LightStorage : : reflection_probe_allocate ( ) {
2024-02-03 00:20:31 +11:00
return reflection_probe_owner . allocate_rid ( ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_initialize ( RID p_rid ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe probe ;
reflection_probe_owner . initialize_rid ( p_rid , probe ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_free ( RID p_rid ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_rid ) ;
reflection_probe - > dependency . deleted_notify ( p_rid ) ;
reflection_probe_owner . free ( p_rid ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_update_mode ( RID p_probe , RS : : ReflectionProbeUpdateMode p_mode ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > update_mode = p_mode ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_intensity ( RID p_probe , float p_intensity ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > intensity = p_intensity ;
2022-04-09 19:34:31 +10:00
}
2024-12-03 12:08:36 +01:00
void LightStorage : : reflection_probe_set_blend_distance ( RID p_probe , float p_blend_distance ) {
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > blend_distance = p_blend_distance ;
}
2022-04-09 19:34:31 +10:00
void LightStorage : : reflection_probe_set_ambient_mode ( RID p_probe , RS : : ReflectionProbeAmbientMode p_mode ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > ambient_mode = p_mode ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_ambient_color ( RID p_probe , const Color & p_color ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > ambient_color = p_color ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_ambient_energy ( RID p_probe , float p_energy ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > ambient_color_energy = p_energy ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_max_distance ( RID p_probe , float p_distance ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > max_distance = p_distance ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
2022-07-12 08:43:01 +01:00
void LightStorage : : reflection_probe_set_size ( RID p_probe , const Vector3 & p_size ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > size = p_size ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_origin_offset ( RID p_probe , const Vector3 & p_offset ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > origin_offset = p_offset ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_as_interior ( RID p_probe , bool p_enable ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > interior = p_enable ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_enable_box_projection ( RID p_probe , bool p_enable ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > box_projection = p_enable ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_enable_shadows ( RID p_probe , bool p_enable ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > enable_shadows = p_enable ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_cull_mask ( RID p_probe , uint32_t p_layers ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > cull_mask = p_layers ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
2023-12-12 13:20:41 +01:00
void LightStorage : : reflection_probe_set_reflection_mask ( RID p_probe , uint32_t p_layers ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > reflection_mask = p_layers ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2023-12-12 13:20:41 +01:00
}
2022-04-09 19:34:31 +10:00
void LightStorage : : reflection_probe_set_resolution ( RID p_probe , int p_resolution ) {
2025-08-01 00:12:32 -07:00
WARN_PRINT_ONCE ( " reflection_probe_set_resolution is not available in Godot 4. ReflectionProbe size is configured in the project settings with the rendering/reflections/reflection_atlas/reflection_size setting. " ) ;
2022-04-09 19:34:31 +10:00
}
AABB LightStorage : : reflection_probe_get_aabb ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , AABB ( ) ) ;
AABB aabb ;
aabb . position = - reflection_probe - > size / 2 ;
aabb . size = reflection_probe - > size ;
return aabb ;
2022-04-09 19:34:31 +10:00
}
RS : : ReflectionProbeUpdateMode LightStorage : : reflection_probe_get_update_mode ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , RenderingServer : : REFLECTION_PROBE_UPDATE_ONCE ) ;
return reflection_probe - > update_mode ;
2022-04-09 19:34:31 +10:00
}
uint32_t LightStorage : : reflection_probe_get_cull_mask ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , 0 ) ;
return reflection_probe - > cull_mask ;
2022-04-09 19:34:31 +10:00
}
2023-12-12 13:20:41 +01:00
uint32_t LightStorage : : reflection_probe_get_reflection_mask ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , 0 ) ;
return reflection_probe - > reflection_mask ;
2023-12-12 13:20:41 +01:00
}
2022-07-12 08:43:01 +01:00
Vector3 LightStorage : : reflection_probe_get_size ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , Vector3 ( ) ) ;
return reflection_probe - > size ;
2022-04-09 19:34:31 +10:00
}
Vector3 LightStorage : : reflection_probe_get_origin_offset ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , Vector3 ( ) ) ;
return reflection_probe - > origin_offset ;
2022-04-09 19:34:31 +10:00
}
float LightStorage : : reflection_probe_get_origin_max_distance ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , 0.0 ) ;
return reflection_probe - > max_distance ;
2022-04-09 19:34:31 +10:00
}
bool LightStorage : : reflection_probe_renders_shadows ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , false ) ;
return reflection_probe - > enable_shadows ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : reflection_probe_set_mesh_lod_threshold ( RID p_probe , float p_ratio ) {
2024-02-03 00:20:31 +11:00
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL ( reflection_probe ) ;
reflection_probe - > mesh_lod_threshold = p_ratio ;
reflection_probe - > dependency . changed_notify ( Dependency : : DEPENDENCY_CHANGED_REFLECTION_PROBE ) ;
2022-04-09 19:34:31 +10:00
}
float LightStorage : : reflection_probe_get_mesh_lod_threshold ( RID p_probe ) const {
2024-02-03 00:20:31 +11:00
const ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , 0.0 ) ;
return reflection_probe - > mesh_lod_threshold ;
}
Dependency * LightStorage : : reflection_probe_get_dependency ( RID p_probe ) const {
ReflectionProbe * reflection_probe = reflection_probe_owner . get_or_null ( p_probe ) ;
ERR_FAIL_NULL_V ( reflection_probe , nullptr ) ;
return & reflection_probe - > dependency ;
2022-04-09 19:34:31 +10:00
}
2022-09-12 19:44:48 +10:00
/* REFLECTION ATLAS */
RID LightStorage : : reflection_atlas_create ( ) {
2024-02-03 00:20:31 +11:00
ReflectionAtlas ra ;
ra . count = GLOBAL_GET ( " rendering/reflections/reflection_atlas/reflection_count " ) ;
ra . size = GLOBAL_GET ( " rendering/reflections/reflection_atlas/reflection_size " ) ;
return reflection_atlas_owner . make_rid ( ra ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : reflection_atlas_free ( RID p_ref_atlas ) {
2024-02-03 00:20:31 +11:00
reflection_atlas_set_size ( p_ref_atlas , 0 , 0 ) ;
reflection_atlas_owner . free ( p_ref_atlas ) ;
2022-09-12 19:44:48 +10:00
}
int LightStorage : : reflection_atlas_get_size ( RID p_ref_atlas ) const {
2024-02-03 00:20:31 +11:00
ReflectionAtlas * ra = reflection_atlas_owner . get_or_null ( p_ref_atlas ) ;
ERR_FAIL_NULL_V ( ra , 0 ) ;
return ra - > size ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : reflection_atlas_set_size ( RID p_ref_atlas , int p_reflection_size , int p_reflection_count ) {
2024-02-03 00:20:31 +11:00
ReflectionAtlas * ra = reflection_atlas_owner . get_or_null ( p_ref_atlas ) ;
ERR_FAIL_NULL ( ra ) ;
if ( ra - > size = = p_reflection_size & & ra - > count = = p_reflection_count ) {
return ; //no changes
}
ra - > size = p_reflection_size ;
ra - > count = p_reflection_count ;
if ( ra - > depth ! = 0 ) {
//clear and invalidate everything
for ( int i = 0 ; i < ra - > reflections . size ( ) ; i + + ) {
for ( int j = 0 ; j < 7 ; j + + ) {
if ( ra - > reflections [ i ] . fbos [ j ] ! = 0 ) {
glDeleteFramebuffers ( 1 , & ra - > reflections [ i ] . fbos [ j ] ) ;
ra - > reflections . write [ i ] . fbos [ j ] = 0 ;
}
}
GLES3 : : Utilities : : get_singleton ( ) - > texture_free_data ( ra - > reflections [ i ] . color ) ;
ra - > reflections . write [ i ] . color = 0 ;
GLES3 : : Utilities : : get_singleton ( ) - > texture_free_data ( ra - > reflections [ i ] . radiance ) ;
ra - > reflections . write [ i ] . radiance = 0 ;
if ( ra - > reflections [ i ] . owner . is_null ( ) ) {
continue ;
}
reflection_probe_release_atlas_index ( ra - > reflections [ i ] . owner ) ;
//rp->atlasindex clear
}
ra - > reflections . clear ( ) ;
GLES3 : : Utilities : : get_singleton ( ) - > texture_free_data ( ra - > depth ) ;
ra - > depth = 0 ;
}
if ( ra - > render_buffers . is_valid ( ) ) {
ra - > render_buffers - > free_render_buffer_data ( ) ;
}
2022-09-12 19:44:48 +10:00
}
/* REFLECTION PROBE INSTANCE */
RID LightStorage : : reflection_probe_instance_create ( RID p_probe ) {
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance rpi ;
rpi . probe = p_probe ;
return reflection_probe_instance_owner . make_rid ( rpi ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : reflection_probe_instance_free ( RID p_instance ) {
2024-02-03 00:20:31 +11:00
reflection_probe_release_atlas_index ( p_instance ) ;
reflection_probe_instance_owner . free ( p_instance ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : reflection_probe_instance_set_transform ( RID p_instance , const Transform3D & p_transform ) {
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL ( rpi ) ;
rpi - > transform = p_transform ;
rpi - > dirty = true ;
2022-09-12 19:44:48 +10:00
}
2024-03-04 20:07:01 +11:00
bool LightStorage : : reflection_probe_has_atlas_index ( RID p_instance ) {
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , false ) ;
if ( rpi - > atlas . is_null ( ) ) {
return false ;
}
return rpi - > atlas_index > = 0 ;
2024-03-04 20:07:01 +11:00
}
2022-09-12 19:44:48 +10:00
void LightStorage : : reflection_probe_release_atlas_index ( RID p_instance ) {
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL ( rpi ) ;
if ( rpi - > atlas . is_null ( ) ) {
return ; //nothing to release
}
ReflectionAtlas * atlas = reflection_atlas_owner . get_or_null ( rpi - > atlas ) ;
ERR_FAIL_NULL ( atlas ) ;
ERR_FAIL_INDEX ( rpi - > atlas_index , atlas - > reflections . size ( ) ) ;
atlas - > reflections . write [ rpi - > atlas_index ] . owner = RID ( ) ;
if ( rpi - > rendering ) {
// We were cancelled mid rendering, trigger refresh.
rpi - > rendering = false ;
rpi - > dirty = true ;
rpi - > processing_layer = 0 ;
}
rpi - > atlas_index = - 1 ;
rpi - > atlas = RID ( ) ;
2022-09-12 19:44:48 +10:00
}
bool LightStorage : : reflection_probe_instance_needs_redraw ( RID p_instance ) {
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , false ) ;
if ( rpi - > rendering ) {
return false ;
}
if ( rpi - > dirty ) {
return true ;
}
if ( reflection_probe_get_update_mode ( rpi - > probe ) = = RS : : REFLECTION_PROBE_UPDATE_ALWAYS ) {
return true ;
}
return rpi - > atlas_index = = - 1 ;
2022-09-12 19:44:48 +10:00
}
bool LightStorage : : reflection_probe_instance_has_reflection ( RID p_instance ) {
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , false ) ;
return rpi - > atlas . is_valid ( ) ;
2022-09-12 19:44:48 +10:00
}
bool LightStorage : : reflection_probe_instance_begin_render ( RID p_instance , RID p_reflection_atlas ) {
2024-02-03 00:20:31 +11:00
TextureStorage * texture_storage = TextureStorage : : get_singleton ( ) ;
ReflectionAtlas * atlas = reflection_atlas_owner . get_or_null ( p_reflection_atlas ) ;
ERR_FAIL_NULL_V ( atlas , false ) ;
2025-09-24 00:40:37 -07:00
ERR_FAIL_COND_V_MSG ( atlas - > size < 4 , false , " Attempted to render to a reflection atlas of invalid resolution. " ) ;
ERR_FAIL_COND_V_MSG ( atlas - > count < 1 , false , " Attempted to render to a reflection atlas of size < 1. " ) ;
2024-02-03 00:20:31 +11:00
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , false ) ;
if ( atlas - > render_buffers . is_null ( ) ) {
atlas - > render_buffers . instantiate ( ) ;
atlas - > render_buffers - > configure_for_probe ( Size2i ( atlas - > size , atlas - > size ) ) ;
}
// First we check if our atlas is initialized.
// Not making an exception for update_mode = REFLECTION_PROBE_UPDATE_ALWAYS, we are using
// the same render techniques regardless of realtime or update once (for now).
if ( atlas - > depth = = 0 ) {
// We need to create our textures
atlas - > mipmap_count = Image : : get_image_required_mipmaps ( atlas - > size , atlas - > size , Image : : FORMAT_RGBAH ) - 1 ;
atlas - > mipmap_count = MIN ( atlas - > mipmap_count , 8 ) ; // No more than 8 please..
glActiveTexture ( GL_TEXTURE0 ) ;
{
// We create one set of 6 layers for depth, we can reuse this when rendering.
glGenTextures ( 1 , & atlas - > depth ) ;
glBindTexture ( GL_TEXTURE_2D_ARRAY , atlas - > depth ) ;
glTexImage3D ( GL_TEXTURE_2D_ARRAY , 0 , GL_DEPTH_COMPONENT24 , atlas - > size , atlas - > size , 6 , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , nullptr ) ;
GLES3 : : Utilities : : get_singleton ( ) - > texture_allocated_data ( atlas - > depth , atlas - > size * atlas - > size * 6 * 3 , " Reflection probe atlas (depth) " ) ;
}
// Make room for our atlas entries
atlas - > reflections . resize ( atlas - > count ) ;
for ( int i = 0 ; i < atlas - > count ; i + + ) {
// Create a cube map for this atlas entry
GLuint color = 0 ;
glGenTextures ( 1 , & color ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , color ) ;
atlas - > reflections . write [ i ] . color = color ;
# ifdef GL_API_ENABLED
if ( RasterizerGLES3 : : is_gles_over_gl ( ) ) {
for ( int s = 0 ; s < 6 ; s + + ) {
glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X + s , 0 , GL_RGB10_A2 , atlas - > size , atlas - > size , 0 , GL_RGBA , GL_UNSIGNED_INT_2_10_10_10_REV , nullptr ) ;
}
glGenerateMipmap ( GL_TEXTURE_CUBE_MAP ) ;
}
# endif
# ifdef GLES_API_ENABLED
if ( ! RasterizerGLES3 : : is_gles_over_gl ( ) ) {
glTexStorage2D ( GL_TEXTURE_CUBE_MAP , atlas - > mipmap_count , GL_RGB10_A2 , atlas - > size , atlas - > size ) ;
}
# endif // GLES_API_ENABLED
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_BASE_LEVEL , 0 ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAX_LEVEL , atlas - > mipmap_count - 1 ) ;
// Setup sizes and calculate how much memory we're using.
int mipmap_size = atlas - > size ;
uint32_t data_size = 0 ;
for ( int m = 0 ; m < atlas - > mipmap_count ; m + + ) {
atlas - > mipmap_size [ m ] = mipmap_size ;
data_size + = mipmap_size * mipmap_size * 6 * 4 ;
mipmap_size = MAX ( mipmap_size > > 1 , 1 ) ;
}
GLES3 : : Utilities : : get_singleton ( ) - > texture_allocated_data ( color , data_size , String ( " Reflection probe atlas ( " ) + String : : num_int64 ( i ) + String ( " , color) " ) ) ;
// Create a radiance map for this atlas entry
GLuint radiance = 0 ;
glGenTextures ( 1 , & radiance ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , radiance ) ;
atlas - > reflections . write [ i ] . radiance = radiance ;
# ifdef GL_API_ENABLED
if ( RasterizerGLES3 : : is_gles_over_gl ( ) ) {
for ( int s = 0 ; s < 6 ; s + + ) {
glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X + s , 0 , GL_RGB10_A2 , atlas - > size , atlas - > size , 0 , GL_RGBA , GL_UNSIGNED_INT_2_10_10_10_REV , nullptr ) ;
}
glGenerateMipmap ( GL_TEXTURE_CUBE_MAP ) ;
}
# endif
# ifdef GLES_API_ENABLED
if ( ! RasterizerGLES3 : : is_gles_over_gl ( ) ) {
glTexStorage2D ( GL_TEXTURE_CUBE_MAP , atlas - > mipmap_count , GL_RGB10_A2 , atlas - > size , atlas - > size ) ;
}
# endif // GLES_API_ENABLED
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_BASE_LEVEL , 0 ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAX_LEVEL , atlas - > mipmap_count - 1 ) ;
// Same data size as our color buffer
GLES3 : : Utilities : : get_singleton ( ) - > texture_allocated_data ( radiance , data_size , String ( " Reflection probe atlas ( " ) + String : : num_int64 ( i ) + String ( " , radiance) " ) ) ;
// Create our framebuffers so we can draw to all sides
for ( int side = 0 ; side < 6 ; side + + ) {
GLuint fbo = 0 ;
glGenFramebuffers ( 1 , & fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
// We use glFramebufferTexture2D for the color buffer as glFramebufferTextureLayer doesn't always work with cubemaps.
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_CUBE_MAP_POSITIVE_X + side , color , 0 ) ;
glFramebufferTextureLayer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , atlas - > depth , 0 , side ) ;
// Validate framebuffer
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
WARN_PRINT ( " Could not create reflections framebuffer, status: " + texture_storage - > get_framebuffer_error ( status ) ) ;
}
atlas - > reflections . write [ i ] . fbos [ side ] = fbo ;
}
// Create an extra framebuffer for building our radiance
{
GLuint fbo = 0 ;
glGenFramebuffers ( 1 , & fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
atlas - > reflections . write [ i ] . fbos [ 6 ] = fbo ;
}
}
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , 0 ) ;
glBindTexture ( GL_TEXTURE_2D_ARRAY , 0 ) ;
}
// Then we find a free slot for our reflection probe
if ( rpi - > atlas_index = = - 1 ) {
for ( int i = 0 ; i < atlas - > reflections . size ( ) ; i + + ) {
if ( atlas - > reflections [ i ] . owner . is_null ( ) ) {
rpi - > atlas_index = i ;
break ;
}
}
//find the one used last
if ( rpi - > atlas_index = = - 1 ) {
//everything is in use, find the one least used via LRU
uint64_t pass_min = 0 ;
for ( int i = 0 ; i < atlas - > reflections . size ( ) ; i + + ) {
ReflectionProbeInstance * rpi2 = reflection_probe_instance_owner . get_or_null ( atlas - > reflections [ i ] . owner ) ;
if ( rpi2 - > last_pass < pass_min ) {
pass_min = rpi2 - > last_pass ;
rpi - > atlas_index = i ;
}
}
}
}
if ( rpi - > atlas_index ! = - 1 ) { // should we fail if this is still -1 ?
atlas - > reflections . write [ rpi - > atlas_index ] . owner = p_instance ;
}
rpi - > atlas = p_reflection_atlas ;
rpi - > rendering = true ;
rpi - > dirty = false ;
rpi - > processing_layer = 0 ;
return true ;
2022-09-12 19:44:48 +10:00
}
2022-12-15 22:20:06 +11:00
Ref < RenderSceneBuffers > LightStorage : : reflection_probe_atlas_get_render_buffers ( RID p_reflection_atlas ) {
2024-02-03 00:20:31 +11:00
ReflectionAtlas * atlas = reflection_atlas_owner . get_or_null ( p_reflection_atlas ) ;
ERR_FAIL_NULL_V ( atlas , Ref < RenderSceneBuffersGLES3 > ( ) ) ;
return atlas - > render_buffers ;
2022-12-15 22:20:06 +11:00
}
2022-09-12 19:44:48 +10:00
bool LightStorage : : reflection_probe_instance_postprocess_step ( RID p_instance ) {
2024-02-03 00:20:31 +11:00
GLES3 : : CubemapFilter * cubemap_filter = GLES3 : : CubemapFilter : : get_singleton ( ) ;
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , false ) ;
ERR_FAIL_COND_V ( ! rpi - > rendering , false ) ;
ERR_FAIL_COND_V ( rpi - > atlas . is_null ( ) , false ) ;
ReflectionAtlas * atlas = reflection_atlas_owner . get_or_null ( rpi - > atlas ) ;
if ( ! atlas | | rpi - > atlas_index = = - 1 ) {
//does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
rpi - > rendering = false ;
rpi - > processing_layer = 0 ;
return false ;
}
if ( LightStorage : : get_singleton ( ) - > reflection_probe_get_update_mode ( rpi - > probe ) = = RS : : REFLECTION_PROBE_UPDATE_ALWAYS ) {
// Using real time reflections, all roughness is done in one step
for ( int m = 0 ; m < atlas - > mipmap_count ; m + + ) {
const GLES3 : : ReflectionAtlas : : Reflection & reflection = atlas - > reflections [ rpi - > atlas_index ] ;
cubemap_filter - > filter_radiance ( reflection . color , reflection . radiance , reflection . fbos [ 6 ] , atlas - > size , atlas - > mipmap_count , m ) ;
}
rpi - > rendering = false ;
rpi - > processing_layer = 0 ;
return true ;
} else {
const GLES3 : : ReflectionAtlas : : Reflection & reflection = atlas - > reflections [ rpi - > atlas_index ] ;
cubemap_filter - > filter_radiance ( reflection . color , reflection . radiance , reflection . fbos [ 6 ] , atlas - > size , atlas - > mipmap_count , rpi - > processing_layer ) ;
rpi - > processing_layer + + ;
if ( rpi - > processing_layer = = atlas - > mipmap_count ) {
rpi - > rendering = false ;
rpi - > processing_layer = 0 ;
return true ;
}
}
return false ;
}
GLuint LightStorage : : reflection_probe_instance_get_texture ( RID p_instance ) {
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , 0 ) ;
ReflectionAtlas * atlas = reflection_atlas_owner . get_or_null ( rpi - > atlas ) ;
ERR_FAIL_NULL_V ( atlas , 0 ) ;
2025-03-18 02:37:43 -05:00
ERR_FAIL_COND_V ( rpi - > atlas_index < 0 , 0 ) ;
2024-02-03 00:20:31 +11:00
return atlas - > reflections [ rpi - > atlas_index ] . radiance ;
}
GLuint LightStorage : : reflection_probe_instance_get_framebuffer ( RID p_instance , int p_index ) {
ReflectionProbeInstance * rpi = reflection_probe_instance_owner . get_or_null ( p_instance ) ;
ERR_FAIL_NULL_V ( rpi , 0 ) ;
ERR_FAIL_INDEX_V ( p_index , 6 , 0 ) ;
ReflectionAtlas * atlas = reflection_atlas_owner . get_or_null ( rpi - > atlas ) ;
ERR_FAIL_NULL_V ( atlas , 0 ) ;
2025-03-18 02:37:43 -05:00
ERR_FAIL_COND_V ( rpi - > atlas_index < 0 , 0 ) ;
2024-02-03 00:20:31 +11:00
return atlas - > reflections [ rpi - > atlas_index ] . fbos [ p_index ] ;
2022-09-12 19:44:48 +10:00
}
2022-04-09 19:34:31 +10:00
/* LIGHTMAP CAPTURE */
RID LightStorage : : lightmap_allocate ( ) {
2022-07-31 16:20:24 -07:00
return lightmap_owner . allocate_rid ( ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_initialize ( RID p_rid ) {
2022-07-31 16:20:24 -07:00
lightmap_owner . initialize_rid ( p_rid , Lightmap ( ) ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_free ( RID p_rid ) {
2022-07-31 16:20:24 -07:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_rid ) ;
2023-11-19 21:39:20 -06:00
ERR_FAIL_NULL ( lightmap ) ;
2022-07-31 16:20:24 -07:00
lightmap - > dependency . deleted_notify ( p_rid ) ;
lightmap_owner . free ( p_rid ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_set_textures ( RID p_lightmap , RID p_light , bool p_uses_spherical_haromics ) {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
lightmap - > light_texture = p_light ;
lightmap - > uses_spherical_harmonics = p_uses_spherical_haromics ;
2024-03-25 17:48:03 +01:00
Vector3i light_texture_size = GLES3 : : TextureStorage : : get_singleton ( ) - > texture_get_size ( lightmap - > light_texture ) ;
lightmap - > light_texture_size = Vector2i ( light_texture_size . x , light_texture_size . y ) ;
2023-11-19 21:39:20 -06:00
GLuint tex = GLES3 : : TextureStorage : : get_singleton ( ) - > texture_get_texid ( lightmap - > light_texture ) ;
glBindTexture ( GL_TEXTURE_2D_ARRAY , tex ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glBindTexture ( GL_TEXTURE_2D_ARRAY , 0 ) ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_set_probe_bounds ( RID p_lightmap , const AABB & p_bounds ) {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
lightmap - > bounds = p_bounds ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_set_probe_interior ( RID p_lightmap , bool p_interior ) {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
lightmap - > interior = p_interior ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_set_probe_capture_data ( RID p_lightmap , const PackedVector3Array & p_points , const PackedColorArray & p_point_sh , const PackedInt32Array & p_tetrahedra , const PackedInt32Array & p_bsp_tree ) {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
if ( p_points . size ( ) ) {
ERR_FAIL_COND ( p_points . size ( ) * 9 ! = p_point_sh . size ( ) ) ;
ERR_FAIL_COND ( ( p_tetrahedra . size ( ) % 4 ) ! = 0 ) ;
ERR_FAIL_COND ( ( p_bsp_tree . size ( ) % 6 ) ! = 0 ) ;
}
lightmap - > points = p_points ;
lightmap - > point_sh = p_point_sh ;
lightmap - > tetrahedra = p_tetrahedra ;
lightmap - > bsp_tree = p_bsp_tree ;
2022-04-09 19:34:31 +10:00
}
2022-07-31 16:20:24 -07:00
void LightStorage : : lightmap_set_baked_exposure_normalization ( RID p_lightmap , float p_exposure ) {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
lightmap - > baked_exposure = p_exposure ;
2022-07-31 16:20:24 -07:00
}
2022-04-09 19:34:31 +10:00
PackedVector3Array LightStorage : : lightmap_get_probe_capture_points ( RID p_lightmap ) const {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , PackedVector3Array ( ) ) ;
return lightmap - > points ;
2022-04-09 19:34:31 +10:00
}
PackedColorArray LightStorage : : lightmap_get_probe_capture_sh ( RID p_lightmap ) const {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , PackedColorArray ( ) ) ;
return lightmap - > point_sh ;
2022-04-09 19:34:31 +10:00
}
PackedInt32Array LightStorage : : lightmap_get_probe_capture_tetrahedra ( RID p_lightmap ) const {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , PackedInt32Array ( ) ) ;
return lightmap - > tetrahedra ;
2022-04-09 19:34:31 +10:00
}
PackedInt32Array LightStorage : : lightmap_get_probe_capture_bsp_tree ( RID p_lightmap ) const {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , PackedInt32Array ( ) ) ;
return lightmap - > bsp_tree ;
2022-04-09 19:34:31 +10:00
}
AABB LightStorage : : lightmap_get_aabb ( RID p_lightmap ) const {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , AABB ( ) ) ;
return lightmap - > bounds ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_tap_sh_light ( RID p_lightmap , const Vector3 & p_point , Color * r_sh ) {
2023-11-19 21:39:20 -06:00
Lightmap * lm = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lm ) ;
for ( int i = 0 ; i < 9 ; i + + ) {
r_sh [ i ] = Color ( 0 , 0 , 0 , 0 ) ;
}
if ( ! lm - > points . size ( ) | | ! lm - > bsp_tree . size ( ) | | ! lm - > tetrahedra . size ( ) ) {
return ;
}
static_assert ( sizeof ( Lightmap : : BSP ) = = 24 ) ;
const Lightmap : : BSP * bsp = ( const Lightmap : : BSP * ) lm - > bsp_tree . ptr ( ) ;
int32_t node = 0 ;
while ( node > = 0 ) {
if ( Plane ( bsp [ node ] . plane [ 0 ] , bsp [ node ] . plane [ 1 ] , bsp [ node ] . plane [ 2 ] , bsp [ node ] . plane [ 3 ] ) . is_point_over ( p_point ) ) {
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( bsp [ node ] . over > = 0 & & bsp [ node ] . over < node ) ;
# endif
node = bsp [ node ] . over ;
} else {
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( bsp [ node ] . under > = 0 & & bsp [ node ] . under < node ) ;
# endif
node = bsp [ node ] . under ;
}
}
if ( node = = Lightmap : : BSP : : EMPTY_LEAF ) {
return ; // Nothing could be done.
}
2022-11-30 17:56:32 +01:00
node = Math : : abs ( node ) - 1 ;
2023-11-19 21:39:20 -06:00
uint32_t * tetrahedron = ( uint32_t * ) & lm - > tetrahedra [ node * 4 ] ;
Vector3 points [ 4 ] = { lm - > points [ tetrahedron [ 0 ] ] , lm - > points [ tetrahedron [ 1 ] ] , lm - > points [ tetrahedron [ 2 ] ] , lm - > points [ tetrahedron [ 3 ] ] } ;
const Color * sh_colors [ 4 ] { & lm - > point_sh [ tetrahedron [ 0 ] * 9 ] , & lm - > point_sh [ tetrahedron [ 1 ] * 9 ] , & lm - > point_sh [ tetrahedron [ 2 ] * 9 ] , & lm - > point_sh [ tetrahedron [ 3 ] * 9 ] } ;
Color barycentric = Geometry3D : : tetrahedron_get_barycentric_coords ( points [ 0 ] , points [ 1 ] , points [ 2 ] , points [ 3 ] , p_point ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
float c = CLAMP ( barycentric [ i ] , 0.0 , 1.0 ) ;
for ( int j = 0 ; j < 9 ; j + + ) {
r_sh [ j ] + = sh_colors [ i ] [ j ] * c ;
}
}
2022-04-09 19:34:31 +10:00
}
bool LightStorage : : lightmap_is_interior ( RID p_lightmap ) const {
2023-11-19 21:39:20 -06:00
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , false ) ;
return lightmap - > interior ;
2022-04-09 19:34:31 +10:00
}
void LightStorage : : lightmap_set_probe_capture_update_speed ( float p_speed ) {
2023-11-19 21:39:20 -06:00
lightmap_probe_capture_update_speed = p_speed ;
2022-04-09 19:34:31 +10:00
}
float LightStorage : : lightmap_get_probe_capture_update_speed ( ) const {
2023-11-19 21:39:20 -06:00
return lightmap_probe_capture_update_speed ;
2022-04-09 19:34:31 +10:00
}
2023-11-30 17:14:45 +01:00
void LightStorage : : lightmap_set_shadowmask_textures ( RID p_lightmap , RID p_shadow ) {
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
lightmap - > shadow_texture = p_shadow ;
GLuint tex = GLES3 : : TextureStorage : : get_singleton ( ) - > texture_get_texid ( lightmap - > shadow_texture ) ;
glBindTexture ( GL_TEXTURE_2D_ARRAY , tex ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glBindTexture ( GL_TEXTURE_2D_ARRAY , 0 ) ;
}
RS : : ShadowmaskMode LightStorage : : lightmap_get_shadowmask_mode ( RID p_lightmap ) {
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL_V ( lightmap , RS : : SHADOWMASK_MODE_NONE ) ;
return lightmap - > shadowmask_mode ;
}
void LightStorage : : lightmap_set_shadowmask_mode ( RID p_lightmap , RS : : ShadowmaskMode p_mode ) {
Lightmap * lightmap = lightmap_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( lightmap ) ;
lightmap - > shadowmask_mode = p_mode ;
}
2022-09-12 19:44:48 +10:00
/* LIGHTMAP INSTANCE */
RID LightStorage : : lightmap_instance_create ( RID p_lightmap ) {
2023-11-19 21:39:20 -06:00
LightmapInstance li ;
li . lightmap = p_lightmap ;
return lightmap_instance_owner . make_rid ( li ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : lightmap_instance_free ( RID p_lightmap ) {
2023-11-19 21:39:20 -06:00
lightmap_instance_owner . free ( p_lightmap ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : lightmap_instance_set_transform ( RID p_lightmap , const Transform3D & p_transform ) {
2023-11-19 21:39:20 -06:00
LightmapInstance * li = lightmap_instance_owner . get_or_null ( p_lightmap ) ;
ERR_FAIL_NULL ( li ) ;
li - > transform = p_transform ;
2022-09-12 19:44:48 +10:00
}
/* SHADOW ATLAS API */
RID LightStorage : : shadow_atlas_create ( ) {
2023-05-25 20:04:00 -07:00
return shadow_atlas_owner . make_rid ( ShadowAtlas ( ) ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : shadow_atlas_free ( RID p_atlas ) {
2023-05-25 20:04:00 -07:00
shadow_atlas_set_size ( p_atlas , 0 ) ;
shadow_atlas_owner . free ( p_atlas ) ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : shadow_atlas_set_size ( RID p_atlas , int p_size , bool p_16_bits ) {
2023-05-25 20:04:00 -07:00
ShadowAtlas * shadow_atlas = shadow_atlas_owner . get_or_null ( p_atlas ) ;
ERR_FAIL_NULL ( shadow_atlas ) ;
ERR_FAIL_COND ( p_size < 0 ) ;
2025-05-19 09:53:53 -07:00
p_size = next_power_of_2 ( ( uint32_t ) p_size ) ;
2023-05-25 20:04:00 -07:00
if ( p_size = = shadow_atlas - > size & & p_16_bits = = shadow_atlas - > use_16_bits ) {
return ;
}
for ( uint32_t i = 0 ; i < 4 ; i + + ) {
// Clear all subdivisions and free shadows.
for ( uint32_t j = 0 ; j < shadow_atlas - > quadrants [ i ] . textures . size ( ) ; j + + ) {
glDeleteTextures ( 1 , & shadow_atlas - > quadrants [ i ] . textures [ j ] ) ;
glDeleteFramebuffers ( 1 , & shadow_atlas - > quadrants [ i ] . fbos [ j ] ) ;
}
shadow_atlas - > quadrants [ i ] . textures . clear ( ) ;
shadow_atlas - > quadrants [ i ] . fbos . clear ( ) ;
shadow_atlas - > quadrants [ i ] . shadows . clear ( ) ;
shadow_atlas - > quadrants [ i ] . shadows . resize ( shadow_atlas - > quadrants [ i ] . subdivision * shadow_atlas - > quadrants [ i ] . subdivision ) ;
}
// Erase shadow atlas reference from lights.
for ( const KeyValue < RID , uint32_t > & E : shadow_atlas - > shadow_owners ) {
LightInstance * li = light_instance_owner . get_or_null ( E . key ) ;
ERR_CONTINUE ( ! li ) ;
li - > shadow_atlases . erase ( p_atlas ) ;
}
if ( shadow_atlas - > debug_texture ! = 0 ) {
glDeleteTextures ( 1 , & shadow_atlas - > debug_texture ) ;
}
if ( shadow_atlas - > debug_fbo ! = 0 ) {
glDeleteFramebuffers ( 1 , & shadow_atlas - > debug_fbo ) ;
}
// Clear owners.
shadow_atlas - > shadow_owners . clear ( ) ;
shadow_atlas - > size = p_size ;
shadow_atlas - > use_16_bits = p_16_bits ;
2022-09-12 19:44:48 +10:00
}
void LightStorage : : shadow_atlas_set_quadrant_subdivision ( RID p_atlas , int p_quadrant , int p_subdivision ) {
2023-05-25 20:04:00 -07:00
ShadowAtlas * shadow_atlas = shadow_atlas_owner . get_or_null ( p_atlas ) ;
ERR_FAIL_NULL ( shadow_atlas ) ;
ERR_FAIL_INDEX ( p_quadrant , 4 ) ;
ERR_FAIL_INDEX ( p_subdivision , 16384 ) ;
2025-05-19 09:53:53 -07:00
uint32_t subdiv = next_power_of_2 ( ( uint32_t ) p_subdivision ) ;
2023-05-25 20:04:00 -07:00
if ( subdiv & 0xaaaaaaaa ) { // sqrt(subdiv) must be integer.
subdiv < < = 1 ;
}
subdiv = int ( Math : : sqrt ( ( float ) subdiv ) ) ;
if ( shadow_atlas - > quadrants [ p_quadrant ] . subdivision = = subdiv ) {
return ;
}
// Erase all data from quadrant.
for ( int i = 0 ; i < shadow_atlas - > quadrants [ p_quadrant ] . shadows . size ( ) ; i + + ) {
if ( shadow_atlas - > quadrants [ p_quadrant ] . shadows [ i ] . owner . is_valid ( ) ) {
shadow_atlas - > shadow_owners . erase ( shadow_atlas - > quadrants [ p_quadrant ] . shadows [ i ] . owner ) ;
LightInstance * li = light_instance_owner . get_or_null ( shadow_atlas - > quadrants [ p_quadrant ] . shadows [ i ] . owner ) ;
ERR_CONTINUE ( ! li ) ;
li - > shadow_atlases . erase ( p_atlas ) ;
}
}
for ( uint32_t j = 0 ; j < shadow_atlas - > quadrants [ p_quadrant ] . textures . size ( ) ; j + + ) {
glDeleteTextures ( 1 , & shadow_atlas - > quadrants [ p_quadrant ] . textures [ j ] ) ;
glDeleteFramebuffers ( 1 , & shadow_atlas - > quadrants [ p_quadrant ] . fbos [ j ] ) ;
}
shadow_atlas - > quadrants [ p_quadrant ] . textures . clear ( ) ;
shadow_atlas - > quadrants [ p_quadrant ] . fbos . clear ( ) ;
shadow_atlas - > quadrants [ p_quadrant ] . shadows . clear ( ) ;
shadow_atlas - > quadrants [ p_quadrant ] . shadows . resize ( subdiv * subdiv ) ;
shadow_atlas - > quadrants [ p_quadrant ] . subdivision = subdiv ;
// Cache the smallest subdiv (for faster allocation in light update).
shadow_atlas - > smallest_subdiv = 1 < < 30 ;
for ( int i = 0 ; i < 4 ; i + + ) {
if ( shadow_atlas - > quadrants [ i ] . subdivision ) {
shadow_atlas - > smallest_subdiv = MIN ( shadow_atlas - > smallest_subdiv , shadow_atlas - > quadrants [ i ] . subdivision ) ;
}
}
if ( shadow_atlas - > smallest_subdiv = = 1 < < 30 ) {
shadow_atlas - > smallest_subdiv = 0 ;
}
// Re-sort the size orders, simple bubblesort for 4 elements.
int swaps = 0 ;
do {
swaps = 0 ;
for ( int i = 0 ; i < 3 ; i + + ) {
if ( shadow_atlas - > quadrants [ shadow_atlas - > size_order [ i ] ] . subdivision < shadow_atlas - > quadrants [ shadow_atlas - > size_order [ i + 1 ] ] . subdivision ) {
SWAP ( shadow_atlas - > size_order [ i ] , shadow_atlas - > size_order [ i + 1 ] ) ;
swaps + + ;
}
}
} while ( swaps > 0 ) ;
}
bool LightStorage : : shadow_atlas_update_light ( RID p_atlas , RID p_light_instance , float p_coverage , uint64_t p_light_version ) {
ShadowAtlas * shadow_atlas = shadow_atlas_owner . get_or_null ( p_atlas ) ;
ERR_FAIL_NULL_V ( shadow_atlas , false ) ;
LightInstance * li = light_instance_owner . get_or_null ( p_light_instance ) ;
ERR_FAIL_NULL_V ( li , false ) ;
if ( shadow_atlas - > size = = 0 | | shadow_atlas - > smallest_subdiv = = 0 ) {
return false ;
}
uint32_t quad_size = shadow_atlas - > size > > 1 ;
2025-05-19 09:53:53 -07:00
int desired_fit = MIN ( quad_size / shadow_atlas - > smallest_subdiv , next_power_of_2 ( uint32_t ( quad_size * p_coverage ) ) ) ;
2023-05-25 20:04:00 -07:00
int valid_quadrants [ 4 ] ;
int valid_quadrant_count = 0 ;
int best_size = - 1 ; // Best size found.
int best_subdiv = - 1 ; // Subdiv for the best size.
// Find the quadrants this fits into, and the best possible size it can fit into.
for ( int i = 0 ; i < 4 ; i + + ) {
int q = shadow_atlas - > size_order [ i ] ;
int sd = shadow_atlas - > quadrants [ q ] . subdivision ;
if ( sd = = 0 ) {
continue ; // Unused.
}
int max_fit = quad_size / sd ;
if ( best_size ! = - 1 & & max_fit > best_size ) {
break ; // Too large.
}
valid_quadrants [ valid_quadrant_count + + ] = q ;
best_subdiv = sd ;
if ( max_fit > = desired_fit ) {
best_size = max_fit ;
}
}
ERR_FAIL_COND_V ( valid_quadrant_count = = 0 , false ) ;
uint64_t tick = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
uint32_t old_key = SHADOW_INVALID ;
uint32_t old_quadrant = SHADOW_INVALID ;
uint32_t old_shadow = SHADOW_INVALID ;
int old_subdivision = - 1 ;
bool should_realloc = false ;
bool should_redraw = false ;
if ( shadow_atlas - > shadow_owners . has ( p_light_instance ) ) {
old_key = shadow_atlas - > shadow_owners [ p_light_instance ] ;
old_quadrant = ( old_key > > QUADRANT_SHIFT ) & 0x3 ;
old_shadow = old_key & SHADOW_INDEX_MASK ;
// Only re-allocate if a better option is available, and enough time has passed.
2024-12-05 11:08:59 -08:00
should_realloc = shadow_atlas - > quadrants [ old_quadrant ] . subdivision ! = ( uint32_t ) best_subdiv & & ( tick - shadow_atlas - > quadrants [ old_quadrant ] . shadows [ old_shadow ] . alloc_tick > shadow_atlas_realloc_tolerance_msec ) ;
2023-05-25 20:04:00 -07:00
should_redraw = shadow_atlas - > quadrants [ old_quadrant ] . shadows [ old_shadow ] . version ! = p_light_version ;
if ( ! should_realloc ) {
shadow_atlas - > quadrants [ old_quadrant ] . shadows . write [ old_shadow ] . version = p_light_version ;
// Already existing, see if it should redraw or it's just OK.
return should_redraw ;
}
old_subdivision = shadow_atlas - > quadrants [ old_quadrant ] . subdivision ;
}
bool is_omni = li - > light_type = = RS : : LIGHT_OMNI ;
bool found_shadow = false ;
int new_quadrant = - 1 ;
int new_shadow = - 1 ;
found_shadow = _shadow_atlas_find_shadow ( shadow_atlas , valid_quadrants , valid_quadrant_count , old_subdivision , tick , is_omni , new_quadrant , new_shadow ) ;
// For new shadows if we found an atlas.
// Or for existing shadows that found a better atlas.
if ( found_shadow ) {
if ( old_quadrant ! = SHADOW_INVALID ) {
shadow_atlas - > quadrants [ old_quadrant ] . shadows . write [ old_shadow ] . version = 0 ;
shadow_atlas - > quadrants [ old_quadrant ] . shadows . write [ old_shadow ] . owner = RID ( ) ;
}
uint32_t new_key = new_quadrant < < QUADRANT_SHIFT ;
new_key | = new_shadow ;
ShadowAtlas : : Quadrant : : Shadow * sh = & shadow_atlas - > quadrants [ new_quadrant ] . shadows . write [ new_shadow ] ;
_shadow_atlas_invalidate_shadow ( sh , p_atlas , shadow_atlas , new_quadrant , new_shadow ) ;
sh - > owner = p_light_instance ;
sh - > owner_is_omni = is_omni ;
sh - > alloc_tick = tick ;
sh - > version = p_light_version ;
li - > shadow_atlases . insert ( p_atlas ) ;
// Update it in map.
shadow_atlas - > shadow_owners [ p_light_instance ] = new_key ;
// Make it dirty, as it should redraw anyway.
return true ;
}
return should_redraw ;
2022-09-12 19:44:48 +10:00
}
2023-05-25 20:04:00 -07:00
bool LightStorage : : _shadow_atlas_find_shadow ( ShadowAtlas * shadow_atlas , int * p_in_quadrants , int p_quadrant_count , int p_current_subdiv , uint64_t p_tick , bool is_omni , int & r_quadrant , int & r_shadow ) {
for ( int i = p_quadrant_count - 1 ; i > = 0 ; i - - ) {
int qidx = p_in_quadrants [ i ] ;
if ( shadow_atlas - > quadrants [ qidx ] . subdivision = = ( uint32_t ) p_current_subdiv ) {
return false ;
}
// Look for an empty space.
int sc = shadow_atlas - > quadrants [ qidx ] . shadows . size ( ) ;
const ShadowAtlas : : Quadrant : : Shadow * sarr = shadow_atlas - > quadrants [ qidx ] . shadows . ptr ( ) ;
// We have a free space in this quadrant, allocate a texture and use it.
if ( sc > ( int ) shadow_atlas - > quadrants [ qidx ] . textures . size ( ) ) {
GLuint fbo_id = 0 ;
glGenFramebuffers ( 1 , & fbo_id ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo_id ) ;
GLuint texture_id = 0 ;
glGenTextures ( 1 , & texture_id ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
int size = ( shadow_atlas - > size > > 1 ) / shadow_atlas - > quadrants [ qidx ] . subdivision ;
GLenum format = shadow_atlas - > use_16_bits ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT24 ;
GLenum type = shadow_atlas - > use_16_bits ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ;
if ( is_omni ) {
glBindTexture ( GL_TEXTURE_CUBE_MAP , texture_id ) ;
for ( int id = 0 ; id < 6 ; id + + ) {
glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X + id , 0 , format , size / 2 , size / 2 , 0 , GL_DEPTH_COMPONENT , type , nullptr ) ;
}
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_COMPARE_MODE , GL_COMPARE_REF_TO_TEXTURE ) ;
2024-02-14 21:39:39 +08:00
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_COMPARE_FUNC , GL_GREATER ) ;
2023-05-25 20:04:00 -07:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_CUBE_MAP_POSITIVE_X , texture_id , 0 ) ;
# ifdef DEBUG_ENABLED
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
ERR_PRINT ( " Could not create omni light shadow framebuffer, status: " + GLES3 : : TextureStorage : : get_singleton ( ) - > get_framebuffer_error ( status ) ) ;
}
# endif
glBindTexture ( GL_TEXTURE_CUBE_MAP , 0 ) ;
} else {
glBindTexture ( GL_TEXTURE_2D , texture_id ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , format , size , size , 0 , GL_DEPTH_COMPONENT , type , nullptr ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_COMPARE_MODE , GL_COMPARE_REF_TO_TEXTURE ) ;
2024-02-14 21:39:39 +08:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_COMPARE_FUNC , GL_GREATER ) ;
2023-05-25 20:04:00 -07:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , texture_id , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
2024-02-23 16:38:34 -08:00
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
2023-05-25 20:04:00 -07:00
r_quadrant = qidx ;
r_shadow = shadow_atlas - > quadrants [ qidx ] . textures . size ( ) ;
shadow_atlas - > quadrants [ qidx ] . textures . push_back ( texture_id ) ;
shadow_atlas - > quadrants [ qidx ] . fbos . push_back ( fbo_id ) ;
return true ;
}
int found_used_idx = - 1 ; // Found existing one, must steal it.
uint64_t min_pass = 0 ; // Pass of the existing one, try to use the least recently used one (LRU fashion).
for ( int j = 0 ; j < sc ; j + + ) {
2024-09-03 07:12:51 +02:00
if ( sarr [ j ] . owner_is_omni ! = is_omni ) {
// Existing light instance type doesn't match new light instance type skip.
continue ;
}
2023-05-25 20:04:00 -07:00
LightInstance * sli = light_instance_owner . get_or_null ( sarr [ j ] . owner ) ;
2024-04-05 07:19:17 +07:00
if ( ! sli ) {
// Found a released light instance.
found_used_idx = j ;
break ;
}
2023-05-25 20:04:00 -07:00
if ( sli - > last_scene_pass ! = RasterizerSceneGLES3 : : get_singleton ( ) - > get_scene_pass ( ) ) {
// Was just allocated, don't kill it so soon, wait a bit.
if ( p_tick - sarr [ j ] . alloc_tick < shadow_atlas_realloc_tolerance_msec ) {
continue ;
}
if ( found_used_idx = = - 1 | | sli - > last_scene_pass < min_pass ) {
found_used_idx = j ;
min_pass = sli - > last_scene_pass ;
}
}
}
if ( found_used_idx ! = - 1 ) {
r_quadrant = qidx ;
r_shadow = found_used_idx ;
return true ;
}
}
2022-09-12 19:44:48 +10:00
return false ;
}
2023-05-25 20:04:00 -07:00
void LightStorage : : _shadow_atlas_invalidate_shadow ( ShadowAtlas : : Quadrant : : Shadow * p_shadow , RID p_atlas , ShadowAtlas * p_shadow_atlas , uint32_t p_quadrant , uint32_t p_shadow_idx ) {
if ( p_shadow - > owner . is_valid ( ) ) {
LightInstance * sli = light_instance_owner . get_or_null ( p_shadow - > owner ) ;
p_shadow_atlas - > shadow_owners . erase ( p_shadow - > owner ) ;
p_shadow - > version = 0 ;
p_shadow - > owner = RID ( ) ;
sli - > shadow_atlases . erase ( p_atlas ) ;
}
}
2022-09-12 19:44:48 +10:00
void LightStorage : : shadow_atlas_update ( RID p_atlas ) {
2023-05-25 20:04:00 -07:00
// Do nothing as there is no shadow atlas texture.
2022-09-12 19:44:48 +10:00
}
2023-05-25 20:04:00 -07:00
/* DIRECTIONAL SHADOW */
// Create if necessary and clear.
void LightStorage : : update_directional_shadow_atlas ( ) {
if ( directional_shadow . depth = = 0 & & directional_shadow . size > 0 ) {
glGenFramebuffers ( 1 , & directional_shadow . fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , directional_shadow . fbo ) ;
glGenTextures ( 1 , & directional_shadow . depth ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , directional_shadow . depth ) ;
GLenum format = directional_shadow . use_16_bits ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT24 ;
GLenum type = directional_shadow . use_16_bits ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ;
glTexImage2D ( GL_TEXTURE_2D , 0 , format , directional_shadow . size , directional_shadow . size , 0 , GL_DEPTH_COMPONENT , type , nullptr ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_COMPARE_MODE , GL_COMPARE_REF_TO_TEXTURE ) ;
2024-02-14 21:39:39 +08:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_COMPARE_FUNC , GL_GREATER ) ;
2023-05-25 20:04:00 -07:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , directional_shadow . depth , 0 ) ;
}
2023-12-11 09:34:03 +11:00
glUseProgram ( 0 ) ;
2023-05-25 20:04:00 -07:00
glDepthMask ( GL_TRUE ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , directional_shadow . fbo ) ;
2024-02-14 21:39:39 +08:00
RasterizerGLES3 : : clear_depth ( 0.0 ) ;
2023-05-25 20:04:00 -07:00
glClear ( GL_DEPTH_BUFFER_BIT ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2024-02-23 16:38:34 -08:00
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
2022-09-12 19:44:48 +10:00
}
2023-05-25 20:04:00 -07:00
void LightStorage : : directional_shadow_atlas_set_size ( int p_size , bool p_16_bits ) {
p_size = nearest_power_of_2_templated ( p_size ) ;
if ( directional_shadow . size = = p_size & & directional_shadow . use_16_bits = = p_16_bits ) {
return ;
}
directional_shadow . size = p_size ;
directional_shadow . use_16_bits = p_16_bits ;
if ( directional_shadow . depth ! = 0 ) {
glDeleteTextures ( 1 , & directional_shadow . depth ) ;
directional_shadow . depth = 0 ;
glDeleteFramebuffers ( 1 , & directional_shadow . fbo ) ;
directional_shadow . fbo = 0 ;
}
2022-09-12 19:44:48 +10:00
}
void LightStorage : : set_directional_shadow_count ( int p_count ) {
2023-05-25 20:04:00 -07:00
directional_shadow . light_count = p_count ;
directional_shadow . current_light = 0 ;
}
static Rect2i _get_directional_shadow_rect ( int p_size , int p_shadow_count , int p_shadow_index ) {
int split_h = 1 ;
int split_v = 1 ;
while ( split_h * split_v < p_shadow_count ) {
if ( split_h = = split_v ) {
split_h < < = 1 ;
} else {
split_v < < = 1 ;
}
}
Rect2i rect ( 0 , 0 , p_size , p_size ) ;
rect . size . width / = split_h ;
rect . size . height / = split_v ;
rect . position . x = rect . size . width * ( p_shadow_index % split_h ) ;
rect . position . y = rect . size . height * ( p_shadow_index / split_h ) ;
return rect ;
}
Rect2i LightStorage : : get_directional_shadow_rect ( ) {
return _get_directional_shadow_rect ( directional_shadow . size , directional_shadow . light_count , directional_shadow . current_light ) ;
}
int LightStorage : : get_directional_light_shadow_size ( RID p_light_instance ) {
ERR_FAIL_COND_V ( directional_shadow . light_count = = 0 , 0 ) ;
Rect2i r = _get_directional_shadow_rect ( directional_shadow . size , directional_shadow . light_count , 0 ) ;
LightInstance * light_instance = light_instance_owner . get_or_null ( p_light_instance ) ;
ERR_FAIL_NULL_V ( light_instance , 0 ) ;
switch ( light_directional_get_shadow_mode ( light_instance - > light ) ) {
case RS : : LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL :
break ; //none
case RS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS :
r . size . height / = 2 ;
break ;
case RS : : LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS :
r . size / = 2 ;
break ;
}
return MAX ( r . size . width , r . size . height ) ;
2022-09-12 19:44:48 +10:00
}
2022-04-09 19:34:31 +10:00
# endif // !GLES3_ENABLED