Merge pull request #77496 from clayjohn/GLES3-shadows
Implement 3D shadows in the GL Compatibility renderer
This commit is contained in:
commit
7ae0fa1083
10 changed files with 2385 additions and 396 deletions
|
@ -134,6 +134,16 @@ void CopyEffects::copy_screen() {
|
||||||
draw_screen_triangle();
|
draw_screen_triangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CopyEffects::copy_cube_to_rect(const Rect2 &p_rect) {
|
||||||
|
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_OCTAHEDRAL);
|
||||||
|
if (!success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
|
||||||
|
draw_screen_quad();
|
||||||
|
}
|
||||||
|
|
||||||
// Intended for efficiently mipmapping textures.
|
// Intended for efficiently mipmapping textures.
|
||||||
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
|
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
|
||||||
GLuint framebuffers[2];
|
GLuint framebuffers[2];
|
||||||
|
|
|
@ -63,6 +63,7 @@ public:
|
||||||
// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
|
// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
|
||||||
void copy_to_rect(const Rect2 &p_rect);
|
void copy_to_rect(const Rect2 &p_rect);
|
||||||
void copy_screen();
|
void copy_screen();
|
||||||
|
void copy_cube_to_rect(const Rect2 &p_rect);
|
||||||
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
|
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
|
||||||
void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
|
void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
|
||||||
void set_color(const Color &p_color, const Rect2i &p_region);
|
void set_color(const Color &p_color, const Rect2i &p_region);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -59,7 +59,6 @@ enum RenderListType {
|
||||||
enum PassMode {
|
enum PassMode {
|
||||||
PASS_MODE_COLOR,
|
PASS_MODE_COLOR,
|
||||||
PASS_MODE_COLOR_TRANSPARENT,
|
PASS_MODE_COLOR_TRANSPARENT,
|
||||||
PASS_MODE_COLOR_ADDITIVE,
|
|
||||||
PASS_MODE_SHADOW,
|
PASS_MODE_SHADOW,
|
||||||
PASS_MODE_DEPTH,
|
PASS_MODE_DEPTH,
|
||||||
};
|
};
|
||||||
|
@ -75,6 +74,8 @@ enum SceneUniformLocation {
|
||||||
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
|
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
|
||||||
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
|
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
|
||||||
SCENE_MULTIVIEW_UNIFORM_LOCATION,
|
SCENE_MULTIVIEW_UNIFORM_LOCATION,
|
||||||
|
SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION,
|
||||||
|
SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SkyUniformLocation {
|
enum SkyUniformLocation {
|
||||||
|
@ -109,6 +110,7 @@ struct RenderDataGLES3 {
|
||||||
const PagedArray<RID> *reflection_probes = nullptr;
|
const PagedArray<RID> *reflection_probes = nullptr;
|
||||||
RID environment;
|
RID environment;
|
||||||
RID camera_attributes;
|
RID camera_attributes;
|
||||||
|
RID shadow_atlas;
|
||||||
RID reflection_probe;
|
RID reflection_probe;
|
||||||
int reflection_probe_pass = 0;
|
int reflection_probe_pass = 0;
|
||||||
|
|
||||||
|
@ -116,10 +118,16 @@ struct RenderDataGLES3 {
|
||||||
float screen_mesh_lod_threshold = 0.0;
|
float screen_mesh_lod_threshold = 0.0;
|
||||||
|
|
||||||
uint32_t directional_light_count = 0;
|
uint32_t directional_light_count = 0;
|
||||||
|
uint32_t directional_shadow_count = 0;
|
||||||
|
|
||||||
uint32_t spot_light_count = 0;
|
uint32_t spot_light_count = 0;
|
||||||
uint32_t omni_light_count = 0;
|
uint32_t omni_light_count = 0;
|
||||||
|
|
||||||
RenderingMethod::RenderInfo *render_info = nullptr;
|
RenderingMethod::RenderInfo *render_info = nullptr;
|
||||||
|
|
||||||
|
/* Shadow data */
|
||||||
|
const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
|
||||||
|
int render_shadow_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RasterizerCanvasGLES3;
|
class RasterizerCanvasGLES3;
|
||||||
|
@ -173,11 +181,36 @@ private:
|
||||||
float size;
|
float size;
|
||||||
|
|
||||||
uint32_t enabled; // For use by SkyShaders
|
uint32_t enabled; // For use by SkyShaders
|
||||||
float pad[2];
|
float pad;
|
||||||
|
float shadow_opacity;
|
||||||
float specular;
|
float specular;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
|
static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
|
||||||
|
|
||||||
|
struct ShadowData {
|
||||||
|
float shadow_matrix[16];
|
||||||
|
|
||||||
|
float light_position[3];
|
||||||
|
float shadow_normal_bias;
|
||||||
|
|
||||||
|
float pad[3];
|
||||||
|
float shadow_atlas_pixel_size;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ShadowData) % 16 == 0, "ShadowData size must be a multiple of 16 bytes");
|
||||||
|
|
||||||
|
struct DirectionalShadowData {
|
||||||
|
float direction[3];
|
||||||
|
float shadow_atlas_pixel_size;
|
||||||
|
float shadow_normal_bias[4];
|
||||||
|
float shadow_split_offsets[4];
|
||||||
|
float shadow_matrices[4][16];
|
||||||
|
float fade_from;
|
||||||
|
float fade_to;
|
||||||
|
uint32_t blend_splits; // Not exposed to the shader.
|
||||||
|
uint32_t pad;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(DirectionalShadowData) % 16 == 0, "DirectionalShadowData size must be a multiple of 16 bytes");
|
||||||
|
|
||||||
class GeometryInstanceGLES3;
|
class GeometryInstanceGLES3;
|
||||||
|
|
||||||
// Cached data for drawing surfaces
|
// Cached data for drawing surfaces
|
||||||
|
@ -221,6 +254,8 @@ private:
|
||||||
uint32_t surface_index = 0;
|
uint32_t surface_index = 0;
|
||||||
uint32_t lod_index = 0;
|
uint32_t lod_index = 0;
|
||||||
uint32_t index_count = 0;
|
uint32_t index_count = 0;
|
||||||
|
int32_t light_pass_index = -1;
|
||||||
|
bool finished_base_pass = false;
|
||||||
|
|
||||||
void *surface = nullptr;
|
void *surface = nullptr;
|
||||||
GLES3::SceneShaderData *shader = nullptr;
|
GLES3::SceneShaderData *shader = nullptr;
|
||||||
|
@ -245,14 +280,23 @@ private:
|
||||||
bool using_projectors = false;
|
bool using_projectors = false;
|
||||||
bool using_softshadows = false;
|
bool using_softshadows = false;
|
||||||
|
|
||||||
uint32_t omni_light_count = 0;
|
struct LightPass {
|
||||||
LocalVector<RID> omni_lights;
|
int32_t light_id = -1; // Position in the light uniform buffer.
|
||||||
uint32_t spot_light_count = 0;
|
int32_t shadow_id = -1; // Position in the shadow uniform buffer.
|
||||||
LocalVector<RID> spot_lights;
|
RID light_instance_rid;
|
||||||
|
bool is_omni = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalVector<LightPass> light_passes;
|
||||||
|
|
||||||
|
uint32_t paired_omni_light_count = 0;
|
||||||
|
uint32_t paired_spot_light_count = 0;
|
||||||
|
LocalVector<RID> paired_omni_lights;
|
||||||
|
LocalVector<RID> paired_spot_lights;
|
||||||
LocalVector<uint32_t> omni_light_gl_cache;
|
LocalVector<uint32_t> omni_light_gl_cache;
|
||||||
LocalVector<uint32_t> spot_light_gl_cache;
|
LocalVector<uint32_t> spot_light_gl_cache;
|
||||||
|
|
||||||
//used during setup
|
// Used during setup.
|
||||||
GeometryInstanceSurface *surface_caches = nullptr;
|
GeometryInstanceSurface *surface_caches = nullptr;
|
||||||
SelfList<GeometryInstanceGLES3> dirty_list_element;
|
SelfList<GeometryInstanceGLES3> dirty_list_element;
|
||||||
|
|
||||||
|
@ -336,10 +380,11 @@ private:
|
||||||
|
|
||||||
float fog_light_color[3];
|
float fog_light_color[3];
|
||||||
float fog_sun_scatter;
|
float fog_sun_scatter;
|
||||||
|
|
||||||
|
float shadow_bias;
|
||||||
|
float pad;
|
||||||
uint32_t camera_visible_layers;
|
uint32_t camera_visible_layers;
|
||||||
uint32_t pad1;
|
bool pancake_shadows;
|
||||||
uint32_t pad2;
|
|
||||||
uint32_t pad3;
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
|
static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
|
||||||
|
|
||||||
|
@ -378,16 +423,22 @@ private:
|
||||||
|
|
||||||
LightData *omni_lights = nullptr;
|
LightData *omni_lights = nullptr;
|
||||||
LightData *spot_lights = nullptr;
|
LightData *spot_lights = nullptr;
|
||||||
|
ShadowData *positional_shadows = nullptr;
|
||||||
|
|
||||||
InstanceSort<GLES3::LightInstance> *omni_light_sort;
|
InstanceSort<GLES3::LightInstance> *omni_light_sort;
|
||||||
InstanceSort<GLES3::LightInstance> *spot_light_sort;
|
InstanceSort<GLES3::LightInstance> *spot_light_sort;
|
||||||
GLuint omni_light_buffer = 0;
|
GLuint omni_light_buffer = 0;
|
||||||
GLuint spot_light_buffer = 0;
|
GLuint spot_light_buffer = 0;
|
||||||
|
GLuint positional_shadow_buffer = 0;
|
||||||
uint32_t omni_light_count = 0;
|
uint32_t omni_light_count = 0;
|
||||||
uint32_t spot_light_count = 0;
|
uint32_t spot_light_count = 0;
|
||||||
|
RS::ShadowQuality positional_shadow_quality = RS::ShadowQuality::SHADOW_QUALITY_SOFT_LOW;
|
||||||
|
|
||||||
DirectionalLightData *directional_lights = nullptr;
|
DirectionalLightData *directional_lights = nullptr;
|
||||||
GLuint directional_light_buffer = 0;
|
GLuint directional_light_buffer = 0;
|
||||||
|
DirectionalShadowData *directional_shadows = nullptr;
|
||||||
|
GLuint directional_shadow_buffer = 0;
|
||||||
|
RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality::SHADOW_QUALITY_SOFT_LOW;
|
||||||
} scene_state;
|
} scene_state;
|
||||||
|
|
||||||
struct RenderListParameters {
|
struct RenderListParameters {
|
||||||
|
@ -462,9 +513,11 @@ private:
|
||||||
|
|
||||||
RenderList render_list[RENDER_LIST_MAX];
|
RenderList render_list[RENDER_LIST_MAX];
|
||||||
|
|
||||||
void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count);
|
void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count, uint32_t &r_directional_shadow_count);
|
||||||
void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows);
|
void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias = 0.0);
|
||||||
void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
|
void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
|
||||||
|
void _render_shadows(const RenderDataGLES3 *p_render_data);
|
||||||
|
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr);
|
||||||
|
|
||||||
template <PassMode p_pass_mode>
|
template <PassMode p_pass_mode>
|
||||||
_FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
|
_FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
|
||||||
|
@ -477,7 +530,7 @@ protected:
|
||||||
float screen_space_roughness_limiter_amount = 0.25;
|
float screen_space_roughness_limiter_amount = 0.25;
|
||||||
float screen_space_roughness_limiter_limit = 0.18;
|
float screen_space_roughness_limiter_limit = 0.18;
|
||||||
|
|
||||||
void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
|
void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas);
|
||||||
|
|
||||||
/* Camera Attributes */
|
/* Camera Attributes */
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
|
||||||
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
|
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
|
||||||
mode_mipmap = #define MODE_MIPMAP
|
mode_mipmap = #define MODE_MIPMAP
|
||||||
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
|
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
|
||||||
|
mode_cube_to_octahedral = #define CUBE_TO_OCTAHEDRAL \n#define USE_COPY_SECTION
|
||||||
|
|
||||||
#[specializations]
|
#[specializations]
|
||||||
|
|
||||||
|
@ -50,8 +51,20 @@ uniform vec4 color_in;
|
||||||
uniform highp vec2 pixel_size;
|
uniform highp vec2 pixel_size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CUBE_TO_OCTAHEDRAL
|
||||||
|
uniform samplerCube source_cube; // texunit:0
|
||||||
|
|
||||||
|
vec3 oct_to_vec3(vec2 e) {
|
||||||
|
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
|
||||||
|
float t = max(-v.z, 0.0);
|
||||||
|
v.xy += t * -sign(v.xy);
|
||||||
|
return normalize(v);
|
||||||
|
}
|
||||||
|
#else
|
||||||
uniform sampler2D source; // texunit:0
|
uniform sampler2D source; // texunit:0
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
layout(location = 0) out vec4 frag_color;
|
layout(location = 0) out vec4 frag_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -90,4 +103,11 @@ void main() {
|
||||||
frag_color += (F + G + L + K) * lesser_weight;
|
frag_color += (F + G + L + K) * lesser_weight;
|
||||||
frag_color += (G + H + M + L) * lesser_weight;
|
frag_color += (G + H + M + L) * lesser_weight;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CUBE_TO_OCTAHEDRAL
|
||||||
|
// Treat the UV coordinates as 0-1 encoded octahedral coordinates.
|
||||||
|
vec3 dir = oct_to_vec3(uv_interp * 2.0 - 1.0);
|
||||||
|
frag_color = texture(source_cube, dir);
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
#[modes]
|
#[modes]
|
||||||
|
|
||||||
mode_color = #define BASE_PASS
|
mode_color =
|
||||||
mode_color_instancing = #define BASE_PASS \n#define USE_INSTANCING
|
mode_color_instancing = \n#define USE_INSTANCING
|
||||||
mode_additive = #define USE_ADDITIVE_LIGHTING
|
|
||||||
mode_additive_instancing = #define USE_ADDITIVE_LIGHTING \n#define USE_INSTANCING
|
|
||||||
mode_depth = #define MODE_RENDER_DEPTH
|
mode_depth = #define MODE_RENDER_DEPTH
|
||||||
mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING
|
mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING
|
||||||
|
|
||||||
|
@ -17,6 +15,19 @@ DISABLE_LIGHT_SPOT = false
|
||||||
DISABLE_FOG = false
|
DISABLE_FOG = false
|
||||||
USE_RADIANCE_MAP = true
|
USE_RADIANCE_MAP = true
|
||||||
USE_MULTIVIEW = false
|
USE_MULTIVIEW = false
|
||||||
|
RENDER_SHADOWS = false
|
||||||
|
RENDER_SHADOWS_LINEAR = false
|
||||||
|
SHADOW_MODE_PCF_5 = false
|
||||||
|
SHADOW_MODE_PCF_13 = false
|
||||||
|
LIGHT_USE_PSSM2 = false
|
||||||
|
LIGHT_USE_PSSM4 = false
|
||||||
|
LIGHT_USE_PSSM_BLEND = false
|
||||||
|
BASE_PASS = true
|
||||||
|
USE_ADDITIVE_LIGHTING = false
|
||||||
|
// We can only use one type of light per additive pass. This means that if USE_ADDITIVE_LIGHTING is defined, and
|
||||||
|
// these are false, we are doing a directional light pass.
|
||||||
|
ADDITIVE_OMNI = false
|
||||||
|
ADDITIVE_SPOT = false
|
||||||
|
|
||||||
|
|
||||||
#[vertex]
|
#[vertex]
|
||||||
|
@ -33,6 +44,12 @@ USE_MULTIVIEW = false
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MODE_UNSHADED
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
#undef USE_ADDITIVE_LIGHTING
|
||||||
|
#endif
|
||||||
|
#endif // MODE_UNSHADED
|
||||||
|
|
||||||
/*
|
/*
|
||||||
from RenderingServer:
|
from RenderingServer:
|
||||||
ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
|
ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
|
||||||
|
@ -151,13 +168,56 @@ layout(std140) uniform SceneData { // ubo:2
|
||||||
|
|
||||||
vec3 fog_light_color;
|
vec3 fog_light_color;
|
||||||
float fog_sun_scatter;
|
float fog_sun_scatter;
|
||||||
|
|
||||||
|
float shadow_bias;
|
||||||
|
float pad;
|
||||||
uint camera_visible_layers;
|
uint camera_visible_layers;
|
||||||
uint pad3;
|
bool pancake_shadows;
|
||||||
uint pad4;
|
|
||||||
uint pad5;
|
|
||||||
}
|
}
|
||||||
scene_data;
|
scene_data;
|
||||||
|
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
|
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
struct PositionalShadowData {
|
||||||
|
highp mat4 shadow_matrix;
|
||||||
|
highp vec3 light_position;
|
||||||
|
highp float shadow_normal_bias;
|
||||||
|
vec3 pad;
|
||||||
|
highp float shadow_atlas_pixel_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform PositionalShadows { // ubo:9
|
||||||
|
PositionalShadowData positional_shadows[MAX_LIGHT_DATA_STRUCTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform lowp uint positional_shadow_index;
|
||||||
|
|
||||||
|
#else // ADDITIVE_DIRECTIONAL
|
||||||
|
|
||||||
|
struct DirectionalShadowData {
|
||||||
|
highp vec3 direction;
|
||||||
|
highp float shadow_atlas_pixel_size;
|
||||||
|
highp vec4 shadow_normal_bias;
|
||||||
|
highp vec4 shadow_split_offsets;
|
||||||
|
highp mat4 shadow_matrix1;
|
||||||
|
highp mat4 shadow_matrix2;
|
||||||
|
highp mat4 shadow_matrix3;
|
||||||
|
highp mat4 shadow_matrix4;
|
||||||
|
mediump float fade_from;
|
||||||
|
mediump float fade_to;
|
||||||
|
mediump vec2 pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform DirectionalShadows { // ubo:10
|
||||||
|
DirectionalShadowData directional_shadows[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform lowp uint directional_shadow_index;
|
||||||
|
|
||||||
|
#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
|
||||||
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
layout(std140) uniform MultiviewData { // ubo:8
|
layout(std140) uniform MultiviewData { // ubo:8
|
||||||
highp mat4 projection_matrix_view[MAX_VIEWS];
|
highp mat4 projection_matrix_view[MAX_VIEWS];
|
||||||
|
@ -201,6 +261,19 @@ out vec3 tangent_interp;
|
||||||
out vec3 binormal_interp;
|
out vec3 binormal_interp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
out highp vec4 shadow_coord;
|
||||||
|
|
||||||
|
#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
|
||||||
|
out highp vec4 shadow_coord2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM4
|
||||||
|
out highp vec4 shadow_coord3;
|
||||||
|
out highp vec4 shadow_coord4;
|
||||||
|
#endif //LIGHT_USE_PSSM4
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MATERIAL_UNIFORMS_USED
|
#ifdef MATERIAL_UNIFORMS_USED
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
@ -351,6 +424,50 @@ void main() {
|
||||||
binormal_interp = binormal;
|
binormal_interp = binormal;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Calculate shadows.
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
// Apply normal bias at draw time to avoid issues with scaling non-fused geometry.
|
||||||
|
vec3 light_rel_vec = positional_shadows[positional_shadow_index].light_position - vertex_interp;
|
||||||
|
float light_length = length(light_rel_vec);
|
||||||
|
float aNdotL = abs(dot(normalize(normal_interp), normalize(light_rel_vec)));
|
||||||
|
vec3 normal_offset = (1.0 - aNdotL) * positional_shadows[positional_shadow_index].shadow_normal_bias * light_length * normal_interp;
|
||||||
|
|
||||||
|
#ifdef ADDITIVE_SPOT
|
||||||
|
// Calculate coord here so we can take advantage of prefetch.
|
||||||
|
shadow_coord = positional_shadows[positional_shadow_index].shadow_matrix * vec4(vertex_interp + normal_offset, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ADDITIVE_OMNI
|
||||||
|
// Can't interpolate unit direction nicely, so forget about prefetch.
|
||||||
|
shadow_coord = vec4(vertex_interp + normal_offset, 1.0);
|
||||||
|
#endif
|
||||||
|
#else // ADDITIVE_DIRECTIONAL
|
||||||
|
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(directional_shadows[directional_shadow_index].direction, -normalize(normal_interp))));
|
||||||
|
vec3 normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.x;
|
||||||
|
shadow_coord = directional_shadows[directional_shadow_index].shadow_matrix1 * vec4(vertex_interp + normal_offset, 1.0);
|
||||||
|
|
||||||
|
#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
|
||||||
|
normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.y;
|
||||||
|
shadow_coord2 = directional_shadows[directional_shadow_index].shadow_matrix2 * vec4(vertex_interp + normal_offset, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM4
|
||||||
|
normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.z;
|
||||||
|
shadow_coord3 = directional_shadows[directional_shadow_index].shadow_matrix3 * vec4(vertex_interp + normal_offset, 1.0);
|
||||||
|
normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.w;
|
||||||
|
shadow_coord4 = directional_shadows[directional_shadow_index].shadow_matrix4 * vec4(vertex_interp + normal_offset, 1.0);
|
||||||
|
#endif //LIGHT_USE_PSSM4
|
||||||
|
|
||||||
|
#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
|
||||||
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
|
#if defined(RENDER_SHADOWS) && !defined(RENDER_SHADOWS_LINEAR)
|
||||||
|
// This is an optimized version of normalize(vertex_interp) * scene_data.shadow_bias / length(vertex_interp).
|
||||||
|
float light_length_sq = dot(vertex_interp, vertex_interp);
|
||||||
|
vertex_interp += vertex_interp * scene_data.shadow_bias / light_length_sq;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(OVERRIDE_POSITION)
|
#if defined(OVERRIDE_POSITION)
|
||||||
gl_Position = position;
|
gl_Position = position;
|
||||||
#else
|
#else
|
||||||
|
@ -372,17 +489,22 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MODE_UNSHADED
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
#undef USE_ADDITIVE_LIGHTING
|
||||||
|
#endif
|
||||||
|
#endif // MODE_UNSHADED
|
||||||
|
|
||||||
#ifndef MODE_RENDER_DEPTH
|
#ifndef MODE_RENDER_DEPTH
|
||||||
#include "tonemap_inc.glsl"
|
#include "tonemap_inc.glsl"
|
||||||
#endif
|
#endif
|
||||||
#include "stdlib_inc.glsl"
|
#include "stdlib_inc.glsl"
|
||||||
|
|
||||||
/* texture unit usage, N is max_texture_unity-N
|
/* texture unit usage, N is max_texture_unit-N
|
||||||
|
|
||||||
1-color correction // In tonemap_inc.glsl
|
1-color correction // In tonemap_inc.glsl
|
||||||
2-radiance
|
2-radiance
|
||||||
3-directional_shadow
|
3-shadow
|
||||||
4-positional_shadow
|
|
||||||
5-screen
|
5-screen
|
||||||
6-depth
|
6-depth
|
||||||
|
|
||||||
|
@ -422,6 +544,19 @@ in vec3 normal_interp;
|
||||||
|
|
||||||
in highp vec3 vertex_interp;
|
in highp vec3 vertex_interp;
|
||||||
|
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
in highp vec4 shadow_coord;
|
||||||
|
|
||||||
|
#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
|
||||||
|
in highp vec4 shadow_coord2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM4
|
||||||
|
in highp vec4 shadow_coord3;
|
||||||
|
in highp vec4 shadow_coord4;
|
||||||
|
#endif //LIGHT_USE_PSSM4
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_RADIANCE_MAP
|
#ifdef USE_RADIANCE_MAP
|
||||||
|
|
||||||
#define RADIANCE_MAX_LOD 5.0
|
#define RADIANCE_MAX_LOD 5.0
|
||||||
|
@ -483,10 +618,11 @@ layout(std140) uniform SceneData { // ubo:2
|
||||||
|
|
||||||
vec3 fog_light_color;
|
vec3 fog_light_color;
|
||||||
float fog_sun_scatter;
|
float fog_sun_scatter;
|
||||||
|
|
||||||
|
float shadow_bias;
|
||||||
|
float pad;
|
||||||
uint camera_visible_layers;
|
uint camera_visible_layers;
|
||||||
uint pad3;
|
bool pancake_shadows;
|
||||||
uint pad4;
|
|
||||||
uint pad5;
|
|
||||||
}
|
}
|
||||||
scene_data;
|
scene_data;
|
||||||
|
|
||||||
|
@ -505,15 +641,17 @@ multiview_data;
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
#ifndef MODE_RENDER_DEPTH
|
||||||
// Directional light data.
|
// Directional light data.
|
||||||
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
|
||||||
|
|
||||||
struct DirectionalLightData {
|
struct DirectionalLightData {
|
||||||
mediump vec3 direction;
|
mediump vec3 direction;
|
||||||
mediump float energy;
|
mediump float energy;
|
||||||
mediump vec3 color;
|
mediump vec3 color;
|
||||||
mediump float size;
|
mediump float size;
|
||||||
mediump vec3 pad;
|
mediump vec2 pad;
|
||||||
|
mediump float shadow_opacity;
|
||||||
mediump float specular;
|
mediump float specular;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -521,10 +659,15 @@ layout(std140) uniform DirectionalLights { // ubo:7
|
||||||
DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
|
DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(USE_ADDITIVE_LIGHTING) && (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
|
||||||
|
// Directional shadows can be in the base pass or in the additive passes
|
||||||
|
uniform highp sampler2DShadow directional_shadow_atlas; // texunit:-3
|
||||||
|
#endif // defined(USE_ADDITIVE_LIGHTING) && (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
|
||||||
|
|
||||||
#endif // !DISABLE_LIGHT_DIRECTIONAL
|
#endif // !DISABLE_LIGHT_DIRECTIONAL
|
||||||
|
|
||||||
// Omni and spot light data.
|
// Omni and spot light data.
|
||||||
#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
struct LightData { // This structure needs to be as packed as possible.
|
struct LightData { // This structure needs to be as packed as possible.
|
||||||
highp vec3 position;
|
highp vec3 position;
|
||||||
|
@ -542,27 +685,119 @@ struct LightData { // This structure needs to be as packed as possible.
|
||||||
mediump float shadow_opacity;
|
mediump float shadow_opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_OMNI
|
#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
|
||||||
layout(std140) uniform OmniLightData { // ubo:5
|
layout(std140) uniform OmniLightData { // ubo:5
|
||||||
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
|
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
|
||||||
};
|
};
|
||||||
|
#ifdef BASE_PASS
|
||||||
uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
|
uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
|
||||||
uniform uint omni_light_count;
|
uniform uint omni_light_count;
|
||||||
#endif
|
#endif // BASE_PASS
|
||||||
|
#endif // DISABLE_LIGHT_OMNI
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_SPOT
|
#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
|
||||||
layout(std140) uniform SpotLightData { // ubo:6
|
layout(std140) uniform SpotLightData { // ubo:6
|
||||||
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
|
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
|
||||||
};
|
};
|
||||||
|
#ifdef BASE_PASS
|
||||||
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
|
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
|
||||||
uniform uint spot_light_count;
|
uniform uint spot_light_count;
|
||||||
#endif
|
#endif // BASE_PASS
|
||||||
|
#endif // DISABLE_LIGHT_SPOT
|
||||||
|
#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
||||||
|
|
||||||
#ifdef USE_ADDITIVE_LIGHTING
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
uniform highp samplerCubeShadow positional_shadow; // texunit:-4
|
#ifdef ADDITIVE_OMNI
|
||||||
|
uniform highp samplerCubeShadow omni_shadow_texture; // texunit:-3
|
||||||
|
uniform lowp uint omni_light_index;
|
||||||
|
#endif
|
||||||
|
#ifdef ADDITIVE_SPOT
|
||||||
|
uniform highp sampler2DShadow spot_shadow_texture; // texunit:-3
|
||||||
|
uniform lowp uint spot_light_index;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
struct PositionalShadowData {
|
||||||
|
highp mat4 shadow_matrix;
|
||||||
|
highp vec3 light_position;
|
||||||
|
highp float shadow_normal_bias;
|
||||||
|
vec3 pad;
|
||||||
|
highp float shadow_atlas_pixel_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform PositionalShadows { // ubo:9
|
||||||
|
PositionalShadowData positional_shadows[MAX_LIGHT_DATA_STRUCTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform lowp uint positional_shadow_index;
|
||||||
|
#else // ADDITIVE_DIRECTIONAL
|
||||||
|
struct DirectionalShadowData {
|
||||||
|
highp vec3 direction;
|
||||||
|
highp float shadow_atlas_pixel_size;
|
||||||
|
highp vec4 shadow_normal_bias;
|
||||||
|
highp vec4 shadow_split_offsets;
|
||||||
|
highp mat4 shadow_matrix1;
|
||||||
|
highp mat4 shadow_matrix2;
|
||||||
|
highp mat4 shadow_matrix3;
|
||||||
|
highp mat4 shadow_matrix4;
|
||||||
|
mediump float fade_from;
|
||||||
|
mediump float fade_to;
|
||||||
|
mediump vec2 pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform DirectionalShadows { // ubo:10
|
||||||
|
DirectionalShadowData directional_shadows[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform lowp uint directional_shadow_index;
|
||||||
|
#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
|
||||||
|
|
||||||
|
#if !defined(ADDITIVE_OMNI)
|
||||||
|
float sample_shadow(highp sampler2DShadow shadow, float shadow_pixel_size, vec4 pos) {
|
||||||
|
float avg = textureProj(shadow, pos);
|
||||||
|
#ifdef SHADOW_MODE_PCF_13
|
||||||
|
pos /= pos.w;
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size * 2.0, 0.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size * 2.0, 0.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, shadow_pixel_size * 2.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, -shadow_pixel_size * 2.0), pos.zw));
|
||||||
|
|
||||||
|
// Early bail if distant samples are fully shaded (or none are shaded) to improve performance.
|
||||||
|
if (avg <= 0.000001) {
|
||||||
|
// None shaded at all.
|
||||||
|
return 0.0;
|
||||||
|
} else if (avg >= 4.999999) {
|
||||||
|
// All fully shaded.
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, 0.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, 0.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, shadow_pixel_size), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, -shadow_pixel_size), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, shadow_pixel_size), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, shadow_pixel_size), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, -shadow_pixel_size), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, -shadow_pixel_size), pos.zw));
|
||||||
|
return avg * (1.0 / 13.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SHADOW_MODE_PCF_5
|
||||||
|
pos /= pos.w;
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, 0.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, 0.0), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, shadow_pixel_size), pos.zw));
|
||||||
|
avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, -shadow_pixel_size), pos.zw));
|
||||||
|
return avg * (1.0 / 5.0);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return avg;
|
||||||
|
}
|
||||||
|
#endif //!defined(ADDITIVE_OMNI)
|
||||||
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
|
#endif // !MODE_RENDER_DEPTH
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
uniform highp sampler2DArray depth_buffer; // texunit:-6
|
uniform highp sampler2DArray depth_buffer; // texunit:-6
|
||||||
|
@ -589,8 +824,8 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
|
||||||
// see https://google.github.io/filament/Filament.md.html
|
// see https://google.github.io/filament/Filament.md.html
|
||||||
return mix(vec3(dielectric), albedo, vec3(metallic));
|
return mix(vec3(dielectric), albedo, vec3(metallic));
|
||||||
}
|
}
|
||||||
|
#ifndef MODE_RENDER_DEPTH
|
||||||
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(USE_ADDITIVE_LIGHTING)
|
||||||
|
|
||||||
float D_GGX(float cos_theta_m, float alpha) {
|
float D_GGX(float cos_theta_m, float alpha) {
|
||||||
float a = cos_theta_m * alpha;
|
float a = cos_theta_m * alpha;
|
||||||
|
@ -787,7 +1022,7 @@ float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
|
||||||
return nd * pow(max(distance, 0.0001), -decay);
|
return nd * pow(max(distance, 0.0001), -decay);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_OMNI
|
#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
|
||||||
void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
|
void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
vec3 backlight,
|
vec3 backlight,
|
||||||
|
@ -813,6 +1048,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
|
||||||
size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
|
size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
omni_attenuation *= shadow;
|
||||||
|
|
||||||
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
|
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -831,7 +1068,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_LIGHT_OMNI
|
#endif // !DISABLE_LIGHT_OMNI
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_SPOT
|
#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
|
||||||
void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
|
void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
vec3 backlight,
|
vec3 backlight,
|
||||||
|
@ -864,6 +1101,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
|
||||||
size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
|
size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spot_attenuation *= shadow;
|
||||||
|
|
||||||
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
|
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -879,11 +1118,10 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
|
||||||
#endif
|
#endif
|
||||||
diffuse_light, specular_light);
|
diffuse_light, specular_light);
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_LIGHT_SPOT
|
#endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
||||||
|
|
||||||
#ifndef MODE_RENDER_DEPTH
|
|
||||||
vec4 fog_process(vec3 vertex) {
|
vec4 fog_process(vec3 vertex) {
|
||||||
vec3 fog_color = scene_data.fog_light_color;
|
vec3 fog_color = scene_data.fog_light_color;
|
||||||
|
|
||||||
|
@ -1191,10 +1429,7 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BASE_PASS
|
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
||||||
//diffuse_light = normal; //
|
|
||||||
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
||||||
light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
|
light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
|
@ -1220,7 +1455,7 @@ void main() {
|
||||||
if (i >= omni_light_count) {
|
if (i >= omni_light_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
|
light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
#endif
|
#endif
|
||||||
|
@ -1243,7 +1478,7 @@ void main() {
|
||||||
if (i >= spot_light_count) {
|
if (i >= spot_light_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
|
light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
#endif
|
#endif
|
||||||
|
@ -1261,7 +1496,7 @@ void main() {
|
||||||
diffuse_light, specular_light);
|
diffuse_light, specular_light);
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_LIGHT_SPOT
|
#endif // !DISABLE_LIGHT_SPOT
|
||||||
|
#endif // BASE_PASS
|
||||||
#endif // !MODE_UNSHADED
|
#endif // !MODE_UNSHADED
|
||||||
|
|
||||||
#endif // !MODE_RENDER_DEPTH
|
#endif // !MODE_RENDER_DEPTH
|
||||||
|
@ -1287,9 +1522,14 @@ void main() {
|
||||||
#endif // USE_SHADOW_TO_OPACITY
|
#endif // USE_SHADOW_TO_OPACITY
|
||||||
|
|
||||||
#ifdef MODE_RENDER_DEPTH
|
#ifdef MODE_RENDER_DEPTH
|
||||||
//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
|
#ifdef RENDER_SHADOWS_LINEAR
|
||||||
#else // !MODE_RENDER_DEPTH
|
// Linearize the depth buffer if rendering cubemap shadows.
|
||||||
|
gl_FragDepth = (length(vertex) + scene_data.shadow_bias) / scene_data.z_far;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
|
||||||
|
#else // !MODE_RENDER_DEPTH
|
||||||
|
#ifdef BASE_PASS
|
||||||
#ifdef MODE_UNSHADED
|
#ifdef MODE_UNSHADED
|
||||||
frag_color = vec4(albedo, alpha);
|
frag_color = vec4(albedo, alpha);
|
||||||
#else
|
#else
|
||||||
|
@ -1300,21 +1540,15 @@ void main() {
|
||||||
ambient_light *= 1.0 - metallic;
|
ambient_light *= 1.0 - metallic;
|
||||||
|
|
||||||
frag_color = vec4(diffuse_light + specular_light, alpha);
|
frag_color = vec4(diffuse_light + specular_light, alpha);
|
||||||
#ifdef BASE_PASS
|
|
||||||
frag_color.rgb += emission + ambient_light;
|
frag_color.rgb += emission + ambient_light;
|
||||||
#endif
|
#endif //!MODE_UNSHADED
|
||||||
#endif //MODE_UNSHADED
|
|
||||||
|
|
||||||
#ifndef FOG_DISABLED
|
#ifndef FOG_DISABLED
|
||||||
fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
|
fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
|
||||||
|
|
||||||
#ifndef DISABLE_FOG
|
#ifndef DISABLE_FOG
|
||||||
if (scene_data.fog_enabled) {
|
if (scene_data.fog_enabled) {
|
||||||
#ifdef BASE_PASS
|
|
||||||
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
|
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
|
||||||
#else
|
|
||||||
frag_color.rgb *= (1.0 - fog.a);
|
|
||||||
#endif // BASE_PASS
|
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_FOG
|
#endif // !DISABLE_FOG
|
||||||
#endif // !FOG_DISABLED
|
#endif // !FOG_DISABLED
|
||||||
|
@ -1331,6 +1565,223 @@ void main() {
|
||||||
#ifdef USE_COLOR_CORRECTION
|
#ifdef USE_COLOR_CORRECTION
|
||||||
frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction);
|
frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction);
|
||||||
#endif
|
#endif
|
||||||
|
#else // !BASE_PASS
|
||||||
|
frag_color = vec4(0.0, 0.0, 0.0, alpha);
|
||||||
|
#endif // !BASE_PASS
|
||||||
|
|
||||||
|
/* ADDITIVE LIGHTING PASS */
|
||||||
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
diffuse_light = vec3(0.0);
|
||||||
|
specular_light = vec3(0.0);
|
||||||
|
|
||||||
|
#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
|
// Orthogonal shadows
|
||||||
|
#if !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
|
||||||
|
float directional_shadow = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
|
||||||
|
#endif // !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
|
||||||
|
|
||||||
|
// PSSM2 shadows
|
||||||
|
#ifdef LIGHT_USE_PSSM2
|
||||||
|
float depth_z = -vertex.z;
|
||||||
|
vec4 light_split_offsets = directional_shadows[directional_shadow_index].shadow_split_offsets;
|
||||||
|
//take advantage of prefetch
|
||||||
|
float shadow1 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
|
||||||
|
float shadow2 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord2);
|
||||||
|
float directional_shadow = 1.0;
|
||||||
|
|
||||||
|
if (depth_z < light_split_offsets.y) {
|
||||||
|
float pssm_fade = 0.0;
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
float directional_shadow2 = 1.0;
|
||||||
|
float pssm_blend = 0.0;
|
||||||
|
bool use_blend = true;
|
||||||
|
#endif
|
||||||
|
if (depth_z < light_split_offsets.x) {
|
||||||
|
float pssm_fade = 0.0;
|
||||||
|
directional_shadow = shadow1;
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
directional_shadow2 = shadow2;
|
||||||
|
pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
directional_shadow = shadow2;
|
||||||
|
pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
use_blend = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
if (use_blend) {
|
||||||
|
directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
directional_shadow = mix(directional_shadow, 1.0, pssm_fade);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LIGHT_USE_PSSM2
|
||||||
|
// PSSM4 shadows
|
||||||
|
#ifdef LIGHT_USE_PSSM4
|
||||||
|
float depth_z = -vertex.z;
|
||||||
|
vec4 light_split_offsets = directional_shadows[directional_shadow_index].shadow_split_offsets;
|
||||||
|
|
||||||
|
float shadow1 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
|
||||||
|
float shadow2 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord2);
|
||||||
|
float shadow3 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord3);
|
||||||
|
float shadow4 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord4);
|
||||||
|
float directional_shadow = 1.0;
|
||||||
|
|
||||||
|
if (depth_z < light_split_offsets.w) {
|
||||||
|
float pssm_fade = 0.0;
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
float directional_shadow2 = 1.0;
|
||||||
|
float pssm_blend = 0.0;
|
||||||
|
bool use_blend = true;
|
||||||
|
#endif
|
||||||
|
if (depth_z < light_split_offsets.y) {
|
||||||
|
if (depth_z < light_split_offsets.x) {
|
||||||
|
directional_shadow = shadow1;
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
directional_shadow2 = shadow2;
|
||||||
|
|
||||||
|
pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
directional_shadow = shadow2;
|
||||||
|
|
||||||
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
|
directional_shadow2 = shadow3;
|
||||||
|
|
||||||
|
pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (depth_z < light_split_offsets.z) {
|
||||||
|
directional_shadow = shadow3;
|
||||||
|
|
||||||
|
#if defined(LIGHT_USE_PSSM_BLEND)
|
||||||
|
directional_shadow2 = shadow4;
|
||||||
|
pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else {
|
||||||
|
directional_shadow = shadow4;
|
||||||
|
pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z);
|
||||||
|
|
||||||
|
#if defined(LIGHT_USE_PSSM_BLEND)
|
||||||
|
use_blend = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(LIGHT_USE_PSSM_BLEND)
|
||||||
|
if (use_blend) {
|
||||||
|
directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
directional_shadow = mix(directional_shadow, 1.0, pssm_fade);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LIGHT_USE_PSSM4
|
||||||
|
directional_shadow = mix(directional_shadow, 1.0, smoothstep(directional_shadows[directional_shadow_index].fade_from, directional_shadows[directional_shadow_index].fade_to, vertex.z));
|
||||||
|
directional_shadow = mix(1.0, directional_shadow, directional_lights[directional_shadow_index].shadow_opacity);
|
||||||
|
|
||||||
|
light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha,
|
||||||
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
|
backlight,
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_RIM_USED
|
||||||
|
rim, rim_tint,
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_CLEARCOAT_USED
|
||||||
|
clearcoat, clearcoat_roughness, normalize(normal_interp),
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_ANISOTROPY_USED
|
||||||
|
binormal,
|
||||||
|
tangent, anisotropy,
|
||||||
|
#endif
|
||||||
|
diffuse_light,
|
||||||
|
specular_light);
|
||||||
|
#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
|
#ifdef ADDITIVE_OMNI
|
||||||
|
vec3 light_ray = ((positional_shadows[positional_shadow_index].shadow_matrix * vec4(shadow_coord.xyz, 1.0))).xyz;
|
||||||
|
|
||||||
|
float omni_shadow = texture(omni_shadow_texture, vec4(light_ray, length(light_ray) * omni_lights[omni_light_index].inv_radius));
|
||||||
|
omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity);
|
||||||
|
|
||||||
|
light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
|
||||||
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
|
backlight,
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_RIM_USED
|
||||||
|
rim,
|
||||||
|
rim_tint,
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_CLEARCOAT_USED
|
||||||
|
clearcoat, clearcoat_roughness, normalize(normal_interp),
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_ANISOTROPY_USED
|
||||||
|
binormal, tangent, anisotropy,
|
||||||
|
#endif
|
||||||
|
diffuse_light, specular_light);
|
||||||
|
#endif // ADDITIVE_OMNI
|
||||||
|
|
||||||
|
#ifdef ADDITIVE_SPOT
|
||||||
|
float spot_shadow = sample_shadow(spot_shadow_texture, positional_shadows[positional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
|
||||||
|
spot_shadow = mix(1.0, spot_shadow, spot_lights[spot_light_index].shadow_opacity);
|
||||||
|
|
||||||
|
light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
|
||||||
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
|
backlight,
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_RIM_USED
|
||||||
|
rim,
|
||||||
|
rim_tint,
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_CLEARCOAT_USED
|
||||||
|
clearcoat, clearcoat_roughness, normalize(normal_interp),
|
||||||
|
#endif
|
||||||
|
#ifdef LIGHT_ANISOTROPY_USED
|
||||||
|
tangent,
|
||||||
|
binormal, anisotropy,
|
||||||
|
#endif
|
||||||
|
diffuse_light, specular_light);
|
||||||
|
|
||||||
|
#endif // ADDITIVE_SPOT
|
||||||
|
|
||||||
|
diffuse_light *= albedo;
|
||||||
|
diffuse_light *= 1.0 - metallic;
|
||||||
|
vec3 additive_light_color = diffuse_light + specular_light;
|
||||||
|
|
||||||
|
#ifndef FOG_DISABLED
|
||||||
|
fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
|
||||||
|
|
||||||
|
#ifndef DISABLE_FOG
|
||||||
|
if (scene_data.fog_enabled) {
|
||||||
|
additive_light_color *= (1.0 - fog.a);
|
||||||
|
}
|
||||||
|
#endif // !DISABLE_FOG
|
||||||
|
#endif // !FOG_DISABLED
|
||||||
|
|
||||||
|
// Tonemap before writing as we are writing to an sRGB framebuffer
|
||||||
|
additive_light_color *= exposure;
|
||||||
|
additive_light_color = apply_tonemapping(additive_light_color, white);
|
||||||
|
additive_light_color = linear_to_srgb(additive_light_color);
|
||||||
|
|
||||||
|
#ifdef USE_BCS
|
||||||
|
additive_light_color = apply_bcs(additive_light_color, bcs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_COLOR_CORRECTION
|
||||||
|
additive_light_color = apply_color_correction(additive_light_color, color_correction);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
frag_color.rgb += additive_light_color;
|
||||||
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
#endif //!MODE_RENDER_DEPTH
|
#endif //!MODE_RENDER_DEPTH
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#ifdef GLES3_ENABLED
|
#ifdef GLES3_ENABLED
|
||||||
|
|
||||||
#include "light_storage.h"
|
#include "light_storage.h"
|
||||||
|
#include "../rasterizer_gles3.h"
|
||||||
|
#include "../rasterizer_scene_gles3.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "texture_storage.h"
|
#include "texture_storage.h"
|
||||||
|
|
||||||
|
@ -358,6 +360,20 @@ RID LightStorage::light_instance_create(RID p_light) {
|
||||||
void LightStorage::light_instance_free(RID p_light_instance) {
|
void LightStorage::light_instance_free(RID p_light_instance) {
|
||||||
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
|
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
|
||||||
ERR_FAIL_NULL(light_instance);
|
ERR_FAIL_NULL(light_instance);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
light_instance_owner.free(p_light_instance);
|
light_instance_owner.free(p_light_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,9 +392,26 @@ void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_a
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightStorage::light_instance_mark_visible(RID p_light_instance) {
|
void LightStorage::light_instance_mark_visible(RID p_light_instance) {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PROBE API */
|
/* PROBE API */
|
||||||
|
@ -598,33 +631,466 @@ void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transfo
|
||||||
/* SHADOW ATLAS API */
|
/* SHADOW ATLAS API */
|
||||||
|
|
||||||
RID LightStorage::shadow_atlas_create() {
|
RID LightStorage::shadow_atlas_create() {
|
||||||
return RID();
|
return shadow_atlas_owner.make_rid(ShadowAtlas());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightStorage::shadow_atlas_free(RID p_atlas) {
|
void LightStorage::shadow_atlas_free(RID p_atlas) {
|
||||||
|
shadow_atlas_set_size(p_atlas, 0);
|
||||||
|
shadow_atlas_owner.free(p_atlas);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
|
void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
|
||||||
|
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL(shadow_atlas);
|
||||||
|
ERR_FAIL_COND(p_size < 0);
|
||||||
|
p_size = next_power_of_2(p_size);
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
|
void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
uint32_t subdiv = next_power_of_2(p_subdivision);
|
||||||
|
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_intance, float p_coverage, uint64_t p_light_version) {
|
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;
|
||||||
|
int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
|
||||||
|
|
||||||
|
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.
|
||||||
|
should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
|
||||||
|
|
||||||
|
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);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture_id, 0);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
|
||||||
|
ERR_CONTINUE(!sli);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LightStorage::shadow_atlas_update(RID p_atlas) {
|
void LightStorage::shadow_atlas_update(RID p_atlas) {
|
||||||
|
// Do nothing as there is no shadow atlas texture.
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0);
|
||||||
|
}
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo);
|
||||||
|
RasterizerGLES3::clear_depth(1.0);
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
|
void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
|
||||||
}
|
p_size = nearest_power_of_2_templated(p_size);
|
||||||
|
|
||||||
int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
|
if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) {
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightStorage::set_directional_shadow_count(int p_count) {
|
void LightStorage::set_directional_shadow_count(int p_count) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !GLES3_ENABLED
|
#endif // !GLES3_ENABLED
|
||||||
|
|
|
@ -73,6 +73,19 @@ struct Light {
|
||||||
|
|
||||||
/* Light instance */
|
/* Light instance */
|
||||||
struct LightInstance {
|
struct LightInstance {
|
||||||
|
struct ShadowTransform {
|
||||||
|
Projection camera;
|
||||||
|
Transform3D transform;
|
||||||
|
float farplane;
|
||||||
|
float split;
|
||||||
|
float bias_scale;
|
||||||
|
float shadow_texel_size;
|
||||||
|
float range_begin;
|
||||||
|
Rect2 atlas_rect;
|
||||||
|
Vector2 uv_scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
ShadowTransform shadow_transform[6];
|
||||||
RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
|
RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
|
||||||
|
|
||||||
AABB aabb;
|
AABB aabb;
|
||||||
|
@ -80,10 +93,6 @@ struct LightInstance {
|
||||||
RID light;
|
RID light;
|
||||||
Transform3D transform;
|
Transform3D transform;
|
||||||
|
|
||||||
Vector3 light_vector;
|
|
||||||
Vector3 spot_vector;
|
|
||||||
float linear_att = 0.0;
|
|
||||||
|
|
||||||
uint64_t shadow_pass = 0;
|
uint64_t shadow_pass = 0;
|
||||||
uint64_t last_scene_pass = 0;
|
uint64_t last_scene_pass = 0;
|
||||||
uint64_t last_scene_shadow_pass = 0;
|
uint64_t last_scene_shadow_pass = 0;
|
||||||
|
@ -93,7 +102,10 @@ struct LightInstance {
|
||||||
|
|
||||||
Rect2 directional_rect;
|
Rect2 directional_rect;
|
||||||
|
|
||||||
uint32_t gl_id = -1;
|
HashSet<RID> shadow_atlases; // Shadow atlases where this light is registered.
|
||||||
|
|
||||||
|
int32_t gl_id = -1;
|
||||||
|
int32_t shadow_id = -1;
|
||||||
|
|
||||||
LightInstance() {}
|
LightInstance() {}
|
||||||
};
|
};
|
||||||
|
@ -144,6 +156,14 @@ struct Lightmap {
|
||||||
};
|
};
|
||||||
|
|
||||||
class LightStorage : public RendererLightStorage {
|
class LightStorage : public RendererLightStorage {
|
||||||
|
public:
|
||||||
|
enum ShadowAtlastQuadrant {
|
||||||
|
QUADRANT_SHIFT = 27,
|
||||||
|
OMNI_LIGHT_FLAG = 1 << 26,
|
||||||
|
SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
|
||||||
|
SHADOW_INVALID = 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static LightStorage *singleton;
|
static LightStorage *singleton;
|
||||||
|
|
||||||
|
@ -162,6 +182,63 @@ private:
|
||||||
|
|
||||||
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
||||||
|
|
||||||
|
/* SHADOW ATLAS */
|
||||||
|
|
||||||
|
// Note: The ShadowAtlas in the OpenGL is virtual. Each light gets assigned its
|
||||||
|
// own texture which is the same size as it would be if it were in a real atlas.
|
||||||
|
// This allows us to maintain the same behavior as the other renderers.
|
||||||
|
|
||||||
|
struct ShadowAtlas {
|
||||||
|
struct Quadrant {
|
||||||
|
uint32_t subdivision = 0;
|
||||||
|
|
||||||
|
struct Shadow {
|
||||||
|
RID owner;
|
||||||
|
bool owner_is_omni = false;
|
||||||
|
uint64_t version = 0;
|
||||||
|
uint64_t alloc_tick = 0;
|
||||||
|
|
||||||
|
Shadow() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<Shadow> shadows;
|
||||||
|
LocalVector<GLuint> textures;
|
||||||
|
LocalVector<GLuint> fbos;
|
||||||
|
|
||||||
|
Quadrant() {}
|
||||||
|
} quadrants[4];
|
||||||
|
|
||||||
|
// Ordered from smallest (worst) shadow size to largest (best).
|
||||||
|
int size_order[4] = { 0, 1, 2, 3 };
|
||||||
|
uint32_t smallest_subdiv = 0;
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
bool use_16_bits = true;
|
||||||
|
|
||||||
|
GLuint debug_texture = 0;
|
||||||
|
GLuint debug_fbo = 0;
|
||||||
|
|
||||||
|
HashMap<RID, uint32_t> shadow_owners;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
|
||||||
|
RID_Owner<ShadowAtlas> shadow_atlas_owner;
|
||||||
|
|
||||||
|
void _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);
|
||||||
|
bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, bool p_omni, int &r_quadrant, int &r_shadow);
|
||||||
|
|
||||||
|
/* DIRECTIONAL SHADOW */
|
||||||
|
|
||||||
|
struct DirectionalShadow {
|
||||||
|
GLuint depth = 0;
|
||||||
|
GLuint fbo = 0;
|
||||||
|
|
||||||
|
int light_count = 0;
|
||||||
|
int size = 0;
|
||||||
|
bool use_16_bits = true;
|
||||||
|
int current_light = 0;
|
||||||
|
} directional_shadow;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static LightStorage *get_singleton();
|
static LightStorage *get_singleton();
|
||||||
|
|
||||||
|
@ -307,15 +384,169 @@ public:
|
||||||
virtual void 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 = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
|
virtual void 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 = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
|
||||||
virtual void light_instance_mark_visible(RID p_light_instance) override;
|
virtual void light_instance_mark_visible(RID p_light_instance) override;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->light;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ AABB light_instance_get_base_aabb(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void light_instance_set_cull_mask(RID p_light_instance, uint32_t p_cull_mask) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
li->cull_mask = p_cull_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint32_t light_instance_get_cull_mask(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->cull_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint light_instance_get_shadow_texture(RID p_light_instance, RID p_shadow_atlas) {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
|
||||||
|
#endif
|
||||||
|
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
|
||||||
|
ERR_FAIL_NULL_V(shadow_atlas, 0);
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
|
||||||
|
#endif
|
||||||
|
uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
|
||||||
|
|
||||||
|
uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
|
||||||
|
uint32_t shadow = key & SHADOW_INDEX_MASK;
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), 0);
|
||||||
|
|
||||||
|
return shadow_atlas_get_quadrant_shadow_texture(p_shadow_atlas, quadrant, shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool light_instance_has_shadow_atlas(RID p_light_instance, RID p_shadow_atlas) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_atlases.has(p_shadow_atlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
|
||||||
|
#endif
|
||||||
|
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
|
||||||
|
ERR_FAIL_NULL_V(shadow_atlas, 0);
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
|
||||||
|
#endif
|
||||||
|
uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
|
||||||
|
|
||||||
|
uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
|
||||||
|
|
||||||
|
uint32_t quadrant_size = shadow_atlas->size >> 1;
|
||||||
|
|
||||||
|
uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
|
||||||
|
|
||||||
|
return float(1.0) / shadow_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].transform;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].bias_scale;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].farplane;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].range_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].uv_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
li->shadow_transform[p_index].atlas_rect = p_atlas_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].atlas_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].split;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_transform[p_index].shadow_texel_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
li->last_pass = p_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->last_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void light_instance_set_shadow_pass(RID p_light_instance, uint64_t p_pass) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
li->last_scene_shadow_pass = p_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint64_t light_instance_get_shadow_pass(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->last_scene_shadow_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void light_instance_set_directional_rect(RID p_light_instance, const Rect2 &p_directional_rect) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
li->directional_rect = p_directional_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Rect2 light_instance_get_directional_rect(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->directional_rect;
|
||||||
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
|
_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
|
||||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
return li->light_type;
|
return li->light_type;
|
||||||
}
|
}
|
||||||
_FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
|
|
||||||
|
_FORCE_INLINE_ int32_t light_instance_get_gl_id(RID p_light_instance) {
|
||||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
return li->gl_id;
|
return li->gl_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int32_t light_instance_get_shadow_id(RID p_light_instance) {
|
||||||
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
|
return li->shadow_id;
|
||||||
|
}
|
||||||
|
|
||||||
/* PROBE API */
|
/* PROBE API */
|
||||||
|
|
||||||
virtual RID reflection_probe_allocate() override;
|
virtual RID reflection_probe_allocate() override;
|
||||||
|
@ -389,23 +620,6 @@ public:
|
||||||
virtual void lightmap_set_probe_capture_update_speed(float p_speed) override;
|
virtual void lightmap_set_probe_capture_update_speed(float p_speed) override;
|
||||||
virtual float lightmap_get_probe_capture_update_speed() const override;
|
virtual float lightmap_get_probe_capture_update_speed() const override;
|
||||||
|
|
||||||
/* LIGHT SHADOW MAPPING */
|
|
||||||
/*
|
|
||||||
struct CanvasOccluder {
|
|
||||||
RID self;
|
|
||||||
|
|
||||||
GLuint vertex_id; // 0 means, unconfigured
|
|
||||||
GLuint index_id; // 0 means, unconfigured
|
|
||||||
LocalVector<Vector2> lines;
|
|
||||||
int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
RID_Owner<CanvasOccluder> canvas_occluder_owner;
|
|
||||||
|
|
||||||
RID canvas_light_occluder_create();
|
|
||||||
void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
virtual RID lightmap_instance_create(RID p_lightmap) override;
|
virtual RID lightmap_instance_create(RID p_lightmap) override;
|
||||||
|
@ -413,6 +627,7 @@ public:
|
||||||
virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
|
virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
|
||||||
|
|
||||||
/* SHADOW ATLAS API */
|
/* SHADOW ATLAS API */
|
||||||
|
bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); };
|
||||||
|
|
||||||
virtual RID shadow_atlas_create() override;
|
virtual RID shadow_atlas_create() override;
|
||||||
virtual void shadow_atlas_free(RID p_atlas) override;
|
virtual void shadow_atlas_free(RID p_atlas) override;
|
||||||
|
@ -420,11 +635,151 @@ public:
|
||||||
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
|
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
|
||||||
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
|
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, false);
|
||||||
|
return atlas->shadow_owners.has(p_light_instance);
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_instance) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, -1);
|
||||||
|
return atlas->shadow_owners[p_light_instance];
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
return atlas->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint shadow_atlas_get_debug_fb(RID p_atlas) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
|
||||||
|
if (atlas->debug_fbo != 0) {
|
||||||
|
return atlas->debug_fbo;
|
||||||
|
}
|
||||||
|
glGenFramebuffers(1, &atlas->debug_fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, atlas->debug_fbo);
|
||||||
|
|
||||||
|
if (atlas->debug_texture == 0) {
|
||||||
|
atlas->debug_texture = shadow_atlas_get_debug_texture(p_atlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, atlas->debug_texture);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, atlas->debug_texture, 0);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
return atlas->debug_fbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint shadow_atlas_get_debug_texture(RID p_atlas) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
|
||||||
|
if (atlas->debug_texture != 0) {
|
||||||
|
return atlas->debug_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenTextures(1, &atlas->debug_texture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, atlas->debug_texture);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, atlas->size, atlas->size, 0, GL_RED, GL_UNSIGNED_INT, nullptr);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
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_SWIZZLE_R, GL_RED);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
return atlas->debug_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadows_length(RID p_atlas, uint32_t p_quadrant) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||||
|
return atlas->quadrants[p_quadrant].shadows.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_shadows_allocated(RID p_atlas, uint32_t p_quadrant) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||||
|
return atlas->quadrants[p_quadrant].textures.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||||
|
return atlas->quadrants[p_quadrant].subdivision;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint shadow_atlas_get_quadrant_shadow_texture(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, atlas->quadrants[p_quadrant].textures.size(), 0);
|
||||||
|
return atlas->quadrants[p_quadrant].textures[p_shadow];
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint shadow_atlas_get_quadrant_shadow_fb(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, atlas->quadrants[p_quadrant].fbos.size(), 0);
|
||||||
|
return atlas->quadrants[p_quadrant].fbos[p_shadow];
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, 0);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||||
|
return (atlas->size >> 1) / atlas->quadrants[p_quadrant].subdivision;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool shadow_atlas_get_quadrant_shadow_is_omni(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
|
||||||
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
|
ERR_FAIL_NULL_V(atlas, false);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, false);
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, (uint32_t)atlas->quadrants[p_quadrant].shadows.size(), false);
|
||||||
|
return atlas->quadrants[p_quadrant].shadows[p_shadow].owner_is_omni;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void shadow_atlas_update(RID p_atlas) override;
|
virtual void shadow_atlas_update(RID p_atlas) override;
|
||||||
|
|
||||||
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
|
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
|
||||||
virtual int get_directional_light_shadow_size(RID p_light_intance) override;
|
virtual int get_directional_light_shadow_size(RID p_light_intance) override;
|
||||||
virtual void set_directional_shadow_count(int p_count) override;
|
virtual void set_directional_shadow_count(int p_count) override;
|
||||||
|
|
||||||
|
Rect2i get_directional_shadow_rect();
|
||||||
|
void update_directional_shadow_atlas();
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint directional_shadow_get_texture() {
|
||||||
|
return directional_shadow.depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int directional_shadow_get_size() {
|
||||||
|
return directional_shadow.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint direction_shadow_get_fb() {
|
||||||
|
return directional_shadow.fbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void directional_shadow_increase_current_light() {
|
||||||
|
directional_shadow.current_light++;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace GLES3
|
} // namespace GLES3
|
||||||
|
|
|
@ -172,10 +172,6 @@ AABB Light3D::get_aabb() const {
|
||||||
PackedStringArray Light3D::get_configuration_warnings() const {
|
PackedStringArray Light3D::get_configuration_warnings() const {
|
||||||
PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
|
PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
|
||||||
|
|
||||||
if (has_shadow() && OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
|
|
||||||
warnings.push_back(RTR("Shadows are not supported when using the GL Compatibility backend yet. Support will be added in a future release."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) {
|
if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) {
|
||||||
warnings.push_back(RTR("A light's scale does not affect the visual size of the light."));
|
warnings.push_back(RTR("A light's scale does not affect the visual size of the light."));
|
||||||
}
|
}
|
||||||
|
|
|
@ -677,8 +677,7 @@ public:
|
||||||
return li->shadow_transform[p_index].camera;
|
return li->shadow_transform[p_index].camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ Transform3D
|
_FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
|
||||||
light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
|
|
||||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||||
return li->shadow_transform[p_index].transform;
|
return li->shadow_transform[p_index].transform;
|
||||||
}
|
}
|
||||||
|
@ -1005,15 +1004,15 @@ public:
|
||||||
virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
|
virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
|
||||||
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
|
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
|
||||||
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
|
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
|
||||||
_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
|
_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) {
|
||||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
ERR_FAIL_NULL_V(atlas, false);
|
ERR_FAIL_NULL_V(atlas, false);
|
||||||
return atlas->shadow_owners.has(p_light_intance);
|
return atlas->shadow_owners.has(p_light_instance);
|
||||||
}
|
}
|
||||||
_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_intance) {
|
_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_instance) {
|
||||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||||
ERR_FAIL_NULL_V(atlas, -1);
|
ERR_FAIL_NULL_V(atlas, -1);
|
||||||
return atlas->shadow_owners[p_light_intance];
|
return atlas->shadow_owners[p_light_instance];
|
||||||
}
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
|
_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
|
||||||
|
@ -1053,7 +1052,7 @@ public:
|
||||||
/* DIRECTIONAL SHADOW */
|
/* DIRECTIONAL SHADOW */
|
||||||
|
|
||||||
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
|
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
|
||||||
virtual int get_directional_light_shadow_size(RID p_light_intance) override;
|
virtual int get_directional_light_shadow_size(RID p_light_instance) override;
|
||||||
virtual void set_directional_shadow_count(int p_count) override;
|
virtual void set_directional_shadow_count(int p_count) override;
|
||||||
|
|
||||||
Rect2i get_directional_shadow_rect();
|
Rect2i get_directional_shadow_rect();
|
||||||
|
|
Loading…
Reference in a new issue