Multires: Fix Apply Base when there are deform modifiers

Their effect was applied twice after hitting Apply Base since the
operator was also applying deformation caused by those modifiers.
This commit is contained in:
Sergey Sharybin 2020-03-17 16:08:31 +01:00
parent 628d799c85
commit 24e44143a1
4 changed files with 99 additions and 10 deletions

View File

@ -224,10 +224,35 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph,
return;
}
multires_reshape_store_original_grids(&reshape_context);
/* At this point base_mesh is object's mesh, the subdiv is initialized to the deformed state of
* the base mesh.
* Store coordinates of top level grids in object space which will define true shape we would
* want to reshape to after modifying the base mesh. */
multires_reshape_assign_final_coords_from_mdisps(&reshape_context);
/* For modifying base mesh we only want to consider deformation caused by multires displacement
* and ignore all deformation which might be caused by deformation modifiers leading the multires
* one.
* So refine the subdiv to the original mesh verticies positions, which will also need to make
* it so object space displacement is re-evaluated for them (as in, can not re-use any knowledge
* from the final coordinates in the object space ). */
multires_reshape_apply_base_refine_from_base(&reshape_context);
/* Modify original mesh coordinates. This happens in two steps:
* - Coordinates are set to their final location, where they are intended to be in the final
* result.
* - Heuristic moves them a bit, kind of canceling out the effect of subsurf (so then when
* multires modifier applies subsurf vertices are placed at the desired location). */
multires_reshape_apply_base_update_mesh_coords(&reshape_context);
multires_reshape_apply_base_refit_base_mesh(&reshape_context);
multires_reshape_apply_base_refine_subdiv(&reshape_context);
/* Reshape to the stored final state.
* Not that the base changed, so the subdiv is to be refined to the new positions. Unfortunately,
* this can not be done foe entirely cheap: if there were deformation modifiers prior to the
* multires they need to be re-evaluated for the new base mesh. */
multires_reshape_apply_base_refine_from_deform(&reshape_context);
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
multires_reshape_context_free(&reshape_context);

View File

@ -36,6 +36,11 @@ struct Subdiv;
struct SubdivCCG;
typedef struct MultiresReshapeContext {
/* NOTE: Only available when context is initialized from object. */
struct Depsgraph *depsgraph;
struct Object *object;
struct MultiresModifierData *mmd;
/* Base mesh from original object.
* NOTE: Does NOT include any leading modifiers in it. */
struct Mesh *base_mesh;
@ -142,6 +147,9 @@ struct Subdiv *multires_reshape_create_subdiv(struct Depsgraph *depsgraph,
struct Object *object,
const struct MultiresModifierData *mmd);
/* NOTE: Initialized base mesh to object's mesh, the Subdiv is created from the deformed
* mesh prior to the multires modifier if depsgraph is not NULL. If the depsgraph is NULL
* then Subdiv is created from base mesh (without any deformation applied). */
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
struct Depsgraph *depsgraph,
struct Object *object,
@ -302,6 +310,12 @@ void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *resh
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context);
/* Refine subdivision surface to the new positions of the base mesh. */
void multires_reshape_apply_base_refine_subdiv(MultiresReshapeContext *reshape_context);
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context);
/* Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
* modifiers leading the multires applied).
*
* 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__ */

View File

@ -27,23 +27,46 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_mapping.h"
#include "BKE_multires.h"
#include "BKE_subdiv_eval.h"
#include "DEG_depsgraph_query.h"
void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context)
{
Mesh *base_mesh = reshape_context->base_mesh;
const int grid_size = reshape_context->top.grid_size;
const int grid_index = grid_size * grid_size - 1;
for (int i = 0; i < base_mesh->totloop; ++i) {
MDisps *displacement_grid = &reshape_context->mdisps[i];
const MLoop *loop = &base_mesh->mloop[i];
MVert *vert = &base_mesh->mvert[loop->v];
copy_v3_v3(vert->co, displacement_grid->disps[grid_index]);
const MLoop *mloop = base_mesh->mloop;
MVert *mvert = base_mesh->mvert;
for (int loop_index = 0; loop_index < base_mesh->totloop; ++loop_index) {
const MLoop *loop = &mloop[loop_index];
MVert *vert = &mvert[loop->v];
GridCoord grid_coord;
grid_coord.grid_index = loop_index;
grid_coord.u = 1.0f;
grid_coord.v = 1.0f;
float P[3];
float tangent_matrix[3][3];
multires_reshape_evaluate_limit_at_grid(reshape_context, &grid_coord, P, tangent_matrix);
ReshapeConstGridElement grid_element = multires_reshape_orig_grid_element_for_grid_coord(
reshape_context, &grid_coord);
float D[3];
mul_v3_m3v3(D, tangent_matrix, grid_element.displacement);
add_v3_v3v3(vert->co, P, D);
}
}
@ -152,7 +175,30 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
BKE_mesh_calc_normals(base_mesh);
}
void multires_reshape_apply_base_refine_subdiv(MultiresReshapeContext *reshape_context)
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
{
BKE_subdiv_eval_update_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
}
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context)
{
struct Depsgraph *depsgraph = reshape_context->depsgraph;
Object *object = reshape_context->object;
MultiresModifierData *mmd = reshape_context->mmd;
BLI_assert(depsgraph != NULL);
BLI_assert(object != NULL);
BLI_assert(mmd != NULL);
/* If there are no modifiers prior to the multires can use base mesh as it have all the updated
* vertices already. */
if (mmd->modifier.prev == NULL) {
BKE_subdiv_eval_update_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
}
else {
/* TODO(sergey): Possible optimization is to only evaluate new verticies positions without
* construction of the entire mesh. */
Mesh *deformed_base_mesh = BKE_multires_create_deformed_base_mesh(depsgraph, object, mmd);
BKE_subdiv_eval_update_from_mesh(reshape_context->subdiv, deformed_base_mesh, NULL);
BKE_id_free(NULL, deformed_base_mesh);
}
}

View File

@ -163,6 +163,10 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
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(depsgraph, object, mmd);