forked from bartvdbraak/blender
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:
parent
01cdd515fb
commit
d327f08f9a
@ -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++)
|
||||
|
Loading…
Reference in New Issue
Block a user