From d327f08f9a948ac59f90379577366e7a807a2e64 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Oct 2010 08:03:05 +0000 Subject: [PATCH] Fix #24255: Multires object gets modified when joining it to another multires object. Fix #22018: joining objects with different multires levels loses levesl from the higher multires object - Synchronyze mulires subdivision level when joining objects - Apply scale on MDISP layer when applying scale - Re-calculate MDISP when joining scaled objects --- source/blender/blenkernel/BKE_multires.h | 3 + source/blender/blenkernel/intern/multires.c | 204 +++++++++++++++++- source/blender/editors/mesh/meshtools.c | 4 + .../blender/editors/object/object_transform.c | 3 + 4 files changed, 207 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index fc0ab2eea1e..4a9b2ec5c0d 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -71,5 +71,8 @@ void multires_free(struct Multires *mr); void multires_load_old(struct Object *ob, struct Mesh *me); void multires_load_old_250(struct Mesh *); +void multiresModifier_scale_disp(struct Scene *scene, struct Object *ob); +void multiresModifier_prepare_join(struct Scene *scene, struct Object *ob, struct Object *to_ob); + #endif diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 91f15d1ee6c..b6e48a12676 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -46,6 +46,7 @@ #include "BKE_scene.h" #include "BKE_subsurf.h" #include "BKE_utildefines.h" +#include "BKE_object.h" #include "CCGSubSurf.h" @@ -89,6 +90,34 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData * return NULL; } +/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects */ +static MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob) +{ + ModifierData *md; + MultiresModifierData *mmd= NULL, *firstmmd= NULL; + + /* find first active multires modifier */ + for(md = ob->modifiers.first; md; md = md->next) { + if(md->type == eModifierType_Multires) { + if(!firstmmd) + firstmmd= (MultiresModifierData*)md; + + if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + mmd= (MultiresModifierData*)md; + break; + } + } + } + + if(!mmd) { + /* active multires have not been found + try to use first one */ + return firstmmd; + } + + return mmd; +} + static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render) { if(render) @@ -389,11 +418,9 @@ static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, int size } } -/* direction=1 for delete higher, direction=0 for lower (not implemented yet) */ -void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction) +static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) { - Mesh *me = get_mesh(ob); - int lvl = multires_get_level(ob, mmd, 0); + Mesh *me = (Mesh*)ob->data; int levels = mmd->totlvl - lvl; MDisps *mdisps; @@ -403,7 +430,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire multires_force_update(ob); - if(mdisps && levels > 0 && direction == 1) { + if(mdisps && levels > 0) { if(lvl > 0) { int nsize = multires_side_tot[lvl]; int hsize = multires_side_tot[mmd->totlvl]; @@ -442,6 +469,27 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire multires_set_tot_level(ob, mmd, lvl); } +/* direction=1 for delete higher, direction=0 for lower (not implemented yet) */ +void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction) +{ + Mesh *me = get_mesh(ob); + int lvl = multires_get_level(ob, mmd, 0); + int levels = mmd->totlvl - lvl; + MDisps *mdisps; + + multires_set_tot_mdisps(me, mmd->totlvl); + CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface); + mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS); + + multires_force_update(ob); + + if(mdisps && levels > 0 && direction == 1) { + multires_del_higher(mmd, ob, lvl); + } + + multires_set_tot_level(ob, mmd, lvl); +} + static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple) { MultiresModifierData mmd; @@ -471,12 +519,11 @@ static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm, return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0); } -void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple) +void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl, int updateblock, int simple) { Mesh *me = ob->data; MDisps *mdisps; int lvl= mmd->totlvl; - int totlvl= mmd->totlvl+1; if(totlvl > multires_max_levels) return; @@ -549,6 +596,11 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat multires_set_tot_level(ob, mmd, totlvl); } +void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple) +{ + multires_subdivide(mmd, ob, mmd->totlvl+1, updateblock, simple); +} + static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3]) { if(axis == 0) { @@ -1386,3 +1438,141 @@ void multires_load_old(Object *ob, Mesh *me) me->mr= NULL; } +static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob) +{ + MultiresModifierData *mmd= get_multires_modifier(scene, ob); + MultiresModifierData *to_mmd= get_multires_modifier(scene, to_ob); + + if(!mmd) { + /* object could have MDISP even when there is no multires modifier + this could lead to troubles due to i've got no idea how mdisp could be + upsampled correct without modifier data. + just remove mdisps if no multires present (nazgul) */ + + Mesh *me= (Mesh*)ob->data; + + CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface); + CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface); + } + + if(!mmd || !to_mmd) return; + + if(mmd->totlvl>to_mmd->totlvl) multires_del_higher(mmd, ob, to_mmd->totlvl); + else multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple); +} + +void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) +{ + DerivedMesh *dm= NULL, *cddm= NULL, *subdm= NULL; + DMGridData **gridData, **subGridData; + Mesh *me= (Mesh*)ob->data; + MFace *mface= me->mface; + MVert *mvert= NULL; + MDisps *mdisps; + int *gridOffset; + int i, numGrids, gridSize, dGridSize, dSkip, totvert; + float (*vertCos)[3] = NULL; + MultiresModifierData *mmd= get_multires_modifier(scene, ob); + + CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface); + mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS); + + if(!mdisps || !mmd) return; + + + /* unscaled multires with applied displacement */ + subdm= get_multires_dm(scene, mmd, ob); + + /* prepare scaled CDDM to create ccgDN */ + cddm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + + totvert= cddm->getNumVerts(cddm); + vertCos= MEM_mallocN(sizeof(*vertCos) * totvert, "multiresScale vertCos"); + cddm->getVertCos(cddm, vertCos); + for(i=0; igetVertArray(cddm); + + /* scaled ccgDM for tangent space of object with applied scale */ + dm= subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0); + cddm->release(cddm); + + numGrids= dm->getNumGrids(dm); + gridSize= dm->getGridSize(dm); + gridData= dm->getGridData(dm); + gridOffset= dm->getGridOffset(dm); + subGridData= subdm->getGridData(subdm); + + dGridSize= multires_side_tot[mmd->totlvl]; + dSkip= (dGridSize-1)/(gridSize-1); + + #pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT) + for(i = 0; i < me->totface; ++i) { + const int numVerts= mface[i].v4 ? 4 : 3; + MDisps *mdisp= &mdisps[i]; + int S, x, y, gIndex = gridOffset[i]; + + for(S = 0; S < numVerts; ++S, ++gIndex) { + DMGridData *grid= gridData[gIndex]; + DMGridData *subgrid= subGridData[gIndex]; + float (*dispgrid)[3]= &mdisp->disps[S*dGridSize*dGridSize]; + + for(y = 0; y < gridSize; y++) { + for(x = 0; x < gridSize; x++) { + float *co= grid[x + y*gridSize].co; + float *sco= subgrid[x + y*gridSize].co; + float *no= grid[x + y*gridSize].no; + float *data= dispgrid[dGridSize*y*dSkip + x*dSkip]; + float mat[3][3], tx[3], ty[3], disp[3]; + + /* construct tangent space matrix */ + grid_tangent(gridSize, gIndex, x, y, 0, gridData, tx); + normalize_v3(tx); + + grid_tangent(gridSize, gIndex, x, y, 1, gridData, ty); + normalize_v3(ty); + + column_vectors_to_mat3(mat, tx, ty, no); + + /* scale subgrid coord and calculate displacement */ + mul_m3_v3(smat, sco); + sub_v3_v3v3(disp, sco, co); + + /* convert difference to tangent space */ + invert_m3(mat); + mul_v3_m3v3(data, mat, disp); + } + } + } + } + + dm->release(dm); + subdm->release(subdm); +} + +void multiresModifier_scale_disp(Scene *scene, Object *ob) +{ + float smat[3][3]; + + /* object's scale matrix */ + object_scale_to_mat3(ob, smat); + + multires_apply_smat(scene, ob, smat); +} + +void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob) +{ + float smat[3][3], tmat[3][3], mat[3][3]; + multires_sync_levels(scene, ob, to_ob); + + /* construct scale matrix for displacement */ + object_scale_to_mat3(to_ob, tmat); + invert_m3(tmat); + object_scale_to_mat3(ob, smat); + mul_m3_m3m3(mat, smat, tmat); + + multires_apply_smat(scene, ob, mat); +} diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index d8b34311e76..0307ba13424 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -63,6 +63,7 @@ #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_report.h" +#include "BKE_multires.h" #include "BLO_sys_types.h" // for intptr_t support @@ -396,6 +397,9 @@ int join_mesh_exec(bContext *C, wmOperator *UNUSED(op)) } } + if(base->object!=ob) + multiresModifier_prepare_join(scene, base->object, ob); + CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface); diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 7be03a4c567..9d6b5e5002b 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -47,6 +47,7 @@ #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_multires.h" #include "RNA_define.h" #include "RNA_access.h" @@ -491,6 +492,8 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo if(ob->type==OB_MESH) { me= ob->data; + multiresModifier_scale_disp(scene, ob); + /* adjust data */ mvert= me->mvert; for(a=0; atotvert; a++, mvert++)