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 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Daniel Dunbar
27 * ***** END GPL LICENSE BLOCK *****
31 /** \file blender/modifiers/intern/MOD_displace.c
36 #include "DNA_mesh_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_object_types.h"
40 #include "BLI_utildefines.h"
44 #include "BKE_customdata.h"
45 #include "BKE_editmesh.h"
46 #include "BKE_library.h"
47 #include "BKE_library_query.h"
48 #include "BKE_image.h"
50 #include "BKE_modifier.h"
51 #include "BKE_texture.h"
52 #include "BKE_deform.h"
53 #include "BKE_object.h"
55 #include "DEG_depsgraph.h"
56 #include "DEG_depsgraph_query.h"
58 #include "MEM_guardedalloc.h"
62 #include "RE_shader_ext.h"
67 static void initData(ModifierData *md)
69 DisplaceModifierData *dmd = (DisplaceModifierData *) md;
73 dmd->direction = MOD_DISP_DIR_NOR;
75 dmd->space = MOD_DISP_SPACE_LOCAL;
78 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
80 DisplaceModifierData *dmd = (DisplaceModifierData *)md;
81 CustomDataMask dataMask = 0;
83 /* ask for vertexgroups if we need them */
84 if (dmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
86 /* ask for UV coordinates if we need them */
87 if (dmd->texmapping == MOD_DISP_MAP_UV) dataMask |= CD_MASK_MTFACE;
89 if (dmd->direction == MOD_DISP_DIR_CLNOR) {
90 dataMask |= CD_MASK_CUSTOMLOOPNORMAL;
96 static bool dependsOnTime(ModifierData *md)
98 DisplaceModifierData *dmd = (DisplaceModifierData *)md;
101 return BKE_texture_dependsOnTime(dmd->texture);
108 static bool dependsOnNormals(ModifierData *md)
110 DisplaceModifierData *dmd = (DisplaceModifierData *)md;
111 return ELEM(dmd->direction, MOD_DISP_DIR_NOR, MOD_DISP_DIR_CLNOR);
114 static void foreachObjectLink(
115 ModifierData *md, Object *ob,
116 ObjectWalkFunc walk, void *userData)
118 DisplaceModifierData *dmd = (DisplaceModifierData *) md;
120 walk(userData, ob, &dmd->map_object, IDWALK_CB_NOP);
123 static void foreachIDLink(
124 ModifierData *md, Object *ob,
125 IDWalkFunc walk, void *userData)
127 DisplaceModifierData *dmd = (DisplaceModifierData *) md;
129 walk(userData, ob, (ID **)&dmd->texture, IDWALK_CB_USER);
131 foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
134 static void foreachTexLink(
135 ModifierData *md, Object *ob,
136 TexWalkFunc walk, void *userData)
138 walk(userData, ob, md, "texture");
141 static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
143 DisplaceModifierData *dmd = (DisplaceModifierData *) md;
144 return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f);
147 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
149 DisplaceModifierData *dmd = (DisplaceModifierData *)md;
150 if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
151 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
152 DEG_add_object_relation(ctx->node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
154 if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
155 (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
156 dmd->space == MOD_DISP_SPACE_GLOBAL))
158 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
160 if (dmd->texture != NULL) {
161 DEG_add_generic_id_relation(ctx->node, &dmd->texture->id, "Displace Modifier");
165 typedef struct DisplaceUserdata {
166 /*const*/ DisplaceModifierData *dmd;
168 struct ImagePool *pool;
173 bool use_global_direction;
175 float (*vertexCos)[3];
176 float local_mat[4][4];
178 float (*vert_clnors)[3];
181 static void displaceModifier_do_task(
182 void *__restrict userdata,
184 const ParallelRangeTLS *__restrict UNUSED(tls))
186 DisplaceUserdata *data = (DisplaceUserdata *)userdata;
187 DisplaceModifierData *dmd = data->dmd;
188 MDeformVert *dvert = data->dvert;
189 float weight = data->weight;
190 int defgrp_index = data->defgrp_index;
191 int direction = data->direction;
192 bool use_global_direction = data->use_global_direction;
193 float (*tex_co)[3] = data->tex_co;
194 float (*vertexCos)[3] = data->vertexCos;
195 MVert *mvert = data->mvert;
196 float (*vert_clnors)[3] = data->vert_clnors;
198 const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
201 float strength = dmd->strength;
206 weight = defvert_find_weight(dvert + iter, defgrp_index);
207 if (weight == 0.0f) {
214 BKE_texture_get_value_ex(data->scene, dmd->texture, tex_co[iter], &texres, data->pool, false);
215 delta = texres.tin - dmd->midlevel;
218 delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
226 CLAMP(delta, -10000, 10000);
230 if (use_global_direction) {
231 vertexCos[iter][0] += delta * data->local_mat[0][0];
232 vertexCos[iter][1] += delta * data->local_mat[1][0];
233 vertexCos[iter][2] += delta * data->local_mat[2][0];
236 vertexCos[iter][0] += delta;
240 if (use_global_direction) {
241 vertexCos[iter][0] += delta * data->local_mat[0][1];
242 vertexCos[iter][1] += delta * data->local_mat[1][1];
243 vertexCos[iter][2] += delta * data->local_mat[2][1];
246 vertexCos[iter][1] += delta;
250 if (use_global_direction) {
251 vertexCos[iter][0] += delta * data->local_mat[0][2];
252 vertexCos[iter][1] += delta * data->local_mat[1][2];
253 vertexCos[iter][2] += delta * data->local_mat[2][2];
256 vertexCos[iter][2] += delta;
259 case MOD_DISP_DIR_RGB_XYZ:
260 local_vec[0] = texres.tr - dmd->midlevel;
261 local_vec[1] = texres.tg - dmd->midlevel;
262 local_vec[2] = texres.tb - dmd->midlevel;
263 if (use_global_direction) {
264 mul_transposed_mat3_m4_v3(data->local_mat, local_vec);
266 mul_v3_fl(local_vec, strength);
267 add_v3_v3(vertexCos[iter], local_vec);
269 case MOD_DISP_DIR_NOR:
270 vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
271 vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
272 vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
274 case MOD_DISP_DIR_CLNOR:
275 madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
280 static void displaceModifier_do(
281 DisplaceModifierData *dmd, const ModifierEvalContext *ctx,
282 Mesh *mesh, float (*vertexCos)[3], const int numVerts)
284 Object *ob = ctx->object;
285 Depsgraph *depsgraph = ctx->depsgraph;
288 int direction = dmd->direction;
291 float weight = 1.0f; /* init value unused but some compilers may complain */
292 float (*vert_clnors)[3] = NULL;
293 float local_mat[4][4] = {{0}};
294 const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL;
296 if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
297 if (dmd->strength == 0.0f) return;
300 MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
303 tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co),
304 "displaceModifier_do tex_co");
305 MOD_get_texture_coords((MappingInfoModifierData *)dmd, ob, mesh, vertexCos, tex_co);
307 MOD_init_texture(depsgraph, dmd->texture);
313 if (direction == MOD_DISP_DIR_CLNOR) {
314 CustomData *ldata = &mesh->ldata;
316 if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) {
317 float (*clnors)[3] = NULL;
319 if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || !CustomData_has_layer(ldata, CD_NORMAL)) {
320 BKE_mesh_calc_normals_split(mesh);
323 clnors = CustomData_get_layer(ldata, CD_NORMAL);
324 vert_clnors = MEM_malloc_arrayN(numVerts, sizeof(*vert_clnors), __func__);
325 BKE_mesh_normals_loop_to_vertex(numVerts, mesh->mloop, mesh->totloop,
326 (const float (*)[3])clnors, vert_clnors);
329 direction = MOD_DISP_DIR_NOR;
332 else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
333 use_global_direction)
335 copy_m4_m4(local_mat, ob->obmat);
338 DisplaceUserdata data = {NULL};
339 data.scene = DEG_get_evaluated_scene(ctx->depsgraph);
342 data.weight = weight;
343 data.defgrp_index = defgrp_index;
344 data.direction = direction;
345 data.use_global_direction = use_global_direction;
346 data.tex_co = tex_co;
347 data.vertexCos = vertexCos;
348 copy_m4_m4(data.local_mat, local_mat);
350 data.vert_clnors = vert_clnors;
351 if (dmd->texture != NULL) {
352 data.pool = BKE_image_pool_new();
353 BKE_texture_fetch_images_for_pool(dmd->texture, data.pool);
355 ParallelRangeSettings settings;
356 BLI_parallel_range_settings_defaults(&settings);
357 settings.use_threading = (numVerts > 512);
358 BLI_task_parallel_range(0, numVerts,
360 displaceModifier_do_task,
363 if (data.pool != NULL) {
364 BKE_image_pool_free(data.pool);
372 MEM_freeN(vert_clnors);
376 static void deformVerts(
378 const ModifierEvalContext *ctx,
380 float (*vertexCos)[3],
383 Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
385 displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts);
387 if (!ELEM(mesh_src, NULL, mesh)) {
388 BKE_id_free(NULL, mesh_src);
392 static void deformVertsEM(
393 ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
394 Mesh *mesh, float (*vertexCos)[3], int numVerts)
396 Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
398 displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts);
400 if (!ELEM(mesh_src, NULL, mesh)) {
401 BKE_id_free(NULL, mesh_src);
406 ModifierTypeInfo modifierType_Displace = {
407 /* name */ "Displace",
408 /* structName */ "DisplaceModifierData",
409 /* structSize */ sizeof(DisplaceModifierData),
410 /* type */ eModifierTypeType_OnlyDeform,
411 /* flags */ eModifierTypeFlag_AcceptsMesh |
412 eModifierTypeFlag_SupportsEditmode,
414 /* copyData */ modifier_copyData_generic,
416 /* deformVerts_DM */ NULL,
417 /* deformMatrices_DM */ NULL,
418 /* deformVertsEM_DM */ NULL,
419 /* deformMatricesEM_DM*/NULL,
420 /* applyModifier_DM */ NULL,
422 /* deformVerts */ deformVerts,
423 /* deformMatrices */ NULL,
424 /* deformVertsEM */ deformVertsEM,
425 /* deformMatricesEM */ NULL,
426 /* applyModifier */ NULL,
428 /* initData */ initData,
429 /* requiredDataMask */ requiredDataMask,
431 /* isDisabled */ isDisabled,
432 /* updateDepsgraph */ updateDepsgraph,
433 /* dependsOnTime */ dependsOnTime,
434 /* dependsOnNormals */ dependsOnNormals,
435 /* foreachObjectLink */ foreachObjectLink,
436 /* foreachIDLink */ foreachIDLink,
437 /* foreachTexLink */ foreachTexLink,