Blender  V2.93
MOD_uvproject.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
24 /* UV Project modifier: Generates UVs projected from an object */
25 
26 #include "BLI_utildefines.h"
27 
28 #include "BLI_math.h"
29 #include "BLI_uvproject.h"
30 
31 #include "BLT_translation.h"
32 
33 #include "DNA_camera_types.h"
34 #include "DNA_defaults.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_meshdata_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_screen_types.h"
39 
40 #include "BKE_camera.h"
41 #include "BKE_context.h"
42 #include "BKE_lib_query.h"
43 #include "BKE_material.h"
44 #include "BKE_mesh.h"
45 #include "BKE_screen.h"
46 
47 #include "UI_interface.h"
48 #include "UI_resources.h"
49 
50 #include "RNA_access.h"
51 
52 #include "MOD_modifiertypes.h"
53 #include "MOD_ui_common.h"
54 
55 #include "MEM_guardedalloc.h"
56 
57 #include "DEG_depsgraph.h"
58 #include "DEG_depsgraph_build.h"
59 #include "DEG_depsgraph_query.h"
60 
61 static void initData(ModifierData *md)
62 {
64 
66 
68 }
69 
70 static void requiredDataMask(Object *UNUSED(ob),
71  ModifierData *UNUSED(md),
72  CustomData_MeshMasks *r_cddata_masks)
73 {
74  /* ask for UV coordinates */
75  r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
76 }
77 
78 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
79 {
81  for (int i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; i++) {
82  walk(userData, ob, (ID **)&umd->projectors[i], IDWALK_CB_NOP);
83  }
84 }
85 
87 {
89  bool do_add_own_transform = false;
90  for (int i = 0; i < umd->num_projectors; i++) {
91  if (umd->projectors[i] != NULL) {
93  ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
94  do_add_own_transform = true;
95  }
96  }
97  if (do_add_own_transform) {
98  DEG_add_modifier_to_transform_relation(ctx->node, "UV Project Modifier");
99  }
100 }
101 
102 typedef struct Projector {
103  Object *ob; /* object this projector is derived from */
104  float projmat[4][4]; /* projection matrix */
105  float normal[3]; /* projector normal in world space */
106  void *uci; /* optional uv-project info (panorama projection) */
108 
110  const ModifierEvalContext *UNUSED(ctx),
111  Object *ob,
112  Mesh *mesh)
113 {
114  float(*coords)[3], (*co)[3];
115  MLoopUV *mloop_uv;
116  int i, numVerts, numPolys, numLoops;
117  MPoly *mpoly, *mp;
118  MLoop *mloop;
120  int num_projectors = 0;
121  char uvname[MAX_CUSTOMDATA_LAYER_NAME];
122  float aspx = umd->aspectx ? umd->aspectx : 1.0f;
123  float aspy = umd->aspecty ? umd->aspecty : 1.0f;
124  float scax = umd->scalex ? umd->scalex : 1.0f;
125  float scay = umd->scaley ? umd->scaley : 1.0f;
126  int free_uci = 0;
127 
128  for (i = 0; i < umd->num_projectors; i++) {
129  if (umd->projectors[i] != NULL) {
130  projectors[num_projectors++].ob = umd->projectors[i];
131  }
132  }
133 
134  if (num_projectors == 0) {
135  return mesh;
136  }
137 
138  /* Create a new layer if no UV Maps are available
139  * (e.g. if a preceding modifier could not preserve it). */
143  }
144 
145  /* make sure we're using an existing layer */
147 
148  /* calculate a projection matrix and normal for each projector */
149  for (i = 0; i < num_projectors; i++) {
150  float tmpmat[4][4];
151  float offsetmat[4][4];
152  Camera *cam = NULL;
153  /* calculate projection matrix */
154  invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat);
155 
156  projectors[i].uci = NULL;
157 
158  if (projectors[i].ob->type == OB_CAMERA) {
159  cam = (Camera *)projectors[i].ob->data;
160  if (cam->type == CAM_PANO) {
161  projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy);
162  BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay);
163  free_uci = 1;
164  }
165  else {
167 
168  /* setup parameters */
170  BKE_camera_params_from_object(&params, projectors[i].ob);
171 
172  /* compute matrix, viewplane, .. */
173  BKE_camera_params_compute_viewplane(&params, 1, 1, aspx, aspy);
174 
175  /* scale the view-plane */
176  params.viewplane.xmin *= scax;
177  params.viewplane.xmax *= scax;
178  params.viewplane.ymin *= scay;
179  params.viewplane.ymax *= scay;
180 
182  mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat);
183  }
184  }
185  else {
186  copy_m4_m4(tmpmat, projectors[i].projmat);
187  }
188 
189  unit_m4(offsetmat);
190  mul_mat3_m4_fl(offsetmat, 0.5);
191  offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
192 
193  mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
194 
195  /* calculate worldspace projector normal (for best projector test) */
196  projectors[i].normal[0] = 0;
197  projectors[i].normal[1] = 0;
198  projectors[i].normal[2] = 1;
199  mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
200  }
201 
202  numPolys = mesh->totpoly;
203  numLoops = mesh->totloop;
204 
205  /* make sure we are not modifying the original UV map */
207  &mesh->ldata, CD_MLOOPUV, uvname, numLoops);
208 
209  coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts);
210 
211  /* convert coords to world space */
212  for (i = 0, co = coords; i < numVerts; i++, co++) {
213  mul_m4_v3(ob->obmat, *co);
214  }
215 
216  /* if only one projector, project coords to UVs */
217  if (num_projectors == 1 && projectors[0].uci == NULL) {
218  for (i = 0, co = coords; i < numVerts; i++, co++) {
219  mul_project_m4_v3(projectors[0].projmat, *co);
220  }
221  }
222 
223  mpoly = mesh->mpoly;
224  mloop = mesh->mloop;
225 
226  /* apply coords as UVs */
227  for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
228  if (num_projectors == 1) {
229  if (projectors[0].uci) {
230  uint fidx = mp->totloop - 1;
231  do {
232  uint lidx = mp->loopstart + fidx;
233  uint vidx = mloop[lidx].v;
234  BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
235  } while (fidx--);
236  }
237  else {
238  /* apply transformed coords as UVs */
239  uint fidx = mp->totloop - 1;
240  do {
241  uint lidx = mp->loopstart + fidx;
242  uint vidx = mloop[lidx].v;
243  copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
244  } while (fidx--);
245  }
246  }
247  else {
248  /* multiple projectors, select the closest to face normal direction */
249  float face_no[3];
250  int j;
251  Projector *best_projector;
252  float best_dot;
253 
254  /* get the untransformed face normal */
256  mp, mloop + mp->loopstart, (const float(*)[3])coords, face_no);
257 
258  /* find the projector which the face points at most directly
259  * (projector normal with largest dot product is best)
260  */
261  best_dot = dot_v3v3(projectors[0].normal, face_no);
262  best_projector = &projectors[0];
263 
264  for (j = 1; j < num_projectors; j++) {
265  float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
266  if (tmp_dot > best_dot) {
267  best_dot = tmp_dot;
268  best_projector = &projectors[j];
269  }
270  }
271 
272  if (best_projector->uci) {
273  uint fidx = mp->totloop - 1;
274  do {
275  uint lidx = mp->loopstart + fidx;
276  uint vidx = mloop[lidx].v;
277  BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
278  } while (fidx--);
279  }
280  else {
281  uint fidx = mp->totloop - 1;
282  do {
283  uint lidx = mp->loopstart + fidx;
284  uint vidx = mloop[lidx].v;
285  mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
286  } while (fidx--);
287  }
288  }
289  }
290 
291  MEM_freeN(coords);
292 
293  if (free_uci) {
294  int j;
295  for (j = 0; j < num_projectors; j++) {
296  if (projectors[j].uci) {
297  MEM_freeN(projectors[j].uci);
298  }
299  }
300  }
301 
302  mesh->runtime.is_original = false;
303 
304  /* Mark tessellated CD layers as dirty. */
306 
307  return mesh;
308 }
309 
311 {
312  Mesh *result;
314 
315  result = uvprojectModifier_do(umd, ctx, ctx->object, mesh);
316 
317  return result;
318 }
319 
320 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
321 {
322  uiLayout *sub;
323  uiLayout *layout = panel->layout;
324 
325  PointerRNA ob_ptr;
327 
328  PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
329 
330  uiLayoutSetPropSep(layout, true);
331 
332  uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
333 
334  /* Aspect and Scale are only used for camera projectors. */
335  bool has_camera = false;
336  RNA_BEGIN (ptr, projector_ptr, "projectors") {
337  PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object");
338  if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) {
339  has_camera = true;
340  break;
341  }
342  }
343  RNA_END;
344 
345  sub = uiLayoutColumn(layout, true);
346  uiLayoutSetActive(sub, has_camera);
347  uiItemR(sub, ptr, "aspect_x", 0, NULL, ICON_NONE);
348  uiItemR(sub, ptr, "aspect_y", 0, IFACE_("Y"), ICON_NONE);
349 
350  sub = uiLayoutColumn(layout, true);
351  uiLayoutSetActive(sub, has_camera);
352  uiItemR(sub, ptr, "scale_x", 0, NULL, ICON_NONE);
353  uiItemR(sub, ptr, "scale_y", 0, IFACE_("Y"), ICON_NONE);
354 
355  uiItemR(layout, ptr, "projector_count", 0, IFACE_("Projectors"), ICON_NONE);
356  RNA_BEGIN (ptr, projector_ptr, "projectors") {
357  uiItemR(layout, &projector_ptr, "object", 0, NULL, ICON_NONE);
358  }
359  RNA_END;
360 
361  modifier_panel_end(layout, ptr);
362 }
363 
364 static void panelRegister(ARegionType *region_type)
365 {
367 }
368 
370  /* name */ "UVProject",
371  /* structName */ "UVProjectModifierData",
372  /* structSize */ sizeof(UVProjectModifierData),
373  /* srna */ &RNA_UVProjectModifier,
377  /* icon */ ICON_MOD_UVPROJECT,
378 
379  /* copyData */ BKE_modifier_copydata_generic,
380 
381  /* deformVerts */ NULL,
382  /* deformMatrices */ NULL,
383  /* deformVertsEM */ NULL,
384  /* deformMatricesEM */ NULL,
385  /* modifyMesh */ modifyMesh,
386  /* modifyHair */ NULL,
387  /* modifyGeometrySet */ NULL,
388  /* modifyVolume */ NULL,
389 
390  /* initData */ initData,
391  /* requiredDataMask */ requiredDataMask,
392  /* freeData */ NULL,
393  /* isDisabled */ NULL,
394  /* updateDepsgraph */ updateDepsgraph,
395  /* dependsOnTime */ NULL,
396  /* dependsOnNormals */ NULL,
397  /* foreachIDLink */ foreachIDLink,
398  /* foreachTexLink */ NULL,
399  /* freeRuntimeData */ NULL,
400  /* panelRegister */ panelRegister,
401  /* blendWrite */ NULL,
402  /* blendRead */ NULL,
403 };
typedef float(TangentPoint)[2]
Camera data-block and utility functions.
void BKE_camera_params_init(CameraParams *params)
Definition: camera.c:271
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:370
void BKE_camera_params_compute_matrix(CameraParams *params)
Definition: camera.c:436
@ CD_DEFAULT
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_duplicate_referenced_layer_named(struct CustomData *data, const int type, const char *name, const int totelem)
Definition: customdata.c:2807
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.c:2637
void CustomData_validate_layer_name(const struct CustomData *data, int type, const char *name, char *outname)
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:47
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:120
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:82
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:92
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:83
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:80
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_NonGeometrical
Definition: BKE_modifier.h:76
#define BLI_assert(a)
Definition: BLI_assert.h:58
void mul_project_m4_v3(const float M[4][4], float vec[3])
Definition: math_matrix.c:824
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void mul_mat3_m4_fl(float R[4][4], float f)
Definition: math_matrix.c:982
void unit_m4(float m[4][4])
Definition: rct.c:1140
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void mul_v2_project_m4_v3(float r[2], const float M[4][4], const float vec[3])
Definition: math_matrix.c:845
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
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:83
#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:41
struct ProjCameraInfo * BLI_uvproject_camera_info(struct Object *ob, float rotmat[4][4], float winx, float winy)
void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y)
Definition: uvproject.c:197
#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
#define CD_MASK_TESSLOOPNORMAL
@ CD_MLOOPUV
#define CD_MASK_MLOOPUV
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
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)
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:86
static Mesh * uvprojectModifier_do(UVProjectModifierData *umd, const ModifierEvalContext *UNUSED(ctx), Object *ob, Mesh *mesh)
static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks)
Definition: MOD_uvproject.c:70
ModifierTypeInfo modifierType_UVProject
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_uvproject.c:78
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
struct Projector Projector
static void initData(ModifierData *md)
Definition: MOD_uvproject.c:61
static void panelRegister(ARegionType *region_type)
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:1248
#define RNA_END
Definition: RNA_access.h:1255
StructRNA RNA_UVProjectModifier
#define C
Definition: RandGen.cpp:39
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:41
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6562
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:174
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
Definition: DNA_ID.h:273
unsigned int v
int64_t cd_dirty_vert
struct CustomData pdata ldata
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
struct Object * object
Definition: BKE_modifier.h:154
struct DepsNodeHandle * node
Definition: BKE_modifier.h:147
float obmat[4][4]
void * data
struct uiLayout * layout
Object * ob
float projmat[4][4]
float normal[3]
void * uci
struct Object * projectors[10]
PointerRNA * ptr
Definition: wm_files.c:3157