Modifiers: option to preserve custom normals for subsurf & multires

This commit is contained in:
Cody Winchester 2020-07-22 15:03:17 +10:00 committed by Campbell Barton
parent a197b81090
commit 5c28955d3a
4 changed files with 96 additions and 4 deletions

View File

@ -155,6 +155,7 @@ typedef enum {
/* DEPRECATED, ONLY USED FOR DO-VERSIONS */
eSubsurfModifierFlag_SubsurfUv_DEPRECATED = (1 << 3),
eSubsurfModifierFlag_UseCrease = (1 << 4),
eSubsurfModifierFlag_UseCustomNormals = (1 << 5),
} SubsurfModifierFlag;
typedef enum {
@ -1026,6 +1027,7 @@ typedef enum {
/* DEPRECATED, only used for versioning. */
eMultiresModifierFlag_PlainUv_DEPRECATED = (1 << 1),
eMultiresModifierFlag_UseCrease = (1 << 2),
eMultiresModifierFlag_UseCustomNormals = (1 << 3),
} MultiresModifierFlag;
/* DEPRECATED, only used for versioning. */

View File

@ -1818,6 +1818,12 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_UseCustomNormals);
RNA_def_property_ui_text(
prop, "Use Custom Normals", "Interpolates existing custom normals to resulting mesh");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);
}
@ -2019,6 +2025,12 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_UseCustomNormals);
RNA_def_property_ui_text(
prop, "Use Custom Normals", "Interpolates existing custom normals to resulting mesh");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);
}

View File

@ -80,6 +80,26 @@ static void initData(ModifierData *md)
md->ui_expand_flag = (1 << 0) | (1 << 1);
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
MultiresModifierData *mmd = (MultiresModifierData *)md;
if (mmd->flags & eMultiresModifierFlag_UseCustomNormals) {
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
}
}
static bool dependsOnNormals(ModifierData *md)
{
MultiresModifierData *mmd = (MultiresModifierData *)md;
if (mmd->flags & eMultiresModifierFlag_UseCustomNormals) {
return true;
}
return false;
}
static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag)
{
BKE_modifier_copydata_generic(md_src, md_dst, flag);
@ -208,6 +228,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Happens on bad topology, ut also on empty input mesh. */
return result;
}
const bool use_clnors = mmd->flags & eMultiresModifierFlag_UseCustomNormals &&
mesh->flag & ME_AUTOSMOOTH &&
CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
/* NOTE: Orco needs final coordinates on CPU side, which are expected to be
* accessible via MVert. For this reason we do not evaluate multires to
* grids when orco is requested. */
@ -243,7 +266,22 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
// BKE_subdiv_stats_print(&subdiv->stats);
}
else {
if (use_clnors) {
/* If custom normals are present and the option is turned on calculate the split
* normals and clear flag so the normals get interpolated to the result mesh. */
BKE_mesh_calc_normals_split(mesh);
CustomData_clear_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
result = multires_as_mesh(mmd, ctx, mesh, subdiv);
if (use_clnors) {
float(*lnors)[3] = CustomData_get_layer(&result->ldata, CD_NORMAL);
BLI_assert(lnors != NULL);
BKE_mesh_set_custom_normals(result, lnors);
CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&result->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
// BKE_subdiv_stats_print(&subdiv->stats);
if (subdiv != runtime_data->subdiv) {
BKE_subdiv_free(subdiv);
@ -442,6 +480,7 @@ static void advanced_panel_draw(const bContext *C, Panel *panel)
uiItemR(col, &ptr, "uv_smooth", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "use_creases", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "use_custom_normals", 0, NULL, ICON_NONE);
}
static void panelRegister(ARegionType *region_type)
@ -476,12 +515,12 @@ ModifierTypeInfo modifierType_Multires = {
/* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,

View File

@ -36,6 +36,7 @@
#include "DNA_screen_types.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_subdiv.h"
@ -77,6 +78,26 @@ static void initData(ModifierData *md)
smd->flags |= (eSubsurfModifierFlag_UseCrease | eSubsurfModifierFlag_ControlEdges);
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
SubsurfModifierData *smd = (SubsurfModifierData *)md;
if (smd->flags & eSubsurfModifierFlag_UseCustomNormals) {
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
}
}
static bool dependsOnNormals(ModifierData *md)
{
SubsurfModifierData *smd = (SubsurfModifierData *)md;
if (smd->flags & eSubsurfModifierFlag_UseCustomNormals) {
return true;
}
return false;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
@ -242,6 +263,15 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Happens on bad topology, but also on empty input mesh. */
return result;
}
const bool use_clnors = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
(mesh->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
if (use_clnors) {
/* If custom normals are present and the option is turned on calculate the split
* normals and clear flag so the normals get interpolated to the result mesh. */
BKE_mesh_calc_normals_split(mesh);
CustomData_clear_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
/* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
* maybe when it is a last modifier in the stack? */
if (true) {
@ -250,6 +280,14 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
else {
result = subdiv_as_ccg(smd, ctx, mesh, subdiv);
}
if (use_clnors) {
float(*lnors)[3] = CustomData_get_layer(&result->ldata, CD_NORMAL);
BLI_assert(lnors != NULL);
BKE_mesh_set_custom_normals(result, lnors);
CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&result->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
// BKE_subdiv_stats_print(&subdiv->stats);
if (subdiv != runtime_data->subdiv) {
BKE_subdiv_free(subdiv);
@ -416,6 +454,7 @@ static void advanced_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, &ptr, "quality", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "uv_smooth", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "use_creases", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "use_custom_normals", 0, NULL, ICON_NONE);
}
static void panelRegister(ARegionType *region_type)
@ -453,12 +492,12 @@ ModifierTypeInfo modifierType_Subsurf = {
/* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,