Blender  V3.3
MOD_uvproject.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
8 /* UV Project modifier: Generates UVs projected from an object */
9 
10 #include "BLI_utildefines.h"
11 
12 #include "BLI_math.h"
13 #include "BLI_uvproject.h"
14 
15 #include "BLT_translation.h"
16 
17 #include "DNA_camera_types.h"
18 #include "DNA_defaults.h"
19 #include "DNA_mesh_types.h"
20 #include "DNA_meshdata_types.h"
21 #include "DNA_object_types.h"
22 #include "DNA_screen_types.h"
23 
24 #include "BKE_camera.h"
25 #include "BKE_context.h"
26 #include "BKE_lib_query.h"
27 #include "BKE_material.h"
28 #include "BKE_mesh.h"
29 #include "BKE_screen.h"
30 
31 #include "UI_interface.h"
32 #include "UI_resources.h"
33 
34 #include "RNA_access.h"
35 #include "RNA_prototypes.h"
36 
37 #include "MOD_modifiertypes.h"
38 #include "MOD_ui_common.h"
39 
40 #include "MEM_guardedalloc.h"
41 
42 #include "DEG_depsgraph.h"
43 #include "DEG_depsgraph_build.h"
44 #include "DEG_depsgraph_query.h"
45 
46 static void initData(ModifierData *md)
47 {
49 
51 
53 }
54 
55 static void requiredDataMask(Object *UNUSED(ob),
56  ModifierData *UNUSED(md),
57  CustomData_MeshMasks *r_cddata_masks)
58 {
59  /* ask for UV coordinates */
60  r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
61 }
62 
63 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
64 {
66  for (int i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; i++) {
67  walk(userData, ob, (ID **)&umd->projectors[i], IDWALK_CB_NOP);
68  }
69 }
70 
72 {
74  bool do_add_own_transform = false;
75  for (int i = 0; i < umd->projectors_num; i++) {
76  if (umd->projectors[i] != NULL) {
78  ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
79  do_add_own_transform = true;
80  }
81  }
82  if (do_add_own_transform) {
83  DEG_add_modifier_to_transform_relation(ctx->node, "UV Project Modifier");
84  }
85 }
86 
87 typedef struct Projector {
88  Object *ob; /* object this projector is derived from */
89  float projmat[4][4]; /* projection matrix */
90  float normal[3]; /* projector normal in world space */
91  void *uci; /* optional uv-project info (panorama projection) */
93 
95  const ModifierEvalContext *UNUSED(ctx),
96  Object *ob,
97  Mesh *mesh)
98 {
99  float(*coords)[3], (*co)[3];
100  MLoopUV *mloop_uv;
101  int i, verts_num, polys_num, loops_num;
102  MPoly *mpoly, *mp;
103  MLoop *mloop;
105  int projectors_num = 0;
106  char uvname[MAX_CUSTOMDATA_LAYER_NAME];
107  float aspx = umd->aspectx ? umd->aspectx : 1.0f;
108  float aspy = umd->aspecty ? umd->aspecty : 1.0f;
109  float scax = umd->scalex ? umd->scalex : 1.0f;
110  float scay = umd->scaley ? umd->scaley : 1.0f;
111  int free_uci = 0;
112 
113  for (i = 0; i < umd->projectors_num; i++) {
114  if (umd->projectors[i] != NULL) {
115  projectors[projectors_num++].ob = umd->projectors[i];
116  }
117  }
118 
119  if (projectors_num == 0) {
120  return mesh;
121  }
122 
123  /* Create a new layer if no UV Maps are available
124  * (e.g. if a preceding modifier could not preserve it). */
128  }
129 
130  /* make sure we're using an existing layer */
132 
133  /* calculate a projection matrix and normal for each projector */
134  for (i = 0; i < projectors_num; i++) {
135  float tmpmat[4][4];
136  float offsetmat[4][4];
137  Camera *cam = NULL;
138  /* calculate projection matrix */
139  invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat);
140 
141  projectors[i].uci = NULL;
142 
143  if (projectors[i].ob->type == OB_CAMERA) {
144  cam = (Camera *)projectors[i].ob->data;
145  if (cam->type == CAM_PANO) {
146  projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy);
147  BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay);
148  free_uci = 1;
149  }
150  else {
152 
153  /* setup parameters */
155  BKE_camera_params_from_object(&params, projectors[i].ob);
156 
157  /* Compute matrix, view-plane, etc. */
158  BKE_camera_params_compute_viewplane(&params, 1, 1, aspx, aspy);
159 
160  /* scale the view-plane */
161  params.viewplane.xmin *= scax;
162  params.viewplane.xmax *= scax;
163  params.viewplane.ymin *= scay;
164  params.viewplane.ymax *= scay;
165 
167  mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat);
168  }
169  }
170  else {
171  copy_m4_m4(tmpmat, projectors[i].projmat);
172  }
173 
174  unit_m4(offsetmat);
175  mul_mat3_m4_fl(offsetmat, 0.5);
176  offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
177 
178  mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
179 
180  /* Calculate world-space projector normal (for best projector test). */
181  projectors[i].normal[0] = 0;
182  projectors[i].normal[1] = 0;
183  projectors[i].normal[2] = 1;
184  mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
185  }
186 
187  polys_num = mesh->totpoly;
188  loops_num = mesh->totloop;
189 
190  /* make sure we are not modifying the original UV map */
192  &mesh->ldata, CD_MLOOPUV, uvname, loops_num);
193 
194  coords = BKE_mesh_vert_coords_alloc(mesh, &verts_num);
195 
196  /* Convert coords to world-space. */
197  for (i = 0, co = coords; i < verts_num; i++, co++) {
198  mul_m4_v3(ob->obmat, *co);
199  }
200 
201  /* if only one projector, project coords to UVs */
202  if (projectors_num == 1 && projectors[0].uci == NULL) {
203  for (i = 0, co = coords; i < verts_num; i++, co++) {
204  mul_project_m4_v3(projectors[0].projmat, *co);
205  }
206  }
207 
208  mpoly = mesh->mpoly;
209  mloop = mesh->mloop;
210 
211  /* apply coords as UVs */
212  for (i = 0, mp = mpoly; i < polys_num; i++, mp++) {
213  if (projectors_num == 1) {
214  if (projectors[0].uci) {
215  uint fidx = mp->totloop - 1;
216  do {
217  uint lidx = mp->loopstart + fidx;
218  uint vidx = mloop[lidx].v;
219  BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
220  } while (fidx--);
221  }
222  else {
223  /* apply transformed coords as UVs */
224  uint fidx = mp->totloop - 1;
225  do {
226  uint lidx = mp->loopstart + fidx;
227  uint vidx = mloop[lidx].v;
228  copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
229  } while (fidx--);
230  }
231  }
232  else {
233  /* multiple projectors, select the closest to face normal direction */
234  float face_no[3];
235  int j;
236  Projector *best_projector;
237  float best_dot;
238 
239  /* get the untransformed face normal */
241  mp, mloop + mp->loopstart, (const float(*)[3])coords, face_no);
242 
243  /* find the projector which the face points at most directly
244  * (projector normal with largest dot product is best)
245  */
246  best_dot = dot_v3v3(projectors[0].normal, face_no);
247  best_projector = &projectors[0];
248 
249  for (j = 1; j < projectors_num; j++) {
250  float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
251  if (tmp_dot > best_dot) {
252  best_dot = tmp_dot;
253  best_projector = &projectors[j];
254  }
255  }
256 
257  if (best_projector->uci) {
258  uint fidx = mp->totloop - 1;
259  do {
260  uint lidx = mp->loopstart + fidx;
261  uint vidx = mloop[lidx].v;
262  BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
263  } while (fidx--);
264  }
265  else {
266  uint fidx = mp->totloop - 1;
267  do {
268  uint lidx = mp->loopstart + fidx;
269  uint vidx = mloop[lidx].v;
270  mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
271  } while (fidx--);
272  }
273  }
274  }
275 
276  MEM_freeN(coords);
277 
278  if (free_uci) {
279  int j;
280  for (j = 0; j < projectors_num; j++) {
281  if (projectors[j].uci) {
282  MEM_freeN(projectors[j].uci);
283  }
284  }
285  }
286 
287  mesh->runtime.is_original = false;
288 
289  return mesh;
290 }
291 
293 {
294  Mesh *result;
296 
297  result = uvprojectModifier_do(umd, ctx, ctx->object, mesh);
298 
299  return result;
300 }
301 
302 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
303 {
304  uiLayout *sub;
305  uiLayout *layout = panel->layout;
306 
307  PointerRNA ob_ptr;
309 
310  PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
311 
312  uiLayoutSetPropSep(layout, true);
313 
314  uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
315 
316  /* Aspect and Scale are only used for camera projectors. */
317  bool has_camera = false;
318  RNA_BEGIN (ptr, projector_ptr, "projectors") {
319  PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object");
320  if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) {
321  has_camera = true;
322  break;
323  }
324  }
325  RNA_END;
326 
327  sub = uiLayoutColumn(layout, true);
328  uiLayoutSetActive(sub, has_camera);
329  uiItemR(sub, ptr, "aspect_x", 0, NULL, ICON_NONE);
330  uiItemR(sub, ptr, "aspect_y", 0, IFACE_("Y"), ICON_NONE);
331 
332  sub = uiLayoutColumn(layout, true);
333  uiLayoutSetActive(sub, has_camera);
334  uiItemR(sub, ptr, "scale_x", 0, NULL, ICON_NONE);
335  uiItemR(sub, ptr, "scale_y", 0, IFACE_("Y"), ICON_NONE);
336 
337  uiItemR(layout, ptr, "projector_count", 0, IFACE_("Projectors"), ICON_NONE);
338  RNA_BEGIN (ptr, projector_ptr, "projectors") {
339  uiItemR(layout, &projector_ptr, "object", 0, NULL, ICON_NONE);
340  }
341  RNA_END;
342 
343  modifier_panel_end(layout, ptr);
344 }
345 
346 static void panelRegister(ARegionType *region_type)
347 {
349 }
350 
352  /* name */ N_("UVProject"),
353  /* structName */ "UVProjectModifierData",
354  /* structSize */ sizeof(UVProjectModifierData),
355  /* srna */ &RNA_UVProjectModifier,
359  /* icon */ ICON_MOD_UVPROJECT,
360 
361  /* copyData */ BKE_modifier_copydata_generic,
362 
363  /* deformVerts */ NULL,
364  /* deformMatrices */ NULL,
365  /* deformVertsEM */ NULL,
366  /* deformMatricesEM */ NULL,
367  /* modifyMesh */ modifyMesh,
368  /* modifyGeometrySet */ NULL,
369 
370  /* initData */ initData,
371  /* requiredDataMask */ requiredDataMask,
372  /* freeData */ NULL,
373  /* isDisabled */ NULL,
374  /* updateDepsgraph */ updateDepsgraph,
375  /* dependsOnTime */ NULL,
376  /* dependsOnNormals */ NULL,
377  /* foreachIDLink */ foreachIDLink,
378  /* foreachTexLink */ NULL,
379  /* freeRuntimeData */ NULL,
380  /* panelRegister */ panelRegister,
381  /* blendWrite */ NULL,
382  /* blendRead */ NULL,
383 };
typedef float(TangentPoint)[2]
Camera data-block and utility functions.
void BKE_camera_params_init(CameraParams *params)
Definition: camera.c:265
void BKE_camera_params_from_object(CameraParams *params, const struct Object *cam_ob)
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy)
Definition: camera.c:364
void BKE_camera_params_compute_matrix(CameraParams *params)
Definition: camera.c:429
@ CD_DEFAULT
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_duplicate_referenced_layer_named(struct CustomData *data, int type, const char *name, int totelem)
Definition: customdata.cc:2995
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
void CustomData_validate_layer_name(const struct CustomData *data, int type, const char *name, char *outname)
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:33
General operations, lookup, etc. for materials.
float(* BKE_mesh_vert_coords_alloc(const struct Mesh *mesh, int *r_vert_len))[3]
void BKE_mesh_calc_poly_normal_coords(const struct MPoly *mpoly, const struct MLoop *loopstart, const float(*vertex_coords)[3], float r_no[3])
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:107
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:68
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:78
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_NonGeometrical
Definition: BKE_modifier.h:62
#define BLI_assert(a)
Definition: BLI_assert.h:46
void mul_project_m4_v3(const float M[4][4], float vec[3])
Definition: math_matrix.c:820
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void mul_mat3_m4_fl(float R[4][4], float f)
Definition: math_matrix.c:978
void unit_m4(float m[4][4])
Definition: rct.c:1090
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:790
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void mul_v2_project_m4_v3(float r[2], const float M[4][4], const float vec[3])
Definition: math_matrix.c:841
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci)
Definition: uvproject.c:27
struct ProjCameraInfo * BLI_uvproject_camera_info(struct Object *ob, float rotmat[4][4], float winx, float winy)
Definition: uvproject.c:120
void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y)
Definition: uvproject.c:180
#define IFACE_(msgid)
void DEG_add_object_relation(struct DepsNodeHandle *node_handle, struct Object *object, eDepsObjectComponentType component, const char *description)
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description)
@ DEG_OB_COMP_TRANSFORM
@ CAM_PANO
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_MLOOPUV
#define CD_MASK_MLOOPUV
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
struct UVProjectModifierData UVProjectModifierData
@ eModifierType_UVProject
#define MOD_UVPROJECT_MAXPROJECTORS
Object is a sort of wrapper for general info.
@ OB_CAMERA
Read Guarded memory(de)allocation.
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition: MOD_uvproject.c:71
static Mesh * uvprojectModifier_do(UVProjectModifierData *umd, const ModifierEvalContext *UNUSED(ctx), Object *ob, Mesh *mesh)
Definition: MOD_uvproject.c:94
static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks)
Definition: MOD_uvproject.c:55
ModifierTypeInfo modifierType_UVProject
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_uvproject.c:63
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
struct Projector Projector
static void initData(ModifierData *md)
Definition: MOD_uvproject.c:46
static void panelRegister(ARegionType *region_type)
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:543
#define RNA_END
Definition: RNA_access.h:550
#define C
Definition: RandGen.cpp:25
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
IconTextureDrawCall normal
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:164
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
Definition: DNA_ID.h:368
unsigned int v
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
struct Object * object
Definition: BKE_modifier.h:141
struct DepsNodeHandle * node
Definition: BKE_modifier.h:134
float obmat[4][4]
void * data
struct uiLayout * layout
Object * ob
Definition: MOD_uvproject.c:88
float projmat[4][4]
Definition: MOD_uvproject.c:89
float normal[3]
Definition: MOD_uvproject.c:90
void * uci
Definition: MOD_uvproject.c:91
struct Object * projectors[10]
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480