static void calc_tangent_spaces(
        DerivedMesh *dm, float (*vertexCos)[3],
        float (*r_tangent_spaces)[3][3])
{
	const unsigned int mpoly_num = (unsigned int)dm->getNumPolys(dm);
#ifndef USE_TANGENT_CALC_INLINE
	const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
#endif
	const MPoly *mpoly = dm->getPolyArray(dm);
	const MLoop *mloop = dm->getLoopArray(dm);
	unsigned int i;

	for (i = 0; i < mpoly_num; i++) {
		const MPoly *mp = &mpoly[i];
		const MLoop *l_next = &mloop[mp->loopstart];
		const MLoop *l_term = l_next + mp->totloop;
		const MLoop *l_prev = l_term - 2;
		const MLoop *l_curr = l_term - 1;

		/* loop directions */
		float v_dir_prev[3], v_dir_next[3];

		/* needed entering the loop */
		sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
		normalize_v3(v_dir_prev);

		for (;
		     l_next != l_term;
		     l_prev = l_curr, l_curr = l_next, l_next++)
		{
			float (*ts)[3] = r_tangent_spaces[l_curr->v];

			/* re-use the previous value */
#if 0
			sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
			normalize_v3(v_dir_prev);
#endif
			sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]);
			normalize_v3(v_dir_next);

			calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts);

			copy_v3_v3(v_dir_prev, v_dir_next);
		}
	}

	/* do inline */
#ifndef USE_TANGENT_CALC_INLINE
	for (i = 0; i < mvert_num; i++) {
		float (*ts)[3] = r_tangent_spaces[i];
		calc_tangent_ortho(ts);
	}
#endif
}
Example #2
0
/**
 * This calculates #CorrectiveSmoothModifierData.delta_cache
 * It's not run on every update (during animation for example).
 */
static void calc_deltas(CorrectiveSmoothModifierData *csmd,
                        Mesh *mesh,
                        MDeformVert *dvert,
                        const int defgrp_index,
                        const float (*rest_coords)[3],
                        unsigned int numVerts)
{
  float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
  float(*tangent_spaces)[3][3];
  unsigned int i;

  tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);

  if (csmd->delta_cache_num != numVerts) {
    MEM_SAFE_FREE(csmd->delta_cache);
  }

  /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
  if (!csmd->delta_cache) {
    csmd->delta_cache_num = numVerts;
    csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
  }

  smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);

  calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces);

  for (i = 0; i < numVerts; i++) {
    float imat[3][3], delta[3];

#ifdef USE_TANGENT_CALC_INLINE
    calc_tangent_ortho(tangent_spaces[i]);
#endif

    sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
    if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
      transpose_m3_m3(imat, tangent_spaces[i]);
    }
    mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
  }

  MEM_freeN(tangent_spaces);
  MEM_freeN(smooth_vertex_coords);
}
static void correctivesmooth_modifier_do(
        ModifierData *md, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], unsigned int numVerts,
        struct BMEditMesh *em)
{
	CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;

	const bool force_delta_cache_update =
	        /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
	        ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
	         (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC));

	bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
	MDeformVert *dvert = NULL;
	int defgrp_index;

	modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index);

	/* if rest bind_coords not are defined, set them (only run during bind) */
	if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
	    /* signal to recalculate, whoever sets MUST also free bind coords */
	    (csmd->bind_coords_num == (unsigned int)-1))
	{
		BLI_assert(csmd->bind_coords == NULL);
		csmd->bind_coords = MEM_dupallocN(vertexCos);
		csmd->bind_coords_num = numVerts;
		BLI_assert(csmd->bind_coords != NULL);
	}

	if (UNLIKELY(use_only_smooth)) {
		smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
		return;
	}

	if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
		modifier_setError(md, "Bind data required");
		goto error;
	}

	/* If the number of verts has changed, the bind is invalid, so we do nothing */
	if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
		if (csmd->bind_coords_num != numVerts) {
			modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
			goto error;
		}
	}
	else {
		/* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
		if (ob->type != OB_MESH) {
			modifier_setError(md, "Object is not a mesh");
			goto error;
		}
		else {
			unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);

			if (me_numVerts != numVerts) {
				modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
				goto error;
			}
		}
	}

	/* check to see if our deltas are still valid */
	if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
		const float (*rest_coords)[3];
		bool is_rest_coords_alloc = false;

		if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
			/* caller needs to do sanity check here */
			csmd->bind_coords_num = numVerts;
			rest_coords = (const float (*)[3])csmd->bind_coords;
		}
		else {
			int me_numVerts;
			rest_coords = (const float (*)[3]) ((em) ?
			        BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
			        BKE_mesh_vertexCos_get(ob->data, &me_numVerts));

			BLI_assert((unsigned int)me_numVerts == numVerts);
			is_rest_coords_alloc = true;
		}

#ifdef DEBUG_TIME
	TIMEIT_START(corrective_smooth_deltas);
#endif

		calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);

#ifdef DEBUG_TIME
	TIMEIT_END(corrective_smooth_deltas);
#endif
		if (is_rest_coords_alloc) {
			MEM_freeN((void *)rest_coords);
		}
	}

	if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
		/* this could be a check, but at this point it _must_ be valid */
		BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
	}


#ifdef DEBUG_TIME
	TIMEIT_START(corrective_smooth);
#endif

	/* do the actual delta mush */
	smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);

	{
		unsigned int i;

		float (*tangent_spaces)[3][3];

		/* calloc, since values are accumulated */
		tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);

		calc_tangent_spaces(dm, vertexCos, tangent_spaces);

		for (i = 0; i < numVerts; i++) {
			float delta[3];

#ifdef USE_TANGENT_CALC_INLINE
			calc_tangent_ortho(tangent_spaces[i]);
#endif

			mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
			add_v3_v3(vertexCos[i], delta);
		}

		MEM_freeN(tangent_spaces);
	}

#ifdef DEBUG_TIME
	TIMEIT_END(corrective_smooth);
#endif

	return;

	/* when the modifier fails to execute */
error:
	MEM_SAFE_FREE(csmd->delta_cache);
	csmd->delta_cache_num = 0;

}