Blender  V3.3
Functions | Variables
multires_unsubdivide.c 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.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 "bmesh.h"
#include "DEG_depsgraph_query.h"
#include "multires_reshape.h"
#include "multires_unsubdivide.h"

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 (Mesh *mesh, int poly, 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, struct 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 (struct Depsgraph *depsgraph, struct Object *object, struct 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.c.

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 494 of file multires_unsubdivide.c.

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

Referenced by multires_unsubdivide_extract_single_grid_from_face_edge(), and multires_unsubdivide_get_grid_corners_on_base_mesh().

◆ face_step()

static BMFace* face_step ( BMEdge edge,
BMFace f 
)
static

◆ get_bmesh_from_mesh()

static BMesh* get_bmesh_from_mesh ( Mesh mesh)
static

◆ 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 528 of file multires_unsubdivide.c.

References BM_EDGES_OF_FACE, BM_ITER_ELEM, NULL, 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 148 of file multires_unsubdivide.c.

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 67 of file multires_unsubdivide.c.

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

Definition at line 78 of file multires_unsubdivide.c.

References BM_vert_edge_count(), BM_vert_is_boundary(), and v.

Referenced by unsubdivide_find_any_pole().

◆ is_vertex_pole_three()

static bool is_vertex_pole_three ( BMVert v)
static

Definition at line 73 of file multires_unsubdivide.c.

References BM_vert_edge_count(), 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 1169 of file multires_unsubdivide.c.

References BKE_ccg_gridsize(), BLI_assert, CD_CALLOC, CD_MDISPS, blender::compositor::context, copy_v3_v3(), CustomData_add_layer(), CustomData_free_layers(), CustomData_has_layer(), MDisps::disps, float(), Mesh::ldata, MDisps::level, MEM_calloc_arrayN, MEM_freeN, NULL, pow_i(), MDisps::totdisp, and Mesh::totloop.

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 899 of file multires_unsubdivide.c.

References CD_CALLOC, CD_PROP_INT32, CustomData_add_layer_named(), Mesh::ldata, lname, mesh, multires_unsubdivide_free_original_datalayers(), NULL, Mesh::totloop, Mesh::totvert, Mesh::vdata, 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,
struct MultiresModifierData mmd 
)

◆ multires_unsubdivide_extract_grids()

static void multires_unsubdivide_extract_grids ( MultiresUnsubdivideContext context)
static

◆ 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 ( Mesh mesh,
int  poly,
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 964 of file multires_unsubdivide.c.

References MPoly::loopstart, mesh, Mesh::mloop, Mesh::mpoly, MPoly::totloop, and MLoop::v.

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 poly 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 818 of file multires_unsubdivide.c.

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()

static void multires_unsubdivide_prepare_original_bmesh_for_extract ( MultiresUnsubdivideContext context)
static

◆ multires_unsubdivide_private_extract_data_free()

static void multires_unsubdivide_private_extract_data_free ( MultiresUnsubdivideContext context)
static

◆ 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 448 of file multires_unsubdivide.c.

References bm, BM_EDGE, 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()

bool multires_unsubdivide_to_basemesh ( MultiresUnsubdivideContext context)

◆ multiresModifier_rebuild_subdiv()

int multiresModifier_rebuild_subdiv ( struct Depsgraph depsgraph,
struct Object object,
struct MultiresModifierData mmd,
int  rebuild_limit,
bool  switch_view_to_lower_level 
)

◆ 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 635 of file multires_unsubdivide.c.

References BKE_ccg_gridsize(), BM_elem_index_get, blender::compositor::context, float(), l, MPoly::loopstart, MEM_calloc_arrayN, MEM_freeN, Mesh::mloop, Mesh::mpoly, MPoly::totloop, BMLoop::v, 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 690 of file multires_unsubdivide.c.

References BMVert::co, copy_v3_v3(), MultiresUnsubdivideGrid::grid_co, MultiresUnsubdivideGrid::grid_size, 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 394 of file multires_unsubdivide.c.

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 162 of file multires_unsubdivide.c.

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(), MEM_calloc_arrayN, MEM_freeN, queue, 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 89 of file multires_unsubdivide.c.

References bm, BM_ITER_MESH, BM_VERTS_OF_MESH, is_vertex_in_id(), is_vertex_pole(), is_vertex_pole_three(), NULL, 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 111 of file multires_unsubdivide.c.

References bm, BM_FACES_OF_MESH, BM_ITER_ELEM, BM_ITER_MESH, BM_vert_edge_count(), BM_vert_is_wire(), BM_VERTS_OF_FACE, BM_VERTS_OF_MESH, count, 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 241 of file multires_unsubdivide.c.

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()

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

◆ 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 609 of file multires_unsubdivide.c.

References copy_v3_v3(), MultiresUnsubdivideGrid::grid_co, MultiresUnsubdivideGrid::grid_size, x, and y.

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 poly giving its corner's loop.

Definition at line 548 of file multires_unsubdivide.c.

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

Referenced by store_grid_data().

Variable Documentation

◆ lname

const char lname[] = "l_remap_index"
static

◆ vname

const char vname[] = "v_remap_index"
static