diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-09-21 12:18:37 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-09-21 12:24:33 +0300 |
commit | 619c55027f718c1018051da41bcd89943445e663 (patch) | |
tree | d61a2b9e7a2fade50248f06c1218e0915c9e9eae /source/blender/blenkernel/intern/multires_reshape.c | |
parent | 495c7463fc39b8bec1f678af28e94a207e0d1217 (diff) |
Multires: Fix reshaping from object at lower level
This brings basic implementation of displacement propagation
to a higher levels. Currently does linear interpolation between
grid points at which reshape happened. It makes results a bit
choppy, proper solution would be to use some interpolation
weights from the limit patch.
Diffstat (limited to 'source/blender/blenkernel/intern/multires_reshape.c')
-rw-r--r-- | source/blender/blenkernel/intern/multires_reshape.c | 225 |
1 files changed, 224 insertions, 1 deletions
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index 7687506e9a7..63def8055b0 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -330,7 +330,224 @@ static void multires_reshape_vertex_from_final_coord( } /* ============================================================================= - * Reshape from deformed veretx coordinates. + * Helpers to propagate displacement to higher levels. + */ + +typedef struct MultiresPropagateData { + int reshape_level; + int top_level; + int num_grids; + int reshape_grid_size; + int top_grid_size; + MDisps *old_displacement_grids; + MDisps *new_displacement_grids; +} MultiresPropagateData; + +static void multires_reshape_propagate_prepare( + MultiresPropagateData *data, + Object *object, + const int reshape_level, + const int top_level) +{ + BLI_assert(reshape_level <= top_level); + data->old_displacement_grids = NULL; + if (reshape_level == top_level) { + /* Nothing to do, reshape will happen on the whole grid conent. */ + return; + } + Mesh *coarse_mesh = object->data; + const int num_grids = coarse_mesh->totloop; + MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); + MDisps *old_mdisps = MEM_dupallocN(mdisps); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + MDisps *displacement_grid = &mdisps[grid_index]; + MDisps *old_displacement_grid = &old_mdisps[grid_index]; + old_displacement_grid->totdisp = displacement_grid->totdisp; + old_displacement_grid->level = displacement_grid->level; + if (displacement_grid->disps) { + displacement_grid->disps = MEM_dupallocN(displacement_grid->disps); + } + else { + old_displacement_grid->disps = NULL; + } + /* TODO(sergey): This might be needed for proper propagation. */ + old_displacement_grid->hidden = NULL; + } + data->reshape_level = reshape_level; + data->top_level = top_level; + data->num_grids = num_grids; + /* TODO(sergey): use grid_size_for_level_get(). */ + data->reshape_grid_size = (1 << (reshape_level - 1)) + 1; + data->top_grid_size = (1 << (top_level - 1)) + 1; + data->old_displacement_grids = old_mdisps; + data->new_displacement_grids = mdisps; +} + +static void multires_reshape_propagate_prepare_from_mmd( + MultiresPropagateData *data, + struct Depsgraph *depsgraph, + Object *object, + const MultiresModifierData *mmd, + const bool use_render_params) +{ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + const int level = multires_get_level( + scene_eval, object, mmd, use_render_params, true); + multires_reshape_propagate_prepare(data, object, level, mmd->totlvl); +} + +static void multires_reshape_propagate_calc_simple_delta( + float r_delta[3], + const MDisps *old_displacement_grid, + const MDisps *new_displacement_grid, + const int grid_size, + const int x, const int y) +{ + copy_v3_v3(r_delta, new_displacement_grid->disps[y * grid_size + x]); + if (old_displacement_grid->disps != NULL) { + sub_v3_v3(r_delta, old_displacement_grid->disps[y * grid_size + x]); + } +} + +static void multires_reshape_propagate_calc_reshape_delta( + float r_delta[3], + const MDisps *old_displacement_grid, + const MDisps *new_displacement_grid, + const int grid_size, + const int grid_skip, + const int reshape_x, const int reshape_y) +{ + const int x = reshape_x * grid_skip; + const int y = reshape_y * grid_skip; + multires_reshape_propagate_calc_simple_delta( + r_delta, + old_displacement_grid, new_displacement_grid, + grid_size, + x, y); +} + +static void multires_reshape_propagate_grid( + MultiresPropagateData *data, + const MDisps *old_displacement_grid, + MDisps *new_displacement_grid) +{ + const int reshape_grid_size = data->reshape_grid_size; + const int top_grid_size = data->top_grid_size; + const int grid_skip = (top_grid_size - 1) / (reshape_grid_size - 1); + const float grid_skip_inv = 1.0f / (float)grid_skip; + for (int reshape_y = 0; + reshape_y < reshape_grid_size - 1; + reshape_y++) + { + for (int reshape_x = 0; + reshape_x < reshape_grid_size - 1; + reshape_x++) + { + /* Calculate delta from the reshape. */ + float delta_corners[4][3]; + multires_reshape_propagate_calc_reshape_delta( + delta_corners[0], + old_displacement_grid, new_displacement_grid, + top_grid_size, + grid_skip, + reshape_x, reshape_y); + multires_reshape_propagate_calc_reshape_delta( + delta_corners[1], + old_displacement_grid, new_displacement_grid, + top_grid_size, + grid_skip, + reshape_x + 1, reshape_y); + multires_reshape_propagate_calc_reshape_delta( + delta_corners[2], + old_displacement_grid, new_displacement_grid, + top_grid_size, + grid_skip, + reshape_x + 1, reshape_y + 1); + multires_reshape_propagate_calc_reshape_delta( + delta_corners[3], + old_displacement_grid, new_displacement_grid, + top_grid_size, + grid_skip, + reshape_x, reshape_y + 1); + /* Propagate to higher levels. */ + for (int y = 0; y <= grid_skip; y++) { + const float v = (float)y * grid_skip_inv; + for (int x = 0; x <= grid_skip; x++) { + /* Ignorevalues at the exact locations of grid which was + * reshape. Those points already have proper displacement. + */ + if ((x == 0 && y == 0) || + (x == grid_skip && y == 0) || + (x == grid_skip && y == grid_skip) || + (x == 0 && y == grid_skip)) + { + continue; + } + /* Ignore right-most column and top-most row, unless this + * is a boundary of the grid, to prevent displacement + * being affected twice. + */ + if (x == grid_skip && reshape_x != reshape_grid_size - 2) { + continue; + } + if (y == grid_skip && reshape_y != reshape_grid_size - 2) { + continue; + } + const float u = (float)x * grid_skip_inv; + const float weights[4] = {(1.0f - u) * (1.0f - v), + u * (1.0f - v), + u * v, + (1.0f - u) * v}; + float delta[3]; + interp_v3_v3v3v3v3( + delta, + delta_corners[0], delta_corners[1], + delta_corners[2], delta_corners[3], + weights); + float *new_displacement = new_displacement_grid->disps[ + (reshape_y * grid_skip + y) * top_grid_size + + (reshape_x * grid_skip) + x]; + add_v3_v3(new_displacement, delta); + } + } + } + } +} + +static void multires_reshape_propagate(MultiresPropagateData *data) { + if (data->old_displacement_grids == NULL) { + return; + } + const int num_grids = data->num_grids; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + const MDisps *old_displacement_grid = + &data->old_displacement_grids[grid_index]; + MDisps *new_displacement_grid = + &data->new_displacement_grids[grid_index]; + if (old_displacement_grid->level != new_displacement_grid->level) { + continue; + } + multires_reshape_propagate_grid( + data, old_displacement_grid, new_displacement_grid); + } +} + +static void multires_reshape_propagate_free(MultiresPropagateData *data) { + if (data->old_displacement_grids != NULL) { + const int num_grids = data->num_grids; + MDisps *old_mdisps = data->old_displacement_grids; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + MDisps *old_displacement_grid = &old_mdisps[grid_index]; + if (old_displacement_grid->disps) { + MEM_freeN(old_displacement_grid->disps); + } + } + MEM_freeN(data->old_displacement_grids); + } +} + +/* ============================================================================= + * Reshape from deformed vertex coordinates. */ typedef struct MultiresReshapeFromDeformedVertsContext { @@ -487,6 +704,10 @@ static bool multires_reshape_from_vertcos( SubdivToMeshSettings mesh_settings; BKE_multires_subdiv_mesh_settings_init( &mesh_settings, scene_eval, object, mmd, use_render_params, true); + /* Initialize propagation to higher levels. */ + MultiresPropagateData data; + multires_reshape_propagate_prepare_from_mmd( + &data, depsgraph, object, mmd, use_render_params); /* Run all the callbacks. */ BKE_subdiv_foreach_subdiv_geometry( subdiv, @@ -494,6 +715,8 @@ static bool multires_reshape_from_vertcos( &mesh_settings, coarse_mesh); BKE_subdiv_free(subdiv); + multires_reshape_propagate(&data); + multires_reshape_propagate_free(&data); return true; } |