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
This commit is contained in:
Sergey Sharybin 2010-10-25 08:03:05 +00:00
parent 01cdd515fb
commit d327f08f9a
4 changed files with 207 additions and 7 deletions

@ -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

@ -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; i<totvert; i++)
mul_m3_v3(smat, vertCos[i]);
CDDM_apply_vert_coords(cddm, vertCos);
MEM_freeN(vertCos);
mvert= cddm->getVertArray(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);
}

@ -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);

@ -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; a<me->totvert; a++, mvert++)