-
-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate shadow meshes from a lower LOD level than the source mesh #2600
Comments
Eh, godotengine/godot#45452 isn't about generating Shadow Mesh LODs... as @reduz said:
This doesn't Mean that the Generated Mesh is supposed to be a LOD mesh. If I understand what the Optimization is doing (Not a Rendering Expert) It's Giving The Renderer Only Verts to render the shadow, instead of triangles, because with triangles it wouldn't be uncommon for a vertex to be a part of multiple triangles, resulting in multiple copies of the same vertex, which increases bandwidth usage, and thus reduces performance. P.S. Someone with some Rendering Experience please debunk this if it's wrong. |
@mrjustaguy is very close, ShadowMeshes are not the same thing as Shadow Imposters. ShadowMeshes are a copy of the mesh that contain vertex positions and indices only (rather than including normals, tangents, UVs, etc.). ShadowMeshes contain all the same LODs as the regular mesh. I think there needs to be a proposal for adding a "Shadow LOD bias" parameter somewhere that shifts which LOD to use for the shadow meshes. Perhaps an import setting? |
Could be a Mesh Instance Setting, like LOD bias is. |
@mrjustaguy Yep you are right, the linked pullrequest is not directly the same but I thought it is involved. I think one issue is that the terms ShadowMesh and ShadowImposter are mixed all the time by people that have no technical render background. I see experiences 3D artists use both terms all the time when they mean ShadowImposters and the user interface in Godot 4.x uses the term "Generate -> Shadow Meshes" right next to LOD generation. I think a pulldown option in the new Advanced Import Settings menu with all available mesh LOD levels could work to pick the starting mesh detail for the shadow meshes / imposters. Set to default LOD1 or LOD2 if available on the mesh. |
Currently a Workaround would be (if Cast Shadow property, under geometry, worked, which it doesn't seem to do in current G4.0) is to make 2 mesh instances, a Mesh that is visible but doesn't cast shadows, and a shadow mesh that is set to just cast shadows, with a lower LOD Bias. |
@mrjustaguy |
I started toying around with this. Here's a diff that quadruples the LOD bias when rendering shadow passes (directional + point): diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 7c35b01b50..604fc7ee07 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -4560,7 +4560,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//cube shadows are rendered in their own way
for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold * 4, true, true, true, p_render_data->render_info);
}
if (render_state.directional_shadows.size()) {
@@ -4590,11 +4590,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//render directional shadows
for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold * 4, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
}
//render positional shadows
for (uint32_t i = 0; i < render_state.shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold * 4, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
}
_render_shadow_process();
@@ -4987,7 +4987,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
if (render_cubemap) {
//rendering to cubemap
- _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, Rect2(), false, true, true, true, p_render_info);
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold * 4, Rect2(), false, true, true, true, p_render_info);
if (finalize_cubemap) {
_render_shadow_process();
_render_shadow_end();
@@ -5005,7 +5005,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
} else {
//render shadow
- _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold * 4, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
}
}
It acts as a multiplier of the viewport and mesh's LOD threshold. This multiplier could be exposed as a project setting and a Viewport property, likely defaulting to 3 or perhaps 4. Higher values are possible, but they start to be quite aggressive. The mesh I'm using in the test project below isn't that detailed by today's AAA standards, so real world gains can be more important in scenes with very detailed (and distant) objects. Performance gains will also increase as you add more lights with shadows (the testing project only has 1 DirectionalLight3D). Testing project: test_auto_lod_2.zip Visual comparison1024×600The difference is more noticeable at this resolution.
2560×1440The difference is less obvious here. If you haven't looked at the original image, it's difficult to discern that shadows use simplified meshes.
Performance comparisonOS: Fedora 34 1024×600
2560×1440
|
The difference in performance will be much more visible with more distant meshes, these are very close to the camera, so they're still fairly high LOD. |
bugsquad edit: Transferred from Godot repository: proposal can be found at #2600 (comment)
Godot version:
Godot 4.x
commit b4b7c97d3839170180e4f3f7c2bd3179b374057a
OS/device including version:
Win 10 64x
Issue description:
After testing the new ShadowMeshes in Godot 4.x and comparing the new feature with manual ShadowMeshes created for Godot 3.x I couldn't help but feel very disappointed by the performance (~80% less than Godot 3.x).
So I looked at the shadowmesh source code and I consider this an implementation bug and not a missing feature for a proposal.
Autogenerated shadowmeshes in Godot 4.x are matched to the same source mesh LoD level while they should be matched 1-3 LoD levels lower. A shadow imposter mesh created manual by an artist always starts at least 1-2 LoD levels below the visible LoD mesh but never at the same level. A typical example would be a characters hair mesh, starting at 150.000 vertex. The shadow looks the same with a LOD3 mesh that has only 5.000 vertex cause the outside mesh shape stays the same and this is enough for shadow casting on solid objects. In the current implementation the shadow casting mesh has a 145.000 vertex overhead that does nothing for the endresult and just consumes performance.
Due to this as mentioned in godotengine/godot#45452 pull request there is currently only a little performance gain with shadow imposters while it should be a considerable one.
I suggest that the autogenerated shadow imposters should be generated and matched with LOD2 or LOD3 meshes by default to fix this issue and give the expected performance boost from shadow imposters.
There is no reason to ever use the same mesh geometry detail for a shadow-only casting object except for edgecases like meshes mixed with semi-transparent surfaces and very lowpoly meshes (that don't need shadow imposters to begin with). A Shadowmesh LoD selection option in the new ResourceImporter would be welcome to solve those edgecases.
Steps to reproduce:
Minimal reproduction project:
The text was updated successfully, but these errors were encountered: