Blender V4.3
MOD_particleinstance.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#include "MEM_guardedalloc.h"
10
11#include "BLI_utildefines.h"
12
13#include "BLI_listbase.h"
14#include "BLI_math_matrix.h"
15#include "BLI_math_rotation.h"
16#include "BLI_math_vector.h"
17#include "BLI_rand.h"
18
19#include "BLT_translation.hh"
20
21#include "DNA_defaults.h"
22#include "DNA_mesh_types.h"
23#include "DNA_meshdata_types.h"
24#include "DNA_screen_types.h"
25
26#include "BKE_customdata.hh"
27#include "BKE_lib_query.hh"
28#include "BKE_mesh.hh"
29#include "BKE_modifier.hh"
30#include "BKE_particle.h"
31#include "BKE_pointcache.h"
32
33#include "UI_interface.hh"
34#include "UI_resources.hh"
35
36#include "RNA_access.hh"
37#include "RNA_prototypes.hh"
38
41
42#include "MOD_ui_common.hh"
43
52
53static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
54{
56
57 if (pimd->index_layer_name[0] != '\0' || pimd->value_layer_name[0] != '\0') {
58 r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR;
59 }
60}
61
62static bool is_disabled(const Scene *scene, ModifierData *md, bool use_render_params)
63{
65 ParticleSystem *psys;
66
67 /* The object type check is only needed here in case we have a placeholder
68 * object assigned (because the library containing the mesh is missing).
69 *
70 * In other cases it should be impossible to have a type mismatch.
71 */
72 if (!pimd->ob || pimd->ob->type != OB_MESH) {
73 return true;
74 }
75
76 psys = static_cast<ParticleSystem *>(BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1));
77 if (psys == nullptr) {
78 return true;
79 }
80
81 /* If the psys modifier is disabled we cannot use its data.
82 * First look up the psys modifier from the object, then check if it is enabled.
83 */
84 LISTBASE_FOREACH (ModifierData *, ob_md, &pimd->ob->modifiers) {
85 if (ob_md->type == eModifierType_ParticleSystem) {
87 if (psmd->psys == psys) {
88 int required_mode;
89
90 if (use_render_params) {
91 required_mode = eModifierMode_Render;
92 }
93 else {
94 required_mode = eModifierMode_Realtime;
95 }
96
97 if (!BKE_modifier_is_enabled(scene, ob_md, required_mode)) {
98 return true;
99 }
100
101 break;
102 }
103 }
104 }
105
106 return false;
107}
108
110{
112 if (pimd->ob != nullptr) {
114 ctx->node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier");
116 ctx->node, pimd->ob, DEG_OB_COMP_GEOMETRY, "Particle Instance Modifier");
117 }
118}
119
120static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
121{
123
124 walk(user_data, ob, (ID **)&pimd->ob, IDWALK_CB_NOP);
125}
126
128{
129 const bool between = (psys->part->childtype == PART_CHILD_FACES);
130 ParticleData *pa;
131 int totpart, randp, minp, maxp;
132
133 if (p >= psys->totpart) {
134 ChildParticle *cpa = psys->child + (p - psys->totpart);
135 pa = psys->particles + (between ? cpa->pa[0] : cpa->parent);
136 }
137 else {
138 pa = psys->particles + p;
139 }
140
141 if (pa) {
142 if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) {
143 return true;
144 }
145 if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) {
146 return true;
147 }
148 if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) {
149 return true;
150 }
151 if (pa->flag & (PARS_UNEXIST | PARS_NO_DISP)) {
152 return true;
153 }
154 }
155
156 if (pimd->particle_amount == 1.0f) {
157 /* Early output, all particles are to be instanced. */
158 return false;
159 }
160
161 /* Randomly skip particles based on desired amount of visible particles. */
162
163 totpart = psys->totpart + psys->totchild;
164
165 /* TODO: make randomization optional? */
166 randp = int(psys_frand(psys, 3578 + p) * totpart) % totpart;
167
168 minp = int(totpart * pimd->particle_offset) % (totpart + 1);
169 maxp = int(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart + 1);
170
171 if (maxp > minp) {
172 return randp < minp || randp >= maxp;
173 }
174 if (maxp < minp) {
175 return randp < minp && randp >= maxp;
176 }
177
178 return true;
179}
180
181static void store_float_in_vcol(MLoopCol *vcol, float float_value)
182{
183 const uchar value = unit_float_to_uchar_clamp(float_value);
184 vcol->r = vcol->g = vcol->b = value;
185 vcol->a = 1.0f;
186}
187
188static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
189{
190 Mesh *result;
194 ParticleSystem *psys = nullptr;
195 ParticleData *pa = nullptr;
196 int totvert, faces_num, totloop, totedge;
197 int maxvert, maxpoly, maxloop, maxedge, part_end = 0, part_start;
198 int k, p, p_skip;
199 short track = ctx->object->trackflag % 3, trackneg, axis = pimd->axis;
200 float max_co = 0.0, min_co = 0.0, temp_co[3];
201 float *size = nullptr;
202 float spacemat[4][4];
203 const bool use_parents = pimd->flag & eParticleInstanceFlag_Parents;
204 const bool use_children = pimd->flag & eParticleInstanceFlag_Children;
205 bool between;
206
207 trackneg = ((ctx->object->trackflag > 2) ? 1 : 0);
208
209 if (pimd->ob == ctx->object) {
210 pimd->ob = nullptr;
211 return mesh;
212 }
213
214 if (pimd->ob) {
215 psys = static_cast<ParticleSystem *>(BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1));
216 if (psys == nullptr || psys->totpart == 0) {
217 return mesh;
218 }
219 }
220 else {
221 return mesh;
222 }
223
224 part_start = use_parents ? 0 : psys->totpart;
225
226 part_end = 0;
227 if (use_parents) {
228 part_end += psys->totpart;
229 }
230 if (use_children) {
231 part_end += psys->totchild;
232 }
233
234 if (part_end == 0) {
235 return mesh;
236 }
237
238 sim.depsgraph = ctx->depsgraph;
239 sim.scene = scene;
240 sim.ob = pimd->ob;
241 sim.psys = psys;
242 sim.psmd = psys_get_modifier(pimd->ob, psys);
243 between = (psys->part->childtype == PART_CHILD_FACES);
244
246 float *si;
247 si = size = static_cast<float *>(MEM_calloc_arrayN(part_end, sizeof(float), __func__));
248
250 for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) {
251 *si = pa->size;
252 }
253 }
254
256 ChildParticle *cpa = psys->child;
257
258 for (p = 0; p < psys->totchild; p++, cpa++, si++) {
259 *si = psys_get_child_size(psys, cpa, 0.0f, nullptr);
260 }
261 }
262 }
263
264 switch (pimd->space) {
266 /* particle states are in world space already */
267 unit_m4(spacemat);
268 break;
270 /* get particle states in the particle object's local space */
271 invert_m4_m4(spacemat, pimd->ob->object_to_world().ptr());
272 break;
273 default:
274 /* should not happen */
275 BLI_assert(false);
276 break;
277 }
278
279 totvert = mesh->verts_num;
280 faces_num = mesh->faces_num;
281 totloop = mesh->corners_num;
282 totedge = mesh->edges_num;
283
284 /* count particles */
285 maxvert = 0;
286 maxpoly = 0;
287 maxloop = 0;
288 maxedge = 0;
289
290 for (p = part_start; p < part_end; p++) {
291 if (particle_skip(pimd, psys, p)) {
292 continue;
293 }
294
295 maxvert += totvert;
296 maxpoly += faces_num;
297 maxloop += totloop;
298 maxedge += totedge;
299 }
300
301 psys_sim_data_init(&sim);
302
303 if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {
304 if (const std::optional<blender::Bounds<blender::float3>> bounds = mesh->bounds_min_max()) {
305 min_co = bounds->min[track];
306 max_co = bounds->max[track];
307 }
308 }
309
310 result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, maxpoly, maxloop);
311
312 const blender::OffsetIndices orig_faces = mesh->faces();
313 const blender::Span<int> orig_corner_verts = mesh->corner_verts();
314 const blender::Span<int> orig_corner_edges = mesh->corner_edges();
315 blender::MutableSpan<blender::float3> positions = result->vert_positions_for_write();
316 blender::MutableSpan<blender::int2> edges = result->edges_for_write();
317 blender::MutableSpan<int> face_offsets = result->face_offsets_for_write();
318 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
319 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
320
321 MLoopCol *mloopcols_index = static_cast<MLoopCol *>(CustomData_get_layer_named_for_write(
322 &result->corner_data, CD_PROP_BYTE_COLOR, pimd->index_layer_name, result->corners_num));
323 MLoopCol *mloopcols_value = static_cast<MLoopCol *>(CustomData_get_layer_named_for_write(
324 &result->corner_data, CD_PROP_BYTE_COLOR, pimd->value_layer_name, result->corners_num));
325 int *vert_part_index = nullptr;
326 float *vert_part_value = nullptr;
327 if (mloopcols_index != nullptr) {
328 vert_part_index = MEM_cnew_array<int>(maxvert, "vertex part index array");
329 }
330 if (mloopcols_value) {
331 vert_part_value = MEM_cnew_array<float>(maxvert, "vertex part value array");
332 }
333
334 for (p = part_start, p_skip = 0; p < part_end; p++) {
335 float prev_dir[3];
336 float frame[4]; /* frame orientation quaternion */
337 float p_random = psys_frand(psys, 77091 + 283 * p);
338
339 /* skip particle? */
340 if (particle_skip(pimd, psys, p)) {
341 continue;
342 }
343
344 /* set vertices coordinates */
345 for (k = 0; k < totvert; k++) {
347 int vindex = p_skip * totvert + k;
348
349 CustomData_copy_data(&mesh->vert_data, &result->vert_data, k, vindex, 1);
350
351 if (vert_part_index != nullptr) {
352 vert_part_index[vindex] = p;
353 }
354 if (vert_part_value != nullptr) {
355 vert_part_value[vindex] = p_random;
356 }
357
358 /* Change orientation based on object trackflag. */
359 copy_v3_v3(temp_co, positions[vindex]);
360 positions[vindex][axis] = temp_co[track];
361 positions[vindex][(axis + 1) % 3] = temp_co[(track + 1) % 3];
362 positions[vindex][(axis + 2) % 3] = temp_co[(track + 2) % 3];
363
364 /* get particle state */
365 if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) &&
367 {
368 float ran = 0.0f;
369 if (pimd->random_position != 0.0f) {
370 ran = pimd->random_position * BLI_hash_frand(psys->seed + p);
371 }
372
374 state.time = pimd->position * (1.0f - ran);
375 }
376 else {
377 state.time = (positions[vindex][axis] - min_co) / (max_co - min_co) * pimd->position *
378 (1.0f - ran);
379
380 if (trackneg) {
381 state.time = 1.0f - state.time;
382 }
383
384 positions[vindex][axis] = 0.0;
385 }
386
387 psys_get_particle_on_path(&sim, p, &state, true);
388
389 normalize_v3(state.vel);
390
391 /* Incrementally Rotating Frame (Bishop Frame) */
392 if (k == 0) {
393 float hairmat[4][4];
394 float mat[3][3];
395
396 if (p < psys->totpart) {
397 pa = psys->particles + p;
398 }
399 else {
400 ChildParticle *cpa = psys->child + (p - psys->totpart);
401 pa = psys->particles + (between ? cpa->pa[0] : cpa->parent);
402 }
403 psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, sim.psys->part->from, pa, hairmat);
404 copy_m3_m4(mat, hairmat);
405 /* to quaternion */
406 mat3_to_quat(frame, mat);
407
408 if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) {
409 float angle = 2.0f * M_PI *
410 (pimd->rotation +
411 pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f));
412 const float eul[3] = {0.0f, 0.0f, angle};
413 float rot[4];
414
415 eul_to_quat(rot, eul);
416 mul_qt_qtqt(frame, frame, rot);
417 }
418
419 /* NOTE: direction is same as normal vector currently,
420 * but best to keep this separate so the frame can be
421 * rotated later if necessary
422 */
423 copy_v3_v3(prev_dir, state.vel);
424 }
425 else {
426 float rot[4];
427
428 /* incrementally rotate along bend direction */
430 mul_qt_qtqt(frame, rot, frame);
431
432 copy_v3_v3(prev_dir, state.vel);
433 }
434
435 copy_qt_qt(state.rot, frame);
436#if 0
437 /* Absolute Frame (Frenet Frame) */
438 if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
439 unit_qt(state.rot);
440 }
441 else {
442 float cross[3];
443 float temp[3] = {0.0f, 0.0f, 0.0f};
444 temp[axis] = 1.0f;
445
446 cross_v3_v3v3(cross, temp, state.vel);
447
448 /* state.vel[axis] is the only component surviving from a dot product with the axis */
450 }
451#endif
452 }
453 else {
454 state.time = -1.0;
455 psys_get_particle_state(&sim, p, &state, true);
456 }
457
458 mul_qt_v3(state.rot, positions[vindex]);
460 mul_v3_fl(positions[vindex], size[p]);
461 }
462 add_v3_v3(positions[vindex], state.co);
463
464 mul_m4_v3(spacemat, positions[vindex]);
465 }
466
467 /* Create edges and adjust edge vertex indices. */
468 CustomData_copy_data(&mesh->edge_data, &result->edge_data, 0, p_skip * totedge, totedge);
469 blender::int2 *edge = &edges[p_skip * totedge];
470 for (k = 0; k < totedge; k++, edge++) {
471 (*edge)[0] += p_skip * totvert;
472 (*edge)[1] += p_skip * totvert;
473 }
474
475 /* create faces and loops */
476 for (k = 0; k < faces_num; k++) {
477 const blender::IndexRange in_face = orig_faces[k];
478
479 CustomData_copy_data(&mesh->face_data, &result->face_data, k, p_skip * faces_num + k, 1);
480 const int dst_face_start = in_face.start() + p_skip * totloop;
481 face_offsets[p_skip * faces_num + k] = dst_face_start;
482
483 {
484 int orig_corner_i = in_face.start();
485 int dst_corner_i = dst_face_start;
486 int j = in_face.size();
487
489 &mesh->corner_data, &result->corner_data, in_face.start(), dst_face_start, j);
490 for (; j; j--, orig_corner_i++, dst_corner_i++) {
491 corner_verts[dst_corner_i] = orig_corner_verts[orig_corner_i] + (p_skip * totvert);
492 corner_edges[dst_corner_i] = orig_corner_edges[orig_corner_i] + (p_skip * totedge);
493 const int vert = corner_verts[dst_corner_i];
494 if (mloopcols_index != nullptr) {
495 const int part_index = vert_part_index[vert];
496 store_float_in_vcol(&mloopcols_index[dst_corner_i],
497 float(part_index) / float(psys->totpart - 1));
498 }
499 if (mloopcols_value != nullptr) {
500 const float part_value = vert_part_value[vert];
501 store_float_in_vcol(&mloopcols_value[dst_corner_i], part_value);
502 }
503 }
504 }
505 }
506 p_skip++;
507 }
508
509 psys_sim_data_free(&sim);
510
511 if (size) {
512 MEM_freeN(size);
513 }
514
515 MEM_SAFE_FREE(vert_part_index);
516 MEM_SAFE_FREE(vert_part_value);
517
518 return result;
519}
520
521static void panel_draw(const bContext * /*C*/, Panel *panel)
522{
523 uiLayout *row;
524 uiLayout *layout = panel->layout;
526
527 PointerRNA ob_ptr;
529
530 PointerRNA particle_obj_ptr = RNA_pointer_get(ptr, "object");
531
532 uiLayoutSetPropSep(layout, true);
533
534 uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
535 if (!RNA_pointer_is_null(&particle_obj_ptr)) {
536 uiItemPointerR(layout,
537 ptr,
538 "particle_system",
539 &particle_obj_ptr,
540 "particle_systems",
541 IFACE_("Particle System"),
542 ICON_NONE);
543 }
544 else {
545 uiItemR(
546 layout, ptr, "particle_system_index", UI_ITEM_NONE, IFACE_("Particle System"), ICON_NONE);
547 }
548
549 uiItemS(layout);
550
551 row = uiLayoutRowWithHeading(layout, true, IFACE_("Create Instances"));
552 uiItemR(row, ptr, "use_normal", toggles_flag, nullptr, ICON_NONE);
553 uiItemR(row, ptr, "use_children", toggles_flag, nullptr, ICON_NONE);
554 uiItemR(row, ptr, "use_size", toggles_flag, nullptr, ICON_NONE);
555
556 row = uiLayoutRowWithHeading(layout, true, IFACE_("Show"));
557 uiItemR(row, ptr, "show_alive", toggles_flag, nullptr, ICON_NONE);
558 uiItemR(row, ptr, "show_dead", toggles_flag, nullptr, ICON_NONE);
559 uiItemR(row, ptr, "show_unborn", toggles_flag, nullptr, ICON_NONE);
560
561 uiItemR(layout, ptr, "particle_amount", UI_ITEM_NONE, IFACE_("Amount"), ICON_NONE);
562 uiItemR(layout, ptr, "particle_offset", UI_ITEM_NONE, IFACE_("Offset"), ICON_NONE);
563
564 uiItemS(layout);
565
566 uiItemR(layout, ptr, "space", UI_ITEM_NONE, IFACE_("Coordinate Space"), ICON_NONE);
567 row = uiLayoutRow(layout, true);
568 uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
569
570 modifier_panel_end(layout, ptr);
571}
572
573static void path_panel_draw_header(const bContext * /*C*/, Panel *panel)
574{
575 uiLayout *layout = panel->layout;
576
578
579 uiItemR(layout, ptr, "use_path", UI_ITEM_NONE, IFACE_("Create Along Paths"), ICON_NONE);
580}
581
582static void path_panel_draw(const bContext * /*C*/, Panel *panel)
583{
584 uiLayout *col;
585 uiLayout *layout = panel->layout;
586
587 PointerRNA ob_ptr;
589
590 uiLayoutSetPropSep(layout, true);
591
592 uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_path"));
593
594 col = uiLayoutColumn(layout, true);
595 uiItemR(col, ptr, "position", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
596 uiItemR(col, ptr, "random_position", UI_ITEM_R_SLIDER, IFACE_("Random"), ICON_NONE);
597 col = uiLayoutColumn(layout, true);
598 uiItemR(col, ptr, "rotation", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
599 uiItemR(col, ptr, "random_rotation", UI_ITEM_R_SLIDER, IFACE_("Random"), ICON_NONE);
600
601 uiItemR(layout, ptr, "use_preserve_shape", UI_ITEM_NONE, nullptr, ICON_NONE);
602}
603
604static void layers_panel_draw(const bContext * /*C*/, Panel *panel)
605{
606 uiLayout *col;
607 uiLayout *layout = panel->layout;
608
609 PointerRNA ob_ptr;
611
612 PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
613
614 uiLayoutSetPropSep(layout, true);
615
616 col = uiLayoutColumn(layout, false);
618 col, ptr, "index_layer_name", &obj_data_ptr, "vertex_colors", IFACE_("Index"), ICON_NONE);
620 col, ptr, "value_layer_name", &obj_data_ptr, "vertex_colors", IFACE_("Value"), ICON_NONE);
621}
622
623static void panel_register(ARegionType *region_type)
624{
628 region_type, "paths", "", path_panel_draw_header, path_panel_draw, panel_type);
630 region_type, "layers", "Layers", nullptr, layers_panel_draw, panel_type);
631}
632
634 /*idname*/ "ParticleInstance",
635 /*name*/ N_("ParticleInstance"),
636 /*struct_name*/ "ParticleInstanceModifierData",
637 /*struct_size*/ sizeof(ParticleInstanceModifierData),
638 /*srna*/ &RNA_ParticleInstanceModifier,
642 /*icon*/ ICON_MOD_PARTICLE_INSTANCE,
643
644 /*copy_data*/ BKE_modifier_copydata_generic,
645
646 /*deform_verts*/ nullptr,
647 /*deform_matrices*/ nullptr,
648 /*deform_verts_EM*/ nullptr,
649 /*deform_matrices_EM*/ nullptr,
650 /*modify_mesh*/ modify_mesh,
651 /*modify_geometry_set*/ nullptr,
652
653 /*init_data*/ init_data,
654 /*required_data_mask*/ required_data_mask,
655 /*free_data*/ nullptr,
656 /*is_disabled*/ is_disabled,
657 /*update_depsgraph*/ update_depsgraph,
658 /*depends_on_time*/ nullptr,
659 /*depends_on_normals*/ nullptr,
660 /*foreach_ID_link*/ foreach_ID_link,
661 /*foreach_tex_link*/ nullptr,
662 /*free_runtime_data*/ nullptr,
663 /*panel_register*/ panel_register,
664 /*blend_write*/ nullptr,
665 /*blend_read*/ nullptr,
666 /*foreach_cache*/ nullptr,
667};
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
@ IDWALK_CB_NOP
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
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
void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, struct ParticleKey *state, bool vel)
Definition particle.cc:4599
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition particle.cc:2150
void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition particle.cc:3907
void psys_sim_data_free(struct ParticleSimulationData *sim)
Definition particle.cc:629
float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time)
Definition particle.cc:4510
void psys_sim_data_init(struct ParticleSimulationData *sim)
Definition particle.cc:588
BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
bool psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, bool always)
Definition particle.cc:4886
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define M_PI
MINLINE float safe_acosf(float a)
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void unit_m4(float m[4][4])
Definition rct.c:1127
void mul_m4_v3(const float M[4][4], float r[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void mat3_to_quat(float q[4], const float mat[3][3])
void mul_qt_v3(const float q[4], float r[3])
void unit_qt(float q[4])
void eul_to_quat(float quat[4], const float eul[3])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
Random number functions.
float BLI_hash_frand(unsigned int seed) ATTR_WARN_UNUSED_RESULT
Definition rand.cc:180
unsigned char uchar
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
#define CD_MASK_PROP_BYTE_COLOR
@ CD_PROP_BYTE_COLOR
#define DNA_struct_default_get(struct_name)
@ eModifierMode_Render
@ eModifierMode_Realtime
@ eParticleInstanceFlag_Parents
@ eParticleInstanceFlag_Alive
@ eParticleInstanceFlag_Dead
@ eParticleInstanceFlag_Children
@ eParticleInstanceFlag_Unborn
@ eParticleInstanceFlag_Path
@ eParticleInstanceFlag_UseSize
@ eParticleInstanceFlag_KeepShape
struct ParticleInstanceModifierData ParticleInstanceModifierData
@ eModifierType_ParticleSystem
@ eModifierType_ParticleInstance
@ eParticleInstanceSpace_World
@ eParticleInstanceSpace_Local
@ OB_MESH
@ PARS_NO_DISP
@ PARS_UNEXIST
@ PARS_ALIVE
@ PARS_DEAD
@ PARS_UNBORN
@ PART_CHILD_FACES
@ PSYS_HAIR_DONE
@ PSYS_KEYED
@ PTCACHE_BAKED
static bool is_disabled
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void init_data(ModifierData *md)
ModifierTypeInfo modifierType_ParticleInstance
static void panel_register(ARegionType *region_type)
static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
static void store_float_in_vcol(MLoopCol *vcol, float float_value)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void path_panel_draw_header(const bContext *, Panel *panel)
static void layers_panel_draw(const bContext *, Panel *panel)
static void panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void path_panel_draw(const bContext *, Panel *panel)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
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)
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
#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)
eUI_Item_Flag
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_SLIDER
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
constexpr int64_t size() const
constexpr int64_t start() const
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define rot(x, k)
uint col
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define unit_float_to_uchar_clamp(val)
ccl_device_inline float cross(const float2 a, const float2 b)
static ulong state[N]
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:413
unsigned char a
unsigned char b
unsigned char r
unsigned char g
ListBase particlesystem
ListBase modifiers
short trackflag
struct uiLayout * layout
struct Depsgraph * depsgraph
struct ParticleSystemModifierData * psmd
struct Scene * scene
struct ParticleSystem * psys
struct Object * ob
struct ParticleSystem * psys
ChildParticle * child
ParticleData * particles
ParticleSettings * part
struct PointCache * pointcache
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126