Multires: Unsubdivide and Rebuild Subdivisions
This implements the main unsubdivide algorithm which rebuilds a base mesh and extracts the grid's data from a high resolution mesh. It includes the Rebuild Subdivisions operator, which generates all subdivision levels down to the level 0 base mesh. It supports: - Rebuilding an arbitrary number of levels (Unsubdivide) or as many levels as possible down to level 0 in a single step (Rebuild Subdivisions). - Rebuilding with already existing grids. - Meshes with n-gons and triangles - Meshes with more than 2 faces per edge - Base mesh made completely out of triangles - Meshes without poles - Meshes with multiple disconnected elements at the same subdivision level Reviewed By: sergey Differential Revision: https://developer.blender.org/D7372
This commit is contained in:
parent
d4c547b7bd
commit
f28875a998
|
@ -698,8 +698,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|||
col.enabled = ob.mode != 'EDIT'
|
||||
col.operator("object.multires_subdivide", text="Subdivide")
|
||||
col.operator("object.multires_higher_levels_delete", text="Delete Higher")
|
||||
col.operator("object.multires_unsubdivide", text="Unsubdivide")
|
||||
col.operator("object.multires_reshape", text="Reshape")
|
||||
col.operator("object.multires_base_apply", text="Apply Base")
|
||||
col.operator("object.multires_rebuild_subdiv", text="Rebuild Subdivisions")
|
||||
col.prop(md, "uv_smooth", text="")
|
||||
col.prop(md, "show_only_control_edges")
|
||||
col.prop(md, "use_creases")
|
||||
|
|
|
@ -110,6 +110,11 @@ void multiresModifier_del_levels(struct MultiresModifierData *mmd,
|
|||
void multiresModifier_base_apply(struct Depsgraph *depsgraph,
|
||||
struct Object *object,
|
||||
struct MultiresModifierData *mmd);
|
||||
int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
|
||||
struct Object *object,
|
||||
struct MultiresModifierData *mmd,
|
||||
int rebuild_limit,
|
||||
bool switch_view_to_lower_level);
|
||||
void multiresModifier_subdivide_legacy(struct MultiresModifierData *mmd,
|
||||
struct Scene *scene,
|
||||
struct Object *ob,
|
||||
|
|
|
@ -178,6 +178,7 @@ set(SRC
|
|||
intern/multires_reshape_util.c
|
||||
intern/multires_reshape_vertcos.c
|
||||
intern/multires_subdiv.c
|
||||
intern/multires_unsubdivide.c
|
||||
intern/nla.c
|
||||
intern/node.c
|
||||
intern/object.c
|
||||
|
@ -397,6 +398,7 @@ set(SRC
|
|||
intern/lib_intern.h
|
||||
intern/multires_inline.h
|
||||
intern/multires_reshape.h
|
||||
intern/multires_unsubdivide.h
|
||||
intern/pbvh_intern.h
|
||||
intern/subdiv_converter.h
|
||||
intern/subdiv_inline.h
|
||||
|
|
|
@ -156,6 +156,11 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
|
|||
struct Object *object,
|
||||
struct MultiresModifierData *mmd);
|
||||
|
||||
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct Object *object,
|
||||
struct MultiresModifierData *mmd);
|
||||
|
||||
bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context,
|
||||
struct SubdivCCG *subdiv_ccg,
|
||||
struct Mesh *base_mesh,
|
||||
|
|
|
@ -152,6 +152,39 @@ static bool context_verify_or_free(MultiresReshapeContext *reshape_context)
|
|||
return is_valid;
|
||||
}
|
||||
|
||||
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
|
||||
Depsgraph *depsgraph,
|
||||
Object *object,
|
||||
MultiresModifierData *mmd)
|
||||
{
|
||||
context_zero(reshape_context);
|
||||
|
||||
const bool use_render_params = false;
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
|
||||
Mesh *base_mesh = (Mesh *)object->data;
|
||||
|
||||
reshape_context->depsgraph = depsgraph;
|
||||
reshape_context->object = object;
|
||||
reshape_context->mmd = mmd;
|
||||
|
||||
reshape_context->base_mesh = base_mesh;
|
||||
|
||||
reshape_context->subdiv = multires_reshape_create_subdiv(NULL, object, mmd);
|
||||
reshape_context->need_free_subdiv = true;
|
||||
|
||||
reshape_context->reshape.level = multires_get_level(
|
||||
scene_eval, object, mmd, use_render_params, true);
|
||||
reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
|
||||
reshape_context->reshape.level);
|
||||
|
||||
reshape_context->top.level = mmd->totlvl;
|
||||
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
|
||||
|
||||
context_init_commoon(reshape_context);
|
||||
|
||||
return context_verify_or_free(reshape_context);
|
||||
}
|
||||
|
||||
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
|
||||
Depsgraph *depsgraph,
|
||||
Object *object,
|
||||
|
@ -272,9 +305,9 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
|
|||
|
||||
multires_reshape_free_original_grids(reshape_context);
|
||||
|
||||
MEM_freeN(reshape_context->face_start_grid_index);
|
||||
MEM_freeN(reshape_context->ptex_start_grid_index);
|
||||
MEM_freeN(reshape_context->grid_to_face_index);
|
||||
MEM_SAFE_FREE(reshape_context->face_start_grid_index);
|
||||
MEM_SAFE_FREE(reshape_context->ptex_start_grid_index);
|
||||
MEM_SAFE_FREE(reshape_context->grid_to_face_index);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__
|
||||
#define __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
struct BMesh;
|
||||
struct Depsgraph;
|
||||
struct Mesh;
|
||||
struct MultiresModifierData;
|
||||
struct Object;
|
||||
|
||||
typedef struct MultiresUnsubdivideGrid {
|
||||
/* For sanity checks. */
|
||||
int grid_index;
|
||||
int grid_size;
|
||||
|
||||
/* Grid coordinates in object space. */
|
||||
float (*grid_co)[3];
|
||||
|
||||
} MultiresUnsubdivideGrid;
|
||||
|
||||
typedef struct MultiresUnsubdivideContext {
|
||||
/* Input Mesh to unsubdivide. */
|
||||
struct Mesh *original_mesh;
|
||||
struct MDisps *original_mdisp;
|
||||
|
||||
/* Number of subdivision in the grids of the input mesh. */
|
||||
int num_original_levels;
|
||||
|
||||
/* Level 0 base mesh after applying the maximum amount of unsubdivisions. */
|
||||
struct Mesh *base_mesh;
|
||||
|
||||
/* Limit on how many levels down the unsubdivide operation should create, if possible. */
|
||||
int max_new_levels;
|
||||
|
||||
/* New levels that were created after unsubdividing. */
|
||||
int num_new_levels;
|
||||
|
||||
/* Number of subdivisions that should be applied to the base mesh. (num_new_levels +
|
||||
* num_original_levels)
|
||||
*/
|
||||
int num_total_levels;
|
||||
|
||||
/* Data for the new grids, indexed by base mesh loop index. */
|
||||
int num_grids;
|
||||
struct MultiresUnsubdivideGrid *base_mesh_grids;
|
||||
|
||||
/* Private data. */
|
||||
struct BMesh *bm_original_mesh;
|
||||
int *loop_to_face_map;
|
||||
int *base_to_orig_vmap;
|
||||
} MultiresUnsubdivideContext;
|
||||
|
||||
/* ================================================================================================
|
||||
* Construct/destruct reshape context.
|
||||
*/
|
||||
|
||||
void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context,
|
||||
struct Mesh *original_mesh,
|
||||
struct MultiresModifierData *mmd);
|
||||
void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context);
|
||||
|
||||
/* ================================================================================================
|
||||
* Rebuild Lower Subdivisions.
|
||||
*/
|
||||
|
||||
/* Rebuilds all subdivision to the level 0 base mesh. */
|
||||
bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context);
|
||||
|
||||
#endif /* __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ */
|
|
@ -169,6 +169,8 @@ void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
|
|||
void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_unsubdivide(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_rebuild_subdiv(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
|
||||
|
|
|
@ -1738,6 +1738,119 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Multires Unsubdivide
|
||||
* \{ */
|
||||
|
||||
static int multires_unsubdivide_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Object *object = ED_object_active_context(C);
|
||||
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
|
||||
op, object, eModifierType_Multires);
|
||||
|
||||
if (!mmd) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
|
||||
if (new_levels == 0) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
if (edit_modifier_invoke_properties(C, op)) {
|
||||
return multires_unsubdivide_exec(C, op);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Unsubdivide";
|
||||
ot->description = "Rebuild a lower subdivision level of the current base mesh";
|
||||
ot->idname = "OBJECT_OT_multires_unsubdivide";
|
||||
|
||||
ot->poll = multires_poll;
|
||||
ot->invoke = multires_unsubdivide_invoke;
|
||||
ot->exec = multires_unsubdivide_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
edit_modifier_properties(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Multires Rebuild Subdivisions
|
||||
* \{ */
|
||||
|
||||
static int multires_rebuild_subdiv_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Object *object = ED_object_active_context(C);
|
||||
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
|
||||
op, object, eModifierType_Multires);
|
||||
|
||||
if (!mmd) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false);
|
||||
if (new_levels == 0) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild lower levels");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels);
|
||||
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int multires_rebuild_subdiv_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *UNUSED(event))
|
||||
{
|
||||
if (edit_modifier_invoke_properties(C, op)) {
|
||||
return multires_rebuild_subdiv_exec(C, op);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Rebuild Lower Subdivisions";
|
||||
ot->description =
|
||||
"Rebuilds all possible subdivisions levels to generate a lower resolution base mesh";
|
||||
ot->idname = "OBJECT_OT_multires_rebuild_subdiv";
|
||||
|
||||
ot->poll = multires_poll;
|
||||
ot->invoke = multires_rebuild_subdiv_invoke;
|
||||
ot->exec = multires_rebuild_subdiv_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
edit_modifier_properties(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Skin Modifier
|
||||
* \{ */
|
||||
|
|
|
@ -137,6 +137,8 @@ void ED_operatortypes_object(void)
|
|||
WM_operatortype_append(OBJECT_OT_multires_reshape);
|
||||
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
|
||||
WM_operatortype_append(OBJECT_OT_multires_base_apply);
|
||||
WM_operatortype_append(OBJECT_OT_multires_unsubdivide);
|
||||
WM_operatortype_append(OBJECT_OT_multires_rebuild_subdiv);
|
||||
WM_operatortype_append(OBJECT_OT_multires_external_save);
|
||||
WM_operatortype_append(OBJECT_OT_multires_external_pack);
|
||||
WM_operatortype_append(OBJECT_OT_skin_root_mark);
|
||||
|
|
Loading…
Reference in New Issue