Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Bishop <nicholasbishop@gmail.com>2011-01-08 00:12:47 +0300
committerNicholas Bishop <nicholasbishop@gmail.com>2011-01-08 00:12:47 +0300
commit473838aec99d81595def7634d61a48118e84b8ff (patch)
treed1463e4d1ac4d4bef59ad7809f4651b85e748683 /source/blender/blenkernel/intern/multires.c
parentab11863b2f3d8456062efc6eed5ae41081b44d72 (diff)
Fix for bug [#21534] Multires modifier strange deformations
This adds the "Apply Base" feature from my gsoc2010 branch. Apply Base partially applies the modifier, in that the mesh is reshaped to more closely match the deformed mesh. The upper-level displacements are recalculated so that the highest multires level appears unchanged. Multires does not currently deal well with too large displacements. An easy-to-reproduce example: create any mesh type, add multires, subdivide a few times, then use the sculpt grab brush to drag the entire mesh over a few units. At the highest level, and at level 0, the mesh looks fine, but all of the intervening levels will have ugly spikes on them. This patch doesn't help with situations where you can't modify the base mesh, but otherwise works around the problem fairly well (albeit with a heuristic, not an exact solution.)
Diffstat (limited to 'source/blender/blenkernel/intern/multires.c')
-rw-r--r--source/blender/blenkernel/intern/multires.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 34a057788a2..6c1b8fb6047 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -472,6 +472,128 @@ static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm,
return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0);
}
+
+
+/* assumes no is normalized; return value's sign is negative if v is on
+ the other side of the plane */
+static float v3_dist_from_plane(float v[3], float center[3], float no[3])
+{
+ float s[3];
+ sub_v3_v3v3(s, v, center);
+ return dot_v3v3(s, no);
+}
+
+void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
+{
+ DerivedMesh *cddm, *dispdm, *origdm;
+ Mesh *me;
+ ListBase *fmap;
+ float (*origco)[3];
+ int i, j, offset, totlvl;
+
+ multires_force_update(ob);
+
+ me = get_mesh(ob);
+ totlvl = mmd->totlvl;
+
+ /* nothing to do */
+ if(!totlvl)
+ return;
+
+ /* XXX - probably not necessary to regenerate the cddm so much? */
+
+ /* generate highest level with displacements */
+ cddm = CDDM_from_mesh(me, NULL);
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+ dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0);
+ cddm->release(cddm);
+
+ /* copy the new locations of the base verts into the mesh */
+ offset = dispdm->getNumVerts(dispdm) - me->totvert;
+ for(i = 0; i < me->totvert; ++i) {
+ dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
+ }
+
+ /* heuristic to produce a better-fitting base mesh */
+
+ cddm = CDDM_from_mesh(me, NULL);
+ fmap = cddm->getFaceMap(ob, cddm);
+ origco = MEM_callocN(sizeof(float)*3*me->totvert, "multires apply base origco");
+ for(i = 0; i < me->totvert ;++i)
+ copy_v3_v3(origco[i], me->mvert[i].co);
+
+ for(i = 0; i < me->totvert; ++i) {
+ IndexNode *n;
+ float avg_no[3] = {0,0,0}, center[3] = {0,0,0}, push[3];
+ float dist;
+ int tot;
+
+ /* don't adjust verts not used by at least one face */
+ if(!fmap[i].first)
+ continue;
+
+ /* find center */
+ for(n = fmap[i].first, tot = 0; n; n = n->next) {
+ MFace *f = &me->mface[n->index];
+ int S = f->v4 ? 4 : 3;
+
+ /* this double counts, not sure if that's bad or good */
+ for(j = 0; j < S; ++j) {
+ int vndx = (&f->v1)[j];
+ if(vndx != i) {
+ add_v3_v3(center, origco[vndx]);
+ ++tot;
+ }
+ }
+ }
+ mul_v3_fl(center, 1.0f / tot);
+
+ /* find normal */
+ for(n = fmap[i].first; n; n = n->next) {
+ MFace *f = &me->mface[n->index];
+ int S = f->v4 ? 4 : 3;
+ float v[4][3], no[3];
+
+ for(j = 0; j < S; ++j) {
+ int vndx = (&f->v1)[j];
+ if(vndx == i)
+ copy_v3_v3(v[j], center);
+ else
+ copy_v3_v3(v[j], origco[vndx]);
+ }
+
+ if(S == 4)
+ normal_quad_v3(no, v[0], v[1], v[2], v[3]);
+ else
+ normal_tri_v3(no, v[0], v[1], v[2]);
+ add_v3_v3(avg_no, no);
+ }
+ normalize_v3(avg_no);
+
+ /* push vertex away from the plane */
+ dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no);
+ copy_v3_v3(push, avg_no);
+ mul_v3_fl(push, dist);
+ add_v3_v3(me->mvert[i].co, push);
+
+ }
+
+ MEM_freeN(origco);
+ cddm->release(cddm);
+
+ /* subdivide the mesh to highest level without displacements */
+ cddm = CDDM_from_mesh(me, NULL);
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+ origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0);
+ cddm->release(cddm);
+
+ /* calc disps */
+ multiresModifier_disp_run(dispdm, me, 1, 0, origdm->getGridData(origdm), totlvl);
+
+ origdm->release(origdm);
+ dispdm->release(dispdm);
+}
+
void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl, int updateblock, int simple)
{
Mesh *me = ob->data;