Multires: Subdivide Simple and Subdivide Linear
This introduces two alternative subdivision modes that generates displacement on the grids that look as Simple subdivisions but while using the Catmull-Clark subdivision type in the modifier. This way, Simple and Catmull-Clark subdivision can be combined when creating new levels if needed, for example, to sculpt hard surface objects. Subdivide simple smooths the sculpted data when creating a new subdivision level. Subdivide linear also preserves the sharpness in the sculpted data. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7415
This commit is contained in:
parent
f28875a998
commit
134619fabb
Notes:
blender-bot
2023-02-13 16:16:21 +01:00
Referenced by issue #95666, Crash when attempting multires linear subdivide
|
@ -696,7 +696,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|||
col = split.column()
|
||||
|
||||
col.enabled = ob.mode != 'EDIT'
|
||||
col.operator("object.multires_subdivide", text="Subdivide")
|
||||
op = col.operator("object.multires_subdivide", text="Subdivide")
|
||||
op.mode = 'CATMULL_CLARK'
|
||||
|
||||
op = col.operator("object.multires_subdivide", text="Subdivide Simple")
|
||||
op.mode = 'SIMPLE'
|
||||
|
||||
op = col.operator("object.multires_subdivide", text="Subdivide Linear")
|
||||
op.mode = 'LINEAR'
|
||||
|
||||
col.operator("object.multires_higher_levels_delete", text="Delete Higher")
|
||||
col.operator("object.multires_unsubdivide", text="Unsubdivide")
|
||||
col.operator("object.multires_reshape", text="Reshape")
|
||||
|
|
|
@ -180,13 +180,25 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
|
|||
struct SubdivCCG *subdiv_ccg);
|
||||
|
||||
/* Subdivide multires displacement once. */
|
||||
void multiresModifier_subdivide(struct Object *object, struct MultiresModifierData *mmd);
|
||||
|
||||
typedef enum eMultiresSubdivideModeType {
|
||||
MULTIRES_SUBDIVIDE_CATMULL_CLARK,
|
||||
MULTIRES_SUBDIVIDE_SIMPLE,
|
||||
MULTIRES_SUBDIVIDE_LINEAR,
|
||||
} eMultiresSubdivideModeType;
|
||||
|
||||
void multiresModifier_subdivide(struct Object *object,
|
||||
struct MultiresModifierData *mmd,
|
||||
const eMultiresSubdivideModeType mode);
|
||||
void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object,
|
||||
struct MultiresModifierData *mmd);
|
||||
|
||||
/* Subdivide displacement to the given level.
|
||||
* If level is lower than the current top level nothing happens. */
|
||||
void multiresModifier_subdivide_to_level(struct Object *object,
|
||||
struct MultiresModifierData *mmd,
|
||||
const int top_level);
|
||||
const int top_level,
|
||||
const eMultiresSubdivideModeType mode);
|
||||
|
||||
/* Subdivision integration, defined in multires_subdiv.c */
|
||||
|
||||
|
|
|
@ -175,6 +175,7 @@ set(SRC
|
|||
intern/multires_reshape_apply_base.c
|
||||
intern/multires_reshape_ccg.c
|
||||
intern/multires_reshape_smooth.c
|
||||
intern/multires_reshape_subdivide.c
|
||||
intern/multires_reshape_util.c
|
||||
intern/multires_reshape_vertcos.c
|
||||
intern/multires_subdiv.c
|
||||
|
|
|
@ -2234,7 +2234,14 @@ void multiresModifier_sync_levels_ex(Object *ob_dst,
|
|||
}
|
||||
|
||||
if (mmd_src->totlvl > mmd_dst->totlvl) {
|
||||
multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl);
|
||||
if (mmd_dst->simple) {
|
||||
multiresModifier_subdivide_to_level(
|
||||
ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_SIMPLE);
|
||||
}
|
||||
else {
|
||||
multiresModifier_subdivide_to_level(
|
||||
ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
|
||||
}
|
||||
}
|
||||
else {
|
||||
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
|
@ -37,6 +35,8 @@
|
|||
#include "BKE_modifier.h"
|
||||
#include "BKE_multires.h"
|
||||
#include "BKE_subdiv.h"
|
||||
#include "BKE_subsurf.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
|
@ -171,15 +171,18 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
|
|||
/** \name Subdivision
|
||||
* \{ */
|
||||
|
||||
void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd)
|
||||
void multiresModifier_subdivide(Object *object,
|
||||
MultiresModifierData *mmd,
|
||||
const eMultiresSubdivideModeType mode)
|
||||
{
|
||||
const int top_level = mmd->totlvl + 1;
|
||||
multiresModifier_subdivide_to_level(object, mmd, top_level);
|
||||
multiresModifier_subdivide_to_level(object, mmd, top_level, mode);
|
||||
}
|
||||
|
||||
void multiresModifier_subdivide_to_level(struct Object *object,
|
||||
struct MultiresModifierData *mmd,
|
||||
const int top_level)
|
||||
const int top_level,
|
||||
const eMultiresSubdivideModeType mode)
|
||||
{
|
||||
if (top_level <= mmd->totlvl) {
|
||||
return;
|
||||
|
@ -196,7 +199,12 @@ void multiresModifier_subdivide_to_level(struct Object *object,
|
|||
}
|
||||
if (!has_mdisps || top_level == 1) {
|
||||
multires_reshape_ensure_grids(coarse_mesh, top_level);
|
||||
multires_set_tot_level(object, mmd, top_level);
|
||||
if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) {
|
||||
multires_subdivide_create_tangent_displacement_linear_grids(object, mmd);
|
||||
}
|
||||
else {
|
||||
multires_set_tot_level(object, mmd, top_level);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -205,16 +213,22 @@ void multiresModifier_subdivide_to_level(struct Object *object,
|
|||
if (!multires_reshape_context_create_from_subdivide(&reshape_context, object, mmd, top_level)) {
|
||||
return;
|
||||
}
|
||||
|
||||
multires_reshape_store_original_grids(&reshape_context);
|
||||
multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level);
|
||||
multires_reshape_assign_final_coords_from_orig_mdisps(&reshape_context);
|
||||
|
||||
/* Free original grids which makes it so smoothing with details thinks all the details were
|
||||
* added against base mesh's limit surface. This is similar behavior to as if we've done all
|
||||
* displacement in sculpt mode at the old top level and then propagated to the new top level. */
|
||||
multires_reshape_free_original_grids(&reshape_context);
|
||||
if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) {
|
||||
multires_reshape_smooth_object_grids(&reshape_context, mode);
|
||||
}
|
||||
else {
|
||||
/* Free original grids which makes it so smoothing with details thinks all the details were
|
||||
* added against base mesh's limit surface. This is similar behavior to as if we've done all
|
||||
* displacement in sculpt mode at the old top level and then propagated to the new top level.*/
|
||||
multires_reshape_free_original_grids(&reshape_context);
|
||||
|
||||
multires_reshape_smooth_object_grids_with_details(&reshape_context);
|
||||
multires_reshape_smooth_object_grids_with_details(&reshape_context);
|
||||
}
|
||||
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
|
||||
multires_reshape_context_free(&reshape_context);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define __BKE_INTERN_MULTIRES_RESHAPE_H__
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BKE_multires.h"
|
||||
|
||||
struct Depsgraph;
|
||||
struct GridPaintMask;
|
||||
|
@ -289,7 +290,8 @@ void multires_reshape_smooth_object_grids_with_details(
|
|||
*
|
||||
* Makes it so surface on top level looks smooth. Details are not preserved
|
||||
*/
|
||||
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context);
|
||||
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
|
||||
const enum eMultiresSubdivideModeType mode);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Displacement, space conversion.
|
||||
|
@ -324,5 +326,4 @@ void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshap
|
|||
*
|
||||
* NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */
|
||||
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);
|
||||
|
||||
#endif /* __BKE_INTERN_MULTIRES_RESHAPE_H__ */
|
||||
|
|
|
@ -119,6 +119,14 @@ typedef struct MultiresReshapeSmoothContext {
|
|||
Subdiv *reshape_subdiv;
|
||||
|
||||
SurfaceGrid *base_surface_grids;
|
||||
|
||||
/* Defines how displacement is interpolated on the higher levels (for example, whether
|
||||
* displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges
|
||||
* of the current sculpt level).
|
||||
*
|
||||
* NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and
|
||||
* decoupling type just adds extra headache to convert one enumerator to another. */
|
||||
eMultiresSubdivideModeType smoothing_type;
|
||||
} MultiresReshapeSmoothContext;
|
||||
|
||||
/** \} */
|
||||
|
@ -412,15 +420,17 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co
|
|||
static char get_effective_edge_crease_char(
|
||||
const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
|
||||
{
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
if (reshape_context->subdiv->settings.is_simple) {
|
||||
if (ELEM(reshape_smooth_context->smoothing_type,
|
||||
MULTIRES_SUBDIVIDE_LINEAR,
|
||||
MULTIRES_SUBDIVIDE_SIMPLE)) {
|
||||
return 255;
|
||||
}
|
||||
return base_edge->crease;
|
||||
}
|
||||
|
||||
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
|
||||
const MultiresReshapeContext *reshape_context)
|
||||
const MultiresReshapeContext *reshape_context,
|
||||
const eMultiresSubdivideModeType mode)
|
||||
{
|
||||
reshape_smooth_context->reshape_context = reshape_context;
|
||||
|
||||
|
@ -440,6 +450,8 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
|
|||
reshape_smooth_context->non_loose_base_edge_map = NULL;
|
||||
reshape_smooth_context->reshape_subdiv = NULL;
|
||||
reshape_smooth_context->base_surface_grids = NULL;
|
||||
|
||||
reshape_smooth_context->smoothing_type = mode;
|
||||
}
|
||||
|
||||
static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context)
|
||||
|
@ -474,12 +486,14 @@ static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
|
|||
|
||||
static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
|
||||
const int num_vertices,
|
||||
const int UNUSED(num_edges),
|
||||
const int num_edges,
|
||||
const int num_loops,
|
||||
const int num_polygons)
|
||||
{
|
||||
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
|
||||
const int max_edges = reshape_smooth_context->geometry.max_edges;
|
||||
const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
|
||||
num_edges :
|
||||
reshape_smooth_context->geometry.max_edges;
|
||||
|
||||
/* NOTE: Calloc so the counters are re-set to 0 "for free". */
|
||||
reshape_smooth_context->geometry.num_vertices = num_vertices;
|
||||
|
@ -672,6 +686,22 @@ static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *fore
|
|||
}
|
||||
}
|
||||
|
||||
static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
|
||||
const int subdiv_v1,
|
||||
const int subdiv_v2,
|
||||
const char crease)
|
||||
{
|
||||
/* This is a bit overhead to use atomics in such a simple function called from many threads,
|
||||
* but this allows to save quite measurable amount of memory. */
|
||||
const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
|
||||
BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
|
||||
|
||||
Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
|
||||
edge->v1 = subdiv_v1;
|
||||
edge->v2 = subdiv_v2;
|
||||
edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
|
||||
}
|
||||
|
||||
static void foreach_edge(const struct SubdivForeachContext *foreach_context,
|
||||
void *UNUSED(tls),
|
||||
const int coarse_edge_index,
|
||||
|
@ -682,8 +712,15 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
|
|||
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
|
||||
/* Ignore all inner face edges as they have sharpness of zero. */
|
||||
if (coarse_edge_index == ORIGINDEX_NONE) {
|
||||
if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) {
|
||||
store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, (char)255);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In
|
||||
* simple mode, all edges have maximum sharpness, so they can't be skipped. */
|
||||
if (coarse_edge_index == ORIGINDEX_NONE &&
|
||||
reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE) {
|
||||
return;
|
||||
}
|
||||
/* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */
|
||||
|
@ -697,16 +734,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
|
|||
if (crease == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is a bit overhead to use atomics in such a simple function called from many threads,
|
||||
* but this allows to save quite measurable amount of memory. */
|
||||
const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
|
||||
BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
|
||||
|
||||
Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
|
||||
edge->v1 = subdiv_v1;
|
||||
edge->v2 = subdiv_v2;
|
||||
edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
|
||||
store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease);
|
||||
}
|
||||
|
||||
static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context)
|
||||
|
@ -1212,7 +1240,12 @@ void multires_reshape_smooth_object_grids_with_details(
|
|||
}
|
||||
|
||||
MultiresReshapeSmoothContext reshape_smooth_context;
|
||||
context_init(&reshape_smooth_context, reshape_context);
|
||||
if (reshape_context->mmd->simple) {
|
||||
context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE);
|
||||
}
|
||||
else {
|
||||
context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
|
||||
}
|
||||
|
||||
geometry_create(&reshape_smooth_context);
|
||||
|
||||
|
@ -1228,7 +1261,8 @@ void multires_reshape_smooth_object_grids_with_details(
|
|||
context_free(&reshape_smooth_context);
|
||||
}
|
||||
|
||||
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context)
|
||||
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
|
||||
const eMultiresSubdivideModeType mode)
|
||||
{
|
||||
const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
|
||||
if (level_difference == 0) {
|
||||
|
@ -1237,7 +1271,7 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
|
|||
}
|
||||
|
||||
MultiresReshapeSmoothContext reshape_smooth_context;
|
||||
context_init(&reshape_smooth_context, reshape_context);
|
||||
context_init(&reshape_smooth_context, reshape_context, mode);
|
||||
|
||||
geometry_create(&reshape_smooth_context);
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2020 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_multires.h"
|
||||
#include "BKE_subdiv.h"
|
||||
#include "BKE_subsurf.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "multires_reshape.h"
|
||||
|
||||
void multires_subdivide_create_object_space_linear_grids(Mesh *mesh)
|
||||
{
|
||||
MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
|
||||
const int totpoly = mesh->totpoly;
|
||||
for (int p = 0; p < totpoly; p++) {
|
||||
MPoly *poly = &mesh->mpoly[p];
|
||||
float poly_center[3];
|
||||
BKE_mesh_calc_poly_center(poly, &mesh->mloop[poly->loopstart], mesh->mvert, poly_center);
|
||||
for (int l = 0; l < poly->totloop; l++) {
|
||||
const int loop_index = poly->loopstart + l;
|
||||
|
||||
float(*disps)[3] = mdisps[loop_index].disps;
|
||||
mdisps[loop_index].totdisp = 4;
|
||||
mdisps[loop_index].level = 1;
|
||||
|
||||
int prev_loop_index = l - 1 >= 0 ? loop_index - 1 : loop_index + poly->totloop - 1;
|
||||
int next_loop_index = l + 1 < poly->totloop ? loop_index + 1 : poly->loopstart;
|
||||
|
||||
MLoop *loop = &mesh->mloop[loop_index];
|
||||
MLoop *loop_next = &mesh->mloop[next_loop_index];
|
||||
MLoop *loop_prev = &mesh->mloop[prev_loop_index];
|
||||
|
||||
copy_v3_v3(disps[0], poly_center);
|
||||
mid_v3_v3v3(disps[1], mesh->mvert[loop->v].co, mesh->mvert[loop_next->v].co);
|
||||
mid_v3_v3v3(disps[2], mesh->mvert[loop->v].co, mesh->mvert[loop_prev->v].co);
|
||||
copy_v3_v3(disps[3], mesh->mvert[loop->v].co);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void multires_subdivide_create_tangent_displacement_linear_grids(Object *object,
|
||||
MultiresModifierData *mmd)
|
||||
{
|
||||
Mesh *coarse_mesh = object->data;
|
||||
multires_force_sculpt_rebuild(object);
|
||||
|
||||
MultiresReshapeContext reshape_context;
|
||||
|
||||
const int new_top_level = mmd->totlvl + 1;
|
||||
|
||||
const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS);
|
||||
if (!has_mdisps) {
|
||||
CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop);
|
||||
}
|
||||
|
||||
if (new_top_level == 1) {
|
||||
/* No MDISPS. Create new grids for level 1 using the edges mid point and poly centers. */
|
||||
multires_reshape_ensure_grids(coarse_mesh, 1);
|
||||
multires_subdivide_create_object_space_linear_grids(coarse_mesh);
|
||||
}
|
||||
|
||||
/* Convert the new grids to tangent displacement. */
|
||||
multires_set_tot_level(object, mmd, new_top_level);
|
||||
|
||||
if (!multires_reshape_context_create_from_subdivide(
|
||||
&reshape_context, object, mmd, new_top_level)) {
|
||||
return;
|
||||
}
|
||||
|
||||
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
|
||||
multires_reshape_context_free(&reshape_context);
|
||||
}
|
|
@ -1433,6 +1433,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
|
|||
/** \name Multires Subdivide Operator
|
||||
* \{ */
|
||||
|
||||
static EnumPropertyItem prop_multires_subdivide_mode_type[] = {
|
||||
{MULTIRES_SUBDIVIDE_CATMULL_CLARK,
|
||||
"CATMULL_CLARK",
|
||||
0,
|
||||
"Catmull-Clark",
|
||||
"Create a new level using Catmull-Clark subdivisions"},
|
||||
{MULTIRES_SUBDIVIDE_SIMPLE,
|
||||
"SIMPLE",
|
||||
0,
|
||||
"Simple",
|
||||
"Create a new level using simple subdivisions"},
|
||||
{MULTIRES_SUBDIVIDE_LINEAR,
|
||||
"LINEAR",
|
||||
0,
|
||||
"Linear",
|
||||
"Create a new level using linear interpolation of the sculpted displacement"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static int multires_subdivide_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *object = ED_object_active_context(C);
|
||||
|
@ -1443,7 +1462,9 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
multiresModifier_subdivide(object, mmd);
|
||||
const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)(
|
||||
RNA_enum_get(op->ptr, "mode"));
|
||||
multiresModifier_subdivide(object, mmd, subdivide_mode);
|
||||
|
||||
ED_object_iter_other(
|
||||
CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl);
|
||||
|
@ -1482,6 +1503,12 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
|
|||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
edit_modifier_properties(ot);
|
||||
RNA_def_enum(ot->srna,
|
||||
"mode",
|
||||
prop_multires_subdivide_mode_type,
|
||||
MULTIRES_SUBDIVIDE_CATMULL_CLARK,
|
||||
"Subdivision Mode",
|
||||
"How the mesh is going to be subdivided to create a new level");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
Loading…
Reference in New Issue