Mesh: Add viewport normals simplify option

Before #108014, toggling "Auto Smooth" was an easy way to disable
evaluation of custom normals and face corner normals for faster
viewport playback performance. Now that corner normals are calculated
automatically as necessary, it's helpful to still have a way to disable
expensive normal computation for faster playback.

This commit adds a "Normals" scene simplify setting. To avoid a bunch
of complexity, it just influences which normals are requested from the
object by viewport rendering. In my tests, skipping calculating at
least doubled viewport FPS in a few test files with a large mesh with
custom normals. This works well because normals are cached and lazily
calculated.

Pull Request: https://projects.blender.org/blender/blender/pulls/113975
This commit is contained in:
Hans Goudey
2023-12-16 00:18:41 +01:00
committed by Hans Goudey
parent bf97dc14ba
commit 912c4c60d8
8 changed files with 46 additions and 13 deletions

View File

@@ -2272,6 +2272,7 @@ class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel):
col.prop(rd, "simplify_child_particles", text="Child Particles")
col.prop(cscene, "texture_limit", text="Texture Limit")
col.prop(rd, "simplify_volumes", text="Volume Resolution")
col.prop(rd, "use_simplify_normals", text="Normals")
class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel):

View File

@@ -1162,6 +1162,9 @@ class RENDER_PT_simplify_viewport(RenderButtonsPanel, Panel):
col = flow.column()
col.prop(rd, "simplify_shadows", text="Shadow Resolution")
col = flow.column()
col.prop(rd, "use_simplify_normals", text="Normals")
class RENDER_PT_simplify_render(RenderButtonsPanel, Panel):
bl_label = "Render"

View File

@@ -4674,7 +4674,7 @@ void blo_do_versions_280(FileData *fd, Library * /*lib*/, Main *bmain)
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->r.mode &= ~(R_MODE_UNUSED_1 | R_MODE_UNUSED_2 | R_MODE_UNUSED_3 | R_MODE_UNUSED_4 |
scene->r.mode &= ~(R_SIMPLIFY_NORMALS | R_MODE_UNUSED_2 | R_MODE_UNUSED_3 | R_MODE_UNUSED_4 |
R_MODE_UNUSED_5 | R_MODE_UNUSED_6 | R_MODE_UNUSED_7 | R_MODE_UNUSED_8 |
R_MODE_UNUSED_10 | R_MODE_UNUSED_13 | R_MODE_UNUSED_16 |
R_MODE_UNUSED_17 | R_MODE_UNUSED_18 | R_MODE_UNUSED_19 |

View File

@@ -699,6 +699,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
mr->use_hide = use_hide;
mr->use_subsurf_fdots = mr->mesh && !mr->mesh->runtime->subsurf_face_dot_tags.is_empty();
mr->use_final_mesh = do_final;
mr->use_simplify_normals = (scene->r.mode & R_SIMPLIFY) && (scene->r.mode & R_SIMPLIFY_NORMALS);
#ifdef DEBUG_TIME
double rdata_end = PIL_check_seconds_timer();

View File

@@ -492,7 +492,7 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
mr.face_normals = mr.mesh->face_normals();
}
if (((data_flag & MR_DATA_LOOP_NOR) &&
if (((data_flag & MR_DATA_LOOP_NOR) && !mr.use_simplify_normals &&
mr.normals_domain == blender::bke::MeshNormalDomain::Corner) ||
(data_flag & MR_DATA_TAN_LOOP_NOR))
{
@@ -504,7 +504,8 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_
if (data_flag & MR_DATA_POLY_NOR) {
/* Use #BMFace.no instead. */
}
if (((data_flag & MR_DATA_LOOP_NOR) && bm_loop_normals_required(mr.bm)) ||
if (((data_flag & MR_DATA_LOOP_NOR) && !mr.use_simplify_normals &&
bm_loop_normals_required(mr.bm)) ||
(data_flag & MR_DATA_TAN_LOOP_NOR))
{

View File

@@ -56,6 +56,7 @@ struct MeshRenderData {
bool use_subsurf_fdots;
bool use_final_mesh;
bool hide_unmapped_edges;
bool use_simplify_normals;
/** Use for #MeshStatVis calculation which use world-space coords. */
float obmat[4][4];

View File

@@ -2090,7 +2090,7 @@ enum {
/** #RenderData::mode. */
enum {
R_MODE_UNUSED_0 = 1 << 0, /* dirty */
R_MODE_UNUSED_1 = 1 << 1, /* cleared */
R_SIMPLIFY_NORMALS = 1 << 1,
R_MODE_UNUSED_2 = 1 << 2, /* cleared */
R_MODE_UNUSED_3 = 1 << 3, /* cleared */
R_MODE_UNUSED_4 = 1 << 4, /* cleared */

View File

@@ -2012,7 +2012,7 @@ static void rna_Scene_uv_select_mode_update(bContext *C, PointerRNA * /*ptr*/)
ED_uvedit_selectmode_clean_multi(C);
}
static void object_simplify_update(Object *ob)
static void object_simplify_update(Scene *scene, Object *ob, bool update_normals)
{
ModifierData *md;
ParticleSystem *psys;
@@ -2037,7 +2037,7 @@ static void object_simplify_update(Object *ob)
if (ob->instance_collection) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (ob->instance_collection, ob_collection) {
object_simplify_update(ob_collection);
object_simplify_update(scene, ob_collection, update_normals);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
@@ -2045,22 +2045,27 @@ static void object_simplify_update(Object *ob)
if (ob->type == OB_VOLUME) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
if (scene->r.mode & R_SIMPLIFY_NORMALS || update_normals) {
if (OB_TYPE_IS_GEOMETRY(ob->type)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
}
}
static void rna_Scene_use_simplify_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
static void rna_Scene_simplify_update_impl(Main *bmain, Scene *sce, bool update_normals)
{
Scene *sce = (Scene *)ptr->owner_id;
Scene *sce_iter;
Base *base;
BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
object_simplify_update(ob);
object_simplify_update(sce, ob, update_normals);
}
FOREACH_SCENE_OBJECT_END;
for (SETLOOPER_SET_ONLY(sce, sce_iter, base)) {
object_simplify_update(base->object);
object_simplify_update(sce, base->object, update_normals);
}
WM_main_add_notifier(NC_GEOM | ND_DATA, nullptr);
@@ -2068,12 +2073,25 @@ static void rna_Scene_use_simplify_update(Main *bmain, Scene * /*scene*/, Pointe
DEG_id_tag_update(&sce->id, ID_RECALC_COPY_ON_WRITE);
}
static void rna_Scene_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Scene_use_simplify_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
{
Scene *sce = (Scene *)ptr->owner_id;
rna_Scene_simplify_update_impl(bmain, sce, false);
}
if (sce->r.mode & R_SIMPLIFY) {
rna_Scene_use_simplify_update(bmain, scene, ptr);
static void rna_Scene_simplify_update(Main *bmain, Scene *scene, PointerRNA * /*ptr*/)
{
if (scene->r.mode & R_SIMPLIFY) {
rna_Scene_simplify_update_impl(bmain, scene, false);
}
}
static void rna_Scene_use_simplify_normals_update(Main *bmain, Scene *scene, PointerRNA * /*ptr*/)
{
/* NOTE: Ideally this would just force recalculation of the draw batch cache normals.
* That's complicated enough to not be worth it here. */
if (scene->r.mode & R_SIMPLIFY) {
rna_Scene_simplify_update_impl(bmain, scene, true);
}
}
@@ -7080,6 +7098,14 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop, "Simplify Volumes", "Resolution percentage of volume objects in viewport");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
prop = RNA_def_property(srna, "use_simplify_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "mode", R_SIMPLIFY_NORMALS);
RNA_def_property_ui_text(prop,
"Mesh Normals",
"Skip computing custom normals and face corner normals for displaying "
"meshes in the viewport");
RNA_def_property_update(prop, 0, "rna_Scene_use_simplify_normals_update");
/* EEVEE - Simplify Options */
prop = RNA_def_property(srna, "simplify_shadows_render", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 1.0);