2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Campbell Barton
20 * ***** END GPL LICENSE BLOCK *****
24 /** \file blender/modifiers/intern/MOD_warp.c
30 #include "MEM_guardedalloc.h"
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34 #include "DNA_object_types.h"
37 #include "BLI_utildefines.h"
39 #include "BKE_editmesh.h"
40 #include "BKE_library.h"
41 #include "BKE_library_query.h"
43 #include "BKE_modifier.h"
44 #include "BKE_deform.h"
45 #include "BKE_texture.h"
46 #include "BKE_colortools.h"
48 #include "DEG_depsgraph.h"
49 #include "DEG_depsgraph_query.h"
51 #include "RE_shader_ext.h"
56 static void initData(ModifierData *md)
58 WarpModifierData *wmd = (WarpModifierData *) md;
60 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
63 wmd->falloff_radius = 1.0f;
64 wmd->falloff_type = eWarp_Falloff_Smooth;
68 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
70 const WarpModifierData *wmd = (const WarpModifierData *) md;
71 WarpModifierData *twmd = (WarpModifierData *) target;
73 modifier_copyData_generic(md, target, flag);
75 twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
78 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
80 WarpModifierData *wmd = (WarpModifierData *)md;
81 CustomDataMask dataMask = 0;
83 /* ask for vertexgroups if we need them */
84 if (wmd->defgrp_name[0]) dataMask |= (CD_MASK_MDEFORMVERT);
85 dataMask |= (CD_MASK_MDEFORMVERT);
87 /* ask for UV coordinates if we need them */
88 if (wmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE);
93 static bool dependsOnTime(ModifierData *md)
95 WarpModifierData *wmd = (WarpModifierData *)md;
98 return BKE_texture_dependsOnTime(wmd->texture);
105 static void freeData(ModifierData *md)
107 WarpModifierData *wmd = (WarpModifierData *) md;
108 curvemapping_free(wmd->curfalloff);
112 static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams))
114 WarpModifierData *wmd = (WarpModifierData *) md;
116 return !(wmd->object_from && wmd->object_to);
119 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
121 WarpModifierData *wmd = (WarpModifierData *) md;
123 walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
124 walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
125 walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
128 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
130 WarpModifierData *wmd = (WarpModifierData *) md;
132 walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
134 foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
137 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
139 walk(userData, ob, md, "texture");
142 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
144 WarpModifierData *wmd = (WarpModifierData *) md;
145 if (wmd->object_from != NULL && wmd->object_to != NULL) {
146 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Warplace Modifier");
147 DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
148 DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
150 if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
151 DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
153 if (wmd->texture != NULL) {
154 DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Warp Modifier");
158 static void warpModifier_do(
159 WarpModifierData *wmd, const ModifierEvalContext *ctx,
160 Mesh *mesh, float (*vertexCos)[3], int numVerts)
162 Object *ob = ctx->object;
163 Depsgraph *depsgraph = ctx->depsgraph;
165 float mat_from[4][4];
166 float mat_from_inv[4][4];
168 float mat_unit[4][4];
169 float mat_final[4][4];
173 const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
174 float strength = wmd->strength;
175 float fac = 1.0f, weight;
178 MDeformVert *dvert, *dv = NULL;
180 float (*tex_co)[3] = NULL;
182 if (!(wmd->object_from && wmd->object_to))
185 MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
190 if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */
191 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
193 if (wmd->curfalloff) {
194 curvemapping_initialize(wmd->curfalloff);
197 invert_m4_m4(obinv, ob->obmat);
199 mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
200 mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);
202 invert_m4_m4(tmat, mat_from); // swap?
203 mul_m4_m4m4(mat_final, tmat, mat_to);
205 invert_m4_m4(mat_from_inv, mat_from);
209 if (strength < 0.0f) {
211 strength = -strength;
213 /* inverted location is not useful, just use the negative */
214 copy_v3_v3(loc, mat_final[3]);
215 invert_m4(mat_final);
216 negate_v3_v3(mat_final[3], loc);
221 if (mesh != NULL && wmd->texture) {
222 tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
223 MOD_get_texture_coords((MappingInfoModifierData *)wmd, ob, mesh, vertexCos, tex_co);
225 MOD_init_texture(depsgraph, wmd->texture);
228 for (i = 0; i < numVerts; i++) {
229 float *co = vertexCos[i];
231 if (wmd->falloff_type == eWarp_Falloff_None ||
232 ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
233 (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius)))
235 /* skip if no vert group found */
236 if (defgrp_index != -1) {
238 weight = defvert_find_weight(dv, defgrp_index) * strength;
239 if (weight <= 0.0f) {
245 /* closely match PROP_SMOOTH and similar */
246 switch (wmd->falloff_type) {
247 case eWarp_Falloff_None:
250 case eWarp_Falloff_Curve:
251 fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
253 case eWarp_Falloff_Sharp:
256 case eWarp_Falloff_Smooth:
257 fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
259 case eWarp_Falloff_Root:
262 case eWarp_Falloff_Linear:
265 case eWarp_Falloff_Const:
268 case eWarp_Falloff_Sphere:
269 fac = sqrtf(2 * fac - fac * fac);
271 case eWarp_Falloff_InvSquare:
272 fac = fac * (2.0f - fac);
279 struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
282 BKE_texture_get_value(scene, wmd->texture, tex_co[i], &texres, false);
287 /* into the 'from' objects space */
288 mul_m4_v3(mat_from_inv, co);
291 mul_m4_v3(mat_final, co);
294 if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
295 /* interpolate the matrix for nicer locations */
296 blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
301 mul_v3_m4v3(tvec, mat_final, co);
302 interp_v3_v3v3(co, co, tvec, fac);
306 /* out of the 'from' objects space */
307 mul_m4_v3(mat_from, co);
317 static void deformVerts(
318 ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
319 float (*vertexCos)[3], int numVerts)
321 WarpModifierData *wmd = (WarpModifierData *)md;
322 Mesh *mesh_src = NULL;
324 if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) {
325 /* mesh_src is only needed for vgroups and textures. */
326 mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
329 warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
331 if (!ELEM(mesh_src, NULL, mesh)) {
332 BKE_id_free(NULL, mesh_src);
336 static void deformVertsEM(
337 ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
338 Mesh *mesh, float (*vertexCos)[3], int numVerts)
340 WarpModifierData *wmd = (WarpModifierData *)md;
341 Mesh *mesh_src = NULL;
343 if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) {
344 /* mesh_src is only needed for vgroups and textures. */
345 mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
348 warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
350 if (!ELEM(mesh_src, NULL, mesh)) {
351 BKE_id_free(NULL, mesh_src);
356 ModifierTypeInfo modifierType_Warp = {
358 /* structName */ "WarpModifierData",
359 /* structSize */ sizeof(WarpModifierData),
360 /* type */ eModifierTypeType_OnlyDeform,
361 /* flags */ eModifierTypeFlag_AcceptsCVs |
362 eModifierTypeFlag_AcceptsLattice |
363 eModifierTypeFlag_SupportsEditmode,
364 /* copyData */ copyData,
366 /* deformVerts_DM */ NULL,
367 /* deformMatrices_DM */ NULL,
368 /* deformVertsEM_DM */ NULL,
369 /* deformMatricesEM_DM*/NULL,
370 /* applyModifier_DM */ NULL,
372 /* deformVerts */ deformVerts,
373 /* deformMatrices */ NULL,
374 /* deformVertsEM */ deformVertsEM,
375 /* deformMatricesEM */ NULL,
376 /* applyModifier */ NULL,
378 /* initData */ initData,
379 /* requiredDataMask */ requiredDataMask,
380 /* freeData */ freeData,
381 /* isDisabled */ isDisabled,
382 /* updateDepsgraph */ updateDepsgraph,
383 /* dependsOnTime */ dependsOnTime,
384 /* dependsOnNormals */ NULL,
385 /* foreachObjectLink */ foreachObjectLink,
386 /* foreachIDLink */ foreachIDLink,
387 /* foreachTexLink */ foreachTexLink,