static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
                                    bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
                                    float (*root)[3], float (*tip)[3], const int *selected, float scale)
{
	/* Create vertex group weights from envelopes */

	Bone *bone;
	bDeformGroup *dgroup;
	float distance;
	int i, iflip, j;
	bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
	bool use_mask = false;

	if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
	    (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)))
	{
		use_mask = true;
	}

	/* for each vertex in the mesh */
	for (i = 0; i < mesh->totvert; i++) {

		if (use_mask && !(mesh->mvert[i].flag & SELECT)) {
			continue;
		}

		iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1;
		
		/* for each skinnable bone */
		for (j = 0; j < numbones; ++j) {
			if (!selected[j])
				continue;
			
			bone = bonelist[j];
			dgroup = dgrouplist[j];
			
			/* store the distance-factor from the vertex to the bone */
			distance = distfactor_to_bone(verts[i], root[j], tip[j],
			                              bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
			
			/* add the vert to the deform group if (weight != 0.0) */
			if (distance != 0.0f)
				ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
			else
				ED_vgroup_vert_remove(ob, dgroup, i);
			
			/* do same for mirror */
			if (dgroupflip && dgroupflip[j] && iflip != -1) {
				if (distance != 0.0f)
					ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
					                   WEIGHT_REPLACE);
				else
					ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
			}
		}
	}
}
void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
                         bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
                         float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
{
	LaplacianSystem *sys;
	MLoopTri *mlooptri;
	MPoly *mp;
	MLoop *ml;
	float solution, weight;
	int *vertsflipped = NULL, *mask = NULL;
	int a, tottri, j, bbone, firstsegment, lastsegment;
	bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;

	MVert *mvert = me->mvert;
	bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
	bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;

	*err_str = NULL;

	/* bone heat needs triangulated faces */
	tottri = poly_to_tri_count(me->totpoly, me->totloop);

	/* count triangles and create mask */
	if (ob->mode & OB_MODE_WEIGHT_PAINT &&
	    (use_face_sel || use_vert_sel))
	{
		mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask");

		/*  (added selectedVerts content for vertex mask, they used to just equal 1) */
		if (use_vert_sel) {
			for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
				for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
					mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0;
				}
			}
		}
		else if (use_face_sel) {
			for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
				if (mp->flag & ME_FACE_SEL) {
					for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
						mask[ml->v] = 1;
					}
				}
			}
		}
	}

	/* create laplacian */
	sys = laplacian_system_construct_begin(me->totvert, tottri, 1);

	sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop);
	mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__);

	BKE_mesh_recalc_looptri(
	        me->mloop, me->mpoly,
	        me->mvert,
	        me->totloop, me->totpoly,
	        mlooptri);

	sys->heat.mlooptri = mlooptri;
	sys->heat.mloop = me->mloop;
	sys->heat.totvert = me->totvert;
	sys->heat.verts = verts;
	sys->heat.root = root;
	sys->heat.tip = tip;
	sys->heat.numsource = numsource;

	heat_ray_tree_create(sys);
	heat_laplacian_create(sys);

	laplacian_system_construct_end(sys);

	if (dgroupflip) {
		vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped");
		for (a = 0; a < me->totvert; a++)
			vertsflipped[a] = mesh_get_x_mirror_vert(ob, NULL, a, use_topology);
	}
	
	/* compute weights per bone */
	for (j = 0; j < numsource; j++) {
		if (!selected[j])
			continue;

		firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]);
		lastsegment = (j == numsource - 1 || dgrouplist[j] != dgrouplist[j + 1]);
		bbone = !(firstsegment && lastsegment);

		/* clear weights */
		if (bbone && firstsegment) {
			for (a = 0; a < me->totvert; a++) {
				if (mask && !mask[a])
					continue;

				ED_vgroup_vert_remove(ob, dgrouplist[j], a);
				if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
					ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
			}
		}

		/* fill right hand side */
		laplacian_begin_solve(sys, -1);

		for (a = 0; a < me->totvert; a++)
			if (heat_source_closest(sys, a, j))
				laplacian_add_right_hand_side(sys, a,
				                              sys->heat.H[a] * sys->heat.p[a]);

		/* solve */
		if (laplacian_system_solve(sys)) {
			/* load solution into vertex groups */
			for (a = 0; a < me->totvert; a++) {
				if (mask && !mask[a])
					continue;

				solution = laplacian_system_get_solution(sys, a);
				
				if (bbone) {
					if (solution > 0.0f)
						ED_vgroup_vert_add(ob, dgrouplist[j], a, solution,
						                   WEIGHT_ADD);
				}
				else {
					weight = heat_limit_weight(solution);
					if (weight > 0.0f)
						ED_vgroup_vert_add(ob, dgrouplist[j], a, weight,
						                   WEIGHT_REPLACE);
					else
						ED_vgroup_vert_remove(ob, dgrouplist[j], a);
				}

				/* do same for mirror */
				if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
					if (bbone) {
						if (solution > 0.0f)
							ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
							                   solution, WEIGHT_ADD);
					}
					else {
						weight = heat_limit_weight(solution);
						if (weight > 0.0f)
							ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
							                   weight, WEIGHT_REPLACE);
						else
							ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
					}
				}
			}
		}
		else if (*err_str == NULL) {
			*err_str = N_("Bone Heat Weighting: failed to find solution for one or more bones");
			break;
		}

		/* remove too small vertex weights */
		if (bbone && lastsegment) {
			for (a = 0; a < me->totvert; a++) {
				if (mask && !mask[a])
					continue;

				weight = ED_vgroup_vert_weight(ob, dgrouplist[j], a);
				weight = heat_limit_weight(weight);
				if (weight <= 0.0f)
					ED_vgroup_vert_remove(ob, dgrouplist[j], a);

				if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
					weight = ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
					weight = heat_limit_weight(weight);
					if (weight <= 0.0f)
						ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
				}
			}
		}
	}

	/* free */
	if (vertsflipped) MEM_freeN(vertsflipped);
	if (mask) MEM_freeN(mask);

	heat_system_free(sys);

	laplacian_system_delete(sys);
}
Пример #3
0
static int object_shape_key_mirror(bContext *C, Object *ob)
{
	KeyBlock *kb;
	Key *key;

	key= ob_get_key(ob);
	if(key==NULL)
		return 0;
	
	kb= BLI_findlink(&key->block, ob->shapenr-1);

	if(kb) {
		int i1, i2;
		float *fp1, *fp2;
		float tvec[3];
		char *tag_elem= MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror");


		if(ob->type==OB_MESH) {
			Mesh *me= ob->data;
			MVert *mv;

			mesh_octree_table(ob, NULL, NULL, 's');

			for(i1=0, mv=me->mvert; i1<me->totvert; i1++, mv++) {
				i2= mesh_get_x_mirror_vert(ob, i1);
				if(i2==i1) {
					fp1= ((float *)kb->data) + i1*3;
					fp1[0] = -fp1[0];
					tag_elem[i1]= 1;
				}
				else if(i2 != -1) {
					if(tag_elem[i1]==0 && tag_elem[i2]==0) {
						fp1= ((float *)kb->data) + i1*3;
						fp2= ((float *)kb->data) + i2*3;

						copy_v3_v3(tvec,	fp1);
						copy_v3_v3(fp1,	fp2);
						copy_v3_v3(fp2,	tvec);

						/* flip x axis */
						fp1[0] = -fp1[0];
						fp2[0] = -fp2[0];
					}
					tag_elem[i1]= tag_elem[i2]= 1;
				}
			}

			mesh_octree_table(ob, NULL, NULL, 'e');
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt= ob->data;
			int i1, i2;
			float *fp1, *fp2;
			int u, v, w;
			/* half but found up odd value */
			const int pntsu_half = (((lt->pntsu / 2) + (lt->pntsu % 2))) ;

			/* currently editmode isnt supported by mesh so
			 * ignore here for now too */

			/* if(lt->editlatt) lt= lt->editlatt->latt; */

			for(w=0; w<lt->pntsw; w++) {
				for(v=0; v<lt->pntsv; v++) {
					for(u=0; u<pntsu_half; u++) {
						int u_inv= (lt->pntsu - 1) - u;
						float tvec[3];
						if(u == u_inv) {
							i1= LT_INDEX(lt, u, v, w);
							fp1= ((float *)kb->data) + i1*3;
							fp1[0]= -fp1[0];
						}
						else {
							i1= LT_INDEX(lt, u, v, w);
							i2= LT_INDEX(lt, u_inv, v, w);

							fp1= ((float *)kb->data) + i1*3;
							fp2= ((float *)kb->data) + i2*3;

							copy_v3_v3(tvec, fp1);
							copy_v3_v3(fp1, fp2);
							copy_v3_v3(fp2, tvec);
							fp1[0]= -fp1[0];
							fp2[0]= -fp2[0];
						}
					}
				}
			}
		}

		MEM_freeN(tag_elem);
	}
	
	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);

	return 1;
}
Пример #4
0
void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
{
	LaplacianSystem *sys;
	MFace *mface;
	float solution, weight;
	int *vertsflipped = NULL, *mask= NULL;
	int a, totface, j, bbone, firstsegment, lastsegment;

	*err_str= NULL;

	/* count triangles and create mask */
	if(me->editflag & ME_EDIT_PAINT_MASK)
		mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask");

	for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) {
		totface++;
		if(mface->v4) totface++;

		if(mask && (mface->flag & ME_FACE_SEL)) {
			mask[mface->v1]= 1;
			mask[mface->v2]= 1;
			mask[mface->v3]= 1;
			if(mface->v4)
				mask[mface->v4]= 1;
		}
	}

	/* create laplacian */
	sys = laplacian_system_construct_begin(me->totvert, totface, 1);

	sys->heat.mface= me->mface;
	sys->heat.totface= me->totface;
	sys->heat.totvert= me->totvert;
	sys->heat.verts= verts;
	sys->heat.root= root;
	sys->heat.tip= tip;
	sys->heat.numsource= numsource;

	heat_ray_tree_create(sys);
	heat_laplacian_create(sys);

	laplacian_system_construct_end(sys);

	if(dgroupflip) {
		vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped");
		for(a=0; a<me->totvert; a++)
			vertsflipped[a] = mesh_get_x_mirror_vert(ob, a);
	}

	/* compute weights per bone */
	for(j=0; j<numsource; j++) {
		if(!selected[j])
			continue;

		firstsegment= (j == 0 || dgrouplist[j-1] != dgrouplist[j]);
		lastsegment= (j == numsource-1 || dgrouplist[j] != dgrouplist[j+1]);
		bbone= !(firstsegment && lastsegment);

		/* clear weights */
		if(bbone && firstsegment) {
			for(a=0; a<me->totvert; a++) {
				if(mask && !mask[a])
					continue;

				ED_vgroup_vert_remove(ob, dgrouplist[j], a);
				if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
					ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
			}
		}

		/* fill right hand side */
		laplacian_begin_solve(sys, -1);

		for(a=0; a<me->totvert; a++)
			if(heat_source_closest(sys, a, j))
				laplacian_add_right_hand_side(sys, a,
					sys->heat.H[a]*sys->heat.p[a]);

		/* solve */
		if(laplacian_system_solve(sys)) {
			/* load solution into vertex groups */
			for(a=0; a<me->totvert; a++) {
				if(mask && !mask[a])
					continue;

				solution= laplacian_system_get_solution(a);
				
				if(bbone) {
					if(solution > 0.0f)
						ED_vgroup_vert_add(ob, dgrouplist[j], a, solution,
							WEIGHT_ADD);
				}
				else {
					weight= heat_limit_weight(solution);
					if(weight > 0.0f)
						ED_vgroup_vert_add(ob, dgrouplist[j], a, weight,
							WEIGHT_REPLACE);
					else
						ED_vgroup_vert_remove(ob, dgrouplist[j], a);
				}

				/* do same for mirror */
				if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
					if(bbone) {
						if(solution > 0.0f)
							ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
								solution, WEIGHT_ADD);
					}
					else {
						weight= heat_limit_weight(solution);
						if(weight > 0.0f)
							ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
								weight, WEIGHT_REPLACE);
						else
							ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
					}
				}
			}
		}
		else if(*err_str == NULL) {
			*err_str= "Bone Heat Weighting: failed to find solution for one or more bones";
			break;
		}

		/* remove too small vertex weights */
		if(bbone && lastsegment) {
			for(a=0; a<me->totvert; a++) {
				if(mask && !mask[a])
					continue;

				weight= ED_vgroup_vert_weight(ob, dgrouplist[j], a);
				weight= heat_limit_weight(weight);
				if(weight <= 0.0f)
					ED_vgroup_vert_remove(ob, dgrouplist[j], a);

				if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
					weight= ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
					weight= heat_limit_weight(weight);
					if(weight <= 0.0f)
						ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
				}
			}
		}
	}

	/* free */
	if(vertsflipped) MEM_freeN(vertsflipped);
	if(mask) MEM_freeN(mask);

	heat_system_free(sys);

	laplacian_system_delete(sys);
}
Пример #5
0
static bool object_shape_key_mirror(
    bContext *C, Object *ob, int *r_totmirr, int *r_totfail, bool use_topology)
{
  KeyBlock *kb;
  Key *key;
  int totmirr = 0, totfail = 0;

  *r_totmirr = *r_totfail = 0;

  key = BKE_key_from_object(ob);
  if (key == NULL) {
    return 0;
  }

  kb = BLI_findlink(&key->block, ob->shapenr - 1);

  if (kb) {
    char *tag_elem = MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror");

    if (ob->type == OB_MESH) {
      Mesh *me = ob->data;
      MVert *mv;
      int i1, i2;
      float *fp1, *fp2;
      float tvec[3];

      ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');

      for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) {
        i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology);
        if (i2 == i1) {
          fp1 = ((float *)kb->data) + i1 * 3;
          fp1[0] = -fp1[0];
          tag_elem[i1] = 1;
          totmirr++;
        }
        else if (i2 != -1) {
          if (tag_elem[i1] == 0 && tag_elem[i2] == 0) {
            fp1 = ((float *)kb->data) + i1 * 3;
            fp2 = ((float *)kb->data) + i2 * 3;

            copy_v3_v3(tvec, fp1);
            copy_v3_v3(fp1, fp2);
            copy_v3_v3(fp2, tvec);

            /* flip x axis */
            fp1[0] = -fp1[0];
            fp2[0] = -fp2[0];
            totmirr++;
          }
          tag_elem[i1] = tag_elem[i2] = 1;
        }
        else {
          totfail++;
        }
      }

      ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
    }
    else if (ob->type == OB_LATTICE) {
      Lattice *lt = ob->data;
      int i1, i2;
      float *fp1, *fp2;
      int u, v, w;
      /* half but found up odd value */
      const int pntsu_half = (lt->pntsu / 2) + (lt->pntsu % 2);

      /* currently editmode isn't supported by mesh so
       * ignore here for now too */

      /* if (lt->editlatt) lt = lt->editlatt->latt; */

      for (w = 0; w < lt->pntsw; w++) {
        for (v = 0; v < lt->pntsv; v++) {
          for (u = 0; u < pntsu_half; u++) {
            int u_inv = (lt->pntsu - 1) - u;
            float tvec[3];
            if (u == u_inv) {
              i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
              fp1 = ((float *)kb->data) + i1 * 3;
              fp1[0] = -fp1[0];
              totmirr++;
            }
            else {
              i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
              i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);

              fp1 = ((float *)kb->data) + i1 * 3;
              fp2 = ((float *)kb->data) + i2 * 3;

              copy_v3_v3(tvec, fp1);
              copy_v3_v3(fp1, fp2);
              copy_v3_v3(fp2, tvec);
              fp1[0] = -fp1[0];
              fp2[0] = -fp2[0];
              totmirr++;
            }
          }
        }
      }
    }

    MEM_freeN(tag_elem);
  }

  *r_totmirr = totmirr;
  *r_totfail = totfail;

  DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
  WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);

  return 1;
}