You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Implement shadowmasks for LightmapGI
Co-authored-by: dearthdev <nathandearthdev@gmail.com>
This commit is contained in:
@@ -69,6 +69,11 @@
|
|||||||
The quality preset to use when baking lightmaps. This affects bake times, but output file sizes remain mostly identical across quality levels.
|
The quality preset to use when baking lightmaps. This affects bake times, but output file sizes remain mostly identical across quality levels.
|
||||||
To further speed up bake times, decrease [member bounces], disable [member use_denoiser] and increase the lightmap texel size on 3D scenes in the Import dock.
|
To further speed up bake times, decrease [member bounces], disable [member use_denoiser] and increase the lightmap texel size on 3D scenes in the Import dock.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="shadowmask_mode" type="int" setter="set_shadowmask_mode" getter="get_shadowmask_mode" enum="LightmapGIData.ShadowmaskMode" default="0" experimental="">
|
||||||
|
The shadowmasking policy to use for directional shadows on static objects that are baked with this [LightmapGI] instance.
|
||||||
|
Shadowmasking allows [DirectionalLight3D] nodes to cast shadows even outside the range defined by their [member DirectionalLight3D.directional_shadow_max_distance] property. This is done by baking a texture that contains a shadowmap for the directional light, then using this texture according to the current shadowmask mode.
|
||||||
|
[b]Note:[/b] The shadowmask texture is only created if [member shadowmask_mode] is not [constant LightmapGIData.SHADOWMASK_MODE_NONE]. To see a difference, you need to bake lightmaps again after switching from [constant LightmapGIData.SHADOWMASK_MODE_NONE] to any other mode.
|
||||||
|
</member>
|
||||||
<member name="texel_scale" type="float" setter="set_texel_scale" getter="get_texel_scale" default="1.0">
|
<member name="texel_scale" type="float" setter="set_texel_scale" getter="get_texel_scale" default="1.0">
|
||||||
Scales the lightmap texel density of all meshes for the current bake. This is a multiplier that builds upon the existing lightmap texel size defined in each imported 3D scene, along with the per-mesh density multiplier (which is designed to be used when the same mesh is used at different scales). Lower values will result in faster bake times.
|
Scales the lightmap texel density of all meshes for the current bake. This is a multiplier that builds upon the existing lightmap texel size defined in each imported 3D scene, along with the per-mesh density multiplier (which is designed to be used when the same mesh is used at different scales). Lower values will result in faster bake times.
|
||||||
For example, doubling [member texel_scale] doubles the lightmap texture resolution for all objects [i]on each axis[/i], so it will [i]quadruple[/i] the texel count.
|
For example, doubling [member texel_scale] doubles the lightmap texture resolution for all objects [i]on each axis[/i], so it will [i]quadruple[/i] the texel count.
|
||||||
|
|||||||
@@ -60,5 +60,19 @@
|
|||||||
<member name="lightmap_textures" type="TextureLayered[]" setter="set_lightmap_textures" getter="get_lightmap_textures" default="[]">
|
<member name="lightmap_textures" type="TextureLayered[]" setter="set_lightmap_textures" getter="get_lightmap_textures" default="[]">
|
||||||
The lightmap atlas textures generated by the lightmapper.
|
The lightmap atlas textures generated by the lightmapper.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="shadowmask_textures" type="TextureLayered[]" setter="set_shadowmask_textures" getter="get_shadowmask_textures" default="[]">
|
||||||
|
The shadowmask atlas textures generated by the lightmapper.
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
<constants>
|
||||||
|
<constant name="SHADOWMASK_MODE_NONE" value="0" enum="ShadowmaskMode">
|
||||||
|
Shadowmasking is disabled. No shadowmask texture will be created when baking lightmaps. Existing shadowmask textures will be removed during baking.
|
||||||
|
</constant>
|
||||||
|
<constant name="SHADOWMASK_MODE_REPLACE" value="1" enum="ShadowmaskMode">
|
||||||
|
Shadowmasking is enabled. Directional shadows that are outside the [member DirectionalLight3D.directional_shadow_max_distance] will be rendered using the shadowmask texture. Shadows that are inside the range will be rendered using real-time shadows exclusively. This mode allows for more precise real-time shadows up close, without the potential "smearing" effect that can occur when using lightmaps with a high texel size. The downside is that when the camera moves fast, the transition between the real-time light and shadowmask can be obvious. Also, objects that only have shadows baked in the shadowmask (and no real-time shadows) won't display any shadows up close.
|
||||||
|
</constant>
|
||||||
|
<constant name="SHADOWMASK_MODE_OVERLAY" value="2" enum="ShadowmaskMode">
|
||||||
|
Shadowmasking is enabled. Directional shadows will be rendered with real-time shadows overlaid on top of the shadowmask texture. This mode makes for smoother shadow transitions when the camera moves fast, at the cost of a potential smearing effect for directional shadows that are up close (due to the real-time shadow being mixed with a low-resolution shadowmask). Objects that only have shadows baked in the shadowmask (and no real-time shadows) will keep their shadows up close.
|
||||||
|
</constant>
|
||||||
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|||||||
@@ -2660,14 +2660,14 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||||||
glBlitFramebuffer(0, 0, size.x, size.y,
|
glBlitFramebuffer(0, 0, size.x, size.y,
|
||||||
0, 0, size.x, size.y,
|
0, 0, size.x, size.y,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
|
||||||
glBindTexture(GL_TEXTURE_2D, backbuffer);
|
glBindTexture(GL_TEXTURE_2D, backbuffer);
|
||||||
}
|
}
|
||||||
if (scene_state.used_depth_texture) {
|
if (scene_state.used_depth_texture) {
|
||||||
glBlitFramebuffer(0, 0, size.x, size.y,
|
glBlitFramebuffer(0, 0, size.x, size.y,
|
||||||
0, 0, size.x, size.y,
|
0, 0, size.x, size.y,
|
||||||
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
|
||||||
glBindTexture(GL_TEXTURE_2D, backbuffer_depth);
|
glBindTexture(GL_TEXTURE_2D, backbuffer_depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3245,8 +3245,28 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||||||
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_OMNI;
|
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_OMNI;
|
||||||
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_SPOT;
|
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_SPOT;
|
||||||
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
|
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
|
||||||
spec_constants |= SceneShaderGLES3::DISABLE_LIGHTMAP;
|
|
||||||
spec_constants |= SceneShaderGLES3::DISABLE_REFLECTION_PROBE;
|
spec_constants |= SceneShaderGLES3::DISABLE_REFLECTION_PROBE;
|
||||||
|
|
||||||
|
bool disable_lightmaps = true;
|
||||||
|
|
||||||
|
// Additive directional passes may use shadowmasks, so enable lightmaps for them.
|
||||||
|
if (pass >= int32_t(inst->light_passes.size()) && inst->lightmap_instance.is_valid()) {
|
||||||
|
GLES3::LightmapInstance *li = GLES3::LightStorage::get_singleton()->get_lightmap_instance(inst->lightmap_instance);
|
||||||
|
GLES3::Lightmap *lm = GLES3::LightStorage::get_singleton()->get_lightmap(li->lightmap);
|
||||||
|
|
||||||
|
if (lm->shadowmask_mode != RS::SHADOWMASK_MODE_NONE) {
|
||||||
|
spec_constants |= SceneShaderGLES3::USE_LIGHTMAP;
|
||||||
|
disable_lightmaps = false;
|
||||||
|
|
||||||
|
if (lightmap_bicubic_upscale) {
|
||||||
|
spec_constants |= SceneShaderGLES3::LIGHTMAP_BICUBIC_FILTER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disable_lightmaps) {
|
||||||
|
spec_constants |= SceneShaderGLES3::DISABLE_LIGHTMAP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uses_additive_lighting) {
|
if (uses_additive_lighting) {
|
||||||
@@ -3341,6 +3361,33 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||||||
GLuint tex = GLES3::LightStorage::get_singleton()->directional_shadow_get_texture();
|
GLuint tex = GLES3::LightStorage::get_singleton()->directional_shadow_get_texture();
|
||||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 3);
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 3);
|
||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
|
|
||||||
|
if (inst->lightmap_instance.is_valid()) {
|
||||||
|
// Use shadowmasks for directional light passes.
|
||||||
|
GLES3::LightmapInstance *li = GLES3::LightStorage::get_singleton()->get_lightmap_instance(inst->lightmap_instance);
|
||||||
|
GLES3::Lightmap *lm = GLES3::LightStorage::get_singleton()->get_lightmap(li->lightmap);
|
||||||
|
|
||||||
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_SLICE, inst->lightmap_slice_index, shader->version, instance_variant, spec_constants);
|
||||||
|
|
||||||
|
Vector4 uv_scale(inst->lightmap_uv_scale.position.x, inst->lightmap_uv_scale.position.y, inst->lightmap_uv_scale.size.x, inst->lightmap_uv_scale.size.y);
|
||||||
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_UV_SCALE, uv_scale, shader->version, instance_variant, spec_constants);
|
||||||
|
|
||||||
|
if (lightmap_bicubic_upscale) {
|
||||||
|
Vector2 light_texture_size(lm->light_texture_size.x, lm->light_texture_size.y);
|
||||||
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_TEXTURE_SIZE, light_texture_size, shader->version, instance_variant, spec_constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_SHADOWMASK_MODE, (uint32_t)lm->shadowmask_mode, shader->version, instance_variant, spec_constants);
|
||||||
|
|
||||||
|
if (lm->shadow_texture.is_valid()) {
|
||||||
|
tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(lm->shadow_texture);
|
||||||
|
} else {
|
||||||
|
tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(GLES3::TextureStorage::get_singleton()->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3399,6 +3446,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||||||
};
|
};
|
||||||
glUniformMatrix3fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_NORMAL_XFORM, shader->version, instance_variant, spec_constants), 1, GL_FALSE, matrix);
|
glUniformMatrix3fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_NORMAL_XFORM, shader->version, instance_variant, spec_constants), 1, GL_FALSE, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (inst->lightmap_sh) {
|
} else if (inst->lightmap_sh) {
|
||||||
glUniform4fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURES, shader->version, instance_variant, spec_constants), 9, reinterpret_cast<const GLfloat *>(inst->lightmap_sh->sh));
|
glUniform4fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURES, shader->version, instance_variant, spec_constants), 9, reinterpret_cast<const GLfloat *>(inst->lightmap_sh->sh));
|
||||||
}
|
}
|
||||||
@@ -3430,7 +3478,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||||||
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE1_AMBIENT_COLOR, probe->ambient_color * probe->ambient_color_energy, shader->version, instance_variant, spec_constants);
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE1_AMBIENT_COLOR, probe->ambient_color * probe->ambient_color_energy, shader->version, instance_variant, spec_constants);
|
||||||
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE1_LOCAL_MATRIX, inst->reflection_probes_local_transform_cache[0], shader->version, instance_variant, spec_constants);
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE1_LOCAL_MATRIX, inst->reflection_probes_local_transform_cache[0], shader->version, instance_variant, spec_constants);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 8);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, light_storage->reflection_probe_instance_get_texture(inst->reflection_probe_rid_cache[0]));
|
glBindTexture(GL_TEXTURE_CUBE_MAP, light_storage->reflection_probe_instance_get_texture(inst->reflection_probe_rid_cache[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3448,7 +3496,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||||||
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE2_AMBIENT_COLOR, probe->ambient_color * probe->ambient_color_energy, shader->version, instance_variant, spec_constants);
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE2_AMBIENT_COLOR, probe->ambient_color * probe->ambient_color_energy, shader->version, instance_variant, spec_constants);
|
||||||
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE2_LOCAL_MATRIX, inst->reflection_probes_local_transform_cache[1], shader->version, instance_variant, spec_constants);
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::REFPROBE2_LOCAL_MATRIX, inst->reflection_probes_local_transform_cache[1], shader->version, instance_variant, spec_constants);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 8);
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 9);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, light_storage->reflection_probe_instance_get_texture(inst->reflection_probe_rid_cache[1]));
|
glBindTexture(GL_TEXTURE_CUBE_MAP, light_storage->reflection_probe_instance_get_texture(inst->reflection_probe_rid_cache[1]));
|
||||||
|
|
||||||
spec_constants |= SceneShaderGLES3::SECOND_REFLECTION_PROBE;
|
spec_constants |= SceneShaderGLES3::SECOND_REFLECTION_PROBE;
|
||||||
|
|||||||
@@ -809,10 +809,11 @@ void main() {
|
|||||||
2-radiance
|
2-radiance
|
||||||
3-shadow
|
3-shadow
|
||||||
4-lightmap textures
|
4-lightmap textures
|
||||||
5-screen
|
5-shadowmask textures
|
||||||
6-depth
|
6-screen
|
||||||
7-reflection probe 1
|
7-depth
|
||||||
8-reflection probe 2
|
8-reflection probe 1
|
||||||
|
9-reflection probe 2
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -887,7 +888,7 @@ uniform float refprobe1_intensity;
|
|||||||
uniform int refprobe1_ambient_mode;
|
uniform int refprobe1_ambient_mode;
|
||||||
uniform vec4 refprobe1_ambient_color;
|
uniform vec4 refprobe1_ambient_color;
|
||||||
|
|
||||||
uniform samplerCube refprobe1_texture; // texunit:-7
|
uniform samplerCube refprobe1_texture; // texunit:-8
|
||||||
|
|
||||||
#ifdef SECOND_REFLECTION_PROBE
|
#ifdef SECOND_REFLECTION_PROBE
|
||||||
|
|
||||||
@@ -900,7 +901,7 @@ uniform float refprobe2_intensity;
|
|||||||
uniform int refprobe2_ambient_mode;
|
uniform int refprobe2_ambient_mode;
|
||||||
uniform vec4 refprobe2_ambient_color;
|
uniform vec4 refprobe2_ambient_color;
|
||||||
|
|
||||||
uniform samplerCube refprobe2_texture; // texunit:-8
|
uniform samplerCube refprobe2_texture; // texunit:-9
|
||||||
|
|
||||||
#endif // SECOND_REFLECTION_PROBE
|
#endif // SECOND_REFLECTION_PROBE
|
||||||
|
|
||||||
@@ -1170,9 +1171,16 @@ float sample_shadow(highp sampler2DShadow shadow, float shadow_pixel_size, vec4
|
|||||||
#ifndef DISABLE_LIGHTMAP
|
#ifndef DISABLE_LIGHTMAP
|
||||||
#ifdef USE_LIGHTMAP
|
#ifdef USE_LIGHTMAP
|
||||||
uniform mediump sampler2DArray lightmap_textures; //texunit:-4
|
uniform mediump sampler2DArray lightmap_textures; //texunit:-4
|
||||||
|
uniform lowp sampler2DArray shadowmask_textures; //texunit:-5
|
||||||
uniform lowp uint lightmap_slice;
|
uniform lowp uint lightmap_slice;
|
||||||
uniform highp vec4 lightmap_uv_scale;
|
uniform highp vec4 lightmap_uv_scale;
|
||||||
uniform float lightmap_exposure_normalization;
|
uniform float lightmap_exposure_normalization;
|
||||||
|
uniform uint lightmap_shadowmask_mode;
|
||||||
|
|
||||||
|
#define SHADOWMASK_MODE_NONE uint(0)
|
||||||
|
#define SHADOWMASK_MODE_REPLACE uint(1)
|
||||||
|
#define SHADOWMASK_MODE_OVERLAY uint(2)
|
||||||
|
#define SHADOWMASK_MODE_ONLY uint(3)
|
||||||
|
|
||||||
#ifdef LIGHTMAP_BICUBIC_FILTER
|
#ifdef LIGHTMAP_BICUBIC_FILTER
|
||||||
uniform highp vec2 lightmap_texture_size;
|
uniform highp vec2 lightmap_texture_size;
|
||||||
@@ -1189,8 +1197,8 @@ uniform mediump vec4[9] lightmap_captures;
|
|||||||
#endif // !DISABLE_LIGHTMAP
|
#endif // !DISABLE_LIGHTMAP
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
uniform highp sampler2DArray depth_buffer; // texunit:-6
|
uniform highp sampler2DArray depth_buffer; // texunit:-7
|
||||||
uniform highp sampler2DArray color_buffer; // texunit:-5
|
uniform highp sampler2DArray color_buffer; // texunit:-6
|
||||||
vec3 multiview_uv(vec2 uv) {
|
vec3 multiview_uv(vec2 uv) {
|
||||||
return vec3(uv, ViewIndex);
|
return vec3(uv, ViewIndex);
|
||||||
}
|
}
|
||||||
@@ -1198,8 +1206,8 @@ ivec3 multiview_uv(ivec2 uv) {
|
|||||||
return ivec3(uv, int(ViewIndex));
|
return ivec3(uv, int(ViewIndex));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
uniform highp sampler2D depth_buffer; // texunit:-6
|
uniform highp sampler2D depth_buffer; // texunit:-7
|
||||||
uniform highp sampler2D color_buffer; // texunit:-5
|
uniform highp sampler2D color_buffer; // texunit:-6
|
||||||
vec2 multiview_uv(vec2 uv) {
|
vec2 multiview_uv(vec2 uv) {
|
||||||
return uv;
|
return uv;
|
||||||
}
|
}
|
||||||
@@ -2278,111 +2286,146 @@ void main() {
|
|||||||
#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
|
#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
#ifndef SHADOWS_DISABLED
|
#ifndef SHADOWS_DISABLED
|
||||||
|
// Baked shadowmasks
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
float shadowmask = 1.0f;
|
||||||
|
|
||||||
|
if (lightmap_shadowmask_mode != SHADOWMASK_MODE_NONE) {
|
||||||
|
vec3 uvw;
|
||||||
|
uvw.xy = uv2 * lightmap_uv_scale.zw + lightmap_uv_scale.xy;
|
||||||
|
uvw.z = float(lightmap_slice);
|
||||||
|
|
||||||
|
#ifdef LIGHTMAP_BICUBIC_FILTER
|
||||||
|
shadowmask = textureArray_bicubic(shadowmask_textures, uvw, lightmap_texture_size).x;
|
||||||
|
#else
|
||||||
|
shadowmask = textureLod(shadowmask_textures, uvw, 0.0).x;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //USE_LIGHTMAP
|
||||||
|
|
||||||
|
float directional_shadow = 1.0;
|
||||||
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
if (lightmap_shadowmask_mode != SHADOWMASK_MODE_ONLY) {
|
||||||
|
#endif
|
||||||
|
|
||||||
// Orthogonal shadows
|
// Orthogonal shadows
|
||||||
#if !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
|
#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);
|
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)
|
#endif // !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
|
||||||
|
|
||||||
// PSSM2 shadows
|
// PSSM2 shadows
|
||||||
#ifdef LIGHT_USE_PSSM2
|
#ifdef LIGHT_USE_PSSM2
|
||||||
float depth_z = -vertex.z;
|
float depth_z = -vertex.z;
|
||||||
vec4 light_split_offsets = directional_shadows[directional_shadow_index].shadow_split_offsets;
|
vec4 light_split_offsets = directional_shadows[directional_shadow_index].shadow_split_offsets;
|
||||||
//take advantage of prefetch
|
//take advantage of prefetch
|
||||||
float shadow1 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
|
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 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) {
|
|
||||||
|
|
||||||
#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) {
|
|
||||||
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
|
|
||||||
use_blend = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef LIGHT_USE_PSSM_BLEND
|
|
||||||
if (use_blend) {
|
|
||||||
directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#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) {
|
|
||||||
|
|
||||||
#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.y) {
|
||||||
|
|
||||||
|
#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) {
|
if (depth_z < light_split_offsets.x) {
|
||||||
directional_shadow = shadow1;
|
directional_shadow = shadow1;
|
||||||
|
|
||||||
#ifdef LIGHT_USE_PSSM_BLEND
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
directional_shadow2 = shadow2;
|
directional_shadow2 = shadow2;
|
||||||
|
|
||||||
pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
|
pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
directional_shadow = shadow2;
|
directional_shadow = shadow2;
|
||||||
|
|
||||||
#ifdef LIGHT_USE_PSSM_BLEND
|
#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;
|
|
||||||
|
|
||||||
#if defined(LIGHT_USE_PSSM_BLEND)
|
|
||||||
use_blend = false;
|
use_blend = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
#ifdef LIGHT_USE_PSSM_BLEND
|
||||||
#if defined(LIGHT_USE_PSSM_BLEND)
|
if (use_blend) {
|
||||||
if (use_blend) {
|
directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
|
||||||
directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
if (depth_z < light_split_offsets.w) {
|
||||||
|
#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;
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
#endif //LIGHT_USE_PSSM4
|
#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));
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
if (lightmap_shadowmask_mode == SHADOWMASK_MODE_REPLACE) {
|
||||||
|
directional_shadow = mix(directional_shadow, shadowmask, smoothstep(directional_shadows[directional_shadow_index].fade_from, directional_shadows[directional_shadow_index].fade_to, vertex.z));
|
||||||
|
} else if (lightmap_shadowmask_mode == SHADOWMASK_MODE_OVERLAY) {
|
||||||
|
directional_shadow = shadowmask * mix(directional_shadow, 1.0, smoothstep(directional_shadows[directional_shadow_index].fade_from, directional_shadows[directional_shadow_index].fade_to, vertex.z));
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
directional_shadow = mix(directional_shadow, 1.0, smoothstep(directional_shadows[directional_shadow_index].fade_from, directional_shadows[directional_shadow_index].fade_to, vertex.z));
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // lightmap_shadowmask_mode == SHADOWMASK_MODE_ONLY
|
||||||
|
directional_shadow = shadowmask;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
directional_shadow = mix(1.0, directional_shadow, directional_lights[directional_shadow_index].shadow_opacity);
|
directional_shadow = mix(1.0, directional_shadow, directional_lights[directional_shadow_index].shadow_opacity);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1204,6 +1204,33 @@ float LightStorage::lightmap_get_probe_capture_update_speed() const {
|
|||||||
return lightmap_probe_capture_update_speed;
|
return lightmap_probe_capture_update_speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightStorage::lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) {
|
||||||
|
Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL(lightmap);
|
||||||
|
lightmap->shadow_texture = p_shadow;
|
||||||
|
|
||||||
|
GLuint tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(lightmap->shadow_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS::ShadowmaskMode LightStorage::lightmap_get_shadowmask_mode(RID p_lightmap) {
|
||||||
|
Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL_V(lightmap, RS::SHADOWMASK_MODE_NONE);
|
||||||
|
|
||||||
|
return lightmap->shadowmask_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightStorage::lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) {
|
||||||
|
Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL(lightmap);
|
||||||
|
lightmap->shadowmask_mode = p_mode;
|
||||||
|
}
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
RID LightStorage::lightmap_instance_create(RID p_lightmap) {
|
RID LightStorage::lightmap_instance_create(RID p_lightmap) {
|
||||||
|
|||||||
@@ -177,12 +177,14 @@ struct ReflectionProbeInstance {
|
|||||||
|
|
||||||
struct Lightmap {
|
struct Lightmap {
|
||||||
RID light_texture;
|
RID light_texture;
|
||||||
|
RID shadow_texture;
|
||||||
bool uses_spherical_harmonics = false;
|
bool uses_spherical_harmonics = false;
|
||||||
bool interior = false;
|
bool interior = false;
|
||||||
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
|
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
|
||||||
float baked_exposure = 1.0;
|
float baked_exposure = 1.0;
|
||||||
Vector2i light_texture_size;
|
Vector2i light_texture_size;
|
||||||
int32_t array_index = -1; //unassigned
|
int32_t array_index = -1; //unassigned
|
||||||
|
RS::ShadowmaskMode shadowmask_mode = RS::SHADOWMASK_MODE_NONE;
|
||||||
PackedVector3Array points;
|
PackedVector3Array points;
|
||||||
PackedColorArray point_sh;
|
PackedColorArray point_sh;
|
||||||
PackedInt32Array tetrahedra;
|
PackedInt32Array tetrahedra;
|
||||||
@@ -231,8 +233,6 @@ private:
|
|||||||
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
|
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
|
||||||
|
|
||||||
/* LIGHTMAP */
|
/* LIGHTMAP */
|
||||||
|
|
||||||
Vector<RID> lightmap_textures;
|
|
||||||
float lightmap_probe_capture_update_speed = 4;
|
float lightmap_probe_capture_update_speed = 4;
|
||||||
|
|
||||||
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
||||||
@@ -737,6 +737,10 @@ 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;
|
||||||
|
|
||||||
|
virtual void lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) override;
|
||||||
|
virtual RS::ShadowmaskMode lightmap_get_shadowmask_mode(RID p_lightmap) override;
|
||||||
|
virtual void lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) override;
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
LightmapInstance *get_lightmap_instance(RID p_rid) { return lightmap_instance_owner.get_or_null(p_rid); }
|
LightmapInstance *get_lightmap_instance(RID p_rid) { return lightmap_instance_owner.get_or_null(p_rid); }
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ void LightmapperRD::add_mesh(const MeshData &p_mesh) {
|
|||||||
mesh_instances.push_back(mi);
|
mesh_instances.push_back(mi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) {
|
void LightmapperRD::add_directional_light(const String &p_name, bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) {
|
||||||
Light l;
|
Light l;
|
||||||
l.type = LIGHT_TYPE_DIRECTIONAL;
|
l.type = LIGHT_TYPE_DIRECTIONAL;
|
||||||
l.direction[0] = p_direction.x;
|
l.direction[0] = p_direction.x;
|
||||||
@@ -77,9 +77,10 @@ void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direct
|
|||||||
l.size = Math::tan(Math::deg_to_rad(p_angular_distance));
|
l.size = Math::tan(Math::deg_to_rad(p_angular_distance));
|
||||||
l.shadow_blur = p_shadow_blur;
|
l.shadow_blur = p_shadow_blur;
|
||||||
lights.push_back(l);
|
lights.push_back(l);
|
||||||
|
light_names.push_back(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) {
|
void LightmapperRD::add_omni_light(const String &p_name, bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) {
|
||||||
Light l;
|
Light l;
|
||||||
l.type = LIGHT_TYPE_OMNI;
|
l.type = LIGHT_TYPE_OMNI;
|
||||||
l.position[0] = p_position.x;
|
l.position[0] = p_position.x;
|
||||||
@@ -96,9 +97,10 @@ void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, con
|
|||||||
l.size = p_size;
|
l.size = p_size;
|
||||||
l.shadow_blur = p_shadow_blur;
|
l.shadow_blur = p_shadow_blur;
|
||||||
lights.push_back(l);
|
lights.push_back(l);
|
||||||
|
light_names.push_back(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) {
|
void LightmapperRD::add_spot_light(const String &p_name, bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) {
|
||||||
Light l;
|
Light l;
|
||||||
l.type = LIGHT_TYPE_SPOT;
|
l.type = LIGHT_TYPE_SPOT;
|
||||||
l.position[0] = p_position.x;
|
l.position[0] = p_position.x;
|
||||||
@@ -120,6 +122,7 @@ void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, con
|
|||||||
l.size = p_size;
|
l.size = p_size;
|
||||||
l.shadow_blur = p_shadow_blur;
|
l.shadow_blur = p_shadow_blur;
|
||||||
lights.push_back(l);
|
lights.push_back(l);
|
||||||
|
light_names.push_back(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightmapperRD::add_probe(const Vector3 &p_position) {
|
void LightmapperRD::add_probe(const Vector3 &p_position) {
|
||||||
@@ -826,9 +829,9 @@ LightmapperRD::BakeError LightmapperRD::_pack_l1(RenderingDevice *rd, Ref<RDShad
|
|||||||
return BAKE_OK;
|
return BAKE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error LightmapperRD::_store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name) {
|
Error LightmapperRD::_store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask) {
|
||||||
Vector<uint8_t> data = p_rd->texture_get_data(p_atlas_tex, p_index);
|
Vector<uint8_t> data = p_rd->texture_get_data(p_atlas_tex, p_index);
|
||||||
Ref<Image> img = Image::create_from_data(p_atlas_size.width, p_atlas_size.height, false, Image::FORMAT_RGBAH, data);
|
Ref<Image> img = Image::create_from_data(p_atlas_size.width, p_atlas_size.height, false, p_shadowmask ? Image::FORMAT_RGBA8 : Image::FORMAT_RGBAH, data);
|
||||||
img->convert(Image::FORMAT_RGBF);
|
img->convert(Image::FORMAT_RGBF);
|
||||||
Vector<uint8_t> data_float = img->get_data();
|
Vector<uint8_t> data_float = img->get_data();
|
||||||
|
|
||||||
@@ -848,7 +851,7 @@ Error LightmapperRD::_store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_in
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Image> LightmapperRD::_read_pfm(const String &p_name) {
|
Ref<Image> LightmapperRD::_read_pfm(const String &p_name, bool p_shadowmask) {
|
||||||
Error err = OK;
|
Error err = OK;
|
||||||
Ref<FileAccess> file = FileAccess::open(p_name, FileAccess::READ, &err);
|
Ref<FileAccess> file = FileAccess::open(p_name, FileAccess::READ, &err);
|
||||||
ERR_FAIL_COND_V_MSG(err, Ref<Image>(), vformat("Can't load PFM at path: '%s'.", p_name));
|
ERR_FAIL_COND_V_MSG(err, Ref<Image>(), vformat("Can't load PFM at path: '%s'.", p_name));
|
||||||
@@ -881,23 +884,23 @@ Ref<Image> LightmapperRD::_read_pfm(const String &p_name) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Ref<Image> img = Image::create_from_data(new_width, new_height, false, Image::FORMAT_RGBF, new_data);
|
Ref<Image> img = Image::create_from_data(new_width, new_height, false, Image::FORMAT_RGBF, new_data);
|
||||||
img->convert(Image::FORMAT_RGBAH);
|
img->convert(p_shadowmask ? Image::FORMAT_RGBA8 : Image::FORMAT_RGBAH);
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, const String &p_exe) {
|
LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, bool p_shadowmask, const String &p_exe) {
|
||||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
|
|
||||||
for (int i = 0; i < p_atlas_slices; i++) {
|
for (int i = 0; i < p_atlas_slices; i++) {
|
||||||
String fname_norm_in = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_norm_%d.pfm", i));
|
String fname_norm_in = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_norm_%d.pfm", i));
|
||||||
_store_pfm(p_rd, p_source_normal_tex, i, p_atlas_size, fname_norm_in);
|
_store_pfm(p_rd, p_source_normal_tex, i, p_atlas_size, fname_norm_in, false);
|
||||||
|
|
||||||
for (int j = 0; j < (p_bake_sh ? 4 : 1); j++) {
|
for (int j = 0; j < (p_bake_sh ? 4 : 1); j++) {
|
||||||
int index = i * (p_bake_sh ? 4 : 1) + j;
|
int index = i * (p_bake_sh ? 4 : 1) + j;
|
||||||
String fname_light_in = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_light_%d.pfm", index));
|
String fname_light_in = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_light_%d.pfm", index));
|
||||||
String fname_out = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_denoised_%d.pfm", index));
|
String fname_out = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_denoised_%d.pfm", index));
|
||||||
|
|
||||||
_store_pfm(p_rd, p_source_light_tex, index, p_atlas_size, fname_light_in);
|
_store_pfm(p_rd, p_source_light_tex, index, p_atlas_size, fname_light_in, p_shadowmask);
|
||||||
|
|
||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back("--device");
|
args.push_back("--device");
|
||||||
@@ -906,7 +909,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID
|
|||||||
args.push_back("--filter");
|
args.push_back("--filter");
|
||||||
args.push_back("RTLightmap");
|
args.push_back("RTLightmap");
|
||||||
|
|
||||||
args.push_back("--hdr");
|
args.push_back(p_shadowmask ? "--ldr" : "--hdr");
|
||||||
args.push_back(fname_light_in);
|
args.push_back(fname_light_in);
|
||||||
|
|
||||||
args.push_back("--nrm");
|
args.push_back("--nrm");
|
||||||
@@ -928,7 +931,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID
|
|||||||
ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat("OIDN denoiser failed, return code: %d", exitcode));
|
ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat("OIDN denoiser failed, return code: %d", exitcode));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Image> img = _read_pfm(fname_out);
|
Ref<Image> img = _read_pfm(fname_out, p_shadowmask);
|
||||||
da->remove(fname_out);
|
da->remove(fname_out);
|
||||||
|
|
||||||
ERR_FAIL_COND_V(img.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
|
ERR_FAIL_COND_V(img.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
|
||||||
@@ -1029,7 +1032,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
|
|||||||
return BAKE_OK;
|
return BAKE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) {
|
LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_bake_shadowmask, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) {
|
||||||
int denoiser = GLOBAL_GET("rendering/lightmapping/denoising/denoiser");
|
int denoiser = GLOBAL_GET("rendering/lightmapping/denoising/denoiser");
|
||||||
String oidn_path = EDITOR_GET("filesystem/tools/oidn/oidn_denoise_path");
|
String oidn_path = EDITOR_GET("filesystem/tools/oidn/oidn_denoise_path");
|
||||||
|
|
||||||
@@ -1050,7 +1053,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
if (p_step_function) {
|
if (p_step_function) {
|
||||||
p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true);
|
p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true);
|
||||||
}
|
}
|
||||||
bake_textures.clear();
|
lightmap_textures.clear();
|
||||||
|
shadowmask_textures.clear();
|
||||||
int grid_size = 128;
|
int grid_size = 128;
|
||||||
|
|
||||||
/* STEP 1: Fetch material textures and compute the bounds */
|
/* STEP 1: Fetch material textures and compute the bounds */
|
||||||
@@ -1066,6 +1070,35 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
return bake_error;
|
return bake_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The index of the directional light used for shadowmasking.
|
||||||
|
int shadowmask_light_idx = -1;
|
||||||
|
|
||||||
|
// If there are no valid directional lights for shadowmasking, the entire
|
||||||
|
// scene would be shadowed and this saves baking time.
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
int shadowmask_lights_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < lights.size(); i++) {
|
||||||
|
if (lights[i].type == LightType::LIGHT_TYPE_DIRECTIONAL && !lights[i].static_bake) {
|
||||||
|
if (shadowmask_light_idx < 0) {
|
||||||
|
shadowmask_light_idx = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowmask_lights_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowmask_light_idx < 0) {
|
||||||
|
p_bake_shadowmask = false;
|
||||||
|
WARN_PRINT("Shadowmask disabled: no directional light with their bake mode set to dynamic exists.");
|
||||||
|
|
||||||
|
} else if (shadowmask_lights_count > 1) {
|
||||||
|
WARN_PRINT(
|
||||||
|
vformat("%d directional lights detected for shadowmask baking. Only %s will be used.",
|
||||||
|
shadowmask_lights_count, light_names[shadowmask_light_idx]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_TEXTURES
|
#ifdef DEBUG_TEXTURES
|
||||||
for (int i = 0; i < atlas_slices; i++) {
|
for (int i = 0; i < atlas_slices; i++) {
|
||||||
albedo_images[i]->save_png("res://0_albedo_" + itos(i) + ".png");
|
albedo_images[i]->save_png("res://0_albedo_" + itos(i) + ".png");
|
||||||
@@ -1119,17 +1152,23 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
RID light_accum_tex;
|
RID light_accum_tex;
|
||||||
RID light_accum_tex2;
|
RID light_accum_tex2;
|
||||||
RID light_environment_tex;
|
RID light_environment_tex;
|
||||||
|
RID shadowmask_tex;
|
||||||
|
RID shadowmask_tex2;
|
||||||
|
|
||||||
#define FREE_TEXTURES \
|
#define FREE_TEXTURES \
|
||||||
rd->free(albedo_array_tex); \
|
rd->free(albedo_array_tex); \
|
||||||
rd->free(emission_array_tex); \
|
rd->free(emission_array_tex); \
|
||||||
rd->free(normal_tex); \
|
rd->free(normal_tex); \
|
||||||
rd->free(position_tex); \
|
rd->free(position_tex); \
|
||||||
rd->free(unocclude_tex); \
|
rd->free(unocclude_tex); \
|
||||||
rd->free(light_source_tex); \
|
rd->free(light_source_tex); \
|
||||||
rd->free(light_accum_tex2); \
|
rd->free(light_accum_tex2); \
|
||||||
rd->free(light_accum_tex); \
|
rd->free(light_accum_tex); \
|
||||||
rd->free(light_environment_tex);
|
rd->free(light_environment_tex); \
|
||||||
|
if (p_bake_shadowmask) { \
|
||||||
|
rd->free(shadowmask_tex); \
|
||||||
|
rd->free(shadowmask_tex2); \
|
||||||
|
}
|
||||||
|
|
||||||
{ // create all textures
|
{ // create all textures
|
||||||
|
|
||||||
@@ -1161,9 +1200,22 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
position_tex = rd->texture_create(tf, RD::TextureView());
|
position_tex = rd->texture_create(tf, RD::TextureView());
|
||||||
unocclude_tex = rd->texture_create(tf, RD::TextureView());
|
unocclude_tex = rd->texture_create(tf, RD::TextureView());
|
||||||
|
|
||||||
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
|
|
||||||
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
|
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
|
||||||
|
|
||||||
|
// shadowmask
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
|
||||||
|
shadowmask_tex = rd->texture_create(tf, RD::TextureView());
|
||||||
|
rd->texture_clear(shadowmask_tex, Color(0, 0, 0, 0), 0, 1, 0, atlas_slices);
|
||||||
|
|
||||||
|
shadowmask_tex2 = rd->texture_create(tf, RD::TextureView());
|
||||||
|
rd->texture_clear(shadowmask_tex2, Color(0, 0, 0, 0), 0, 1, 0, atlas_slices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lightmap
|
||||||
|
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
|
||||||
|
|
||||||
light_source_tex = rd->texture_create(tf, RD::TextureView());
|
light_source_tex = rd->texture_create(tf, RD::TextureView());
|
||||||
rd->texture_clear(light_source_tex, Color(0, 0, 0, 0), 0, 1, 0, atlas_slices);
|
rd->texture_clear(light_source_tex, Color(0, 0, 0, 0), 0, 1, 0, atlas_slices);
|
||||||
|
|
||||||
@@ -1266,6 +1318,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
bake_parameters.exposure_normalization = p_exposure_normalization;
|
bake_parameters.exposure_normalization = p_exposure_normalization;
|
||||||
bake_parameters.bounces = p_bounces;
|
bake_parameters.bounces = p_bounces;
|
||||||
bake_parameters.bounce_indirect_energy = p_bounce_indirect_energy;
|
bake_parameters.bounce_indirect_energy = p_bounce_indirect_energy;
|
||||||
|
bake_parameters.shadowmask_light_idx = shadowmask_light_idx;
|
||||||
|
|
||||||
bake_parameters_buffer = rd->uniform_buffer_create(sizeof(BakeParameters));
|
bake_parameters_buffer = rd->uniform_buffer_create(sizeof(BakeParameters));
|
||||||
rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters);
|
rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters);
|
||||||
@@ -1463,6 +1516,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
defines += "\n#define USE_LIGHT_TEXTURE_FOR_BOUNCES\n";
|
defines += "\n#define USE_LIGHT_TEXTURE_FOR_BOUNCES\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
defines += "\n#define USE_SHADOWMASK\n";
|
||||||
|
}
|
||||||
|
|
||||||
compute_shader.instantiate();
|
compute_shader.instantiate();
|
||||||
err = compute_shader->parse_versions_from_text(lm_compute_shader_glsl, defines);
|
err = compute_shader->parse_versions_from_text(lm_compute_shader_glsl, defines);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
@@ -1634,6 +1691,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
u.append_id(light_accum_tex);
|
u.append_id(light_accum_tex);
|
||||||
uniforms.push_back(u);
|
uniforms.push_back(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
RD::Uniform u;
|
||||||
|
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||||
|
u.binding = 5;
|
||||||
|
u.append_id(shadowmask_tex);
|
||||||
|
uniforms.push_back(u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RID light_uniform_set = rd->uniform_set_create(uniforms, compute_shader_primary, 1);
|
RID light_uniform_set = rd->uniform_set_create(uniforms, compute_shader_primary, 1);
|
||||||
@@ -1945,7 +2010,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
BakeError error;
|
BakeError error;
|
||||||
if (denoiser == 1) {
|
if (denoiser == 1) {
|
||||||
// OIDN (external).
|
// OIDN (external).
|
||||||
error = _denoise_oidn(rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh, oidn_path);
|
error = _denoise_oidn(rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh, false, oidn_path);
|
||||||
} else {
|
} else {
|
||||||
// JNLM (built-in).
|
// JNLM (built-in).
|
||||||
SWAP(light_accum_tex, light_accum_tex2);
|
SWAP(light_accum_tex, light_accum_tex2);
|
||||||
@@ -1955,14 +2020,39 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
BakeError error;
|
||||||
|
if (denoiser == 1) {
|
||||||
|
// OIDN (external).
|
||||||
|
error = _denoise_oidn(rd, shadowmask_tex, normal_tex, shadowmask_tex, atlas_size, atlas_slices, false, true, oidn_path);
|
||||||
|
} else {
|
||||||
|
// JNLM (built-in).
|
||||||
|
SWAP(shadowmask_tex, shadowmask_tex2);
|
||||||
|
error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, shadowmask_tex2, normal_tex, shadowmask_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, false, p_step_function, p_bake_userdata);
|
||||||
|
}
|
||||||
|
if (unlikely(error != BAKE_OK)) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* DILATE */
|
||||||
|
|
||||||
{
|
{
|
||||||
SWAP(light_accum_tex, light_accum_tex2);
|
SWAP(light_accum_tex, light_accum_tex2);
|
||||||
BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
|
BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
|
||||||
if (unlikely(error != BAKE_OK)) {
|
if (unlikely(error != BAKE_OK)) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
SWAP(shadowmask_tex, shadowmask_tex2);
|
||||||
|
error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, shadowmask_tex2, shadowmask_tex, atlas_size, atlas_slices);
|
||||||
|
if (unlikely(error != BAKE_OK)) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_TEXTURES
|
#ifdef DEBUG_TEXTURES
|
||||||
@@ -2139,6 +2229,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
img->save_exr("res://5_blendseams" + itos(i) + ".exr", false);
|
img->save_exr("res://5_blendseams" + itos(i) + ".exr", false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (p_step_function) {
|
if (p_step_function) {
|
||||||
p_step_function(0.9, RTR("Retrieving textures"), p_bake_userdata, true);
|
p_step_function(0.9, RTR("Retrieving textures"), p_bake_userdata, true);
|
||||||
}
|
}
|
||||||
@@ -2147,7 +2238,16 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
|
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
|
||||||
Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
|
Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
|
||||||
img->convert(Image::FORMAT_RGBH); //remove alpha
|
img->convert(Image::FORMAT_RGBH); //remove alpha
|
||||||
bake_textures.push_back(img);
|
lightmap_textures.push_back(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_bake_shadowmask) {
|
||||||
|
for (int i = 0; i < atlas_slices; i++) {
|
||||||
|
Vector<uint8_t> s = rd->texture_get_data(shadowmask_tex, i);
|
||||||
|
Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBA8, s);
|
||||||
|
img->convert(Image::FORMAT_R8);
|
||||||
|
shadowmask_textures.push_back(img);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (probe_positions.size() > 0) {
|
if (probe_positions.size() > 0) {
|
||||||
@@ -2180,12 +2280,21 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||||||
}
|
}
|
||||||
|
|
||||||
int LightmapperRD::get_bake_texture_count() const {
|
int LightmapperRD::get_bake_texture_count() const {
|
||||||
return bake_textures.size();
|
return lightmap_textures.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Image> LightmapperRD::get_bake_texture(int p_index) const {
|
Ref<Image> LightmapperRD::get_bake_texture(int p_index) const {
|
||||||
ERR_FAIL_INDEX_V(p_index, bake_textures.size(), Ref<Image>());
|
ERR_FAIL_INDEX_V(p_index, lightmap_textures.size(), Ref<Image>());
|
||||||
return bake_textures[p_index];
|
return lightmap_textures[p_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int LightmapperRD::get_shadowmask_texture_count() const {
|
||||||
|
return shadowmask_textures.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Image> LightmapperRD::get_shadowmask_texture(int p_index) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_index, shadowmask_textures.size(), Ref<Image>());
|
||||||
|
return shadowmask_textures[p_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
int LightmapperRD::get_bake_mesh_count() const {
|
int LightmapperRD::get_bake_mesh_count() const {
|
||||||
@@ -2198,9 +2307,9 @@ Variant LightmapperRD::get_bake_mesh_userdata(int p_index) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rect2 LightmapperRD::get_bake_mesh_uv_scale(int p_index) const {
|
Rect2 LightmapperRD::get_bake_mesh_uv_scale(int p_index) const {
|
||||||
ERR_FAIL_COND_V(bake_textures.is_empty(), Rect2());
|
ERR_FAIL_COND_V(lightmap_textures.is_empty(), Rect2());
|
||||||
Rect2 uv_ofs;
|
Rect2 uv_ofs;
|
||||||
Vector2 atlas_size = Vector2(bake_textures[0]->get_width(), bake_textures[0]->get_height());
|
Vector2 atlas_size = Vector2(lightmap_textures[0]->get_width(), lightmap_textures[0]->get_height());
|
||||||
uv_ofs.position = Vector2(mesh_instances[p_index].offset) / atlas_size;
|
uv_ofs.position = Vector2(mesh_instances[p_index].offset) / atlas_size;
|
||||||
uv_ofs.size = Vector2(mesh_instances[p_index].data.albedo_on_uv2->get_width(), mesh_instances[p_index].data.albedo_on_uv2->get_height()) / atlas_size;
|
uv_ofs.size = Vector2(mesh_instances[p_index].data.albedo_on_uv2->get_width(), mesh_instances[p_index].data.albedo_on_uv2->get_height()) / atlas_size;
|
||||||
return uv_ofs;
|
return uv_ofs;
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class LightmapperRD : public Lightmapper {
|
|||||||
uint32_t bounces = 0;
|
uint32_t bounces = 0;
|
||||||
|
|
||||||
float bounce_indirect_energy = 0.0f;
|
float bounce_indirect_energy = 0.0f;
|
||||||
uint32_t pad[3] = {};
|
int shadowmask_light_idx = 0;
|
||||||
|
uint32_t pad[2] = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MeshInstance {
|
struct MeshInstance {
|
||||||
@@ -202,6 +203,7 @@ class LightmapperRD : public Lightmapper {
|
|||||||
Vector<MeshInstance> mesh_instances;
|
Vector<MeshInstance> mesh_instances;
|
||||||
|
|
||||||
Vector<Light> lights;
|
Vector<Light> lights;
|
||||||
|
Vector<String> light_names;
|
||||||
|
|
||||||
struct TriangleSort {
|
struct TriangleSort {
|
||||||
uint32_t cell_index = 0;
|
uint32_t cell_index = 0;
|
||||||
@@ -253,7 +255,8 @@ class LightmapperRD : public Lightmapper {
|
|||||||
uint32_t pad = 0;
|
uint32_t pad = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<Ref<Image>> bake_textures;
|
Vector<Ref<Image>> lightmap_textures;
|
||||||
|
Vector<Ref<Image>> shadowmask_textures;
|
||||||
Vector<Color> probe_values;
|
Vector<Color> probe_values;
|
||||||
|
|
||||||
struct DenoiseParams {
|
struct DenoiseParams {
|
||||||
@@ -275,20 +278,22 @@ class LightmapperRD : public Lightmapper {
|
|||||||
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
|
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
|
||||||
BakeError _pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
|
BakeError _pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
|
||||||
|
|
||||||
Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name);
|
Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask);
|
||||||
Ref<Image> _read_pfm(const String &p_name);
|
Ref<Image> _read_pfm(const String &p_name, bool p_shadowmask);
|
||||||
BakeError _denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, const String &p_exe);
|
BakeError _denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, bool p_shadowmask, const String &p_exe);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void add_mesh(const MeshData &p_mesh) override;
|
virtual void add_mesh(const MeshData &p_mesh) override;
|
||||||
virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) override;
|
virtual void add_directional_light(const String &p_name, bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) override;
|
||||||
virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override;
|
virtual void add_omni_light(const String &p_name, bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override;
|
||||||
virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override;
|
virtual void add_spot_light(const String &p_name, bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override;
|
||||||
virtual void add_probe(const Vector3 &p_position) override;
|
virtual void add_probe(const Vector3 &p_position) override;
|
||||||
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override;
|
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_bake_shadowmask, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override;
|
||||||
|
|
||||||
int get_bake_texture_count() const override;
|
int get_bake_texture_count() const override;
|
||||||
Ref<Image> get_bake_texture(int p_index) const override;
|
Ref<Image> get_bake_texture(int p_index) const override;
|
||||||
|
int get_shadowmask_texture_count() const override;
|
||||||
|
Ref<Image> get_shadowmask_texture(int p_index) const override;
|
||||||
int get_bake_mesh_count() const override;
|
int get_bake_mesh_count() const override;
|
||||||
Variant get_bake_mesh_userdata(int p_index) const override;
|
Variant get_bake_mesh_userdata(int p_index) const override;
|
||||||
Rect2 get_bake_mesh_uv_scale(int p_index) const override;
|
Rect2 get_bake_mesh_uv_scale(int p_index) const override;
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ layout(set = 0, binding = 0) uniform BakeParameters {
|
|||||||
uint bounces;
|
uint bounces;
|
||||||
|
|
||||||
float bounce_indirect_energy;
|
float bounce_indirect_energy;
|
||||||
|
int shadowmask_light_idx;
|
||||||
|
uint pad0;
|
||||||
|
uint pad1;
|
||||||
}
|
}
|
||||||
bake_params;
|
bake_params;
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ layout(rgba16f, set = 1, binding = 4) uniform restrict image2DArray accum_light;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODE_BOUNCE_LIGHT
|
#if defined(MODE_DIRECT_LIGHT) && defined(USE_SHADOWMASK)
|
||||||
|
layout(rgba8, set = 1, binding = 5) uniform restrict writeonly image2DArray shadowmask;
|
||||||
|
#elif defined(MODE_BOUNCE_LIGHT)
|
||||||
layout(set = 1, binding = 5) uniform texture2D environment;
|
layout(set = 1, binding = 5) uniform texture2D environment;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -389,8 +391,9 @@ vec2 get_vogel_disk(float p_i, float p_rotation, float p_sample_count_sqrt) {
|
|||||||
return vec2(cos(theta), sin(theta)) * r;
|
return vec2(cos(theta), sin(theta)) * r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool p_soft_shadowing, out vec3 r_light, out vec3 r_light_dir, inout uint r_noise, float p_texel_size) {
|
void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool p_soft_shadowing, out vec3 r_light, out vec3 r_light_dir, inout uint r_noise, float p_texel_size, out float r_shadow) {
|
||||||
r_light = vec3(0.0f);
|
r_light = vec3(0.0f);
|
||||||
|
r_shadow = 0.0f;
|
||||||
|
|
||||||
vec3 light_pos;
|
vec3 light_pos;
|
||||||
float dist;
|
float dist;
|
||||||
@@ -507,6 +510,7 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r_shadow = penumbra;
|
||||||
r_light = light_data.color * light_data.energy * attenuation * penumbra;
|
r_light = light_data.color * light_data.energy * attenuation * penumbra;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,7 +560,8 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f
|
|||||||
for (uint i = 0; i < bake_params.light_count; i++) {
|
for (uint i = 0; i < bake_params.light_count; i++) {
|
||||||
vec3 light;
|
vec3 light;
|
||||||
vec3 light_dir;
|
vec3 light_dir;
|
||||||
trace_direct_light(position, normal, i, false, light, light_dir, r_noise, p_texel_size);
|
float shadow;
|
||||||
|
trace_direct_light(position, normal, i, false, light, light_dir, r_noise, p_texel_size, shadow);
|
||||||
direct_light += light * lights.data[i].indirect_energy;
|
direct_light += light * lights.data[i].indirect_energy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +619,6 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODE_DIRECT_LIGHT
|
#ifdef MODE_DIRECT_LIGHT
|
||||||
|
|
||||||
vec3 normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
|
vec3 normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
|
||||||
if (length(normal) < 0.5) {
|
if (length(normal) < 0.5) {
|
||||||
return; //empty texel, no process
|
return; //empty texel, no process
|
||||||
@@ -631,6 +635,10 @@ void main() {
|
|||||||
vec3 light_for_texture = vec3(0.0);
|
vec3 light_for_texture = vec3(0.0);
|
||||||
vec3 light_for_bounces = vec3(0.0);
|
vec3 light_for_bounces = vec3(0.0);
|
||||||
|
|
||||||
|
#ifdef USE_SHADOWMASK
|
||||||
|
float shadowmask_value = 0.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SH_LIGHTMAPS
|
#ifdef USE_SH_LIGHTMAPS
|
||||||
vec4 sh_accum[4] = vec4[](
|
vec4 sh_accum[4] = vec4[](
|
||||||
vec4(0.0, 0.0, 0.0, 1.0),
|
vec4(0.0, 0.0, 0.0, 1.0),
|
||||||
@@ -644,7 +652,8 @@ void main() {
|
|||||||
for (uint i = 0; i < bake_params.light_count; i++) {
|
for (uint i = 0; i < bake_params.light_count; i++) {
|
||||||
vec3 light;
|
vec3 light;
|
||||||
vec3 light_dir;
|
vec3 light_dir;
|
||||||
trace_direct_light(position, normal, i, true, light, light_dir, noise, texel_size_world_space);
|
float shadow;
|
||||||
|
trace_direct_light(position, normal, i, true, light, light_dir, noise, texel_size_world_space, shadow);
|
||||||
|
|
||||||
if (lights.data[i].static_bake) {
|
if (lights.data[i].static_bake) {
|
||||||
light_for_texture += light;
|
light_for_texture += light;
|
||||||
@@ -669,6 +678,12 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
light_for_bounces += light * lights.data[i].indirect_energy;
|
light_for_bounces += light * lights.data[i].indirect_energy;
|
||||||
|
|
||||||
|
#ifdef USE_SHADOWMASK
|
||||||
|
if (lights.data[i].type == LIGHT_TYPE_DIRECTIONAL && i == bake_params.shadowmask_light_idx) {
|
||||||
|
shadowmask_value = max(shadowmask_value, shadow);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
light_for_bounces *= bake_params.exposure_normalization;
|
light_for_bounces *= bake_params.exposure_normalization;
|
||||||
@@ -685,6 +700,10 @@ void main() {
|
|||||||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), vec4(light_for_texture, 1.0));
|
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), vec4(light_for_texture, 1.0));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SHADOWMASK
|
||||||
|
imageStore(shadowmask, ivec3(atlas_pos, params.atlas_slice), vec4(shadowmask_value, shadowmask_value, shadowmask_value, 1.0));
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODE_BOUNCE_LIGHT
|
#ifdef MODE_BOUNCE_LIGHT
|
||||||
@@ -850,7 +869,7 @@ void main() {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODE_DILATE
|
#if defined(MODE_DILATE)
|
||||||
|
|
||||||
vec4 c = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0);
|
vec4 c = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0);
|
||||||
//sides first, as they are closer
|
//sides first, as they are closer
|
||||||
|
|||||||
@@ -130,6 +130,52 @@ TypedArray<TextureLayered> LightmapGIData::get_lightmap_textures() const {
|
|||||||
return storage_light_textures;
|
return storage_light_textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightmapGIData::set_shadowmask_textures(const TypedArray<TextureLayered> &p_data) {
|
||||||
|
storage_shadowmask_textures = p_data;
|
||||||
|
|
||||||
|
if (p_data.is_empty()) {
|
||||||
|
combined_shadowmask_texture = Ref<TextureLayered>();
|
||||||
|
_reset_shadowmask_textures();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_data.size() == 1) {
|
||||||
|
combined_shadowmask_texture = p_data[0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Vector<Ref<Image>> images;
|
||||||
|
for (int i = 0; i < p_data.size(); i++) {
|
||||||
|
Ref<TextureLayered> texture = p_data[i];
|
||||||
|
ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i));
|
||||||
|
for (int j = 0; j < texture->get_layers(); j++) {
|
||||||
|
images.push_back(texture->get_layer_data(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Texture2DArray> combined_texture;
|
||||||
|
combined_texture.instantiate();
|
||||||
|
|
||||||
|
combined_texture->create_from_images(images);
|
||||||
|
combined_shadowmask_texture = combined_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
_reset_shadowmask_textures();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedArray<TextureLayered> LightmapGIData::get_shadowmask_textures() const {
|
||||||
|
return storage_shadowmask_textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightmapGIData::clear_shadowmask_textures() {
|
||||||
|
RS::get_singleton()->lightmap_set_shadowmask_textures(lightmap, RID());
|
||||||
|
storage_shadowmask_textures.clear();
|
||||||
|
combined_shadowmask_texture.unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LightmapGIData::has_shadowmask_textures() {
|
||||||
|
return !storage_shadowmask_textures.is_empty() && combined_shadowmask_texture.is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
RID LightmapGIData::get_rid() const {
|
RID LightmapGIData::get_rid() const {
|
||||||
return lightmap;
|
return lightmap;
|
||||||
}
|
}
|
||||||
@@ -142,6 +188,10 @@ void LightmapGIData::_reset_lightmap_textures() {
|
|||||||
RS::get_singleton()->lightmap_set_textures(lightmap, combined_light_texture.is_valid() ? combined_light_texture->get_rid() : RID(), uses_spherical_harmonics);
|
RS::get_singleton()->lightmap_set_textures(lightmap, combined_light_texture.is_valid() ? combined_light_texture->get_rid() : RID(), uses_spherical_harmonics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightmapGIData::_reset_shadowmask_textures() {
|
||||||
|
RS::get_singleton()->lightmap_set_shadowmask_textures(lightmap, combined_shadowmask_texture.is_valid() ? combined_shadowmask_texture->get_rid() : RID());
|
||||||
|
}
|
||||||
|
|
||||||
void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
|
void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
|
||||||
uses_spherical_harmonics = p_enable;
|
uses_spherical_harmonics = p_enable;
|
||||||
_reset_lightmap_textures();
|
_reset_lightmap_textures();
|
||||||
@@ -159,6 +209,14 @@ bool LightmapGIData::_is_using_packed_directional() const {
|
|||||||
return _uses_packed_directional;
|
return _uses_packed_directional;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightmapGIData::update_shadowmask_mode(ShadowmaskMode p_mode) {
|
||||||
|
RS::get_singleton()->lightmap_set_shadowmask_mode(lightmap, (RS::ShadowmaskMode)p_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
LightmapGIData::ShadowmaskMode LightmapGIData::get_shadowmask_mode() const {
|
||||||
|
return (ShadowmaskMode)RS::get_singleton()->lightmap_get_shadowmask_mode(lightmap);
|
||||||
|
}
|
||||||
|
|
||||||
void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure) {
|
void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure) {
|
||||||
if (p_points.size()) {
|
if (p_points.size()) {
|
||||||
int pc = p_points.size();
|
int pc = p_points.size();
|
||||||
@@ -260,6 +318,9 @@ void LightmapGIData::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("set_lightmap_textures", "light_textures"), &LightmapGIData::set_lightmap_textures);
|
ClassDB::bind_method(D_METHOD("set_lightmap_textures", "light_textures"), &LightmapGIData::set_lightmap_textures);
|
||||||
ClassDB::bind_method(D_METHOD("get_lightmap_textures"), &LightmapGIData::get_lightmap_textures);
|
ClassDB::bind_method(D_METHOD("get_lightmap_textures"), &LightmapGIData::get_lightmap_textures);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_shadowmask_textures", "shadowmask_textures"), &LightmapGIData::set_shadowmask_textures);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_shadowmask_textures"), &LightmapGIData::get_shadowmask_textures);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
|
ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
|
||||||
ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
|
ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
|
||||||
|
|
||||||
@@ -275,6 +336,7 @@ void LightmapGIData::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
|
ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), "set_lightmap_textures", "get_lightmap_textures");
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), "set_lightmap_textures", "get_lightmap_textures");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "shadowmask_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), "set_shadowmask_textures", "get_shadowmask_textures");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
|
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
|
||||||
@@ -290,6 +352,10 @@ void LightmapGIData::_bind_methods() {
|
|||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_NONE), "set_light_texture", "get_light_texture");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_NONE), "set_light_texture", "get_light_texture");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(SHADOWMASK_MODE_NONE);
|
||||||
|
BIND_ENUM_CONSTANT(SHADOWMASK_MODE_REPLACE);
|
||||||
|
BIND_ENUM_CONSTANT(SHADOWMASK_MODE_OVERLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
LightmapGIData::LightmapGIData() {
|
LightmapGIData::LightmapGIData() {
|
||||||
@@ -738,12 +804,12 @@ void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_compress) const {
|
LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_is_shadowmask, bool p_compress) const {
|
||||||
Vector<Ref<Image>> images;
|
Vector<Ref<Image>> images;
|
||||||
images.resize(p_lightmapper->get_bake_texture_count());
|
images.resize(p_is_shadowmask ? p_lightmapper->get_shadowmask_texture_count() : p_lightmapper->get_bake_texture_count());
|
||||||
|
|
||||||
for (int i = 0; i < images.size(); i++) {
|
for (int i = 0; i < images.size(); i++) {
|
||||||
images.set(i, p_lightmapper->get_bake_texture(i));
|
images.set(i, p_is_shadowmask ? p_lightmapper->get_shadowmask_texture(i) : p_lightmapper->get_bake_texture(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
const int slice_count = images.size();
|
const int slice_count = images.size();
|
||||||
@@ -765,7 +831,7 @@ LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Li
|
|||||||
texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
|
texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
|
||||||
}
|
}
|
||||||
|
|
||||||
const String atlas_path = (texture_count > 1 ? p_base_name + "_" + itos(i) : p_base_name) + ".exr";
|
const String atlas_path = (texture_count > 1 ? p_base_name + "_" + itos(i) : p_base_name) + (p_is_shadowmask ? ".png" : ".exr");
|
||||||
const String config_path = atlas_path + ".import";
|
const String config_path = atlas_path + ".import";
|
||||||
|
|
||||||
Ref<ConfigFile> config;
|
Ref<ConfigFile> config;
|
||||||
@@ -790,7 +856,12 @@ LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Li
|
|||||||
config->save(config_path);
|
config->save(config_path);
|
||||||
|
|
||||||
// Save the file.
|
// Save the file.
|
||||||
Error save_err = texture_image->save_exr(atlas_path, false);
|
Error save_err;
|
||||||
|
if (p_is_shadowmask) {
|
||||||
|
save_err = texture_image->save_png(atlas_path);
|
||||||
|
} else {
|
||||||
|
save_err = texture_image->save_exr(atlas_path, false);
|
||||||
|
}
|
||||||
|
|
||||||
ERR_FAIL_COND_V(save_err, LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE);
|
ERR_FAIL_COND_V(save_err, LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE);
|
||||||
|
|
||||||
@@ -1104,20 +1175,20 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||||||
if (Object::cast_to<DirectionalLight3D>(light)) {
|
if (Object::cast_to<DirectionalLight3D>(light)) {
|
||||||
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
|
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
|
||||||
if (l->get_sky_mode() != DirectionalLight3D::SKY_MODE_SKY_ONLY) {
|
if (l->get_sky_mode() != DirectionalLight3D::SKY_MODE_SKY_ONLY) {
|
||||||
lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, indirect_energy, l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
|
lightmapper->add_directional_light(light->get_name(), light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, indirect_energy, l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
|
||||||
}
|
}
|
||||||
} else if (Object::cast_to<OmniLight3D>(light)) {
|
} else if (Object::cast_to<OmniLight3D>(light)) {
|
||||||
OmniLight3D *l = Object::cast_to<OmniLight3D>(light);
|
OmniLight3D *l = Object::cast_to<OmniLight3D>(light);
|
||||||
if (use_physical_light_units) {
|
if (use_physical_light_units) {
|
||||||
energy *= (1.0 / (Math_PI * 4.0));
|
energy *= (1.0 / (Math_PI * 4.0));
|
||||||
}
|
}
|
||||||
lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy, indirect_energy, l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
|
lightmapper->add_omni_light(light->get_name(), light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy, indirect_energy, l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
|
||||||
} else if (Object::cast_to<SpotLight3D>(light)) {
|
} else if (Object::cast_to<SpotLight3D>(light)) {
|
||||||
SpotLight3D *l = Object::cast_to<SpotLight3D>(light);
|
SpotLight3D *l = Object::cast_to<SpotLight3D>(light);
|
||||||
if (use_physical_light_units) {
|
if (use_physical_light_units) {
|
||||||
energy *= (1.0 / Math_PI);
|
energy *= (1.0 / Math_PI);
|
||||||
}
|
}
|
||||||
lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, indirect_energy, l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
|
lightmapper->add_spot_light(light->get_name(), light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, indirect_energy, l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < probes_found.size(); i++) {
|
for (int i = 0; i < probes_found.size(); i++) {
|
||||||
@@ -1181,7 +1252,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, denoiser_strength, denoiser_range, bounces, bounce_indirect_energy, bias, max_texture_size, directional, use_texture_for_bounces, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization);
|
Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, denoiser_strength, denoiser_range, bounces, bounce_indirect_energy, bias, max_texture_size, directional, shadowmask_mode != LightmapGIData::SHADOWMASK_MODE_NONE, use_texture_for_bounces, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization);
|
||||||
|
|
||||||
if (bake_err == Lightmapper::BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE) {
|
if (bake_err == Lightmapper::BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE) {
|
||||||
return BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL;
|
return BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL;
|
||||||
@@ -1196,15 +1267,23 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||||||
// POSTBAKE: Save Textures.
|
// POSTBAKE: Save Textures.
|
||||||
|
|
||||||
TypedArray<TextureLayered> lightmap_textures;
|
TypedArray<TextureLayered> lightmap_textures;
|
||||||
|
TypedArray<TextureLayered> shadowmask_textures;
|
||||||
|
|
||||||
const String texture_filename = p_image_data_path.get_basename();
|
const String texture_filename = p_image_data_path.get_basename();
|
||||||
|
const int shadowmask_texture_count = lightmapper->get_shadowmask_texture_count();
|
||||||
|
const bool save_shadowmask = shadowmask_mode != LightmapGIData::SHADOWMASK_MODE_NONE && shadowmask_texture_count > 0;
|
||||||
|
|
||||||
// Save the lightmap atlases.
|
// Save the lightmap atlases.
|
||||||
BakeError save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename, lightmap_textures, false);
|
BakeError save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename, lightmap_textures, false, false);
|
||||||
ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err);
|
ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err);
|
||||||
|
|
||||||
// POSTBAKE: Save Light Data.
|
if (save_shadowmask) {
|
||||||
|
// Save the shadowmask atlases.
|
||||||
|
save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename + "_shadow", shadowmask_textures, true, true);
|
||||||
|
ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* POSTBAKE: Save Light Data. */
|
||||||
Ref<LightmapGIData> gi_data;
|
Ref<LightmapGIData> gi_data;
|
||||||
|
|
||||||
if (get_light_data().is_valid()) {
|
if (get_light_data().is_valid()) {
|
||||||
@@ -1217,6 +1296,13 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
gi_data->set_lightmap_textures(lightmap_textures);
|
gi_data->set_lightmap_textures(lightmap_textures);
|
||||||
|
|
||||||
|
if (save_shadowmask) {
|
||||||
|
gi_data->set_shadowmask_textures(shadowmask_textures);
|
||||||
|
} else {
|
||||||
|
gi_data->clear_shadowmask_textures();
|
||||||
|
}
|
||||||
|
|
||||||
gi_data->set_uses_spherical_harmonics(directional);
|
gi_data->set_uses_spherical_harmonics(directional);
|
||||||
gi_data->_set_uses_packed_directional(directional); // New SH lightmaps are packed automatically.
|
gi_data->_set_uses_packed_directional(directional); // New SH lightmaps are packed automatically.
|
||||||
|
|
||||||
@@ -1375,6 +1461,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_light_data(gi_data);
|
set_light_data(gi_data);
|
||||||
|
update_configuration_warnings();
|
||||||
|
|
||||||
return BAKE_ERROR_OK;
|
return BAKE_ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -1452,6 +1539,7 @@ void LightmapGI::set_light_data(const Ref<LightmapGIData> &p_data) {
|
|||||||
if (is_inside_tree()) {
|
if (is_inside_tree()) {
|
||||||
_assign_lightmaps();
|
_assign_lightmaps();
|
||||||
}
|
}
|
||||||
|
light_data->update_shadowmask_mode(shadowmask_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_gizmos();
|
update_gizmos();
|
||||||
@@ -1506,6 +1594,19 @@ bool LightmapGI::is_directional() const {
|
|||||||
return directional;
|
return directional;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightmapGI::set_shadowmask_mode(LightmapGIData::ShadowmaskMode p_mode) {
|
||||||
|
shadowmask_mode = p_mode;
|
||||||
|
if (light_data.is_valid()) {
|
||||||
|
light_data->update_shadowmask_mode(p_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_configuration_warnings();
|
||||||
|
}
|
||||||
|
|
||||||
|
LightmapGIData::ShadowmaskMode LightmapGI::get_shadowmask_mode() const {
|
||||||
|
return shadowmask_mode;
|
||||||
|
}
|
||||||
|
|
||||||
void LightmapGI::set_use_texture_for_bounces(bool p_enable) {
|
void LightmapGI::set_use_texture_for_bounces(bool p_enable) {
|
||||||
use_texture_for_bounces = p_enable;
|
use_texture_for_bounces = p_enable;
|
||||||
}
|
}
|
||||||
@@ -1625,6 +1726,11 @@ PackedStringArray LightmapGI::get_configuration_warnings() const {
|
|||||||
warnings.push_back(vformat(RTR("Lightmaps can only be baked from a GPU that supports the RenderingDevice backends.\nYour GPU (%s) does not support RenderingDevice, as it does not support Vulkan, Direct3D 12, or Metal.\nLightmap baking will not be available on this device, although rendering existing baked lightmaps will work."), RenderingServer::get_singleton()->get_video_adapter_name()));
|
warnings.push_back(vformat(RTR("Lightmaps can only be baked from a GPU that supports the RenderingDevice backends.\nYour GPU (%s) does not support RenderingDevice, as it does not support Vulkan, Direct3D 12, or Metal.\nLightmap baking will not be available on this device, although rendering existing baked lightmaps will work."), RenderingServer::get_singleton()->get_video_adapter_name()));
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shadowmask_mode != LightmapGIData::SHADOWMASK_MODE_NONE && light_data.is_valid() && !light_data->has_shadowmask_textures()) {
|
||||||
|
warnings.push_back(RTR("The lightmap has no baked shadowmask textures. Please rebake with the Shadowmask Mode set to anything other than None."));
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
|
#elif defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
|
||||||
warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
|
warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
|
||||||
#else
|
#else
|
||||||
@@ -1704,6 +1810,9 @@ void LightmapGI::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional);
|
ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional);
|
||||||
ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional);
|
ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_shadowmask_mode", "mode"), &LightmapGI::set_shadowmask_mode);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_shadowmask_mode"), &LightmapGI::get_shadowmask_mode);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_use_texture_for_bounces", "use_texture_for_bounces"), &LightmapGI::set_use_texture_for_bounces);
|
ClassDB::bind_method(D_METHOD("set_use_texture_for_bounces", "use_texture_for_bounces"), &LightmapGI::set_use_texture_for_bounces);
|
||||||
ClassDB::bind_method(D_METHOD("is_using_texture_for_bounces"), &LightmapGI::is_using_texture_for_bounces);
|
ClassDB::bind_method(D_METHOD("is_using_texture_for_bounces"), &LightmapGI::is_using_texture_for_bounces);
|
||||||
|
|
||||||
@@ -1717,6 +1826,7 @@ void LightmapGI::_bind_methods() {
|
|||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "bounces", PROPERTY_HINT_RANGE, "0,6,1,or_greater"), "set_bounces", "get_bounces");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "bounces", PROPERTY_HINT_RANGE, "0,6,1,or_greater"), "set_bounces", "get_bounces");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce_indirect_energy", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_bounce_indirect_energy", "get_bounce_indirect_energy");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce_indirect_energy", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_bounce_indirect_energy", "get_bounce_indirect_energy");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional"), "set_directional", "is_directional");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional"), "set_directional", "is_directional");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadowmask_mode", PROPERTY_HINT_ENUM, "None,Replace,Overlay"), "set_shadowmask_mode", "get_shadowmask_mode");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_texture_for_bounces"), "set_use_texture_for_bounces", "is_using_texture_for_bounces");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_texture_for_bounces"), "set_use_texture_for_bounces", "is_using_texture_for_bounces");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
|
||||||
|
|||||||
@@ -43,12 +43,23 @@ class LightmapGIData : public Resource {
|
|||||||
GDCLASS(LightmapGIData, Resource);
|
GDCLASS(LightmapGIData, Resource);
|
||||||
RES_BASE_EXTENSION("lmbake")
|
RES_BASE_EXTENSION("lmbake")
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ShadowmaskMode {
|
||||||
|
SHADOWMASK_MODE_NONE,
|
||||||
|
SHADOWMASK_MODE_REPLACE,
|
||||||
|
SHADOWMASK_MODE_OVERLAY,
|
||||||
|
SHADOWMASK_MODE_ONLY,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
// The 'merged' texture atlases actually used by the renderer.
|
// The 'merged' texture atlases actually used by the renderer.
|
||||||
Ref<TextureLayered> combined_light_texture;
|
Ref<TextureLayered> combined_light_texture;
|
||||||
|
Ref<TextureLayered> combined_shadowmask_texture;
|
||||||
|
|
||||||
// The temporary texture atlas arrays which are used for storage.
|
// The temporary texture atlas arrays which are used for storage.
|
||||||
// If a single atlas is too large, it's split and recombined during loading.
|
// If a single atlas is too large, it's split and recombined during loading.
|
||||||
TypedArray<TextureLayered> storage_light_textures;
|
TypedArray<TextureLayered> storage_light_textures;
|
||||||
|
TypedArray<TextureLayered> storage_shadowmask_textures;
|
||||||
|
|
||||||
bool uses_spherical_harmonics = false;
|
bool uses_spherical_harmonics = false;
|
||||||
bool interior = false;
|
bool interior = false;
|
||||||
@@ -74,6 +85,7 @@ class LightmapGIData : public Resource {
|
|||||||
Dictionary _get_probe_data() const;
|
Dictionary _get_probe_data() const;
|
||||||
|
|
||||||
void _reset_lightmap_textures();
|
void _reset_lightmap_textures();
|
||||||
|
void _reset_shadowmask_textures();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
@@ -101,6 +113,9 @@ public:
|
|||||||
void _set_uses_packed_directional(bool p_enable);
|
void _set_uses_packed_directional(bool p_enable);
|
||||||
bool _is_using_packed_directional() const;
|
bool _is_using_packed_directional() const;
|
||||||
|
|
||||||
|
void update_shadowmask_mode(ShadowmaskMode p_mode);
|
||||||
|
ShadowmaskMode get_shadowmask_mode() const;
|
||||||
|
|
||||||
bool is_interior() const;
|
bool is_interior() const;
|
||||||
float get_baked_exposure() const;
|
float get_baked_exposure() const;
|
||||||
|
|
||||||
@@ -116,6 +131,11 @@ public:
|
|||||||
void set_lightmap_textures(const TypedArray<TextureLayered> &p_data);
|
void set_lightmap_textures(const TypedArray<TextureLayered> &p_data);
|
||||||
TypedArray<TextureLayered> get_lightmap_textures() const;
|
TypedArray<TextureLayered> get_lightmap_textures() const;
|
||||||
|
|
||||||
|
void set_shadowmask_textures(const TypedArray<TextureLayered> &p_data);
|
||||||
|
TypedArray<TextureLayered> get_shadowmask_textures() const;
|
||||||
|
void clear_shadowmask_textures();
|
||||||
|
bool has_shadowmask_textures();
|
||||||
|
|
||||||
virtual RID get_rid() const override;
|
virtual RID get_rid() const override;
|
||||||
LightmapGIData();
|
LightmapGIData();
|
||||||
~LightmapGIData();
|
~LightmapGIData();
|
||||||
@@ -179,6 +199,7 @@ private:
|
|||||||
float environment_custom_energy = 1.0;
|
float environment_custom_energy = 1.0;
|
||||||
bool directional = false;
|
bool directional = false;
|
||||||
bool use_texture_for_bounces = true;
|
bool use_texture_for_bounces = true;
|
||||||
|
LightmapGIData::ShadowmaskMode shadowmask_mode = LightmapGIData::SHADOWMASK_MODE_NONE;
|
||||||
GenerateProbes gen_probes = GENERATE_PROBES_SUBDIV_8;
|
GenerateProbes gen_probes = GENERATE_PROBES_SUBDIV_8;
|
||||||
Ref<CameraAttributes> camera_attributes;
|
Ref<CameraAttributes> camera_attributes;
|
||||||
|
|
||||||
@@ -249,7 +270,7 @@ private:
|
|||||||
void _plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle);
|
void _plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle);
|
||||||
void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds);
|
void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds);
|
||||||
|
|
||||||
BakeError _save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_compress = false) const;
|
BakeError _save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_is_shadowmask = false, bool p_compress = false) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _validate_property(PropertyInfo &p_property) const;
|
void _validate_property(PropertyInfo &p_property) const;
|
||||||
@@ -275,6 +296,9 @@ public:
|
|||||||
void set_directional(bool p_enable);
|
void set_directional(bool p_enable);
|
||||||
bool is_directional() const;
|
bool is_directional() const;
|
||||||
|
|
||||||
|
void set_shadowmask_mode(LightmapGIData::ShadowmaskMode p_mode);
|
||||||
|
LightmapGIData::ShadowmaskMode get_shadowmask_mode() const;
|
||||||
|
|
||||||
void set_use_texture_for_bounces(bool p_enable);
|
void set_use_texture_for_bounces(bool p_enable);
|
||||||
bool is_using_texture_for_bounces() const;
|
bool is_using_texture_for_bounces() const;
|
||||||
|
|
||||||
@@ -323,6 +347,7 @@ public:
|
|||||||
LightmapGI();
|
LightmapGI();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(LightmapGIData::ShadowmaskMode);
|
||||||
VARIANT_ENUM_CAST(LightmapGI::BakeQuality);
|
VARIANT_ENUM_CAST(LightmapGI::BakeQuality);
|
||||||
VARIANT_ENUM_CAST(LightmapGI::GenerateProbes);
|
VARIANT_ENUM_CAST(LightmapGI::GenerateProbes);
|
||||||
VARIANT_ENUM_CAST(LightmapGI::BakeError);
|
VARIANT_ENUM_CAST(LightmapGI::BakeError);
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ public:
|
|||||||
GENERATE_PROBES_SUBDIV_8,
|
GENERATE_PROBES_SUBDIV_8,
|
||||||
GENERATE_PROBES_SUBDIV_16,
|
GENERATE_PROBES_SUBDIV_16,
|
||||||
GENERATE_PROBES_SUBDIV_32,
|
GENERATE_PROBES_SUBDIV_32,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LightType {
|
enum LightType {
|
||||||
@@ -178,14 +177,16 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual void add_mesh(const MeshData &p_mesh) = 0;
|
virtual void add_mesh(const MeshData &p_mesh) = 0;
|
||||||
virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) = 0;
|
virtual void add_directional_light(const String &p_name, bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_angular_distance, float p_shadow_blur) = 0;
|
||||||
virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0;
|
virtual void add_omni_light(const String &p_name, bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0;
|
||||||
virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0;
|
virtual void add_spot_light(const String &p_name, bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0;
|
||||||
virtual void add_probe(const Vector3 &p_position) = 0;
|
virtual void add_probe(const Vector3 &p_position) = 0;
|
||||||
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, float p_exposure_normalization = 1.0) = 0;
|
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_denoiser_range, int p_bounces, float p_bounce_indirect_energy, float p_bias, int p_max_texture_size, bool p_bake_sh, bool p_bake_shadowmask, bool p_texture_for_bounces, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, float p_exposure_normalization = 1.0) = 0;
|
||||||
|
|
||||||
virtual int get_bake_texture_count() const = 0;
|
virtual int get_bake_texture_count() const = 0;
|
||||||
virtual Ref<Image> get_bake_texture(int p_index) const = 0;
|
virtual Ref<Image> get_bake_texture(int p_index) const = 0;
|
||||||
|
virtual int get_shadowmask_texture_count() const = 0;
|
||||||
|
virtual Ref<Image> get_shadowmask_texture(int p_index) const = 0;
|
||||||
virtual int get_bake_mesh_count() const = 0;
|
virtual int get_bake_mesh_count() const = 0;
|
||||||
virtual Variant get_bake_mesh_userdata(int p_index) const = 0;
|
virtual Variant get_bake_mesh_userdata(int p_index) const = 0;
|
||||||
virtual Rect2 get_bake_mesh_uv_scale(int p_index) const = 0;
|
virtual Rect2 get_bake_mesh_uv_scale(int p_index) const = 0;
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ 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 { return 0; }
|
virtual float lightmap_get_probe_capture_update_speed() const override { return 0; }
|
||||||
|
|
||||||
|
virtual void lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) override {}
|
||||||
|
virtual RS::ShadowmaskMode lightmap_get_shadowmask_mode(RID p_lightmap) override { return RS::SHADOWMASK_MODE_NONE; }
|
||||||
|
virtual void lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) override {}
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
|
bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
|
||||||
|
|||||||
@@ -1167,6 +1167,7 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data,
|
|||||||
|
|
||||||
// Exposure.
|
// Exposure.
|
||||||
scene_state.lightmaps[i].exposure_normalization = 1.0;
|
scene_state.lightmaps[i].exposure_normalization = 1.0;
|
||||||
|
scene_state.lightmaps[i].flags = light_storage->lightmap_get_shadowmask_mode(lightmap);
|
||||||
if (p_render_data->camera_attributes.is_valid()) {
|
if (p_render_data->camera_attributes.is_valid()) {
|
||||||
float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
|
float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
|
||||||
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
|
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
|
||||||
@@ -3223,15 +3224,29 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
|
|||||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
||||||
|
|
||||||
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
||||||
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
|
for (uint32_t i = 0; i < scene_state.max_lightmaps * 2; i++) {
|
||||||
if (p_render_data && i < p_render_data->lightmaps->size()) {
|
uint32_t current_lightmap_index = i < scene_state.max_lightmaps ? i : i - scene_state.max_lightmaps;
|
||||||
RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
|
|
||||||
RID texture = light_storage->lightmap_get_texture(base);
|
if (p_render_data && current_lightmap_index < p_render_data->lightmaps->size()) {
|
||||||
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
|
RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[current_lightmap_index]);
|
||||||
u.append_id(rd_texture);
|
RID texture;
|
||||||
} else {
|
|
||||||
u.append_id(default_tex);
|
if (i < scene_state.max_lightmaps) {
|
||||||
|
// Lightmap
|
||||||
|
texture = light_storage->lightmap_get_texture(base);
|
||||||
|
} else {
|
||||||
|
// Shadowmask
|
||||||
|
texture = light_storage->shadowmask_get_texture(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture.is_valid()) {
|
||||||
|
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
|
||||||
|
u.append_id(rd_texture);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.append_id(default_tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms.push_back(u);
|
uniforms.push_back(u);
|
||||||
@@ -3535,7 +3550,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
|
|||||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
||||||
|
|
||||||
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
||||||
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
|
for (uint32_t i = 0; i < scene_state.max_lightmaps * 2; i++) {
|
||||||
u.append_id(default_tex);
|
u.append_id(default_tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ private:
|
|||||||
float normal_xform[12];
|
float normal_xform[12];
|
||||||
float texture_size[2];
|
float texture_size[2];
|
||||||
float exposure_normalization;
|
float exposure_normalization;
|
||||||
float pad;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LightmapCaptureData {
|
struct LightmapCaptureData {
|
||||||
|
|||||||
@@ -477,15 +477,29 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
|
|||||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
||||||
|
|
||||||
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
||||||
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
|
for (uint32_t i = 0; i < scene_state.max_lightmaps * 2; i++) {
|
||||||
if (p_render_data && i < p_render_data->lightmaps->size()) {
|
uint32_t current_lightmap_index = i < scene_state.max_lightmaps ? i : i - scene_state.max_lightmaps;
|
||||||
RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
|
|
||||||
RID texture = light_storage->lightmap_get_texture(base);
|
if (p_render_data && current_lightmap_index < p_render_data->lightmaps->size()) {
|
||||||
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
|
RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[current_lightmap_index]);
|
||||||
u.append_id(rd_texture);
|
RID texture;
|
||||||
} else {
|
|
||||||
u.append_id(default_tex);
|
if (i < scene_state.max_lightmaps) {
|
||||||
|
// Lightmap
|
||||||
|
texture = light_storage->lightmap_get_texture(base);
|
||||||
|
} else {
|
||||||
|
// Shadowmask
|
||||||
|
texture = light_storage->shadowmask_get_texture(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture.is_valid()) {
|
||||||
|
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
|
||||||
|
u.append_id(rd_texture);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.append_id(default_tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms.push_back(u);
|
uniforms.push_back(u);
|
||||||
@@ -642,6 +656,7 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
|
|||||||
|
|
||||||
// Exposure.
|
// Exposure.
|
||||||
scene_state.lightmaps[i].exposure_normalization = 1.0;
|
scene_state.lightmaps[i].exposure_normalization = 1.0;
|
||||||
|
scene_state.lightmaps[i].flags = light_storage->lightmap_get_shadowmask_mode(lightmap);
|
||||||
if (p_render_data->camera_attributes.is_valid()) {
|
if (p_render_data->camera_attributes.is_valid()) {
|
||||||
float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
|
float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
|
||||||
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
|
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ private:
|
|||||||
float normal_xform[12];
|
float normal_xform[12];
|
||||||
float texture_size[2];
|
float texture_size[2];
|
||||||
float exposure_normalization;
|
float exposure_normalization;
|
||||||
float pad;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LightmapCaptureData {
|
struct LightmapCaptureData {
|
||||||
|
|||||||
@@ -1978,9 +1978,34 @@ void fragment_shader(in SceneData scene_data) {
|
|||||||
uint shadow0 = 0;
|
uint shadow0 = 0;
|
||||||
uint shadow1 = 0;
|
uint shadow1 = 0;
|
||||||
|
|
||||||
|
float shadowmask = 1.0;
|
||||||
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
uint shadowmask_mode = LIGHTMAP_SHADOWMASK_MODE_NONE;
|
||||||
|
|
||||||
|
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
|
||||||
|
const uint ofs = instances.data[instance_index].gi_offset & 0xFFFF;
|
||||||
|
shadowmask_mode = lightmaps.data[ofs].flags;
|
||||||
|
|
||||||
|
if (shadowmask_mode != LIGHTMAP_SHADOWMASK_MODE_NONE) {
|
||||||
|
const uint slice = instances.data[instance_index].gi_offset >> 16;
|
||||||
|
const vec2 scaled_uv = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy;
|
||||||
|
const vec3 uvw = vec3(scaled_uv, float(slice));
|
||||||
|
|
||||||
|
if (sc_use_lightmap_bicubic_filter()) {
|
||||||
|
shadowmask = textureArray_bicubic(lightmap_textures[MAX_LIGHTMAP_TEXTURES + ofs], uvw, lightmaps.data[ofs].light_texture_size).x;
|
||||||
|
} else {
|
||||||
|
shadowmask = textureLod(sampler2DArray(lightmap_textures[MAX_LIGHTMAP_TEXTURES + ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowmask_mode != LIGHTMAP_SHADOWMASK_MODE_ONLY) {
|
||||||
|
#endif // USE_LIGHTMAP
|
||||||
|
|
||||||
#ifdef USE_VERTEX_LIGHTING
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
// Only process the first light's shadow for vertex lighting.
|
// Only process the first light's shadow for vertex lighting.
|
||||||
for (uint i = 0; i < 1; i++) {
|
for (uint i = 0; i < 1; i++) {
|
||||||
#else
|
#else
|
||||||
for (uint i = 0; i < 8; i++) {
|
for (uint i = 0; i < 8; i++) {
|
||||||
if (i >= scene_data.directional_light_count) {
|
if (i >= scene_data.directional_light_count) {
|
||||||
@@ -1988,20 +2013,20 @@ void fragment_shader(in SceneData scene_data) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
|
if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
|
||||||
continue; //not masked
|
continue; //not masked
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
|
if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
|
||||||
continue; // Statically baked light and object uses lightmap, skip
|
continue; // Statically baked light and object uses lightmap, skip
|
||||||
}
|
}
|
||||||
|
|
||||||
float shadow = 1.0;
|
float shadow = 1.0;
|
||||||
|
|
||||||
if (directional_lights.data[i].shadow_opacity > 0.001) {
|
if (directional_lights.data[i].shadow_opacity > 0.001) {
|
||||||
float depth_z = -vertex.z;
|
float depth_z = -vertex.z;
|
||||||
vec3 light_dir = directional_lights.data[i].direction;
|
vec3 light_dir = directional_lights.data[i].direction;
|
||||||
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
|
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
|
||||||
|
|
||||||
#define BIAS_FUNC(m_var, m_idx) \
|
#define BIAS_FUNC(m_var, m_idx) \
|
||||||
m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
|
m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
|
||||||
@@ -2009,195 +2034,218 @@ void fragment_shader(in SceneData scene_data) {
|
|||||||
normal_bias -= light_dir * dot(light_dir, normal_bias); \
|
normal_bias -= light_dir * dot(light_dir, normal_bias); \
|
||||||
m_var.xyz += normal_bias;
|
m_var.xyz += normal_bias;
|
||||||
|
|
||||||
//version with soft shadows, more expensive
|
//version with soft shadows, more expensive
|
||||||
if (sc_use_directional_soft_shadows() && directional_lights.data[i].softshadow_angle > 0) {
|
if (sc_use_directional_soft_shadows() && directional_lights.data[i].softshadow_angle > 0) {
|
||||||
uint blend_count = 0;
|
uint blend_count = 0;
|
||||||
const uint blend_max = directional_lights.data[i].blend_splits ? 2 : 1;
|
const uint blend_max = directional_lights.data[i].blend_splits ? 2 : 1;
|
||||||
|
|
||||||
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 0)
|
|
||||||
|
|
||||||
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
|
||||||
pssm_coord /= pssm_coord.w;
|
|
||||||
|
|
||||||
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
|
||||||
float range_begin = directional_lights.data[i].shadow_range_begin.x;
|
|
||||||
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
|
||||||
vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
|
|
||||||
shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
|
||||||
blend_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 1)
|
|
||||||
|
|
||||||
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
|
||||||
pssm_coord /= pssm_coord.w;
|
|
||||||
|
|
||||||
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
|
||||||
float range_begin = directional_lights.data[i].shadow_range_begin.y;
|
|
||||||
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
|
||||||
vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
|
|
||||||
float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
|
||||||
|
|
||||||
if (blend_count == 0) {
|
|
||||||
shadow = s;
|
|
||||||
} else {
|
|
||||||
//blend
|
|
||||||
float blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
|
|
||||||
shadow = mix(shadow, s, blend);
|
|
||||||
}
|
|
||||||
|
|
||||||
blend_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 2)
|
|
||||||
|
|
||||||
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
|
||||||
pssm_coord /= pssm_coord.w;
|
|
||||||
|
|
||||||
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
|
||||||
float range_begin = directional_lights.data[i].shadow_range_begin.z;
|
|
||||||
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
|
||||||
vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
|
|
||||||
float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
|
||||||
|
|
||||||
if (blend_count == 0) {
|
|
||||||
shadow = s;
|
|
||||||
} else {
|
|
||||||
//blend
|
|
||||||
float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
|
|
||||||
shadow = mix(shadow, s, blend);
|
|
||||||
}
|
|
||||||
|
|
||||||
blend_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blend_count < blend_max) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 3)
|
|
||||||
|
|
||||||
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
|
||||||
pssm_coord /= pssm_coord.w;
|
|
||||||
|
|
||||||
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
|
||||||
float range_begin = directional_lights.data[i].shadow_range_begin.w;
|
|
||||||
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
|
||||||
vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
|
|
||||||
float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
|
||||||
|
|
||||||
if (blend_count == 0) {
|
|
||||||
shadow = s;
|
|
||||||
} else {
|
|
||||||
//blend
|
|
||||||
float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
|
|
||||||
shadow = mix(shadow, s, blend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { //no soft shadows
|
|
||||||
|
|
||||||
vec4 pssm_coord;
|
|
||||||
float blur_factor;
|
|
||||||
|
|
||||||
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 0)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
|
||||||
blur_factor = 1.0;
|
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 1)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
|
||||||
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 2)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
|
||||||
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
|
||||||
} else {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 3)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
|
||||||
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
pssm_coord /= pssm_coord.w;
|
|
||||||
|
|
||||||
shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor + (1.0 - blur_factor) * float(directional_lights.data[i].blend_splits)), pssm_coord, scene_data.taa_frame_count);
|
|
||||||
|
|
||||||
if (directional_lights.data[i].blend_splits) {
|
|
||||||
float pssm_blend;
|
|
||||||
float blur_factor2;
|
|
||||||
|
|
||||||
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||||
vec4 v = vec4(vertex, 1.0);
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
|
||||||
|
BIAS_FUNC(v, 0)
|
||||||
|
|
||||||
|
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
||||||
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
|
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
||||||
|
float range_begin = directional_lights.data[i].shadow_range_begin.x;
|
||||||
|
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
||||||
|
vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
|
||||||
|
shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
||||||
|
blend_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
|
||||||
BIAS_FUNC(v, 1)
|
BIAS_FUNC(v, 1)
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
|
||||||
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x - directional_lights.data[i].shadow_split_offsets.x * 0.1, directional_lights.data[i].shadow_split_offsets.x, depth_z);
|
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
pssm_coord /= pssm_coord.w;
|
||||||
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
|
||||||
|
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
||||||
|
float range_begin = directional_lights.data[i].shadow_range_begin.y;
|
||||||
|
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
||||||
|
vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
|
||||||
|
float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
||||||
|
|
||||||
|
if (blend_count == 0) {
|
||||||
|
shadow = s;
|
||||||
|
} else {
|
||||||
|
//blend
|
||||||
|
float blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
|
||||||
|
shadow = mix(shadow, s, blend);
|
||||||
|
}
|
||||||
|
|
||||||
|
blend_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
|
||||||
|
BIAS_FUNC(v, 2)
|
||||||
|
|
||||||
|
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
||||||
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
|
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
||||||
|
float range_begin = directional_lights.data[i].shadow_range_begin.z;
|
||||||
|
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
||||||
|
vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
|
||||||
|
float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
||||||
|
|
||||||
|
if (blend_count == 0) {
|
||||||
|
shadow = s;
|
||||||
|
} else {
|
||||||
|
//blend
|
||||||
|
float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
|
||||||
|
shadow = mix(shadow, s, blend);
|
||||||
|
}
|
||||||
|
|
||||||
|
blend_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blend_count < blend_max) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
|
||||||
|
BIAS_FUNC(v, 3)
|
||||||
|
|
||||||
|
vec4 pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
||||||
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
|
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
|
||||||
|
float range_begin = directional_lights.data[i].shadow_range_begin.w;
|
||||||
|
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
|
||||||
|
vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
|
||||||
|
float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
|
||||||
|
|
||||||
|
if (blend_count == 0) {
|
||||||
|
shadow = s;
|
||||||
|
} else {
|
||||||
|
//blend
|
||||||
|
float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
|
||||||
|
shadow = mix(shadow, s, blend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { //no soft shadows
|
||||||
|
|
||||||
|
vec4 pssm_coord;
|
||||||
|
float blur_factor;
|
||||||
|
|
||||||
|
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
|
||||||
|
BIAS_FUNC(v, 0)
|
||||||
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
||||||
|
blur_factor = 1.0;
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||||
vec4 v = vec4(vertex, 1.0);
|
vec4 v = vec4(vertex, 1.0);
|
||||||
BIAS_FUNC(v, 2)
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
BIAS_FUNC(v, 1)
|
||||||
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y - directional_lights.data[i].shadow_split_offsets.y * 0.1, directional_lights.data[i].shadow_split_offsets.y, depth_z);
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
||||||
vec4 v = vec4(vertex, 1.0);
|
vec4 v = vec4(vertex, 1.0);
|
||||||
BIAS_FUNC(v, 3)
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
BIAS_FUNC(v, 2)
|
||||||
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.z - directional_lights.data[i].shadow_split_offsets.z * 0.1, directional_lights.data[i].shadow_split_offsets.z, depth_z);
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
||||||
} else {
|
} else {
|
||||||
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
|
vec4 v = vec4(vertex, 1.0);
|
||||||
blur_factor2 = 1.0;
|
|
||||||
|
BIAS_FUNC(v, 3)
|
||||||
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
pssm_coord /= pssm_coord.w;
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor2 + (1.0 - blur_factor2) * float(directional_lights.data[i].blend_splits)), pssm_coord, scene_data.taa_frame_count);
|
shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor + (1.0 - blur_factor) * float(directional_lights.data[i].blend_splits)), pssm_coord, scene_data.taa_frame_count);
|
||||||
shadow = mix(shadow, shadow2, pssm_blend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
if (directional_lights.data[i].blend_splits) {
|
||||||
|
float pssm_blend;
|
||||||
|
float blur_factor2;
|
||||||
|
|
||||||
|
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
BIAS_FUNC(v, 1)
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
||||||
|
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x - directional_lights.data[i].shadow_split_offsets.x * 0.1, directional_lights.data[i].shadow_split_offsets.x, depth_z);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
||||||
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
BIAS_FUNC(v, 2)
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
||||||
|
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y - directional_lights.data[i].shadow_split_offsets.y * 0.1, directional_lights.data[i].shadow_split_offsets.y, depth_z);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
||||||
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
BIAS_FUNC(v, 3)
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
||||||
|
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.z - directional_lights.data[i].shadow_split_offsets.z * 0.1, directional_lights.data[i].shadow_split_offsets.z, depth_z);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
||||||
|
} else {
|
||||||
|
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
|
||||||
|
blur_factor2 = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
|
float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor2 + (1.0 - blur_factor2) * float(directional_lights.data[i].blend_splits)), pssm_coord, scene_data.taa_frame_count);
|
||||||
|
shadow = mix(shadow, shadow2, pssm_blend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
if (shadowmask_mode == LIGHTMAP_SHADOWMASK_MODE_REPLACE) {
|
||||||
|
shadow = mix(shadow, shadowmask, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
||||||
|
} else if (shadowmask_mode == LIGHTMAP_SHADOWMASK_MODE_OVERLAY) {
|
||||||
|
shadow = shadowmask * mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_VERTEX_LIGHTING
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a);
|
diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a);
|
||||||
specular_light *= mix(1.0, shadow, specular_light_interp.a);
|
specular_light *= mix(1.0, shadow, specular_light_interp.a);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef BIAS_FUNC
|
#undef BIAS_FUNC
|
||||||
} // shadows
|
} // shadows
|
||||||
|
|
||||||
if (i < 4) {
|
if (i < 4) {
|
||||||
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
|
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
|
||||||
} else {
|
} else {
|
||||||
shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
|
shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
} else { // shadowmask_mode == LIGHTMAP_SHADOWMASK_MODE_ONLY
|
||||||
|
|
||||||
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
|
diffuse_light *= mix(1.0, shadowmask, diffuse_light_interp.a);
|
||||||
|
specular_light *= mix(1.0, shadowmask, specular_light_interp.a);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
shadow0 |= uint(clamp(shadowmask * 255.0, 0.0, 255.0));
|
||||||
}
|
}
|
||||||
|
#endif // USE_LIGHTMAP
|
||||||
|
|
||||||
#endif // SHADOWS_DISABLED
|
#endif // SHADOWS_DISABLED
|
||||||
|
|
||||||
#ifndef USE_VERTEX_LIGHTING
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
|
|||||||
@@ -200,11 +200,16 @@ directional_lights;
|
|||||||
#define LIGHTMAP_FLAG_USE_DIRECTION 1
|
#define LIGHTMAP_FLAG_USE_DIRECTION 1
|
||||||
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
|
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
|
||||||
|
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_NONE 0
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_REPLACE 1
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_OVERLAY 2
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_ONLY 3
|
||||||
|
|
||||||
struct Lightmap {
|
struct Lightmap {
|
||||||
mat3 normal_xform;
|
mat3 normal_xform;
|
||||||
vec2 light_texture_size;
|
vec2 light_texture_size;
|
||||||
float exposure_normalization;
|
float exposure_normalization;
|
||||||
float pad;
|
uint flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
|
layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
|
||||||
@@ -349,7 +354,7 @@ layout(set = 1, binding = 5) uniform texture2D shadow_atlas;
|
|||||||
|
|
||||||
layout(set = 1, binding = 6) uniform texture2D directional_shadow_atlas;
|
layout(set = 1, binding = 6) uniform texture2D directional_shadow_atlas;
|
||||||
|
|
||||||
layout(set = 1, binding = 7) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
|
layout(set = 1, binding = 7) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES * 2];
|
||||||
|
|
||||||
layout(set = 1, binding = 8) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
|
layout(set = 1, binding = 8) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
|
||||||
|
|
||||||
|
|||||||
@@ -1434,30 +1434,54 @@ void main() {
|
|||||||
uint shadow0 = 0;
|
uint shadow0 = 0;
|
||||||
uint shadow1 = 0;
|
uint shadow1 = 0;
|
||||||
|
|
||||||
|
float shadowmask = 1.0;
|
||||||
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
uint shadowmask_mode = LIGHTMAP_SHADOWMASK_MODE_NONE;
|
||||||
|
|
||||||
|
if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
|
||||||
|
const uint ofs = instances.data[draw_call.instance_index].gi_offset & 0xFFFF;
|
||||||
|
shadowmask_mode = lightmaps.data[ofs].flags;
|
||||||
|
|
||||||
|
if (shadowmask_mode != LIGHTMAP_SHADOWMASK_MODE_NONE) {
|
||||||
|
const uint slice = instances.data[draw_call.instance_index].gi_offset >> 16;
|
||||||
|
const vec2 scaled_uv = uv2 * instances.data[draw_call.instance_index].lightmap_uv_scale.zw + instances.data[draw_call.instance_index].lightmap_uv_scale.xy;
|
||||||
|
const vec3 uvw = vec3(scaled_uv, float(slice));
|
||||||
|
|
||||||
|
if (sc_use_lightmap_bicubic_filter()) {
|
||||||
|
shadowmask = textureArray_bicubic(lightmap_textures[MAX_LIGHTMAP_TEXTURES + ofs], uvw, lightmaps.data[ofs].light_texture_size).x;
|
||||||
|
} else {
|
||||||
|
shadowmask = textureLod(sampler2DArray(lightmap_textures[MAX_LIGHTMAP_TEXTURES + ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowmask_mode != LIGHTMAP_SHADOWMASK_MODE_ONLY) {
|
||||||
|
#endif // USE_LIGHTMAP
|
||||||
|
|
||||||
#ifdef USE_VERTEX_LIGHTING
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
// Only process the first light's shadow for vertex lighting.
|
// Only process the first light's shadow for vertex lighting.
|
||||||
for (uint i = 0; i < 1; i++) {
|
for (uint i = 0; i < 1; i++) {
|
||||||
#else
|
#else
|
||||||
for (uint i = 0; i < sc_directional_lights(); i++) {
|
for (uint i = 0; i < sc_directional_lights(); i++) {
|
||||||
#endif
|
#endif
|
||||||
|
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
|
||||||
|
continue; //not masked
|
||||||
|
}
|
||||||
|
|
||||||
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
|
if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
|
||||||
continue; //not masked
|
continue; // Statically baked light and object uses lightmap, skip.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
|
float shadow = 1.0;
|
||||||
continue; // Statically baked light and object uses lightmap, skip.
|
|
||||||
}
|
|
||||||
|
|
||||||
float shadow = 1.0;
|
if (directional_lights.data[i].shadow_opacity > 0.001) {
|
||||||
|
float depth_z = -vertex.z;
|
||||||
|
|
||||||
if (directional_lights.data[i].shadow_opacity > 0.001) {
|
vec4 pssm_coord;
|
||||||
float depth_z = -vertex.z;
|
float blur_factor;
|
||||||
|
vec3 light_dir = directional_lights.data[i].direction;
|
||||||
vec4 pssm_coord;
|
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
|
||||||
float blur_factor;
|
|
||||||
vec3 light_dir = directional_lights.data[i].direction;
|
|
||||||
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
|
|
||||||
|
|
||||||
#define BIAS_FUNC(m_var, m_idx) \
|
#define BIAS_FUNC(m_var, m_idx) \
|
||||||
m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
|
m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
|
||||||
@@ -1465,97 +1489,119 @@ void main() {
|
|||||||
normal_bias -= light_dir * dot(light_dir, normal_bias); \
|
normal_bias -= light_dir * dot(light_dir, normal_bias); \
|
||||||
m_var.xyz += normal_bias;
|
m_var.xyz += normal_bias;
|
||||||
|
|
||||||
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 0)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
|
||||||
blur_factor = 1.0;
|
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 1)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
|
||||||
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
|
||||||
;
|
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 2)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
|
||||||
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
|
||||||
} else {
|
|
||||||
vec4 v = vec4(vertex, 1.0);
|
|
||||||
|
|
||||||
BIAS_FUNC(v, 3)
|
|
||||||
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
|
||||||
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
pssm_coord /= pssm_coord.w;
|
|
||||||
|
|
||||||
bool blend_split = sc_directional_light_blend_split(i);
|
|
||||||
float blend_split_weight = blend_split ? 1.0f : 0.0f;
|
|
||||||
shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor + (1.0 - blur_factor) * blend_split_weight), pssm_coord, scene_data.taa_frame_count);
|
|
||||||
|
|
||||||
if (blend_split) {
|
|
||||||
float pssm_blend;
|
|
||||||
float blur_factor2;
|
|
||||||
|
|
||||||
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||||
vec4 v = vec4(vertex, 1.0);
|
vec4 v = vec4(vertex, 1.0);
|
||||||
BIAS_FUNC(v, 1)
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
BIAS_FUNC(v, 0)
|
||||||
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x - directional_lights.data[i].shadow_split_offsets.x * 0.1, directional_lights.data[i].shadow_split_offsets.x, depth_z);
|
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
||||||
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
blur_factor = 1.0;
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||||
vec4 v = vec4(vertex, 1.0);
|
vec4 v = vec4(vertex, 1.0);
|
||||||
BIAS_FUNC(v, 2)
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
BIAS_FUNC(v, 1)
|
||||||
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y - directional_lights.data[i].shadow_split_offsets.y * 0.1, directional_lights.data[i].shadow_split_offsets.y, depth_z);
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
||||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
||||||
vec4 v = vec4(vertex, 1.0);
|
vec4 v = vec4(vertex, 1.0);
|
||||||
BIAS_FUNC(v, 3)
|
|
||||||
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
BIAS_FUNC(v, 2)
|
||||||
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.z - directional_lights.data[i].shadow_split_offsets.z * 0.1, directional_lights.data[i].shadow_split_offsets.z, depth_z);
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
||||||
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
||||||
} else {
|
} else {
|
||||||
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
|
vec4 v = vec4(vertex, 1.0);
|
||||||
blur_factor2 = 1.0;
|
|
||||||
|
BIAS_FUNC(v, 3)
|
||||||
|
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
pssm_coord /= pssm_coord.w;
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor2 + (1.0 - blur_factor2) * blend_split_weight), pssm_coord, scene_data.taa_frame_count);
|
bool blend_split = sc_directional_light_blend_split(i);
|
||||||
shadow = mix(shadow, shadow2, pssm_blend);
|
float blend_split_weight = blend_split ? 1.0f : 0.0f;
|
||||||
}
|
shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor + (1.0 - blur_factor) * blend_split_weight), pssm_coord, scene_data.taa_frame_count);
|
||||||
|
|
||||||
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
if (blend_split) {
|
||||||
|
float pssm_blend;
|
||||||
|
float blur_factor2;
|
||||||
|
|
||||||
|
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
BIAS_FUNC(v, 1)
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
||||||
|
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x - directional_lights.data[i].shadow_split_offsets.x * 0.1, directional_lights.data[i].shadow_split_offsets.x, depth_z);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
|
||||||
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
BIAS_FUNC(v, 2)
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
||||||
|
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y - directional_lights.data[i].shadow_split_offsets.y * 0.1, directional_lights.data[i].shadow_split_offsets.y, depth_z);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
|
||||||
|
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
||||||
|
vec4 v = vec4(vertex, 1.0);
|
||||||
|
BIAS_FUNC(v, 3)
|
||||||
|
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
||||||
|
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.z - directional_lights.data[i].shadow_split_offsets.z * 0.1, directional_lights.data[i].shadow_split_offsets.z, depth_z);
|
||||||
|
// Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
|
||||||
|
blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
|
||||||
|
} else {
|
||||||
|
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
|
||||||
|
blur_factor2 = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pssm_coord /= pssm_coord.w;
|
||||||
|
|
||||||
|
float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor2 + (1.0 - blur_factor2) * blend_split_weight), pssm_coord, scene_data.taa_frame_count);
|
||||||
|
shadow = mix(shadow, shadow2, pssm_blend);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
if (shadowmask_mode == LIGHTMAP_SHADOWMASK_MODE_REPLACE) {
|
||||||
|
shadow = mix(shadow, shadowmask, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
||||||
|
} else if (shadowmask_mode == LIGHTMAP_SHADOWMASK_MODE_OVERLAY) {
|
||||||
|
shadow = shadowmask * mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
|
||||||
|
#ifdef USE_LIGHTMAP
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_VERTEX_LIGHTING
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a);
|
diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a);
|
||||||
specular_light *= mix(1.0, shadow, specular_light_interp.a);
|
specular_light *= mix(1.0, shadow, specular_light_interp.a);
|
||||||
#endif
|
#endif
|
||||||
#undef BIAS_FUNC
|
#undef BIAS_FUNC
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 4) {
|
||||||
|
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
|
||||||
|
} else {
|
||||||
|
shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < 4) {
|
#ifdef USE_LIGHTMAP
|
||||||
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
|
} else { // shadowmask_mode == LIGHTMAP_SHADOWMASK_MODE_ONLY
|
||||||
} else {
|
|
||||||
shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
}
|
diffuse_light *= mix(1.0, shadowmask, diffuse_light_interp.a);
|
||||||
|
specular_light *= mix(1.0, shadowmask, specular_light_interp.a);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
shadow0 |= uint(clamp(shadowmask * 255.0, 0.0, 255.0));
|
||||||
}
|
}
|
||||||
|
#endif // USE_LIGHTMAP
|
||||||
|
|
||||||
#endif // SHADOWS_DISABLED
|
#endif // SHADOWS_DISABLED
|
||||||
|
|
||||||
#ifndef USE_VERTEX_LIGHTING
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
|
|||||||
@@ -246,11 +246,16 @@ directional_lights;
|
|||||||
#define LIGHTMAP_FLAG_USE_DIRECTION 1
|
#define LIGHTMAP_FLAG_USE_DIRECTION 1
|
||||||
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
|
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
|
||||||
|
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_NONE 0
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_REPLACE 1
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_OVERLAY 2
|
||||||
|
#define LIGHTMAP_SHADOWMASK_MODE_ONLY 3
|
||||||
|
|
||||||
struct Lightmap {
|
struct Lightmap {
|
||||||
mediump mat3 normal_xform;
|
mediump mat3 normal_xform;
|
||||||
vec2 light_texture_size;
|
vec2 light_texture_size;
|
||||||
float exposure_normalization;
|
float exposure_normalization;
|
||||||
float pad;
|
uint flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
|
layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
|
||||||
@@ -330,7 +335,7 @@ layout(set = 1, binding = 4) uniform highp texture2D shadow_atlas;
|
|||||||
layout(set = 1, binding = 5) uniform highp texture2D directional_shadow_atlas;
|
layout(set = 1, binding = 5) uniform highp texture2D directional_shadow_atlas;
|
||||||
|
|
||||||
// this needs to change to providing just the lightmap we're using..
|
// this needs to change to providing just the lightmap we're using..
|
||||||
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
|
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES * 2];
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
layout(set = 1, binding = 9) uniform highp texture2DArray depth_buffer;
|
layout(set = 1, binding = 9) uniform highp texture2DArray depth_buffer;
|
||||||
|
|||||||
@@ -55,12 +55,18 @@ LightStorage::LightStorage() {
|
|||||||
|
|
||||||
if (textures_per_stage <= 256) {
|
if (textures_per_stage <= 256) {
|
||||||
lightmap_textures.resize(32);
|
lightmap_textures.resize(32);
|
||||||
|
shadowmask_textures.resize(32);
|
||||||
} else {
|
} else {
|
||||||
lightmap_textures.resize(1024);
|
lightmap_textures.resize(1024);
|
||||||
|
shadowmask_textures.resize(1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < lightmap_textures.size(); i++) {
|
for (RID &lightmap_texture : lightmap_textures) {
|
||||||
lightmap_textures.write[i] = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
lightmap_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RID &shadowmask_texture : shadowmask_textures) {
|
||||||
|
shadowmask_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2003,6 +2009,64 @@ AABB LightStorage::lightmap_get_aabb(RID p_lightmap) const {
|
|||||||
return lm->bounds;
|
return lm->bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightStorage::lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) {
|
||||||
|
TextureStorage *texture_storage = TextureStorage::get_singleton();
|
||||||
|
|
||||||
|
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL(lm);
|
||||||
|
|
||||||
|
// Erase lightmap users from shadow texture.
|
||||||
|
if (lm->shadow_texture.is_valid()) {
|
||||||
|
TextureStorage::Texture *t = texture_storage->get_texture(lm->shadow_texture);
|
||||||
|
if (t) {
|
||||||
|
t->lightmap_users.erase(p_lightmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureStorage::Texture *t = texture_storage->get_texture(p_shadow);
|
||||||
|
lm->shadow_texture = p_shadow;
|
||||||
|
|
||||||
|
RID default_2d_array = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
|
||||||
|
if (!t) {
|
||||||
|
if (lm->array_index >= 0) {
|
||||||
|
shadowmask_textures.write[lm->array_index] = default_2d_array;
|
||||||
|
lm->array_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->lightmap_users.insert(p_lightmap);
|
||||||
|
|
||||||
|
if (lm->array_index < 0) {
|
||||||
|
// Not in array, try to put in array.
|
||||||
|
for (int i = 0; i < shadowmask_textures.size(); i++) {
|
||||||
|
if (shadowmask_textures[i] == default_2d_array) {
|
||||||
|
lm->array_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND_MSG(lm->array_index < 0, vformat("Maximum amount of shadowmasks in use (%d) has been exceeded, shadowmask will not display properly.", shadowmask_textures.size()));
|
||||||
|
|
||||||
|
shadowmask_textures.write[lm->array_index] = t->rd_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
RS::ShadowmaskMode LightStorage::lightmap_get_shadowmask_mode(RID p_lightmap) {
|
||||||
|
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL_V(lm, RS::SHADOWMASK_MODE_NONE);
|
||||||
|
|
||||||
|
return lm->shadowmask_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightStorage::lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) {
|
||||||
|
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL(lm);
|
||||||
|
|
||||||
|
lm->shadowmask_mode = p_mode;
|
||||||
|
}
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
RID LightStorage::lightmap_instance_create(RID p_lightmap) {
|
RID LightStorage::lightmap_instance_create(RID p_lightmap) {
|
||||||
|
|||||||
@@ -329,6 +329,8 @@ private:
|
|||||||
|
|
||||||
struct Lightmap {
|
struct Lightmap {
|
||||||
RID light_texture;
|
RID light_texture;
|
||||||
|
RID shadow_texture;
|
||||||
|
RS::ShadowmaskMode shadowmask_mode = RS::SHADOWMASK_MODE_NONE;
|
||||||
bool uses_spherical_harmonics = false;
|
bool uses_spherical_harmonics = false;
|
||||||
bool interior = false;
|
bool interior = false;
|
||||||
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
|
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
|
||||||
@@ -356,6 +358,8 @@ private:
|
|||||||
|
|
||||||
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
||||||
|
|
||||||
|
Vector<RID> shadowmask_textures;
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
struct LightmapInstance {
|
struct LightmapInstance {
|
||||||
@@ -985,6 +989,10 @@ public:
|
|||||||
|
|
||||||
Dependency *lightmap_get_dependency(RID p_lightmap) const;
|
Dependency *lightmap_get_dependency(RID p_lightmap) const;
|
||||||
|
|
||||||
|
virtual void lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) override;
|
||||||
|
virtual RS::ShadowmaskMode lightmap_get_shadowmask_mode(RID p_lightmap) override;
|
||||||
|
virtual void lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) override;
|
||||||
|
|
||||||
virtual float lightmap_get_probe_capture_update_speed() const override {
|
virtual float lightmap_get_probe_capture_update_speed() const override {
|
||||||
return lightmap_probe_capture_update_speed;
|
return lightmap_probe_capture_update_speed;
|
||||||
}
|
}
|
||||||
@@ -1027,6 +1035,12 @@ public:
|
|||||||
return lightmap_textures;
|
return lightmap_textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ RID shadowmask_get_texture(RID p_lightmap) const {
|
||||||
|
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
|
||||||
|
ERR_FAIL_NULL_V(lm, RID());
|
||||||
|
return lm->shadow_texture;
|
||||||
|
}
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
|
bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
|
||||||
|
|||||||
@@ -489,6 +489,10 @@ public:
|
|||||||
FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
|
FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
|
||||||
FUNC1(lightmap_set_probe_capture_update_speed, float)
|
FUNC1(lightmap_set_probe_capture_update_speed, float)
|
||||||
|
|
||||||
|
FUNC2(lightmap_set_shadowmask_textures, RID, RID)
|
||||||
|
FUNC1R(ShadowmaskMode, lightmap_get_shadowmask_mode, RID)
|
||||||
|
FUNC2(lightmap_set_shadowmask_mode, RID, ShadowmaskMode)
|
||||||
|
|
||||||
/* Shadow Atlas */
|
/* Shadow Atlas */
|
||||||
FUNC0R(RID, shadow_atlas_create)
|
FUNC0R(RID, shadow_atlas_create)
|
||||||
FUNC3(shadow_atlas_set_size, RID, int, bool)
|
FUNC3(shadow_atlas_set_size, RID, int, bool)
|
||||||
|
|||||||
@@ -175,6 +175,10 @@ public:
|
|||||||
virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0;
|
virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0;
|
||||||
virtual float lightmap_get_probe_capture_update_speed() const = 0;
|
virtual float lightmap_get_probe_capture_update_speed() const = 0;
|
||||||
|
|
||||||
|
virtual void lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) = 0;
|
||||||
|
virtual RS::ShadowmaskMode lightmap_get_shadowmask_mode(RID p_lightmap) = 0;
|
||||||
|
virtual void lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) = 0;
|
||||||
|
|
||||||
/* LIGHTMAP INSTANCE */
|
/* LIGHTMAP INSTANCE */
|
||||||
|
|
||||||
virtual RID lightmap_instance_create(RID p_lightmap) = 0;
|
virtual RID lightmap_instance_create(RID p_lightmap) = 0;
|
||||||
|
|||||||
@@ -709,6 +709,13 @@ public:
|
|||||||
|
|
||||||
/* LIGHTMAP */
|
/* LIGHTMAP */
|
||||||
|
|
||||||
|
enum ShadowmaskMode {
|
||||||
|
SHADOWMASK_MODE_NONE,
|
||||||
|
SHADOWMASK_MODE_REPLACE,
|
||||||
|
SHADOWMASK_MODE_OVERLAY,
|
||||||
|
SHADOWMASK_MODE_ONLY,
|
||||||
|
};
|
||||||
|
|
||||||
virtual RID lightmap_create() = 0;
|
virtual RID lightmap_create() = 0;
|
||||||
|
|
||||||
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0;
|
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0;
|
||||||
@@ -722,9 +729,12 @@ public:
|
|||||||
virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const = 0;
|
virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const = 0;
|
||||||
|
|
||||||
virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0;
|
virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0;
|
||||||
|
|
||||||
virtual void lightmaps_set_bicubic_filter(bool p_enable) = 0;
|
virtual void lightmaps_set_bicubic_filter(bool p_enable) = 0;
|
||||||
|
|
||||||
|
virtual void lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) = 0;
|
||||||
|
virtual ShadowmaskMode lightmap_get_shadowmask_mode(RID p_lightmap) = 0;
|
||||||
|
virtual void lightmap_set_shadowmask_mode(RID p_lightmap, ShadowmaskMode p_mode) = 0;
|
||||||
|
|
||||||
/* PARTICLES API */
|
/* PARTICLES API */
|
||||||
|
|
||||||
virtual RID particles_create() = 0;
|
virtual RID particles_create() = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user