Skip to content

Commit 189c8eb

Browse files
BlueCube3310DearthDev
andcommittedDec 12, 2024·
Implement shadowmasks for LightmapGI
Co-authored-by: dearthdev <nathandearthdev@gmail.com>
1 parent a40fc23 commit 189c8eb

27 files changed

+1043
-396
lines changed
 

‎doc/classes/LightmapGI.xml

+5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@
6969
The quality preset to use when baking lightmaps. This affects bake times, but output file sizes remain mostly identical across quality levels.
7070
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.
7171
</member>
72+
<member name="shadowmask_mode" type="int" setter="set_shadowmask_mode" getter="get_shadowmask_mode" enum="LightmapGIData.ShadowmaskMode" default="0" experimental="">
73+
The shadowmasking policy to use for directional shadows on static objects that are baked with this [LightmapGI] instance.
74+
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.
75+
[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.
76+
</member>
7277
<member name="texel_scale" type="float" setter="set_texel_scale" getter="get_texel_scale" default="1.0">
7378
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.
7479
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.

‎doc/classes/LightmapGIData.xml

+14
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,19 @@
6060
<member name="lightmap_textures" type="TextureLayered[]" setter="set_lightmap_textures" getter="get_lightmap_textures" default="[]">
6161
The lightmap atlas textures generated by the lightmapper.
6262
</member>
63+
<member name="shadowmask_textures" type="TextureLayered[]" setter="set_shadowmask_textures" getter="get_shadowmask_textures" default="[]">
64+
The shadowmask atlas textures generated by the lightmapper.
65+
</member>
6366
</members>
67+
<constants>
68+
<constant name="SHADOWMASK_MODE_NONE" value="0" enum="ShadowmaskMode">
69+
Shadowmasking is disabled. No shadowmask texture will be created when baking lightmaps. Existing shadowmask textures will be removed during baking.
70+
</constant>
71+
<constant name="SHADOWMASK_MODE_REPLACE" value="1" enum="ShadowmaskMode">
72+
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.
73+
</constant>
74+
<constant name="SHADOWMASK_MODE_OVERLAY" value="2" enum="ShadowmaskMode">
75+
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.
76+
</constant>
77+
</constants>
6478
</class>

‎drivers/gles3/rasterizer_scene_gles3.cpp

+53-5
Original file line numberDiff line numberDiff line change
@@ -2660,14 +2660,14 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
26602660
glBlitFramebuffer(0, 0, size.x, size.y,
26612661
0, 0, size.x, size.y,
26622662
GL_COLOR_BUFFER_BIT, GL_NEAREST);
2663-
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
2663+
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
26642664
glBindTexture(GL_TEXTURE_2D, backbuffer);
26652665
}
26662666
if (scene_state.used_depth_texture) {
26672667
glBlitFramebuffer(0, 0, size.x, size.y,
26682668
0, 0, size.x, size.y,
26692669
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
2670-
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
2670+
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
26712671
glBindTexture(GL_TEXTURE_2D, backbuffer_depth);
26722672
}
26732673
}
@@ -3245,8 +3245,28 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
32453245
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_OMNI;
32463246
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_SPOT;
32473247
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
3248-
spec_constants |= SceneShaderGLES3::DISABLE_LIGHTMAP;
32493248
spec_constants |= SceneShaderGLES3::DISABLE_REFLECTION_PROBE;
3249+
3250+
bool disable_lightmaps = true;
3251+
3252+
// Additive directional passes may use shadowmasks, so enable lightmaps for them.
3253+
if (pass >= int32_t(inst->light_passes.size()) && inst->lightmap_instance.is_valid()) {
3254+
GLES3::LightmapInstance *li = GLES3::LightStorage::get_singleton()->get_lightmap_instance(inst->lightmap_instance);
3255+
GLES3::Lightmap *lm = GLES3::LightStorage::get_singleton()->get_lightmap(li->lightmap);
3256+
3257+
if (lm->shadowmask_mode != RS::SHADOWMASK_MODE_NONE) {
3258+
spec_constants |= SceneShaderGLES3::USE_LIGHTMAP;
3259+
disable_lightmaps = false;
3260+
3261+
if (lightmap_bicubic_upscale) {
3262+
spec_constants |= SceneShaderGLES3::LIGHTMAP_BICUBIC_FILTER;
3263+
}
3264+
}
3265+
}
3266+
3267+
if (disable_lightmaps) {
3268+
spec_constants |= SceneShaderGLES3::DISABLE_LIGHTMAP;
3269+
}
32503270
}
32513271

32523272
if (uses_additive_lighting) {
@@ -3341,6 +3361,33 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
33413361
GLuint tex = GLES3::LightStorage::get_singleton()->directional_shadow_get_texture();
33423362
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 3);
33433363
glBindTexture(GL_TEXTURE_2D, tex);
3364+
3365+
if (inst->lightmap_instance.is_valid()) {
3366+
// Use shadowmasks for directional light passes.
3367+
GLES3::LightmapInstance *li = GLES3::LightStorage::get_singleton()->get_lightmap_instance(inst->lightmap_instance);
3368+
GLES3::Lightmap *lm = GLES3::LightStorage::get_singleton()->get_lightmap(li->lightmap);
3369+
3370+
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_SLICE, inst->lightmap_slice_index, shader->version, instance_variant, spec_constants);
3371+
3372+
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);
3373+
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_UV_SCALE, uv_scale, shader->version, instance_variant, spec_constants);
3374+
3375+
if (lightmap_bicubic_upscale) {
3376+
Vector2 light_texture_size(lm->light_texture_size.x, lm->light_texture_size.y);
3377+
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_TEXTURE_SIZE, light_texture_size, shader->version, instance_variant, spec_constants);
3378+
}
3379+
3380+
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_SHADOWMASK_MODE, (uint32_t)lm->shadowmask_mode, shader->version, instance_variant, spec_constants);
3381+
3382+
if (lm->shadow_texture.is_valid()) {
3383+
tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(lm->shadow_texture);
3384+
} else {
3385+
tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(GLES3::TextureStorage::get_singleton()->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE));
3386+
}
3387+
3388+
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
3389+
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
3390+
}
33443391
}
33453392
}
33463393

@@ -3399,6 +3446,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
33993446
};
34003447
glUniformMatrix3fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_NORMAL_XFORM, shader->version, instance_variant, spec_constants), 1, GL_FALSE, matrix);
34013448
}
3449+
34023450
} else if (inst->lightmap_sh) {
34033451
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));
34043452
}
@@ -3430,7 +3478,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
34303478
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);
34313479
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);
34323480

3433-
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
3481+
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 8);
34343482
glBindTexture(GL_TEXTURE_CUBE_MAP, light_storage->reflection_probe_instance_get_texture(inst->reflection_probe_rid_cache[0]));
34353483
}
34363484

@@ -3448,7 +3496,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
34483496
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);
34493497
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);
34503498

3451-
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 8);
3499+
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 9);
34523500
glBindTexture(GL_TEXTURE_CUBE_MAP, light_storage->reflection_probe_instance_get_texture(inst->reflection_probe_rid_cache[1]));
34533501

34543502
spec_constants |= SceneShaderGLES3::SECOND_REFLECTION_PROBE;

0 commit comments

Comments
 (0)
Please sign in to comment.