Blender V4.3
multires_unsubdivide.cc File Reference
#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 "BLI_gsqueue.h"
#include "BLI_math_vector.h"
#include "BKE_customdata.hh"
#include "BKE_mesh.hh"
#include "BKE_multires.hh"
#include "BKE_subsurf.hh"
#include "bmesh.hh"
#include "multires_reshape.hh"
#include "multires_unsubdivide.hh"

Go to the source code of this file.

Functions

static bool is_vertex_in_id (BMVert *v, const int *elem_id, int elem)
 
static bool is_vertex_pole_three (BMVert *v)
 
static bool is_vertex_pole (BMVert *v)
 
static BMVertunsubdivide_find_any_pole (BMesh *bm, int *elem_id, int elem)
 
static bool unsubdivide_is_all_quads (BMesh *bm)
 
static bool is_vertex_diagonal (BMVert *from_v, BMVert *to_v)
 
static void unsubdivide_face_center_vertex_tag (BMesh *bm, BMVert *initial_vertex)
 
static bool unsubdivide_is_center_vertex_tag_valid (BMesh *bm, int *elem_id, int elem)
 
static bool unsubdivide_tag_disconnected_mesh_element (BMesh *bm, int *elem_id, int elem)
 
static int unsubdivide_init_elem_ids (BMesh *bm, int *elem_id)
 
static void unsubdivide_build_base_mesh_from_tags (BMesh *bm)
 
static bool multires_unsubdivide_single_level (BMesh *bm)
 
static BMEdgeedge_step (BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
 
static BMFaceface_step (BMEdge *edge, BMFace *f)
 
static BMEdgeget_initial_edge_y (BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
 
static void write_loop_in_face_grid (float(*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
 
static void write_face_grid_in_unsubdivide_grid (MultiresUnsubdivideGrid *grid, float(*face_grid)[3], int face_grid_size, int gunsub_x, int gunsub_y)
 
static void store_grid_data (MultiresUnsubdivideContext *context, MultiresUnsubdivideGrid *grid, BMVert *v, BMFace *f, int grid_x, int grid_y)
 
static void store_vertex_data (MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
 
static void multires_unsubdivide_extract_single_grid_from_face_edge (MultiresUnsubdivideContext *context, BMFace *f1, BMEdge *e1, bool flip_grid, MultiresUnsubdivideGrid *grid)
 
static void multires_unsubdivide_get_grid_corners_on_base_mesh (BMFace *f1, BMEdge *e1, BMVert **r_corner_x, BMVert **r_corner_y)
 
static BMeshget_bmesh_from_mesh (Mesh *mesh)
 
static void multires_unsubdivide_free_original_datalayers (Mesh *mesh)
 
static void multires_unsubdivide_add_original_index_datalayers (Mesh *mesh)
 
static void multires_unsubdivide_prepare_original_bmesh_for_extract (MultiresUnsubdivideContext *context)
 
static bool multires_unsubdivide_flip_grid_x_axis (const blender::OffsetIndices< int > faces, const blender::Span< int > corner_verts, int face_index, int loop, int v_x)
 
static void multires_unsubdivide_extract_grids (MultiresUnsubdivideContext *context)
 
static void multires_unsubdivide_private_extract_data_free (MultiresUnsubdivideContext *context)
 
void multires_unsubdivide_context_init (MultiresUnsubdivideContext *context, Mesh *original_mesh, MultiresModifierData *mmd)
 
bool multires_unsubdivide_to_basemesh (MultiresUnsubdivideContext *context)
 
void multires_unsubdivide_context_free (MultiresUnsubdivideContext *context)
 
static void multires_create_grids_in_unsubdivided_base_mesh (MultiresUnsubdivideContext *context, Mesh *base_mesh)
 
int multiresModifier_rebuild_subdiv (Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd, int rebuild_limit, bool switch_view_to_lower_level)
 

Variables

static const char lname [] = "l_remap_index"
 
static const char vname [] = "v_remap_index"
 

Detailed Description

This implements the un-subdivide algorithm, which generates a lower resolution base mesh and its corresponding grids to match a given original mesh.

Definition in file multires_unsubdivide.cc.

Function Documentation

◆ edge_step()

static BMEdge * edge_step ( BMVert * v,
BMEdge * edge,
BMVert ** r_next_vertex )
static

Returns the next edge and vertex in the direction of a given edge.

Definition at line 482 of file multires_unsubdivide.cc.

References BM_edge_other_vert(), BM_edge_share_quad_check(), BM_EDGES_OF_VERT, BM_ITER_ELEM, and v.

Referenced by multires_unsubdivide_extract_single_grid_from_face_edge(), and multires_unsubdivide_get_grid_corners_on_base_mesh().

◆ face_step()

◆ get_bmesh_from_mesh()

◆ get_initial_edge_y()

static BMEdge * get_initial_edge_y ( BMFace * f,
BMEdge * edge_x,
BMVert * initial_vertex )
static

Returns the other edge which belongs to the face f which is different from edge_x and shares initial_vertex.

Definition at line 516 of file multires_unsubdivide.cc.

References BM_EDGES_OF_FACE, BM_ITER_ELEM, BMEdge::v1, and BMEdge::v2.

Referenced by multires_unsubdivide_extract_single_grid_from_face_edge(), and multires_unsubdivide_get_grid_corners_on_base_mesh().

◆ is_vertex_diagonal()

static bool is_vertex_diagonal ( BMVert * from_v,
BMVert * to_v )
static

Returns true if from_v and to_v, which should be part of the same quad face, are diagonals.

Definition at line 134 of file multires_unsubdivide.cc.

References BM_edge_exists().

Referenced by unsubdivide_face_center_vertex_tag().

◆ is_vertex_in_id()

static bool is_vertex_in_id ( BMVert * v,
const int * elem_id,
int elem )
static

Used to check if a vertex is in a disconnected element ID.

Definition at line 62 of file multires_unsubdivide.cc.

References BM_elem_index_get, and v.

Referenced by unsubdivide_find_any_pole(), unsubdivide_is_center_vertex_tag_valid(), and unsubdivide_tag_disconnected_mesh_element().

◆ is_vertex_pole()

static bool is_vertex_pole ( BMVert * v)
static

◆ is_vertex_pole_three()

static bool is_vertex_pole_three ( BMVert * v)
static

Definition at line 68 of file multires_unsubdivide.cc.

References BM_vert_edge_count_is_equal, BM_vert_is_boundary(), and v.

Referenced by unsubdivide_find_any_pole().

◆ multires_create_grids_in_unsubdivided_base_mesh()

static void multires_create_grids_in_unsubdivided_base_mesh ( MultiresUnsubdivideContext * context,
Mesh * base_mesh )
static

This function allocates new mdisps with the right size to fit the new extracted grids from the base mesh and copies the data to them.

Definition at line 1175 of file multires_unsubdivide.cc.

References BKE_ccg_gridsize(), BLI_assert, CD_MDISPS, CD_SET_DEFAULT, copy_v3_v3(), Mesh::corner_data, Mesh::corners_num, CustomData_add_layer(), CustomData_free_layers(), CustomData_has_layer(), MDisps::disps, float, MDisps::level, MEM_calloc_arrayN, MEM_freeN(), pow_i(), and MDisps::totdisp.

Referenced by multiresModifier_rebuild_subdiv().

◆ multires_unsubdivide_add_original_index_datalayers()

static void multires_unsubdivide_add_original_index_datalayers ( Mesh * mesh)
static

Generates two data-layers to map loops and vertices from base mesh to original mesh after dissolving the vertices.

Definition at line 889 of file multires_unsubdivide.cc.

References CD_PROP_INT32, CD_SET_DEFAULT, CustomData_add_layer_named(), lname, multires_unsubdivide_free_original_datalayers(), and vname.

Referenced by multires_unsubdivide_extract_grids(), and multires_unsubdivide_to_basemesh().

◆ multires_unsubdivide_context_free()

void multires_unsubdivide_context_free ( MultiresUnsubdivideContext * context)

◆ multires_unsubdivide_context_init()

void multires_unsubdivide_context_init ( MultiresUnsubdivideContext * context,
Mesh * original_mesh,
MultiresModifierData * mmd )

Definition at line 1102 of file multires_unsubdivide.cc.

References MultiresModifierData::totlvl.

Referenced by multiresModifier_rebuild_subdiv().

◆ multires_unsubdivide_extract_grids()

◆ multires_unsubdivide_extract_single_grid_from_face_edge()

static void multires_unsubdivide_extract_single_grid_from_face_edge ( MultiresUnsubdivideContext * context,
BMFace * f1,
BMEdge * e1,
bool flip_grid,
MultiresUnsubdivideGrid * grid )
static

◆ multires_unsubdivide_flip_grid_x_axis()

static bool multires_unsubdivide_flip_grid_x_axis ( const blender::OffsetIndices< int > faces,
const blender::Span< int > corner_verts,
int face_index,
int loop,
int v_x )
static

Checks the orientation of the loops to flip the x and y axis when extracting the grid if necessary.

Definition at line 944 of file multires_unsubdivide.cc.

Referenced by multires_unsubdivide_extract_grids().

◆ multires_unsubdivide_free_original_datalayers()

static void multires_unsubdivide_free_original_datalayers ( Mesh * mesh)
static

◆ multires_unsubdivide_get_grid_corners_on_base_mesh()

static void multires_unsubdivide_get_grid_corners_on_base_mesh ( BMFace * f1,
BMEdge * e1,
BMVert ** r_corner_x,
BMVert ** r_corner_y )
static

Returns the l+1 and l-1 vertices of the base mesh face were the grid from the face f1 and edge e1 is going to be extracted.

These vertices should always have an corresponding existing vertex on the base mesh.

Definition at line 808 of file multires_unsubdivide.cc.

References BM_elem_flag_test, BM_ELEM_TAG, edge_step(), get_initial_edge_y(), BMEdge::v1, and BMEdge::v2.

Referenced by multires_unsubdivide_extract_grids().

◆ multires_unsubdivide_prepare_original_bmesh_for_extract()

◆ multires_unsubdivide_private_extract_data_free()

static void multires_unsubdivide_private_extract_data_free ( MultiresUnsubdivideContext * context)
static

Definition at line 1095 of file multires_unsubdivide.cc.

References BM_mesh_free().

Referenced by multires_unsubdivide_context_free().

◆ multires_unsubdivide_single_level()

static bool multires_unsubdivide_single_level ( BMesh * bm)
static

Main function to get a base mesh one level down from the current original mesh if it exists.

This searches for different un-subdivide solutions and stores them as a combination of BMVert flags for each disconnected mesh element.

If the solution for all elements are valid, it builds a new base mesh based on those tags by dissolving and merging vertices.

Definition at line 435 of file multires_unsubdivide.cc.

References bm, BM_EDGE, BM_ELEM_HIDDEN, BM_ELEM_SELECT, BM_ELEM_TAG, BM_FACE, BM_mesh_elem_hflag_disable_all(), BM_mesh_elem_table_ensure(), BM_mesh_elem_table_init(), BM_VERT, MEM_calloc_arrayN, MEM_freeN(), BMesh::totvert, unsubdivide_build_base_mesh_from_tags(), unsubdivide_init_elem_ids(), unsubdivide_is_all_quads(), and unsubdivide_tag_disconnected_mesh_element().

Referenced by multires_unsubdivide_to_basemesh().

◆ multires_unsubdivide_to_basemesh()

◆ multiresModifier_rebuild_subdiv()

◆ store_grid_data()

static void store_grid_data ( MultiresUnsubdivideContext * context,
MultiresUnsubdivideGrid * grid,
BMVert * v,
BMFace * f,
int grid_x,
int grid_y )
static

Stores the data from the mdisps grids of the loops of the face f into the new grid for the new base mesh.

Used when there are already grids in the original mesh.

Definition at line 623 of file multires_unsubdivide.cc.

References BKE_ccg_gridsize(), BM_elem_index_get, float, MEM_calloc_arrayN, MEM_freeN(), v, write_face_grid_in_unsubdivide_grid(), and write_loop_in_face_grid().

Referenced by multires_unsubdivide_extract_single_grid_from_face_edge().

◆ store_vertex_data()

static void store_vertex_data ( MultiresUnsubdivideGrid * grid,
BMVert * v,
int grid_x,
int grid_y )
static

Stores the data into the new grid from a BMVert. Used when there are no grids in the original mesh.

Definition at line 679 of file multires_unsubdivide.cc.

References BMVert::co, copy_v3_v3(), and v.

Referenced by multires_unsubdivide_extract_single_grid_from_face_edge().

◆ unsubdivide_build_base_mesh_from_tags()

static void unsubdivide_build_base_mesh_from_tags ( BMesh * bm)
static

Builds a base mesh one subdivision level down from the current original mesh if the original mesh has a valid solution stored in the BMVert tags.

Definition at line 381 of file multires_unsubdivide.cc.

References bm, BM_EDGE, BM_edge_other_vert(), BM_EDGES_OF_VERT, BM_elem_flag_set, BM_elem_flag_test, BM_ELEM_SELECT, BM_ELEM_TAG, BM_FACE, BM_ITER_ELEM, BM_ITER_MESH, BM_mesh_elem_hflag_disable_all(), BM_mesh_elem_hflag_enable_all(), BM_VERT, BM_VERTS_OF_MESH, BMO_FLAG_DEFAULTS, BMO_FLAG_RESPECT_HIDE, BMO_op_callf(), and v.

Referenced by multires_unsubdivide_single_level().

◆ unsubdivide_face_center_vertex_tag()

static void unsubdivide_face_center_vertex_tag ( BMesh * bm,
BMVert * initial_vertex )
static

Generates a possible solution for un-subdivision by tagging the (0,0) vertices of the possible grids.

This works using a flood fill operation using the quads diagonals to jump to the next vertex.

If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0) vertices of the grids that need to be dissolved, and nothing else.

Definition at line 148 of file multires_unsubdivide.cc.

References BLI_gsqueue_free(), BLI_gsqueue_is_empty(), BLI_gsqueue_new(), BLI_gsqueue_pop(), BLI_gsqueue_push(), bm, BM_elem_flag_set, BM_elem_index_get, BM_ELEM_TAG, BM_FACES_OF_VERT, BM_ITER_ELEM, BM_VERTS_OF_FACE, is_vertex_diagonal(), and BMesh::totvert.

Referenced by unsubdivide_tag_disconnected_mesh_element().

◆ unsubdivide_find_any_pole()

static BMVert * unsubdivide_find_any_pole ( BMesh * bm,
int * elem_id,
int elem )
static

Returns the first pole that is found in an element ID.

Tries to give priority to 3 vert poles as they generally generate better results in cases were the un-subdivide solution is ambiguous.

Definition at line 85 of file multires_unsubdivide.cc.

References bm, BM_ITER_MESH, BM_VERTS_OF_MESH, is_vertex_in_id(), is_vertex_pole(), is_vertex_pole_three(), and v.

Referenced by unsubdivide_tag_disconnected_mesh_element().

◆ unsubdivide_init_elem_ids()

static int unsubdivide_init_elem_ids ( BMesh * bm,
int * elem_id )
static

◆ unsubdivide_is_all_quads()

static bool unsubdivide_is_all_quads ( BMesh * bm)
static

Checks if the mesh is all quads.

TODO(pablodp606): This can perform additional checks if they are faster than trying to search for an un-subdivide solution. This way it is possible to cancel the operation faster.

Definition at line 107 of file multires_unsubdivide.cc.

References bm, BM_FACES_OF_MESH, BM_ITER_MESH, BM_vert_is_wire(), BM_VERTS_OF_MESH, BMVert::e, BMFace::len, BMesh::totface, and v.

Referenced by multires_unsubdivide_single_level().

◆ unsubdivide_is_center_vertex_tag_valid()

static bool unsubdivide_is_center_vertex_tag_valid ( BMesh * bm,
int * elem_id,
int elem )
static

This function checks if the current status of the BMVert tags corresponds to a valid un-subdivide solution.

This means that all vertices corresponding to the (0,0) grid coordinate should be tagged.

On a valid solution, the following things should happen:

  • No boundary vertices should be tagged
  • No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged
  • All boundary vertices should have one vertex connected by an edge or a diagonal tagged

Definition at line 227 of file multires_unsubdivide.cc.

References bm, BM_elem_flag_test, BM_ELEM_TAG, BM_FACES_OF_VERT, BM_ITER_ELEM, BM_ITER_MESH, BM_vert_is_boundary(), BM_VERTS_OF_FACE, BM_VERTS_OF_MESH, is_vertex_in_id(), and v.

Referenced by unsubdivide_tag_disconnected_mesh_element().

◆ unsubdivide_tag_disconnected_mesh_element()

◆ write_face_grid_in_unsubdivide_grid()

static void write_face_grid_in_unsubdivide_grid ( MultiresUnsubdivideGrid * grid,
float(*) face_grid[3],
int face_grid_size,
int gunsub_x,
int gunsub_y )
static

Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into the main MultiresUnsubdivideGrid that is being extracted.

Definition at line 597 of file multires_unsubdivide.cc.

References copy_v3_v3().

Referenced by store_grid_data().

◆ write_loop_in_face_grid()

static void write_loop_in_face_grid ( float(*) face_grid[3],
MDisps * mdisp,
int face_grid_size,
int orig_grid_size,
int loop )
static

Writes the current mdisp data into the corresponding area of quad face giving its corner's loop.

Definition at line 536 of file multires_unsubdivide.cc.

References BLI_assert_msg, copy_v3_v3(), MDisps::disps, and x.

Referenced by store_grid_data().

Variable Documentation

◆ lname

◆ vname