Blender V4.3
MOD_uvproject.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9/* UV Project modifier: Generates UVs projected from an object */
10
11#include "BLI_utildefines.h"
12
13#include "BLI_math_matrix.h"
14#include "BLI_math_vector.h"
15#include "BLI_uvproject.h"
16
17#include "BLT_translation.hh"
18
19#include "DNA_camera_types.h"
20#include "DNA_defaults.h"
21#include "DNA_mesh_types.h"
22#include "DNA_object_types.h"
23#include "DNA_screen_types.h"
24
25#include "BKE_attribute.hh"
26#include "BKE_camera.h"
27#include "BKE_customdata.hh"
28#include "BKE_lib_query.hh"
29#include "BKE_mesh.hh"
30
31#include "UI_interface.hh"
32#include "UI_resources.hh"
33
34#include "RNA_access.hh"
35#include "RNA_prototypes.hh"
36
37#include "MOD_modifiertypes.hh"
38#include "MOD_ui_common.hh"
39
40#include "MEM_guardedalloc.h"
41
43
52
53static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
54{
55 /* ask for UV coordinates */
56 r_cddata_masks->lmask |= CD_MASK_PROP_FLOAT2;
57}
58
59static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
60{
62 for (int i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; i++) {
63 walk(user_data, ob, (ID **)&umd->projectors[i], IDWALK_CB_NOP);
64 }
65}
66
68{
70 bool do_add_own_transform = false;
71 for (int i = 0; i < umd->projectors_num; i++) {
72 if (umd->projectors[i] != nullptr) {
74 ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
75 do_add_own_transform = true;
76 }
77 }
78 if (do_add_own_transform) {
79 DEG_add_depends_on_transform_relation(ctx->node, "UV Project Modifier");
80 }
81}
82
83struct Projector {
84 Object *ob; /* object this projector is derived from */
85 float projmat[4][4]; /* projection matrix */
86 float normal[3]; /* projector normal in world space */
87 void *uci; /* optional uv-project info (panorama projection) */
88};
89
91 Mesh &mesh, const blender::StringRef md_name)
92{
93 using namespace blender;
94 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
95 if (md_name.is_empty()) {
96 const StringRef name = CustomData_get_active_layer_name(&mesh.corner_data, CD_PROP_FLOAT2);
97 return attributes.lookup_or_add_for_write_span<float2>(name.is_empty() ? "Float2" : name,
98 bke::AttrDomain::Corner);
99 }
100 if (bke::SpanAttributeWriter<float2> attribute = attributes.lookup_or_add_for_write_span<float2>(
101 md_name, bke::AttrDomain::Corner))
102 {
103 return attribute;
104 }
105 AttributeOwner owner = AttributeOwner::from_id(&mesh.id);
106 const std::string name = BKE_attribute_calc_unique_name(owner, md_name);
107 return attributes.lookup_or_add_for_write_span<float2>(name, bke::AttrDomain::Corner);
108}
109
111 const ModifierEvalContext * /*ctx*/,
112 Object *ob,
113 Mesh *mesh)
114{
115 using namespace blender;
117 int projectors_num = 0;
118 float aspx = umd->aspectx ? umd->aspectx : 1.0f;
119 float aspy = umd->aspecty ? umd->aspecty : 1.0f;
120 float scax = umd->scalex ? umd->scalex : 1.0f;
121 float scay = umd->scaley ? umd->scaley : 1.0f;
122 bool free_uci = false;
123
124 for (int i = 0; i < umd->projectors_num; i++) {
125 if (umd->projectors[i] != nullptr) {
126 projectors[projectors_num++].ob = umd->projectors[i];
127 }
128 }
129
130 if (projectors_num == 0) {
131 return mesh;
132 }
133
134 bke::SpanAttributeWriter uv_attribute = get_uv_attribute(*mesh, umd->uvlayer_name);
135 if (!uv_attribute) {
136 return mesh;
137 }
138
139 /* calculate a projection matrix and normal for each projector */
140 for (int i = 0; i < projectors_num; i++) {
141 float tmpmat[4][4];
142 float offsetmat[4][4];
143 /* calculate projection matrix */
144 invert_m4_m4(projectors[i].projmat, projectors[i].ob->object_to_world().ptr());
145
146 projectors[i].uci = nullptr;
147
148 if (projectors[i].ob->type == OB_CAMERA) {
149 const Camera *cam = (const Camera *)projectors[i].ob->data;
150 if (cam->type == CAM_PANO) {
151 projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, nullptr, aspx, aspy);
153 static_cast<ProjCameraInfo *>(projectors[i].uci), scax, scay);
154 free_uci = true;
155 }
156 else {
158
159 /* setup parameters */
161 BKE_camera_params_from_object(&params, projectors[i].ob);
162
163 /* Compute matrix, view-plane, etc. */
165
166 /* scale the view-plane */
167 params.viewplane.xmin *= scax;
168 params.viewplane.xmax *= scax;
169 params.viewplane.ymin *= scay;
170 params.viewplane.ymax *= scay;
171
173 mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat);
174 }
175 }
176 else {
177 copy_m4_m4(tmpmat, projectors[i].projmat);
178 }
179
180 unit_m4(offsetmat);
181 mul_mat3_m4_fl(offsetmat, 0.5);
182 offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
183
184 mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
185
186 /* Calculate world-space projector normal (for best projector test). */
187 projectors[i].normal[0] = 0;
188 projectors[i].normal[1] = 0;
189 projectors[i].normal[2] = 1;
190 mul_mat3_m4_v3(projectors[i].ob->object_to_world().ptr(), projectors[i].normal);
191 }
192
193 const Span<float3> positions = mesh->vert_positions();
194 const OffsetIndices faces = mesh->faces();
195 const Span<int> corner_verts = mesh->corner_verts();
196 MutableSpan<float2> mloop_uv = uv_attribute.span;
197
198 /* Convert coords to world-space. */
199 Array<float3> coords(positions.size());
200 for (int64_t i = 0; i < positions.size(); i++) {
201 mul_v3_m4v3(coords[i], ob->object_to_world().ptr(), positions[i]);
202 }
203
204 /* if only one projector, project coords to UVs */
205 if (projectors_num == 1 && projectors[0].uci == nullptr) {
206 for (int64_t i = 0; i < coords.size(); i++) {
207 mul_project_m4_v3(projectors[0].projmat, coords[i]);
208 }
209 }
210
211 /* apply coords as UVs */
212 for (const int i : faces.index_range()) {
213 const IndexRange face = faces[i];
214 if (projectors_num == 1) {
215 if (projectors[0].uci) {
216 for (const int corner : face) {
217 const int vert = corner_verts[corner];
219 mloop_uv[corner], coords[vert], static_cast<ProjCameraInfo *>(projectors[0].uci));
220 }
221 }
222 else {
223 /* apply transformed coords as UVs */
224 for (const int corner : face) {
225 const int vert = corner_verts[corner];
226 copy_v2_v2(mloop_uv[corner], coords[vert]);
227 }
228 }
229 }
230 else {
231 /* multiple projectors, select the closest to face normal direction */
232 int j;
233 Projector *best_projector;
234 float best_dot;
235
236 /* get the untransformed face normal */
237 const float3 face_no = blender::bke::mesh::face_normal_calc(positions,
238 corner_verts.slice(face));
239
240 /* find the projector which the face points at most directly
241 * (projector normal with largest dot product is best)
242 */
243 best_dot = dot_v3v3(projectors[0].normal, face_no);
244 best_projector = &projectors[0];
245
246 for (j = 1; j < projectors_num; j++) {
247 float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
248 if (tmp_dot > best_dot) {
249 best_dot = tmp_dot;
250 best_projector = &projectors[j];
251 }
252 }
253
254 if (best_projector->uci) {
255 for (const int corner : face) {
256 const int vert = corner_verts[corner];
258 mloop_uv[corner], coords[vert], static_cast<ProjCameraInfo *>(best_projector->uci));
259 }
260 }
261 else {
262 for (const int corner : face) {
263 const int vert = corner_verts[corner];
264 mul_v2_project_m4_v3(mloop_uv[corner], best_projector->projmat, coords[vert]);
265 }
266 }
267 }
268 }
269
270 if (free_uci) {
271 int j;
272 for (j = 0; j < projectors_num; j++) {
273 if (projectors[j].uci) {
274 MEM_freeN(projectors[j].uci);
275 }
276 }
277 }
278
279 uv_attribute.finish();
280
281 mesh->runtime->is_original_bmesh = false;
282
283 return mesh;
284}
285
286static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
287{
288 Mesh *result;
290
291 result = uvprojectModifier_do(umd, ctx, ctx->object, mesh);
292
293 return result;
294}
295
296static void panel_draw(const bContext * /*C*/, Panel *panel)
297{
298 uiLayout *sub;
299 uiLayout *layout = panel->layout;
300
301 PointerRNA ob_ptr;
303
304 PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
305
306 uiLayoutSetPropSep(layout, true);
307
308 uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", nullptr, ICON_GROUP_UVS);
309
310 /* Aspect and Scale are only used for camera projectors. */
311 bool has_camera = false;
312 RNA_BEGIN (ptr, projector_ptr, "projectors") {
313 PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object");
314 if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) {
315 has_camera = true;
316 break;
317 }
318 }
319 RNA_END;
320
321 sub = uiLayoutColumn(layout, true);
322 uiLayoutSetActive(sub, has_camera);
323 uiItemR(sub, ptr, "aspect_x", UI_ITEM_NONE, nullptr, ICON_NONE);
324 uiItemR(sub, ptr, "aspect_y", UI_ITEM_NONE, IFACE_("Y"), ICON_NONE);
325
326 sub = uiLayoutColumn(layout, true);
327 uiLayoutSetActive(sub, has_camera);
328 uiItemR(sub, ptr, "scale_x", UI_ITEM_NONE, nullptr, ICON_NONE);
329 uiItemR(sub, ptr, "scale_y", UI_ITEM_NONE, IFACE_("Y"), ICON_NONE);
330
331 uiItemR(layout, ptr, "projector_count", UI_ITEM_NONE, IFACE_("Projectors"), ICON_NONE);
332 RNA_BEGIN (ptr, projector_ptr, "projectors") {
333 uiItemR(layout, &projector_ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
334 }
335 RNA_END;
336
337 modifier_panel_end(layout, ptr);
338}
339
340static void panel_register(ARegionType *region_type)
341{
343}
344
346 /*idname*/ "UVProject",
347 /*name*/ N_("UVProject"),
348 /*struct_name*/ "UVProjectModifierData",
349 /*struct_size*/ sizeof(UVProjectModifierData),
350 /*srna*/ &RNA_UVProjectModifier,
354 /*icon*/ ICON_MOD_UVPROJECT,
355
356 /*copy_data*/ BKE_modifier_copydata_generic,
357
358 /*deform_verts*/ nullptr,
359 /*deform_matrices*/ nullptr,
360 /*deform_verts_EM*/ nullptr,
361 /*deform_matrices_EM*/ nullptr,
362 /*modify_mesh*/ modify_mesh,
363 /*modify_geometry_set*/ nullptr,
364
365 /*init_data*/ init_data,
366 /*required_data_mask*/ required_data_mask,
367 /*free_data*/ nullptr,
368 /*is_disabled*/ nullptr,
369 /*update_depsgraph*/ update_depsgraph,
370 /*depends_on_time*/ nullptr,
371 /*depends_on_normals*/ nullptr,
372 /*foreach_ID_link*/ foreach_ID_link,
373 /*foreach_tex_link*/ nullptr,
374 /*free_runtime_data*/ nullptr,
375 /*panel_register*/ panel_register,
376 /*blend_write*/ nullptr,
377 /*blend_read*/ nullptr,
378 /*foreach_cache*/ nullptr,
379};
std::string BKE_attribute_calc_unique_name(const AttributeOwner &owner, const blender::StringRef name)
Definition attribute.cc:359
Camera data-block and utility functions.
void BKE_camera_params_init(CameraParams *params)
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)
void BKE_camera_params_compute_matrix(CameraParams *params)
CustomData interface, see also DNA_customdata_types.h.
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
@ IDWALK_CB_NOP
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
#define BLI_assert(a)
Definition BLI_assert.h:50
void mul_v2_project_m4_v3(float r[2], const float mat[4][4], const float vec[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_mat3_m4_fl(float R[4][4], float f)
void unit_m4(float m[4][4])
Definition rct.c:1127
void mul_project_m4_v3(const float mat[4][4], float vec[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
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
#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.cc:31
struct ProjCameraInfo * BLI_uvproject_camera_info(const struct Object *ob, const 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.cc:187
#define IFACE_(msgid)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
@ CAM_PANO
#define CD_MASK_PROP_FLOAT2
@ CD_PROP_FLOAT2
#define DNA_struct_default_get(struct_name)
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.
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
ModifierTypeInfo modifierType_UVProject
static blender::bke::SpanAttributeWriter< blender::float2 > get_uv_attribute(Mesh &mesh, const blender::StringRef md_name)
static Mesh * uvprojectModifier_do(UVProjectModifierData *umd, const ModifierEvalContext *, Object *ob, Mesh *mesh)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
#define RNA_BEGIN(sptr, itemptr, propname)
#define RNA_END
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
int64_t size() const
Definition BLI_array.hh:245
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr bool is_empty() const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
int RNA_enum_get(PointerRNA *ptr, const char *name)
__int64 int64_t
Definition stdint.h:89
Definition DNA_ID.h:413
struct uiLayout * layout
Object * ob
float projmat[4][4]
float normal[3]
struct Object * projectors[10]
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126