2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2005 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2006-08-28 01:12:36 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
2022-02-09 16:00:03 +11:00
|
|
|
* Modifier stack implementation.
|
2023-11-14 09:30:40 +01:00
|
|
|
* BKE_modifier.hh contains the function prototypes for this file.
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
|
|
|
|
|
2020-11-06 17:13:04 +01:00
|
|
|
/* Allow using deprecated functionality for .blend file I/O. */
|
|
|
|
|
#define DNA_DEPRECATED_ALLOW
|
|
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
#include <cfloat>
|
Modifiers: measure execution time and provide Python access
The goal is to give technical artists the ability to optimize modifier usage
and/or geometry node groups for performance. In the long term, it
would be useful if Blender could provide its own UI to display profiling
information to users. However, right now, there are too many open
design questions making it infeasible to tackle this in the short term.
This commit uses a simpler approach: Instead of adding new ui for
profiling data, it exposes the execution-time of modifiers in the Python
API. This allows technical artists to access the information and to build
their own UI to display the relevant information. In the long term this
will hopefully also help us to integrate a native ui for this in Blender
by observing how users use this information.
Note: The execution time of a modifier highly depends on what other
things the CPU is doing at the same time. For example, in many more
complex files, many objects and therefore modifiers are evaluated at
the same time by multiple threads which makes the measurement
much less reliable. For best results, make sure that only one object
is evaluated at a time (e.g. by changing it in isolation) and that no
other process on the system keeps the CPU busy.
As shown below, the execution time has to be accessed on the
evaluated object, not the original object.
```lang=python
import bpy
depsgraph = bpy.context.view_layer.depsgraph
ob = bpy.context.active_object
ob_eval = ob.evaluated_get(depsgraph)
modifier_eval = ob_eval.modifiers[0]
print(modifier_eval.execution_time, "s")
```
Differential Revision: https://developer.blender.org/D17185
2023-02-06 15:39:59 +01:00
|
|
|
#include <chrono>
|
2022-09-29 16:43:09 -05:00
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdarg>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
2005-07-19 20:14:17 +00:00
|
|
|
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2005-10-20 16:31:46 +00:00
|
|
|
#include "DNA_armature_types.h"
|
2020-11-06 17:13:04 +01:00
|
|
|
#include "DNA_cloth_types.h"
|
2020-12-15 10:47:58 +11:00
|
|
|
#include "DNA_dynamicpaint_types.h"
|
2020-11-06 17:13:04 +01:00
|
|
|
#include "DNA_fluid_types.h"
|
2020-09-03 14:59:34 +02:00
|
|
|
#include "DNA_gpencil_modifier_types.h"
|
2018-04-18 15:45:54 +02:00
|
|
|
#include "DNA_mesh_types.h"
|
2020-11-06 17:13:04 +01:00
|
|
|
#include "DNA_object_fluidsim_types.h"
|
|
|
|
|
#include "DNA_object_force_types.h"
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "DNA_object_types.h"
|
2024-04-24 17:01:22 +02:00
|
|
|
#include "DNA_particle_types.h"
|
2019-04-30 16:43:44 -03:00
|
|
|
#include "DNA_scene_types.h"
|
2020-10-29 19:34:29 -05:00
|
|
|
#include "DNA_screen_types.h"
|
2005-07-19 20:14:17 +00:00
|
|
|
|
2011-10-22 01:53:35 +00:00
|
|
|
#include "BLI_linklist.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_listbase.h"
|
2024-09-26 21:13:39 +10:00
|
|
|
#include "BLI_path_utils.hh"
|
Modifiers: add unique modifier identifiers
This adds a new `ModifierData.persistent_uid` integer property with the following properties:
* It's unique within the object.
* Match between the original and evaluated object.
* Stable across Blender sessions.
* Stable across renames and reorderings of modifiers.
Potential use-cases:
* Everywhere where we currently use the name as identifier. For example,
`ModifierComputeContext` and `ModifierViewerPathElem`.
* Can be used as part of a key in `IDCacheKey` to support caches that stay
in-tact across undo steps.
* Can be stored in the `SpaceNode` to identify the modifier whose geometry node
tree is currently pinned (this could use the name currently, but that hasn't been
implemented yet).
This new identifier has some overlap with `ModifierData.session_uid`, but there
are some differences:
* `session_uid` is unique within the entire Blender session (except for duplicates
between the original and evaluated data blocks).
* `session_uid` is not stable across Blender sessions.
Especially due to the first difference, it's not immediately obvious that the new
`persistent_uid` can fulfill all use-cases of the existing `session_uid`. Nevertheless,
this seems likely and will be cleaned up separately.
Unfortunately, there is not a single place where modifiers are added to objects currently.
Therefore, there are quite a few places that need to ensure valid identifiers. I tried to catch
all the places, but it's hard to be sure. Therefore, I added an assert in `object_copy_data`
that checks if all identifiers are valid. This way, we should be notified relatively quickly if
issues are caused by invalid identifiers.
Pull Request: https://projects.blender.org/blender/blender/pulls/117347
2024-02-06 17:10:40 +01:00
|
|
|
#include "BLI_rand.hh"
|
2024-01-22 13:47:13 +01:00
|
|
|
#include "BLI_session_uid.h"
|
2011-10-20 13:50:24 +00:00
|
|
|
#include "BLI_string.h"
|
2023-05-13 17:38:48 +10:00
|
|
|
#include "BLI_string_utf8.h"
|
2023-10-18 17:15:30 +02:00
|
|
|
#include "BLI_string_utils.hh"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2010-08-16 05:46:10 +00:00
|
|
|
|
2024-02-09 18:59:42 +01:00
|
|
|
#include "BLT_translation.hh"
|
2012-10-27 11:12:09 +00:00
|
|
|
|
2024-01-21 19:42:13 +01:00
|
|
|
#include "BKE_appdir.hh"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_editmesh.hh"
|
2023-07-07 08:19:52 -04:00
|
|
|
#include "BKE_editmesh_cache.hh"
|
2020-11-06 17:13:04 +01:00
|
|
|
#include "BKE_effect.h"
|
|
|
|
|
#include "BKE_fluid.h"
|
2024-02-10 18:25:14 +01:00
|
|
|
#include "BKE_global.hh"
|
2024-01-20 19:17:36 +01:00
|
|
|
#include "BKE_idtype.hh"
|
2024-01-30 14:42:07 -05:00
|
|
|
#include "BKE_key.hh"
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2024-01-18 12:20:42 +01:00
|
|
|
#include "BKE_lib_query.hh"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_mesh_wrapper.hh"
|
|
|
|
|
#include "BKE_multires.hh"
|
2023-10-09 23:41:53 +02:00
|
|
|
#include "BKE_object.hh"
|
2020-11-06 17:13:04 +01:00
|
|
|
#include "BKE_pointcache.h"
|
2023-09-25 17:48:21 -04:00
|
|
|
#include "BKE_screen.hh"
|
2006-08-28 01:12:36 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
/* may move these, only for BKE_modifier_path_relbase */
|
2023-12-01 19:43:16 +01:00
|
|
|
#include "BKE_main.hh"
|
2011-11-20 14:38:11 +00:00
|
|
|
/* end */
|
|
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
|
|
|
|
#include "DEG_depsgraph_query.hh"
|
2018-02-06 19:34:36 +11:00
|
|
|
|
2023-05-04 18:35:37 +02:00
|
|
|
#include "MOD_modifiertypes.hh"
|
2009-06-09 13:03:00 +00:00
|
|
|
|
2023-08-28 15:01:05 +02:00
|
|
|
#include "BLO_read_write.hh"
|
2020-11-06 17:13:04 +01:00
|
|
|
|
2019-02-01 12:44:19 +11:00
|
|
|
#include "CLG_log.h"
|
|
|
|
|
|
|
|
|
|
static CLG_LogRef LOG = {"bke.modifier"};
|
2022-09-29 16:43:09 -05:00
|
|
|
static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {nullptr};
|
2013-08-19 09:05:34 +00:00
|
|
|
static VirtualModifierData virtualModifierCommonData;
|
|
|
|
|
|
2023-07-02 19:37:22 +10:00
|
|
|
void BKE_modifier_init()
|
2009-06-09 13:03:00 +00:00
|
|
|
{
|
2013-08-19 09:05:34 +00:00
|
|
|
ModifierData *md;
|
2009-06-09 13:03:00 +00:00
|
|
|
|
2013-08-19 09:05:34 +00:00
|
|
|
/* Initialize modifier types */
|
|
|
|
|
modifier_type_init(modifier_types); /* MOD_utils.c */
|
|
|
|
|
|
2021-09-23 22:06:49 +10:00
|
|
|
/* Initialize global common storage used for virtual modifier list. */
|
2020-05-08 10:14:02 +02:00
|
|
|
md = BKE_modifier_new(eModifierType_Armature);
|
2013-08-19 09:05:34 +00:00
|
|
|
virtualModifierCommonData.amd = *((ArmatureModifierData *)md);
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifier_free(md);
|
2013-08-19 09:05:34 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
md = BKE_modifier_new(eModifierType_Curve);
|
2013-08-19 09:05:34 +00:00
|
|
|
virtualModifierCommonData.cmd = *((CurveModifierData *)md);
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifier_free(md);
|
2009-06-09 13:03:00 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
md = BKE_modifier_new(eModifierType_Lattice);
|
2013-08-19 09:05:34 +00:00
|
|
|
virtualModifierCommonData.lmd = *((LatticeModifierData *)md);
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifier_free(md);
|
2013-08-19 09:05:34 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
md = BKE_modifier_new(eModifierType_ShapeKey);
|
2013-08-19 09:05:34 +00:00
|
|
|
virtualModifierCommonData.smd = *((ShapeKeyModifierData *)md);
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifier_free(md);
|
2013-08-19 09:05:34 +00:00
|
|
|
|
|
|
|
|
virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual;
|
|
|
|
|
virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
|
|
|
|
|
virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual;
|
|
|
|
|
virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type)
|
2013-08-19 09:05:34 +00:00
|
|
|
{
|
2012-04-21 15:11:03 +00:00
|
|
|
/* type unsigned, no need to check < 0 */
|
2019-12-17 08:58:43 +11:00
|
|
|
if (type < NUM_MODIFIER_TYPES && modifier_types[type] && modifier_types[type]->name[0] != '\0') {
|
2013-08-19 09:05:34 +00:00
|
|
|
return modifier_types[type];
|
2010-01-06 12:05:46 +00:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
return nullptr;
|
2005-07-19 20:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
2020-06-05 10:41:03 -04:00
|
|
|
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname)
|
|
|
|
|
{
|
|
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
|
2023-07-26 17:08:14 +02:00
|
|
|
BLI_string_join(r_idname, sizeof(PanelType::idname), MODIFIER_TYPE_PANEL_PREFIX, mti->idname);
|
2020-06-05 10:41:03 -04:00
|
|
|
}
|
|
|
|
|
|
2020-10-28 11:43:10 -06:00
|
|
|
void BKE_modifier_panel_expand(ModifierData *md)
|
|
|
|
|
{
|
2020-10-29 19:34:29 -05:00
|
|
|
md->ui_expand_flag |= UI_PANEL_DATA_EXPAND_ROOT;
|
2020-10-28 11:43:10 -06:00
|
|
|
}
|
|
|
|
|
|
- added eModifierTypeFlag_RequiresOriginalData for modifiers that
can only follow deform (for example, they store mesh vertex
indices)
- added ModifierType.foreachObjectLink for iterating over Object
links inside modifier data (used for file load, relinking, etc)
- switched various modifiers_ functions to take object argument
instead of ListBase
- added user editable name field to modifiers
- bug fix, duplicate and make single user didn't relink object
pointers in modifier data
- added modifiers to outliner, needs icon
- added armature, hook, and softbody modifiers (softbody doesn't
do anything atm). added conversion of old hooks to modifiers.
NOTE-THE-FIRST: User name field is not initialized on loading 2.38 files
so if you have saved stuff with a cvs blender you will see blank names.
NOTE-THE-SECOND: Since modifiers aren't evaluated yet for non-Mesh
objects, hooks for lattices and curves are broken. Don't updated if
you actually, say, *use* Blender.
NOTE-THE-THIRD: Old hooks used a quirky weighting system during
deformation which can't be extended to modifiers. On the upside,
I doubt anyone relied on the old quirky system and the new system
makes much more sense. (Although the way falloff works is still
quite stupid I think).
2005-08-10 22:05:52 +00:00
|
|
|
/***/
|
|
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
static ModifierData *modifier_allocate_and_init(ModifierType type)
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
{
|
2020-05-08 10:14:02 +02:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
|
2023-07-27 12:04:18 +10:00
|
|
|
ModifierData *md = static_cast<ModifierData *>(MEM_callocN(mti->struct_size, mti->struct_name));
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: this name must be made unique later. */
|
2023-05-13 17:38:48 +10:00
|
|
|
STRNCPY_UTF8(md->name, DATA_(mti->name));
|
- added eModifierTypeFlag_RequiresOriginalData for modifiers that
can only follow deform (for example, they store mesh vertex
indices)
- added ModifierType.foreachObjectLink for iterating over Object
links inside modifier data (used for file load, relinking, etc)
- switched various modifiers_ functions to take object argument
instead of ListBase
- added user editable name field to modifiers
- bug fix, duplicate and make single user didn't relink object
pointers in modifier data
- added modifiers to outliner, needs icon
- added armature, hook, and softbody modifiers (softbody doesn't
do anything atm). added conversion of old hooks to modifiers.
NOTE-THE-FIRST: User name field is not initialized on loading 2.38 files
so if you have saved stuff with a cvs blender you will see blank names.
NOTE-THE-SECOND: Since modifiers aren't evaluated yet for non-Mesh
objects, hooks for lattices and curves are broken. Don't updated if
you actually, say, *use* Blender.
NOTE-THE-THIRD: Old hooks used a quirky weighting system during
deformation which can't be extended to modifiers. On the upside,
I doubt anyone relied on the old quirky system and the new system
makes much more sense. (Although the way falloff works is still
quite stupid I think).
2005-08-10 22:05:52 +00:00
|
|
|
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
md->type = type;
|
2020-06-05 10:41:03 -04:00
|
|
|
md->mode = eModifierMode_Realtime | eModifierMode_Render;
|
2019-06-14 23:16:04 +02:00
|
|
|
md->flag = eModifierFlag_OverrideLibrary_Local;
|
2022-08-12 10:47:37 +10:00
|
|
|
/* Only open the main panel at the beginning, not the sub-panels. */
|
|
|
|
|
md->ui_expand_flag = UI_PANEL_DATA_EXPAND_ROOT;
|
2005-07-23 19:15:08 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (mti->flags & eModifierTypeFlag_EnableInEditmode) {
|
2005-07-23 19:15:08 +00:00
|
|
|
md->mode |= eModifierMode_Editmode;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->init_data) {
|
|
|
|
|
mti->init_data(md);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
|
2022-02-16 11:56:04 +01:00
|
|
|
return md;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ModifierData *BKE_modifier_new(int type)
|
|
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
ModifierData *md = modifier_allocate_and_init(ModifierType(type));
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
return md;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
static void modifier_free_data_id_us_cb(void * /*user_data*/,
|
2022-10-03 17:37:25 -05:00
|
|
|
Object * /*ob*/,
|
2018-04-04 14:56:32 +02:00
|
|
|
ID **idpoin,
|
|
|
|
|
int cb_flag)
|
|
|
|
|
{
|
|
|
|
|
ID *id = *idpoin;
|
2022-09-29 16:43:09 -05:00
|
|
|
if (id != nullptr && (cb_flag & IDWALK_CB_USER) != 0) {
|
2018-04-04 14:56:32 +02:00
|
|
|
id_us_min(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifier_free_ex(ModifierData *md, const int flag)
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
|
2018-04-04 14:56:32 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->foreach_ID_link) {
|
|
|
|
|
mti->foreach_ID_link(md, nullptr, modifier_free_data_id_us_cb, nullptr);
|
2018-04-04 14:56:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->free_data) {
|
|
|
|
|
mti->free_data(md);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (md->error) {
|
2005-08-04 07:25:43 +00:00
|
|
|
MEM_freeN(md->error);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
|
|
|
|
|
MEM_freeN(md);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifier_free(ModifierData *md)
|
2018-04-04 14:56:32 +02:00
|
|
|
{
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifier_free_ex(md, 0);
|
2018-04-04 14:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:35:07 +01:00
|
|
|
void BKE_modifier_remove_from_list(Object *ob, ModifierData *md)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(BLI_findindex(&ob->modifiers, md) != -1);
|
|
|
|
|
|
|
|
|
|
if (md->flag & eModifierFlag_Active) {
|
|
|
|
|
/* Prefer the previous modifier but use the next if this modifier is the first in the list. */
|
2022-09-29 16:43:09 -05:00
|
|
|
if (md->next != nullptr) {
|
2020-12-02 13:35:07 +01:00
|
|
|
BKE_object_modifier_set_active(ob, md->next);
|
|
|
|
|
}
|
2022-09-29 16:43:09 -05:00
|
|
|
else if (md->prev != nullptr) {
|
2020-12-02 13:35:07 +01:00
|
|
|
BKE_object_modifier_set_active(ob, md->prev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_remlink(&ob->modifiers, md);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-19 15:07:57 +02:00
|
|
|
void BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
|
2009-10-09 09:48:04 +00:00
|
|
|
{
|
|
|
|
|
if (modifiers && md) {
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2013-03-25 08:29:06 +00:00
|
|
|
|
2023-10-19 15:07:57 +02:00
|
|
|
BLI_uniquename(
|
2015-02-13 13:44:13 +05:00
|
|
|
modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
|
2009-10-09 09:48:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-01 15:27:11 +02:00
|
|
|
bool BKE_modifier_depends_ontime(Scene *scene, ModifierData *md)
|
2005-07-20 04:14:21 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2005-07-20 04:14:21 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
return mti->depends_on_time && mti->depends_on_time(scene, md);
|
2005-07-20 04:14:21 +00:00
|
|
|
}
|
2005-07-27 20:16:41 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
bool BKE_modifier_supports_mapping(ModifierData *md)
|
2005-08-03 04:04:05 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2005-08-03 04:04:05 +00:00
|
|
|
|
2023-11-14 10:03:56 +01:00
|
|
|
return (mti->type == ModifierTypeType::OnlyDeform ||
|
2012-05-06 17:22:54 +00:00
|
|
|
(mti->flags & eModifierTypeFlag_SupportsMapping));
|
2005-08-03 04:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
2021-05-07 10:44:13 +10:00
|
|
|
ModifierData *BKE_modifiers_findby_type(const Object *ob, ModifierType type)
|
2005-07-27 20:16:41 +00:00
|
|
|
{
|
2020-10-09 13:51:13 -05:00
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (md->type == type) {
|
2020-10-09 13:51:13 -05:00
|
|
|
return md;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-29 16:43:09 -05:00
|
|
|
return nullptr;
|
2005-07-27 20:16:41 +00:00
|
|
|
}
|
|
|
|
|
|
2021-05-07 10:44:13 +10:00
|
|
|
ModifierData *BKE_modifiers_findby_name(const Object *ob, const char *name)
|
2010-04-22 01:55:10 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
return static_cast<ModifierData *>(
|
|
|
|
|
BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name)));
|
2010-04-22 01:55:10 +00:00
|
|
|
}
|
|
|
|
|
|
Modifiers: add unique modifier identifiers
This adds a new `ModifierData.persistent_uid` integer property with the following properties:
* It's unique within the object.
* Match between the original and evaluated object.
* Stable across Blender sessions.
* Stable across renames and reorderings of modifiers.
Potential use-cases:
* Everywhere where we currently use the name as identifier. For example,
`ModifierComputeContext` and `ModifierViewerPathElem`.
* Can be used as part of a key in `IDCacheKey` to support caches that stay
in-tact across undo steps.
* Can be stored in the `SpaceNode` to identify the modifier whose geometry node
tree is currently pinned (this could use the name currently, but that hasn't been
implemented yet).
This new identifier has some overlap with `ModifierData.session_uid`, but there
are some differences:
* `session_uid` is unique within the entire Blender session (except for duplicates
between the original and evaluated data blocks).
* `session_uid` is not stable across Blender sessions.
Especially due to the first difference, it's not immediately obvious that the new
`persistent_uid` can fulfill all use-cases of the existing `session_uid`. Nevertheless,
this seems likely and will be cleaned up separately.
Unfortunately, there is not a single place where modifiers are added to objects currently.
Therefore, there are quite a few places that need to ensure valid identifiers. I tried to catch
all the places, but it's hard to be sure. Therefore, I added an assert in `object_copy_data`
that checks if all identifiers are valid. This way, we should be notified relatively quickly if
issues are caused by invalid identifiers.
Pull Request: https://projects.blender.org/blender/blender/pulls/117347
2024-02-06 17:10:40 +01:00
|
|
|
ModifierData *BKE_modifiers_findby_persistent_uid(const Object *ob, const int persistent_uid)
|
|
|
|
|
{
|
|
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
|
|
|
|
if (md->persistent_uid == persistent_uid) {
|
|
|
|
|
return md;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifiers_clear_errors(Object *ob)
|
2005-08-04 07:25:43 +00:00
|
|
|
{
|
2020-10-09 13:51:13 -05:00
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
2005-08-04 07:25:43 +00:00
|
|
|
if (md->error) {
|
|
|
|
|
MEM_freeN(md->error);
|
2022-09-29 16:43:09 -05:00
|
|
|
md->error = nullptr;
|
2005-08-04 07:25:43 +00:00
|
|
|
}
|
|
|
|
|
}
|
- added eModifierTypeFlag_RequiresOriginalData for modifiers that
can only follow deform (for example, they store mesh vertex
indices)
- added ModifierType.foreachObjectLink for iterating over Object
links inside modifier data (used for file load, relinking, etc)
- switched various modifiers_ functions to take object argument
instead of ListBase
- added user editable name field to modifiers
- bug fix, duplicate and make single user didn't relink object
pointers in modifier data
- added modifiers to outliner, needs icon
- added armature, hook, and softbody modifiers (softbody doesn't
do anything atm). added conversion of old hooks to modifiers.
NOTE-THE-FIRST: User name field is not initialized on loading 2.38 files
so if you have saved stuff with a cvs blender you will see blank names.
NOTE-THE-SECOND: Since modifiers aren't evaluated yet for non-Mesh
objects, hooks for lattices and curves are broken. Don't updated if
you actually, say, *use* Blender.
NOTE-THE-THIRD: Old hooks used a quirky weighting system during
deformation which can't be extended to modifiers. On the upside,
I doubt anyone relied on the old quirky system and the new system
makes much more sense. (Although the way falloff works is still
quite stupid I think).
2005-08-10 22:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *user_data)
|
- added eModifierTypeFlag_RequiresOriginalData for modifiers that
can only follow deform (for example, they store mesh vertex
indices)
- added ModifierType.foreachObjectLink for iterating over Object
links inside modifier data (used for file load, relinking, etc)
- switched various modifiers_ functions to take object argument
instead of ListBase
- added user editable name field to modifiers
- bug fix, duplicate and make single user didn't relink object
pointers in modifier data
- added modifiers to outliner, needs icon
- added armature, hook, and softbody modifiers (softbody doesn't
do anything atm). added conversion of old hooks to modifiers.
NOTE-THE-FIRST: User name field is not initialized on loading 2.38 files
so if you have saved stuff with a cvs blender you will see blank names.
NOTE-THE-SECOND: Since modifiers aren't evaluated yet for non-Mesh
objects, hooks for lattices and curves are broken. Don't updated if
you actually, say, *use* Blender.
NOTE-THE-THIRD: Old hooks used a quirky weighting system during
deformation which can't be extended to modifiers. On the upside,
I doubt anyone relied on the old quirky system and the new system
makes much more sense. (Although the way falloff works is still
quite stupid I think).
2005-08-10 22:05:52 +00:00
|
|
|
{
|
2020-10-09 13:51:13 -05:00
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
- added eModifierTypeFlag_RequiresOriginalData for modifiers that
can only follow deform (for example, they store mesh vertex
indices)
- added ModifierType.foreachObjectLink for iterating over Object
links inside modifier data (used for file load, relinking, etc)
- switched various modifiers_ functions to take object argument
instead of ListBase
- added user editable name field to modifiers
- bug fix, duplicate and make single user didn't relink object
pointers in modifier data
- added modifiers to outliner, needs icon
- added armature, hook, and softbody modifiers (softbody doesn't
do anything atm). added conversion of old hooks to modifiers.
NOTE-THE-FIRST: User name field is not initialized on loading 2.38 files
so if you have saved stuff with a cvs blender you will see blank names.
NOTE-THE-SECOND: Since modifiers aren't evaluated yet for non-Mesh
objects, hooks for lattices and curves are broken. Don't updated if
you actually, say, *use* Blender.
NOTE-THE-THIRD: Old hooks used a quirky weighting system during
deformation which can't be extended to modifiers. On the upside,
I doubt anyone relied on the old quirky system and the new system
makes much more sense. (Although the way falloff works is still
quite stupid I think).
2005-08-10 22:05:52 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->foreach_ID_link) {
|
|
|
|
|
mti->foreach_ID_link(md, ob, walk, user_data);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
- added eModifierTypeFlag_RequiresOriginalData for modifiers that
can only follow deform (for example, they store mesh vertex
indices)
- added ModifierType.foreachObjectLink for iterating over Object
links inside modifier data (used for file load, relinking, etc)
- switched various modifiers_ functions to take object argument
instead of ListBase
- added user editable name field to modifiers
- bug fix, duplicate and make single user didn't relink object
pointers in modifier data
- added modifiers to outliner, needs icon
- added armature, hook, and softbody modifiers (softbody doesn't
do anything atm). added conversion of old hooks to modifiers.
NOTE-THE-FIRST: User name field is not initialized on loading 2.38 files
so if you have saved stuff with a cvs blender you will see blank names.
NOTE-THE-SECOND: Since modifiers aren't evaluated yet for non-Mesh
objects, hooks for lattices and curves are broken. Don't updated if
you actually, say, *use* Blender.
NOTE-THE-THIRD: Old hooks used a quirky weighting system during
deformation which can't be extended to modifiers. On the upside,
I doubt anyone relied on the old quirky system and the new system
makes much more sense. (Although the way falloff works is still
quite stupid I think).
2005-08-10 22:05:52 +00:00
|
|
|
}
|
2005-08-04 07:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *user_data)
|
2011-08-12 18:11:22 +00:00
|
|
|
{
|
2020-10-09 13:51:13 -05:00
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2011-08-12 18:11:22 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->foreach_tex_link) {
|
|
|
|
|
mti->foreach_tex_link(md, ob, walk, user_data);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2011-08-12 18:11:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-16 11:56:04 +01:00
|
|
|
ModifierData *BKE_modifier_copy_ex(const ModifierData *md, int flag)
|
|
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
ModifierData *md_dst = modifier_allocate_and_init(ModifierType(md->type));
|
2022-02-16 11:56:04 +01:00
|
|
|
|
2023-05-09 12:50:37 +10:00
|
|
|
STRNCPY(md_dst->name, md->name);
|
2022-02-16 11:56:04 +01:00
|
|
|
BKE_modifier_copydata_ex(md, md_dst, flag);
|
|
|
|
|
|
|
|
|
|
return md_dst;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifier_copydata_generic(const ModifierData *md_src,
|
2020-05-08 19:02:03 +10:00
|
|
|
ModifierData *md_dst,
|
2022-10-03 17:37:25 -05:00
|
|
|
const int /*flag*/)
|
2013-12-22 04:35:52 +11:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md_src->type));
|
2018-05-07 17:58:35 +02:00
|
|
|
|
2022-10-03 10:24:08 +11:00
|
|
|
/* `md_dst` may have already be fully initialized with some extra allocated data,
|
|
|
|
|
* we need to free it now to avoid a memory leak. */
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->free_data) {
|
|
|
|
|
mti->free_data(md_dst);
|
2018-05-07 17:58:35 +02:00
|
|
|
}
|
|
|
|
|
|
2013-12-22 04:35:52 +11:00
|
|
|
const size_t data_size = sizeof(ModifierData);
|
2015-01-14 05:10:18 +11:00
|
|
|
const char *md_src_data = ((const char *)md_src) + data_size;
|
|
|
|
|
char *md_dst_data = ((char *)md_dst) + data_size;
|
2023-07-27 12:04:18 +10:00
|
|
|
BLI_assert(data_size <= size_t(mti->struct_size));
|
|
|
|
|
memcpy(md_dst_data, md_src_data, size_t(mti->struct_size) - data_size);
|
2019-03-20 14:45:01 +01:00
|
|
|
|
|
|
|
|
/* Runtime fields are never to be preserved. */
|
2022-09-29 16:43:09 -05:00
|
|
|
md_dst->runtime = nullptr;
|
2013-12-22 04:35:52 +11:00
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
static void modifier_copy_data_id_us_cb(void * /*user_data*/,
|
2022-10-03 17:37:25 -05:00
|
|
|
Object * /*ob*/,
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
ID **idpoin,
|
|
|
|
|
int cb_flag)
|
|
|
|
|
{
|
|
|
|
|
ID *id = *idpoin;
|
2022-09-29 16:43:09 -05:00
|
|
|
if (id != nullptr && (cb_flag & IDWALK_CB_USER) != 0) {
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
id_us_plus(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-16 11:52:48 +01:00
|
|
|
void BKE_modifier_copydata_ex(const ModifierData *md, ModifierData *target, const int flag)
|
2005-07-27 20:16:41 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2005-07-27 20:16:41 +00:00
|
|
|
|
|
|
|
|
target->mode = md->mode;
|
2018-05-02 18:13:15 +02:00
|
|
|
target->flag = md->flag;
|
2020-06-05 10:41:03 -04:00
|
|
|
target->ui_expand_flag = md->ui_expand_flag;
|
Modifiers: add unique modifier identifiers
This adds a new `ModifierData.persistent_uid` integer property with the following properties:
* It's unique within the object.
* Match between the original and evaluated object.
* Stable across Blender sessions.
* Stable across renames and reorderings of modifiers.
Potential use-cases:
* Everywhere where we currently use the name as identifier. For example,
`ModifierComputeContext` and `ModifierViewerPathElem`.
* Can be used as part of a key in `IDCacheKey` to support caches that stay
in-tact across undo steps.
* Can be stored in the `SpaceNode` to identify the modifier whose geometry node
tree is currently pinned (this could use the name currently, but that hasn't been
implemented yet).
This new identifier has some overlap with `ModifierData.session_uid`, but there
are some differences:
* `session_uid` is unique within the entire Blender session (except for duplicates
between the original and evaluated data blocks).
* `session_uid` is not stable across Blender sessions.
Especially due to the first difference, it's not immediately obvious that the new
`persistent_uid` can fulfill all use-cases of the existing `session_uid`. Nevertheless,
this seems likely and will be cleaned up separately.
Unfortunately, there is not a single place where modifiers are added to objects currently.
Therefore, there are quite a few places that need to ensure valid identifiers. I tried to catch
all the places, but it's hard to be sure. Therefore, I added an assert in `object_copy_data`
that checks if all identifiers are valid. This way, we should be notified relatively quickly if
issues are caused by invalid identifiers.
Pull Request: https://projects.blender.org/blender/blender/pulls/117347
2024-02-06 17:10:40 +01:00
|
|
|
target->persistent_uid = md->persistent_uid;
|
2005-07-27 20:16:41 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->copy_data) {
|
|
|
|
|
mti->copy_data(md, target, flag);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->foreach_ID_link) {
|
|
|
|
|
mti->foreach_ID_link(target, nullptr, modifier_copy_data_id_us_cb, nullptr);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-16 11:52:48 +01:00
|
|
|
void BKE_modifier_copydata(const ModifierData *md, ModifierData *target)
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
{
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifier_copydata_ex(md, target, 0);
|
2005-07-27 20:16:41 +00:00
|
|
|
}
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool BKE_modifier_supports_cage(Scene *scene, ModifierData *md)
|
2013-12-13 20:57:36 +01:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2013-12-13 20:57:36 +01:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
return ((!mti->is_disabled || !mti->is_disabled(scene, md, false)) &&
|
2020-05-08 10:14:02 +02:00
|
|
|
(mti->flags & eModifierTypeFlag_SupportsEditmode) && BKE_modifier_supports_mapping(md));
|
2013-12-13 20:57:36 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool BKE_modifier_couldbe_cage(Scene *scene, ModifierData *md)
|
2005-08-04 07:25:43 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2012-05-06 17:22:54 +00:00
|
|
|
return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) &&
|
2023-07-27 12:04:18 +10:00
|
|
|
(!mti->is_disabled || !mti->is_disabled(scene, md, false)) &&
|
2020-05-08 19:02:03 +10:00
|
|
|
BKE_modifier_supports_mapping(md));
|
2005-08-04 07:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
bool BKE_modifier_is_same_topology(ModifierData *md)
|
2009-11-22 13:44:09 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2023-11-14 10:03:56 +01:00
|
|
|
return ELEM(mti->type, ModifierTypeType::OnlyDeform, ModifierTypeType::NonGeometrical);
|
2011-12-20 14:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
bool BKE_modifier_is_non_geometrical(ModifierData *md)
|
2011-12-20 14:15:59 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2023-11-14 10:03:56 +01:00
|
|
|
return (mti->type == ModifierTypeType::NonGeometrical);
|
2009-11-22 13:44:09 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-26 17:07:58 +11:00
|
|
|
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_format, ...)
|
2005-08-04 07:25:43 +00:00
|
|
|
{
|
2011-02-12 16:54:24 +00:00
|
|
|
char buffer[512];
|
2005-08-04 07:25:43 +00:00
|
|
|
va_list ap;
|
2024-01-11 19:49:03 +01:00
|
|
|
const char *format = RPT_(_format);
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2012-10-27 11:12:09 +00:00
|
|
|
va_start(ap, _format);
|
2011-02-12 16:54:24 +00:00
|
|
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
2005-08-04 07:25:43 +00:00
|
|
|
va_end(ap);
|
2012-05-06 17:22:54 +00:00
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (md->error) {
|
2005-08-04 07:25:43 +00:00
|
|
|
MEM_freeN(md->error);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-04 07:25:43 +00:00
|
|
|
|
|
|
|
|
md->error = BLI_strdup(buffer);
|
|
|
|
|
|
2020-10-26 17:07:58 +11:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
if ((md->mode & eModifierMode_Virtual) == 0) {
|
|
|
|
|
/* Ensure correct object is passed in. */
|
2022-09-29 16:43:09 -05:00
|
|
|
BLI_assert(BKE_modifier_get_original(ob, md) != nullptr);
|
2020-10-26 17:07:58 +11:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-09-05 12:37:05 +02:00
|
|
|
CLOG_WARN(&LOG, "Object: \"%s\", Modifier: \"%s\", %s", ob->id.name + 2, md->name, md->error);
|
2005-08-04 07:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
void BKE_modifier_set_warning(const Object *ob, ModifierData *md, const char *_format, ...)
|
2022-07-15 15:54:14 +02:00
|
|
|
{
|
|
|
|
|
char buffer[512];
|
|
|
|
|
va_list ap;
|
2024-01-11 19:49:03 +01:00
|
|
|
const char *format = RPT_(_format);
|
2022-07-15 15:54:14 +02:00
|
|
|
|
|
|
|
|
va_start(ap, _format);
|
|
|
|
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Store the warning in the same field as the error.
|
|
|
|
|
* It is not expected to have both error and warning and having a single place to store the
|
|
|
|
|
* message simplifies interface code. */
|
|
|
|
|
|
|
|
|
|
if (md->error) {
|
|
|
|
|
MEM_freeN(md->error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
md->error = BLI_strdup(buffer);
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
if ((md->mode & eModifierMode_Virtual) == 0) {
|
|
|
|
|
/* Ensure correct object is passed in. */
|
2022-09-29 16:43:09 -05:00
|
|
|
BLI_assert(BKE_modifier_get_original(ob, md) != nullptr);
|
2022-07-15 15:54:14 +02:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
UNUSED_VARS_NDEBUG(ob);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-17 10:27:50 +11:00
|
|
|
int BKE_modifiers_get_cage_index(const Scene *scene,
|
2020-05-08 19:02:03 +10:00
|
|
|
Object *ob,
|
|
|
|
|
int *r_lastPossibleCageIndex,
|
|
|
|
|
bool is_virtual)
|
2005-08-04 07:25:43 +00:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
2020-05-08 19:02:03 +10:00
|
|
|
ModifierData *md = (is_virtual) ?
|
2023-07-27 12:04:18 +10:00
|
|
|
BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data) :
|
2022-09-29 16:43:09 -05:00
|
|
|
static_cast<ModifierData *>(ob->modifiers.first);
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2014-03-16 03:24:05 +11:00
|
|
|
if (r_lastPossibleCageIndex) {
|
2011-02-22 12:19:27 +00:00
|
|
|
/* ensure the value is initialized */
|
2014-03-16 03:24:05 +11:00
|
|
|
*r_lastPossibleCageIndex = -1;
|
2011-02-22 12:19:27 +00:00
|
|
|
}
|
|
|
|
|
|
2008-04-08 12:58:25 +00:00
|
|
|
/* Find the last modifier acting on the cage. */
|
2020-10-09 13:51:13 -05:00
|
|
|
int cageIndex = -1;
|
|
|
|
|
for (int i = 0; md; i++, md = md->next) {
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2014-08-17 09:35:57 +02:00
|
|
|
bool supports_mapping;
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->is_disabled && mti->is_disabled(scene, md, false)) {
|
2018-06-21 17:54:12 +02:00
|
|
|
continue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) {
|
2006-08-28 01:12:36 +00:00
|
|
|
continue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (md->mode & eModifierMode_DisableTemporary) {
|
2007-07-28 21:04:30 +00:00
|
|
|
continue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
supports_mapping = BKE_modifier_supports_mapping(md);
|
2014-08-17 09:35:57 +02:00
|
|
|
if (r_lastPossibleCageIndex && supports_mapping) {
|
|
|
|
|
*r_lastPossibleCageIndex = i;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!(md->mode & eModifierMode_Realtime)) {
|
2014-05-30 20:22:23 +02:00
|
|
|
continue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (!(md->mode & eModifierMode_Editmode)) {
|
2014-05-30 20:22:23 +02:00
|
|
|
continue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2014-05-30 20:22:23 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!supports_mapping) {
|
2005-08-04 07:25:43 +00:00
|
|
|
break;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-04 07:25:43 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (md->mode & eModifierMode_OnCage) {
|
2005-08-04 07:25:43 +00:00
|
|
|
cageIndex = i;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-04 07:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cageIndex;
|
|
|
|
|
}
|
2005-08-11 02:23:52 +00:00
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
|
2009-06-15 11:48:42 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if ((md->mode & required_mode) != required_mode) {
|
2014-08-20 20:41:30 +02:00
|
|
|
return false;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2023-07-27 12:04:18 +10:00
|
|
|
if (scene != nullptr && mti->is_disabled &&
|
|
|
|
|
mti->is_disabled(scene, md, required_mode == eModifierMode_Render))
|
2019-04-22 09:39:35 +10:00
|
|
|
{
|
2014-08-20 20:41:30 +02:00
|
|
|
return false;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (md->mode & eModifierMode_DisableTemporary) {
|
2014-08-20 20:41:30 +02:00
|
|
|
return false;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2014-08-20 20:41:30 +02:00
|
|
|
if ((required_mode & eModifierMode_Editmode) &&
|
2024-01-02 18:12:54 +01:00
|
|
|
!(mti->flags & eModifierTypeFlag_SupportsEditmode))
|
|
|
|
|
{
|
2018-06-21 17:54:12 +02:00
|
|
|
return false;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-08-20 20:41:30 +02:00
|
|
|
return true;
|
2009-06-15 11:48:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-12-08 09:40:42 +01:00
|
|
|
bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md)
|
2020-12-07 16:52:45 +01:00
|
|
|
{
|
2020-12-08 09:40:42 +01:00
|
|
|
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
|
2022-09-29 16:43:09 -05:00
|
|
|
(md == nullptr || (md->flag & eModifierFlag_OverrideLibrary_Local) == 0));
|
2020-12-07 16:52:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
CDMaskLink *BKE_modifier_calc_data_masks(const Scene *scene,
|
2020-05-08 19:02:03 +10:00
|
|
|
ModifierData *md,
|
|
|
|
|
CustomData_MeshMasks *final_datamask,
|
2023-12-05 09:30:13 -05:00
|
|
|
int required_mode)
|
2006-12-05 17:42:03 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
CDMaskLink *dataMasks = nullptr;
|
2012-03-26 16:25:21 +00:00
|
|
|
CDMaskLink *curr, *prev;
|
2019-06-10 15:42:15 +02:00
|
|
|
bool have_deform_modifier = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2006-12-05 17:42:03 +00:00
|
|
|
/* build a list of modifier data requirements in reverse order */
|
2012-03-24 06:18:31 +00:00
|
|
|
for (; md; md = md->next) {
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
curr = MEM_cnew<CDMaskLink>(__func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
if (BKE_modifier_is_enabled(scene, md, required_mode)) {
|
2023-11-14 10:03:56 +01:00
|
|
|
if (mti->type == ModifierTypeType::OnlyDeform) {
|
2019-06-10 15:42:15 +02:00
|
|
|
have_deform_modifier = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if (mti->required_data_mask) {
|
|
|
|
|
mti->required_data_mask(md, &curr->mask);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-10 15:42:15 +02:00
|
|
|
if (!have_deform_modifier) {
|
|
|
|
|
/* Don't create orco layer when there is no deformation, we fall
|
|
|
|
|
* back to regular vertex coordinates */
|
|
|
|
|
curr->mask.vmask &= ~CD_MASK_ORCO;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-26 16:25:21 +00:00
|
|
|
/* prepend new datamask */
|
|
|
|
|
curr->next = dataMasks;
|
|
|
|
|
dataMasks = curr;
|
2006-12-05 17:42:03 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-10 15:42:15 +02:00
|
|
|
if (!have_deform_modifier) {
|
|
|
|
|
final_datamask->vmask &= ~CD_MASK_ORCO;
|
|
|
|
|
}
|
|
|
|
|
|
2006-12-05 17:42:03 +00:00
|
|
|
/* build the list of required data masks - each mask in the list must
|
2012-03-03 20:19:11 +00:00
|
|
|
* include all elements of the masks that follow it
|
|
|
|
|
*
|
|
|
|
|
* note the list is currently in reverse order, so "masks that follow it"
|
|
|
|
|
* actually means "masks that precede it" at the moment
|
|
|
|
|
*/
|
2022-09-29 16:43:09 -05:00
|
|
|
for (curr = dataMasks, prev = nullptr; curr; prev = curr, curr = curr->next) {
|
2012-03-24 06:18:31 +00:00
|
|
|
if (prev) {
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
CustomData_MeshMasks_update(&curr->mask, &prev->mask);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2019-06-10 15:42:15 +02:00
|
|
|
CustomData_MeshMasks_update(&curr->mask, final_datamask);
|
2006-12-05 17:42:03 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2006-12-05 17:42:03 +00:00
|
|
|
/* reverse the list so it's in the correct order */
|
2012-05-06 17:22:54 +00:00
|
|
|
BLI_linklist_reverse((LinkNode **)&dataMasks);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2006-12-05 17:42:03 +00:00
|
|
|
return dataMasks;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData *virtual_modifier_data)
|
2005-08-11 03:31:33 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
*virtual_modifier_data = virtualModifierCommonData;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (ob->parent) {
|
2012-05-06 17:22:54 +00:00
|
|
|
if (ob->parent->type == OB_ARMATURE && ob->partype == PARSKEL) {
|
2023-07-27 12:04:18 +10:00
|
|
|
virtual_modifier_data->amd.object = ob->parent;
|
|
|
|
|
virtual_modifier_data->amd.modifier.next = md;
|
|
|
|
|
virtual_modifier_data->amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag;
|
|
|
|
|
md = &virtual_modifier_data->amd.modifier;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2022-02-18 09:50:29 -06:00
|
|
|
else if (ob->parent->type == OB_CURVES_LEGACY && ob->partype == PARSKEL) {
|
2023-07-27 12:04:18 +10:00
|
|
|
virtual_modifier_data->cmd.object = ob->parent;
|
|
|
|
|
virtual_modifier_data->cmd.defaxis = ob->trackflag + 1;
|
|
|
|
|
virtual_modifier_data->cmd.modifier.next = md;
|
|
|
|
|
md = &virtual_modifier_data->cmd.modifier;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2012-05-06 17:22:54 +00:00
|
|
|
else if (ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
|
2023-07-27 12:04:18 +10:00
|
|
|
virtual_modifier_data->lmd.object = ob->parent;
|
|
|
|
|
virtual_modifier_data->lmd.modifier.next = md;
|
|
|
|
|
md = &virtual_modifier_data->lmd.modifier;
|
2005-08-11 03:31:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-10-22 16:35:51 +00:00
|
|
|
/* shape key modifier, not yet for curves */
|
2022-04-28 10:53:50 -05:00
|
|
|
if (ELEM(ob->type, OB_MESH, OB_LATTICE) && BKE_key_from_object((Object *)ob)) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE)) {
|
2023-07-27 12:04:18 +10:00
|
|
|
virtual_modifier_data->smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-27 12:04:18 +10:00
|
|
|
virtual_modifier_data->smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
virtual_modifier_data->smd.modifier.next = md;
|
|
|
|
|
md = &virtual_modifier_data->smd.modifier;
|
2009-10-22 16:35:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-10-22 16:35:51 +00:00
|
|
|
return md;
|
2005-08-11 03:31:33 +00:00
|
|
|
}
|
2012-10-15 03:16:38 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
|
2005-08-22 20:24:59 +00:00
|
|
|
{
|
2024-07-29 10:37:29 +02:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
|
|
|
|
|
2024-09-12 20:25:27 +02:00
|
|
|
Object *armature = nullptr;
|
2024-07-29 10:37:29 +02:00
|
|
|
/* return the first selected armature, this lets us use multiple armatures */
|
2024-09-12 20:25:27 +02:00
|
|
|
if (ob->type == OB_GREASE_PENCIL) {
|
|
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_GreasePencilArmature) {
|
|
|
|
|
auto *amd = reinterpret_cast<GreasePencilArmatureModifierData *>(md);
|
|
|
|
|
armature = amd->object;
|
|
|
|
|
if (armature && (armature->base_flag & BASE_SELECTED)) {
|
|
|
|
|
return armature;
|
|
|
|
|
}
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-22 20:24:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-09-12 20:25:27 +02:00
|
|
|
else {
|
|
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_Armature) {
|
|
|
|
|
auto *amd = reinterpret_cast<ArmatureModifierData *>(md);
|
|
|
|
|
armature = amd->object;
|
|
|
|
|
if (armature && (armature->base_flag & BASE_SELECTED)) {
|
|
|
|
|
return armature;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2024-09-12 20:25:27 +02:00
|
|
|
/* If we're still here then return the last armature. */
|
|
|
|
|
return armature;
|
New: CrazySpace [tm] correction
When Modifiers are used in Edit Mode to show the deformed result for
editing, all actual coordinates Blender works with are still the ones from
the original Cage. You can notice that with the Transform Widget or
helper lines while transforming.
Even worse, the actual transformations still happened on the original Cage
as well, making it very hard to edit. That caused the feature to be named
"CrazySpace" (baptized by Andy, afaik?).
This commit calculates the deformation transformation per vertex, and
inverse corrects it, so it's more intuitive editing this way.
Unfortunately all the deformation features of Blender don't use matrices
for defining deform, so the existing code cannot be re-used to retrieve
the correct deformation matrix per vertex. The solution I found is based
on calculating per face the transformation based on its first 3 vertices,
and store this transformation averaged in the face's vertices.
The solution can also only work on entire faces, because the full deform
can only be retrieved using 3 vertices. (using 2 vertices will miss edge-
aligned rotation, using 1 vertex can only retrieve translation).
By deriving the deformations per face, small errors will still happen,
especially on very low-poly Meshes with extreme deformations.
The only alternative I know now, is providing each vertex in
a mesh with 2 extreme small tangent vectors, which get deformed using the
existing code as well. That will mess up the existing deformation code too
much though, this solution has the benefit it works with each deform we can
up with later too.
Last note about CrazySpace: it can only be used to tweak Meshes. Do not
even try to add vertices, extrude, or duplicate. Probably we should disable
this... but preventing user errors isn't always power-user-friendly, eh. :)
2005-10-26 09:56:52 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
|
2018-05-11 08:16:41 +02:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
2022-09-29 16:43:09 -05:00
|
|
|
MeshDeformModifierData *mdmd = nullptr;
|
2018-05-11 08:16:41 +02:00
|
|
|
|
|
|
|
|
/* return the first selected armature, this lets us use multiple armatures */
|
|
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_MeshDeform) {
|
|
|
|
|
mdmd = (MeshDeformModifierData *)md;
|
2019-04-30 16:43:44 -03:00
|
|
|
if (mdmd->object && (mdmd->object->base_flag & BASE_SELECTED)) {
|
2018-05-11 08:16:41 +02:00
|
|
|
return mdmd->object;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-05-11 08:16:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-19 20:33:23 +01:00
|
|
|
if (mdmd) { /* if we're still here then return the last armature */
|
2018-05-11 08:16:41 +02:00
|
|
|
return mdmd->object;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-05-11 08:16:41 +02:00
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
return nullptr;
|
2018-05-11 08:16:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
|
2006-12-23 11:56:22 +00:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
2022-09-29 16:43:09 -05:00
|
|
|
LatticeModifierData *lmd = nullptr;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2012-03-03 20:19:11 +00:00
|
|
|
/* return the first selected lattice, this lets us use multiple lattices */
|
2012-05-06 17:22:54 +00:00
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_Lattice) {
|
|
|
|
|
lmd = (LatticeModifierData *)md;
|
2019-04-30 16:43:44 -03:00
|
|
|
if (lmd->object && (lmd->object->base_flag & BASE_SELECTED)) {
|
2006-12-23 11:56:22 +00:00
|
|
|
return lmd->object;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2006-12-23 11:56:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2020-03-19 20:33:23 +01:00
|
|
|
if (lmd) { /* if we're still here then return the last lattice */
|
2006-12-23 11:56:22 +00:00
|
|
|
return lmd->object;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
return nullptr;
|
2006-12-23 11:56:22 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
Object *BKE_modifiers_is_deformed_by_curve(Object *ob)
|
2012-10-15 03:16:38 +00:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
2022-09-29 16:43:09 -05:00
|
|
|
CurveModifierData *cmd = nullptr;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2012-10-15 03:16:38 +00:00
|
|
|
/* return the first selected curve, this lets us use multiple curves */
|
|
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_Curve) {
|
|
|
|
|
cmd = (CurveModifierData *)md;
|
2019-04-30 16:43:44 -03:00
|
|
|
if (cmd->object && (cmd->object->base_flag & BASE_SELECTED)) {
|
2012-10-15 03:16:38 +00:00
|
|
|
return cmd->object;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-10-15 03:16:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2020-03-19 20:33:23 +01:00
|
|
|
if (cmd) { /* if we're still here then return the last curve */
|
2012-10-15 03:16:38 +00:00
|
|
|
return cmd->object;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
return nullptr;
|
2012-10-15 03:16:38 +00:00
|
|
|
}
|
2006-12-23 11:56:22 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
bool BKE_modifiers_uses_multires(Object *ob)
|
2019-10-01 22:30:14 +02:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
2022-09-29 16:43:09 -05:00
|
|
|
MultiresModifierData *mmd = nullptr;
|
2019-10-01 22:30:14 +02:00
|
|
|
|
|
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_Multires) {
|
|
|
|
|
mmd = (MultiresModifierData *)md;
|
|
|
|
|
if (mmd->totlvl != 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
bool BKE_modifiers_uses_armature(Object *ob, bArmature *arm)
|
2006-05-04 00:59:02 +00:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
2006-05-04 00:59:02 +00:00
|
|
|
|
2012-05-06 17:22:54 +00:00
|
|
|
for (; md; md = md->next) {
|
|
|
|
|
if (md->type == eModifierType_Armature) {
|
2024-11-04 17:00:51 +01:00
|
|
|
ArmatureModifierData *amd = reinterpret_cast<ArmatureModifierData *>(md);
|
|
|
|
|
if (amd->object && amd->object->data == arm) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_GreasePencilArmature) {
|
|
|
|
|
GreasePencilArmatureModifierData *amd = reinterpret_cast<GreasePencilArmatureModifierData *>(
|
|
|
|
|
md);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (amd->object && amd->object->data == arm) {
|
2013-06-02 03:59:19 +00:00
|
|
|
return true;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2006-05-04 00:59:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-02 03:59:19 +00:00
|
|
|
return false;
|
2006-05-04 00:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
bool BKE_modifier_is_correctable_deformed(ModifierData *md)
|
2007-07-28 21:04:30 +00:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2023-07-27 12:04:18 +10:00
|
|
|
return mti->deform_matrices_EM != nullptr;
|
2007-07-28 21:04:30 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool BKE_modifiers_is_correctable_deformed(const Scene *scene, Object *ob)
|
New: CrazySpace [tm] correction
When Modifiers are used in Edit Mode to show the deformed result for
editing, all actual coordinates Blender works with are still the ones from
the original Cage. You can notice that with the Transform Widget or
helper lines while transforming.
Even worse, the actual transformations still happened on the original Cage
as well, making it very hard to edit. That caused the feature to be named
"CrazySpace" (baptized by Andy, afaik?).
This commit calculates the deformation transformation per vertex, and
inverse corrects it, so it's more intuitive editing this way.
Unfortunately all the deformation features of Blender don't use matrices
for defining deform, so the existing code cannot be re-used to retrieve
the correct deformation matrix per vertex. The solution I found is based
on calculating per face the transformation based on its first 3 vertices,
and store this transformation averaged in the face's vertices.
The solution can also only work on entire faces, because the full deform
can only be retrieved using 3 vertices. (using 2 vertices will miss edge-
aligned rotation, using 1 vertex can only retrieve translation).
By deriving the deformations per face, small errors will still happen,
especially on very low-poly Meshes with extreme deformations.
The only alternative I know now, is providing each vertex in
a mesh with 2 extreme small tangent vectors, which get deformed using the
existing code as well. That will mess up the existing deformation code too
much though, this solution has the benefit it works with each deform we can
up with later too.
Last note about CrazySpace: it can only be used to tweak Meshes. Do not
even try to add vertices, extrude, or duplicate. Probably we should disable
this... but preventing user errors isn't always power-user-friendly, eh. :)
2005-10-26 09:56:52 +00:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
|
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
|
2013-09-24 00:56:47 +00:00
|
|
|
int required_mode = eModifierMode_Realtime;
|
|
|
|
|
|
2018-04-05 18:20:27 +02:00
|
|
|
if (ob->mode == OB_MODE_EDIT) {
|
2013-09-24 00:56:47 +00:00
|
|
|
required_mode |= eModifierMode_Editmode;
|
2018-02-06 19:34:36 +11:00
|
|
|
}
|
2012-05-06 17:22:54 +00:00
|
|
|
for (; md; md = md->next) {
|
2020-05-08 10:14:02 +02:00
|
|
|
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
|
2012-10-07 09:48:59 +00:00
|
|
|
/* pass */
|
|
|
|
|
}
|
2020-05-08 10:14:02 +02:00
|
|
|
else if (BKE_modifier_is_correctable_deformed(md)) {
|
2013-06-02 03:59:19 +00:00
|
|
|
return true;
|
2012-10-07 09:48:59 +00:00
|
|
|
}
|
New: CrazySpace [tm] correction
When Modifiers are used in Edit Mode to show the deformed result for
editing, all actual coordinates Blender works with are still the ones from
the original Cage. You can notice that with the Transform Widget or
helper lines while transforming.
Even worse, the actual transformations still happened on the original Cage
as well, making it very hard to edit. That caused the feature to be named
"CrazySpace" (baptized by Andy, afaik?).
This commit calculates the deformation transformation per vertex, and
inverse corrects it, so it's more intuitive editing this way.
Unfortunately all the deformation features of Blender don't use matrices
for defining deform, so the existing code cannot be re-used to retrieve
the correct deformation matrix per vertex. The solution I found is based
on calculating per face the transformation based on its first 3 vertices,
and store this transformation averaged in the face's vertices.
The solution can also only work on entire faces, because the full deform
can only be retrieved using 3 vertices. (using 2 vertices will miss edge-
aligned rotation, using 1 vertex can only retrieve translation).
By deriving the deformations per face, small errors will still happen,
especially on very low-poly Meshes with extreme deformations.
The only alternative I know now, is providing each vertex in
a mesh with 2 extreme small tangent vectors, which get deformed using the
existing code as well. That will mess up the existing deformation code too
much though, this solution has the benefit it works with each deform we can
up with later too.
Last note about CrazySpace: it can only be used to tweak Meshes. Do not
even try to add vertices, extrude, or duplicate. Probably we should disable
this... but preventing user errors isn't always power-user-friendly, eh. :)
2005-10-26 09:56:52 +00:00
|
|
|
}
|
2013-06-02 03:59:19 +00:00
|
|
|
return false;
|
New: CrazySpace [tm] correction
When Modifiers are used in Edit Mode to show the deformed result for
editing, all actual coordinates Blender works with are still the ones from
the original Cage. You can notice that with the Transform Widget or
helper lines while transforming.
Even worse, the actual transformations still happened on the original Cage
as well, making it very hard to edit. That caused the feature to be named
"CrazySpace" (baptized by Andy, afaik?).
This commit calculates the deformation transformation per vertex, and
inverse corrects it, so it's more intuitive editing this way.
Unfortunately all the deformation features of Blender don't use matrices
for defining deform, so the existing code cannot be re-used to retrieve
the correct deformation matrix per vertex. The solution I found is based
on calculating per face the transformation based on its first 3 vertices,
and store this transformation averaged in the face's vertices.
The solution can also only work on entire faces, because the full deform
can only be retrieved using 3 vertices. (using 2 vertices will miss edge-
aligned rotation, using 1 vertex can only retrieve translation).
By deriving the deformations per face, small errors will still happen,
especially on very low-poly Meshes with extreme deformations.
The only alternative I know now, is providing each vertex in
a mesh with 2 extreme small tangent vectors, which get deformed using the
existing code as well. That will mess up the existing deformation code too
much though, this solution has the benefit it works with each deform we can
up with later too.
Last note about CrazySpace: it can only be used to tweak Meshes. Do not
even try to add vertices, extrude, or duplicate. Probably we should disable
this... but preventing user errors isn't always power-user-friendly, eh. :)
2005-10-26 09:56:52 +00:00
|
|
|
}
|
2007-11-04 22:00:24 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifier_free_temporary_data(ModifierData *md)
|
2007-12-17 11:47:24 +00:00
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (md->type == eModifierType_Armature) {
|
2012-05-06 17:22:54 +00:00
|
|
|
ArmatureModifierData *amd = (ArmatureModifierData *)md;
|
2007-12-17 11:47:24 +00:00
|
|
|
|
2020-06-12 14:29:59 +10:00
|
|
|
MEM_SAFE_FREE(amd->vert_coords_prev);
|
2007-12-17 11:47:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifiers_test_object(Object *ob)
|
2010-09-09 00:14:51 +00:00
|
|
|
{
|
|
|
|
|
/* just multires checked for now, since only multires
|
2012-03-03 20:19:11 +00:00
|
|
|
* modifies mesh data */
|
2010-09-09 00:14:51 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ob->type != OB_MESH) {
|
2012-03-24 06:18:31 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2007-12-17 11:47:24 +00:00
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
2012-03-24 06:18:31 +00:00
|
|
|
if (md->type == eModifierType_Multires) {
|
2012-05-06 17:22:54 +00:00
|
|
|
MultiresModifierData *mmd = (MultiresModifierData *)md;
|
2008-09-24 11:52:31 +00:00
|
|
|
|
2010-09-09 00:14:51 +00:00
|
|
|
multiresModifier_set_levels_from_disps(mmd, ob);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-11-20 14:38:11 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
|
2011-11-20 14:38:11 +00:00
|
|
|
{
|
2021-12-07 18:23:57 +11:00
|
|
|
/* - If the ID is from a library, return library path.
|
|
|
|
|
* - Else if the file has been saved return the blend file path.
|
2024-07-13 16:56:57 +10:00
|
|
|
* - Else if the file isn't saved and the ID isn't from a library, return the temp directory.
|
2021-12-07 18:23:57 +11:00
|
|
|
*/
|
2021-12-16 11:38:10 +11:00
|
|
|
if ((bmain->filepath[0] != '\0') || ID_IS_LINKED(ob)) {
|
2018-05-31 15:24:30 +02:00
|
|
|
return ID_BLEND_PATH(bmain, &ob->id);
|
2011-11-20 14:38:11 +00:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
2021-12-07 18:23:57 +11:00
|
|
|
/* Last resort, better than using "" which resolves to the current working directory. */
|
2020-08-07 12:30:43 +02:00
|
|
|
return BKE_tempdir_session();
|
2011-11-20 14:38:11 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
const char *BKE_modifier_path_relbase_from_global(Object *ob)
|
2018-06-09 15:16:44 +02:00
|
|
|
{
|
2021-12-07 18:23:57 +11:00
|
|
|
return BKE_modifier_path_relbase(G_MAIN, ob);
|
2018-06-09 15:16:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-07 15:22:58 +10:00
|
|
|
void BKE_modifier_path_init(char *path, int path_maxncpy, const char *name)
|
2011-11-20 14:38:11 +00:00
|
|
|
{
|
2021-12-16 11:38:10 +11:00
|
|
|
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
2023-05-07 15:22:58 +10:00
|
|
|
BLI_path_join(path, path_maxncpy, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
|
2011-11-20 14:38:11 +00:00
|
|
|
}
|
2013-06-19 08:00:20 +00:00
|
|
|
|
2020-05-25 20:16:42 +10:00
|
|
|
/**
|
2023-07-27 12:04:18 +10:00
|
|
|
* Call when #ModifierTypeInfo.depends_on_normals callback requests normals.
|
2024-04-04 22:46:41 +02:00
|
|
|
* Necessary for BMesh normals when there is no separate #EditMeshData positions array,
|
|
|
|
|
* since they cannot be calculated lazily.
|
2020-05-25 20:16:42 +10:00
|
|
|
*/
|
2024-04-04 22:46:41 +02:00
|
|
|
static void ensure_non_lazy_normals(Mesh *mesh)
|
2020-05-25 20:16:42 +10:00
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
switch (mesh->runtime->wrapper_type) {
|
2020-05-25 20:16:42 +10:00
|
|
|
case ME_WRAPPER_TYPE_BMESH: {
|
2023-12-08 16:40:06 -05:00
|
|
|
blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
|
2024-03-28 18:25:24 -04:00
|
|
|
if (!edit_data.vert_positions.is_empty()) {
|
2020-05-25 20:16:42 +10:00
|
|
|
/* Note that 'ensure' is acceptable here since these values aren't modified in-place.
|
|
|
|
|
* If that changes we'll need to recalculate. */
|
2024-03-21 23:18:49 +01:00
|
|
|
BKE_editmesh_cache_ensure_vert_normals(*mesh->runtime->edit_mesh, edit_data);
|
2020-05-25 20:16:42 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2024-03-21 23:18:49 +01:00
|
|
|
BM_mesh_normals_update(mesh->runtime->edit_mesh->bm);
|
2020-05-25 20:16:42 +10:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
OpenSubDiv: add support for an OpenGL evaluator
This evaluator is used in order to evaluate subdivision at render time, allowing for
faster renders of meshes with a subdivision surface modifier placed at the last
position in the modifier list.
When evaluating the subsurf modifier, we detect whether we can delegate evaluation
to the draw code. If so, the subdivision is first evaluated on the GPU using our own
custom evaluator (only the coarse data needs to be initially sent to the GPU), then,
buffers for the final `MeshBufferCache` are filled on the GPU using a set of
compute shaders. However, some buffers are still filled on the CPU side, if doing so
on the GPU is impractical (e.g. the line adjacency buffer used for x-ray, whose
logic is hardly GPU compatible).
This is done at the mesh buffer extraction level so that the result can be readily used
in the various OpenGL engines, without having to write custom geometry or tesselation
shaders.
We use our own subdivision evaluation shaders, instead of OpenSubDiv's vanilla one, in
order to control the data layout, and interpolation. For example, we store vertex colors
as compressed 16-bit integers, while OpenSubDiv's default evaluator only work for float
types.
In order to still access the modified geometry on the CPU side, for use in modifiers
or transform operators, a dedicated wrapper type is added `MESH_WRAPPER_TYPE_SUBD`.
Subdivision will be lazily evaluated via `BKE_object_get_evaluated_mesh` which will
create such a wrapper if possible. If the final subdivision surface is not needed on
the CPU side, `BKE_object_get_evaluated_mesh_no_subsurf` should be used.
Enabling or disabling GPU subdivision can be done through the user preferences (under
Viewport -> Subdivision).
See patch description for benchmarks.
Reviewed By: campbellbarton, jbakker, fclem, brecht, #eevee_viewport
Differential Revision: https://developer.blender.org/D12406
2021-12-27 16:34:47 +01:00
|
|
|
case ME_WRAPPER_TYPE_SUBD:
|
2022-04-19 17:08:02 -05:00
|
|
|
/* Not an expected case. */
|
|
|
|
|
break;
|
2020-05-25 20:16:42 +10:00
|
|
|
case ME_WRAPPER_TYPE_MDATA:
|
2022-04-19 17:08:02 -05:00
|
|
|
/* Normals are calculated lazily. */
|
2020-05-25 20:16:42 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
/* wrapper around ModifierTypeInfo.modify_mesh that ensures valid normals */
|
2013-06-19 08:00:20 +00:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *BKE_modifier_modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
2018-10-09 13:19:21 +11:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2018-10-09 13:19:21 +11:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
|
2020-05-25 20:16:42 +10:00
|
|
|
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
|
2023-12-08 16:40:06 -05:00
|
|
|
BKE_mesh_wrapper_ensure_mdata(mesh);
|
2020-05-25 20:16:42 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
return mti->modify_mesh(md, ctx, mesh);
|
2018-10-09 13:19:21 +11:00
|
|
|
}
|
2013-06-19 08:00:20 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifier_deform_verts(ModifierData *md,
|
2020-05-08 19:02:03 +10:00
|
|
|
const ModifierEvalContext *ctx,
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh,
|
2023-11-14 10:54:57 +01:00
|
|
|
blender::MutableSpan<blender::float3> positions)
|
2018-10-09 13:19:21 +11:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2023-12-08 16:40:06 -05:00
|
|
|
mti->deform_verts(md, ctx, mesh, positions);
|
|
|
|
|
if (mesh) {
|
2023-12-12 15:38:42 -05:00
|
|
|
mesh->tag_positions_changed();
|
2023-02-06 14:34:16 -05:00
|
|
|
}
|
2018-10-09 13:19:21 +11:00
|
|
|
}
|
2013-06-19 08:00:20 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
void BKE_modifier_deform_vertsEM(ModifierData *md,
|
2020-05-08 19:02:03 +10:00
|
|
|
const ModifierEvalContext *ctx,
|
2024-05-20 10:11:13 -04:00
|
|
|
const BMEditMesh *em,
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh,
|
2023-11-14 10:54:57 +01:00
|
|
|
blender::MutableSpan<blender::float3> positions)
|
2018-04-24 04:08:16 -04:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2023-12-08 16:40:06 -05:00
|
|
|
if (mesh && mti->depends_on_normals && mti->depends_on_normals(md)) {
|
2024-04-04 22:46:41 +02:00
|
|
|
ensure_non_lazy_normals(mesh);
|
2018-04-24 04:08:16 -04:00
|
|
|
}
|
2023-12-08 16:40:06 -05:00
|
|
|
mti->deform_verts_EM(md, ctx, em, mesh, positions);
|
2018-04-18 15:45:54 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-09 13:19:21 +11:00
|
|
|
/* end modifier callback wrappers */
|
2018-04-24 04:08:16 -04:00
|
|
|
|
2022-07-20 15:57:16 +02:00
|
|
|
Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
|
2018-05-09 12:44:22 +02:00
|
|
|
{
|
Fix #119589: use-after-free when accessing not-fully-evaluated object geometry
While the evaluated result is not well defined, we expect Blender to not crash
when there are dependency cycles.
The evaluation of one object often takes the evaluated geometry of another
object into account. This works fine if the other object is already fully
evaluated. However, if there is a dependency cycle, the other object may not be
evaluated already. Currently, we have no way to check for this and were mostly
just relying on luck that the other objects geometry is in some valid state
(even if it's not the fully evaluated geometry).
This patch adds the ability to explicitly check if an objects geometry is fully
evaluated already, so that it can be accessed by other objects. If there are not
dependency cycles, this should always be true. If not, it may be false
sometimes, and in this case the other objects geometry should be ignored. The
same also applies to the object transforms and the geometry of a collection.
For that, new functions are added in `DEG_depsgraph_query.hh`. Those should be
used whenever accessing another objects or collections object during depsgraph
evaluation. More similar functions may be added in the future.
```
bool DEG_object_geometry_is_evaluated(const Object &object);
bool DEG_object_transform_is_evaluated(const Object &object);
bool DEG_collection_geometry_is_evaluated(const Collection &collection);
```
To determine if the these components are fully evaluated, a reference to the
corresponding depsgraph is needed. A possible solution to that is to pass the
depsgraph through the call stack to these functions. While possible, there are a
couple of annoyances. For one, the parameter would need to be added in many new
places. I don't have an exact number, but it's like 50 or so. Another
complication is that under some circumstances, multiple depsgraphs may have to
be passed around, for example when evaluating node tools (also see
`GeoNodesOperatorDepsgraphs`).
To simplify the patch and other code in the future, a different route is taken
where the depsgraph pointer is added to `ID_Runtime`, making it readily
accessible similar to the `ID.orig_id`. The depsgraph pointer is set in the same
place where the `orig_id` is set.
As a nice side benefit, this also improves the situation in simple cases like
having two cubes with a boolean modifier and they union each other.
Pull Request: https://projects.blender.org/blender/blender/pulls/123444
2024-06-20 15:24:38 +02:00
|
|
|
if (!DEG_object_geometry_is_evaluated(*ob_eval)) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = nullptr;
|
2018-05-30 11:34:08 +02:00
|
|
|
|
|
|
|
|
if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
|
2019-02-11 20:20:12 +01:00
|
|
|
/* In EditMode, evaluated mesh is stored in BMEditMesh, not the object... */
|
2024-03-28 18:57:57 -04:00
|
|
|
const BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
|
2023-02-12 14:37:16 +11:00
|
|
|
/* 'em' might not exist yet in some cases, just after loading a .blend file, see #57878. */
|
2022-09-29 16:43:09 -05:00
|
|
|
if (em != nullptr) {
|
2024-03-28 18:57:57 -04:00
|
|
|
mesh = const_cast<Mesh *>(BKE_object_get_editmesh_eval_final(ob_eval));
|
2018-11-29 15:48:08 +01:00
|
|
|
}
|
2018-05-30 11:34:08 +02:00
|
|
|
}
|
2023-12-08 16:40:06 -05:00
|
|
|
if (mesh == nullptr) {
|
|
|
|
|
mesh = BKE_object_get_evaluated_mesh(ob_eval);
|
2018-05-30 11:34:08 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
return mesh;
|
2018-05-09 12:44:22 +02:00
|
|
|
}
|
2019-04-04 14:42:33 +02:00
|
|
|
|
2022-02-02 12:20:03 +01:00
|
|
|
ModifierData *BKE_modifier_get_original(const Object *object, ModifierData *md)
|
2019-04-04 14:42:33 +02:00
|
|
|
{
|
2022-02-02 12:20:03 +01:00
|
|
|
const Object *object_orig = DEG_get_original_object((Object *)object);
|
2024-02-06 18:02:32 +01:00
|
|
|
return BKE_modifiers_findby_persistent_uid(object_orig, md->persistent_uid);
|
2019-04-04 14:42:33 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph, Object *object, ModifierData *md)
|
2019-04-04 14:42:33 +02:00
|
|
|
{
|
|
|
|
|
Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
|
|
|
|
|
if (object_eval == object) {
|
|
|
|
|
return md;
|
|
|
|
|
}
|
2024-02-06 18:02:32 +01:00
|
|
|
return BKE_modifiers_findby_persistent_uid(object_eval, md->persistent_uid);
|
2020-08-05 11:54:18 +02:00
|
|
|
}
|
2020-11-06 17:13:04 +01:00
|
|
|
|
Modifiers: add unique modifier identifiers
This adds a new `ModifierData.persistent_uid` integer property with the following properties:
* It's unique within the object.
* Match between the original and evaluated object.
* Stable across Blender sessions.
* Stable across renames and reorderings of modifiers.
Potential use-cases:
* Everywhere where we currently use the name as identifier. For example,
`ModifierComputeContext` and `ModifierViewerPathElem`.
* Can be used as part of a key in `IDCacheKey` to support caches that stay
in-tact across undo steps.
* Can be stored in the `SpaceNode` to identify the modifier whose geometry node
tree is currently pinned (this could use the name currently, but that hasn't been
implemented yet).
This new identifier has some overlap with `ModifierData.session_uid`, but there
are some differences:
* `session_uid` is unique within the entire Blender session (except for duplicates
between the original and evaluated data blocks).
* `session_uid` is not stable across Blender sessions.
Especially due to the first difference, it's not immediately obvious that the new
`persistent_uid` can fulfill all use-cases of the existing `session_uid`. Nevertheless,
this seems likely and will be cleaned up separately.
Unfortunately, there is not a single place where modifiers are added to objects currently.
Therefore, there are quite a few places that need to ensure valid identifiers. I tried to catch
all the places, but it's hard to be sure. Therefore, I added an assert in `object_copy_data`
that checks if all identifiers are valid. This way, we should be notified relatively quickly if
issues are caused by invalid identifiers.
Pull Request: https://projects.blender.org/blender/blender/pulls/117347
2024-02-06 17:10:40 +01:00
|
|
|
void BKE_modifiers_persistent_uid_init(const Object &object, ModifierData &md)
|
|
|
|
|
{
|
|
|
|
|
uint64_t hash = blender::get_default_hash(blender::StringRef(md.name));
|
|
|
|
|
if (ID_IS_LINKED(&object)) {
|
2024-04-08 13:08:36 +02:00
|
|
|
hash = blender::get_default_hash(hash,
|
|
|
|
|
blender::StringRef(object.id.lib->runtime.filepath_abs));
|
Modifiers: add unique modifier identifiers
This adds a new `ModifierData.persistent_uid` integer property with the following properties:
* It's unique within the object.
* Match between the original and evaluated object.
* Stable across Blender sessions.
* Stable across renames and reorderings of modifiers.
Potential use-cases:
* Everywhere where we currently use the name as identifier. For example,
`ModifierComputeContext` and `ModifierViewerPathElem`.
* Can be used as part of a key in `IDCacheKey` to support caches that stay
in-tact across undo steps.
* Can be stored in the `SpaceNode` to identify the modifier whose geometry node
tree is currently pinned (this could use the name currently, but that hasn't been
implemented yet).
This new identifier has some overlap with `ModifierData.session_uid`, but there
are some differences:
* `session_uid` is unique within the entire Blender session (except for duplicates
between the original and evaluated data blocks).
* `session_uid` is not stable across Blender sessions.
Especially due to the first difference, it's not immediately obvious that the new
`persistent_uid` can fulfill all use-cases of the existing `session_uid`. Nevertheless,
this seems likely and will be cleaned up separately.
Unfortunately, there is not a single place where modifiers are added to objects currently.
Therefore, there are quite a few places that need to ensure valid identifiers. I tried to catch
all the places, but it's hard to be sure. Therefore, I added an assert in `object_copy_data`
that checks if all identifiers are valid. This way, we should be notified relatively quickly if
issues are caused by invalid identifiers.
Pull Request: https://projects.blender.org/blender/blender/pulls/117347
2024-02-06 17:10:40 +01:00
|
|
|
}
|
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(&object)) {
|
|
|
|
|
BLI_assert(ID_IS_LINKED(object.id.override_library->reference));
|
|
|
|
|
hash = blender::get_default_hash(
|
2024-04-08 13:08:36 +02:00
|
|
|
hash,
|
|
|
|
|
blender::StringRef(object.id.override_library->reference->lib->runtime.filepath_abs));
|
Modifiers: add unique modifier identifiers
This adds a new `ModifierData.persistent_uid` integer property with the following properties:
* It's unique within the object.
* Match between the original and evaluated object.
* Stable across Blender sessions.
* Stable across renames and reorderings of modifiers.
Potential use-cases:
* Everywhere where we currently use the name as identifier. For example,
`ModifierComputeContext` and `ModifierViewerPathElem`.
* Can be used as part of a key in `IDCacheKey` to support caches that stay
in-tact across undo steps.
* Can be stored in the `SpaceNode` to identify the modifier whose geometry node
tree is currently pinned (this could use the name currently, but that hasn't been
implemented yet).
This new identifier has some overlap with `ModifierData.session_uid`, but there
are some differences:
* `session_uid` is unique within the entire Blender session (except for duplicates
between the original and evaluated data blocks).
* `session_uid` is not stable across Blender sessions.
Especially due to the first difference, it's not immediately obvious that the new
`persistent_uid` can fulfill all use-cases of the existing `session_uid`. Nevertheless,
this seems likely and will be cleaned up separately.
Unfortunately, there is not a single place where modifiers are added to objects currently.
Therefore, there are quite a few places that need to ensure valid identifiers. I tried to catch
all the places, but it's hard to be sure. Therefore, I added an assert in `object_copy_data`
that checks if all identifiers are valid. This way, we should be notified relatively quickly if
issues are caused by invalid identifiers.
Pull Request: https://projects.blender.org/blender/blender/pulls/117347
2024-02-06 17:10:40 +01:00
|
|
|
}
|
|
|
|
|
blender::RandomNumberGenerator rng{uint32_t(hash)};
|
|
|
|
|
while (true) {
|
|
|
|
|
const int new_uid = rng.get_int32();
|
|
|
|
|
if (new_uid <= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (BKE_modifiers_findby_persistent_uid(&object, new_uid) != nullptr) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
md.persistent_uid = new_uid;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BKE_modifiers_persistent_uids_are_valid(const Object &object)
|
|
|
|
|
{
|
|
|
|
|
blender::Set<int> uids;
|
|
|
|
|
int modifiers_num = 0;
|
|
|
|
|
LISTBASE_FOREACH (const ModifierData *, md, &object.modifiers) {
|
|
|
|
|
if (md->persistent_uid <= 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
uids.add(md->persistent_uid);
|
|
|
|
|
modifiers_num++;
|
|
|
|
|
}
|
|
|
|
|
if (uids.size() != modifiers_num) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-16 16:00:00 +02:00
|
|
|
void BKE_modifier_blend_write(BlendWriter *writer, const ID *id_owner, ListBase *modbase)
|
2020-11-06 17:13:04 +01:00
|
|
|
{
|
2022-09-29 16:43:09 -05:00
|
|
|
if (modbase == nullptr) {
|
2020-11-06 17:13:04 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LISTBASE_FOREACH (ModifierData *, md, modbase) {
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
|
|
|
|
if (mti == nullptr) {
|
2022-05-16 16:00:00 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
/* If the blend_write callback is defined, it should handle the whole writing process. */
|
|
|
|
|
if (mti->blend_write != nullptr) {
|
|
|
|
|
mti->blend_write(writer, id_owner, md);
|
2022-05-16 16:00:00 +02:00
|
|
|
continue;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
BLO_write_struct_by_name(writer, mti->struct_name, md);
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
if (md->type == eModifierType_Cloth) {
|
|
|
|
|
ClothModifierData *clmd = (ClothModifierData *)md;
|
|
|
|
|
|
|
|
|
|
BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
|
|
|
|
|
BLO_write_struct(writer, ClothCollSettings, clmd->coll_parms);
|
|
|
|
|
BLO_write_struct(writer, EffectorWeights, clmd->sim_parms->effector_weights);
|
|
|
|
|
BKE_ptcache_blend_write(writer, &clmd->ptcaches);
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_Fluid) {
|
|
|
|
|
FluidModifierData *fmd = (FluidModifierData *)md;
|
|
|
|
|
|
|
|
|
|
if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
|
|
|
|
|
BLO_write_struct(writer, FluidDomainSettings, fmd->domain);
|
|
|
|
|
|
|
|
|
|
if (fmd->domain) {
|
|
|
|
|
BKE_ptcache_blend_write(writer, &(fmd->domain->ptcaches[0]));
|
|
|
|
|
|
|
|
|
|
/* create fake pointcache so that old blender versions can read it */
|
|
|
|
|
fmd->domain->point_cache[1] = BKE_ptcache_add(&fmd->domain->ptcaches[1]);
|
|
|
|
|
fmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
|
|
|
|
|
fmd->domain->point_cache[1]->step = 1;
|
|
|
|
|
|
|
|
|
|
BKE_ptcache_blend_write(writer, &(fmd->domain->ptcaches[1]));
|
|
|
|
|
|
|
|
|
|
if (fmd->domain->coba) {
|
|
|
|
|
BLO_write_struct(writer, ColorBand, fmd->domain->coba);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* cleanup the fake pointcache */
|
|
|
|
|
BKE_ptcache_free_list(&fmd->domain->ptcaches[1]);
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->domain->point_cache[1] = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
BLO_write_struct(writer, EffectorWeights, fmd->domain->effector_weights);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (fmd->type & MOD_FLUID_TYPE_FLOW) {
|
|
|
|
|
BLO_write_struct(writer, FluidFlowSettings, fmd->flow);
|
|
|
|
|
}
|
|
|
|
|
else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
|
|
|
|
|
BLO_write_struct(writer, FluidEffectorSettings, fmd->effector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_Fluidsim) {
|
2024-08-04 13:45:06 +10:00
|
|
|
BLI_assert_unreachable(); /* Deprecated data, should never be written. */
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_DynamicPaint) {
|
|
|
|
|
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
|
|
|
|
|
|
|
|
|
|
if (pmd->canvas) {
|
|
|
|
|
BLO_write_struct(writer, DynamicPaintCanvasSettings, pmd->canvas);
|
|
|
|
|
|
|
|
|
|
/* write surfaces */
|
|
|
|
|
LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
|
|
|
|
|
BLO_write_struct(writer, DynamicPaintSurface, surface);
|
|
|
|
|
}
|
|
|
|
|
/* write caches and effector weights */
|
|
|
|
|
LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
|
|
|
|
|
BKE_ptcache_blend_write(writer, &(surface->ptcaches));
|
|
|
|
|
|
|
|
|
|
BLO_write_struct(writer, EffectorWeights, surface->effector_weights);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pmd->brush) {
|
|
|
|
|
BLO_write_struct(writer, DynamicPaintBrushSettings, pmd->brush);
|
|
|
|
|
BLO_write_struct(writer, ColorBand, pmd->brush->paint_ramp);
|
|
|
|
|
BLO_write_struct(writer, ColorBand, pmd->brush->vel_ramp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_Collision) {
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
CollisionModifierData *collmd = (CollisionModifierData *)md;
|
2022-02-02 13:15:43 +11:00
|
|
|
/* TODO: CollisionModifier should use pointcache
|
|
|
|
|
* + have proper reset events before enabling this. */
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
writestruct(wd, DATA, float[3], collmd->numverts, collmd->x);
|
|
|
|
|
writestruct(wd, DATA, float[3], collmd->numverts, collmd->xnew);
|
2020-11-06 17:13:04 +01:00
|
|
|
writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO(sergey): Find a better place for this.
|
|
|
|
|
*
|
|
|
|
|
* Unfortunately, this can not be done as a regular do_versions() since the modifier type is
|
|
|
|
|
* set to NONE, so the do_versions code wouldn't know where the modifier came from.
|
|
|
|
|
*
|
2023-07-31 11:50:54 +10:00
|
|
|
* The best approach seems to have the functionality in `versioning_280.cc` but still call the
|
2020-11-06 17:13:04 +01:00
|
|
|
* function from #BKE_modifier_blend_read_data().
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Domain, inflow, ... */
|
|
|
|
|
static void modifier_ensure_type(FluidModifierData *fluid_modifier_data, int type)
|
|
|
|
|
{
|
|
|
|
|
fluid_modifier_data->type = type;
|
|
|
|
|
BKE_fluid_modifier_free(fluid_modifier_data);
|
|
|
|
|
BKE_fluid_modifier_create_type_data(fluid_modifier_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \note The old_modifier_data is NOT linked.
|
|
|
|
|
* This means that in order to access sub-data pointers #BLO_read_get_new_data_address is to be
|
|
|
|
|
* used.
|
|
|
|
|
*/
|
|
|
|
|
static ModifierData *modifier_replace_with_fluid(BlendDataReader *reader,
|
|
|
|
|
Object *object,
|
|
|
|
|
ListBase *modifiers,
|
|
|
|
|
ModifierData *old_modifier_data)
|
|
|
|
|
{
|
|
|
|
|
ModifierData *new_modifier_data = BKE_modifier_new(eModifierType_Fluid);
|
|
|
|
|
FluidModifierData *fluid_modifier_data = (FluidModifierData *)new_modifier_data;
|
|
|
|
|
|
|
|
|
|
if (old_modifier_data->type == eModifierType_Fluidsim) {
|
|
|
|
|
FluidsimModifierData *old_fluidsim_modifier_data = (FluidsimModifierData *)old_modifier_data;
|
2024-07-31 19:05:17 +02:00
|
|
|
/* Only get access to the data, do not mark it as used, otherwise there will be memory leak
|
|
|
|
|
* since readfile code won't free it. */
|
2022-09-29 16:43:09 -05:00
|
|
|
FluidsimSettings *old_fluidsim_settings = static_cast<FluidsimSettings *>(
|
2024-07-31 19:05:17 +02:00
|
|
|
BLO_read_get_new_data_address_no_us(
|
|
|
|
|
reader, old_fluidsim_modifier_data->fss, sizeof(FluidsimSettings)));
|
2020-11-06 17:13:04 +01:00
|
|
|
switch (old_fluidsim_settings->type) {
|
|
|
|
|
case OB_FLUIDSIM_ENABLE:
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, 0);
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_DOMAIN:
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_DOMAIN);
|
|
|
|
|
BKE_fluid_domain_type_set(object, fluid_modifier_data->domain, FLUID_DOMAIN_TYPE_LIQUID);
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_FLUID:
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_FLOW);
|
|
|
|
|
BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_LIQUID);
|
|
|
|
|
/* No need to emit liquid far away from surface. */
|
|
|
|
|
fluid_modifier_data->flow->surface_distance = 0.0f;
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_OBSTACLE:
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_EFFEC);
|
|
|
|
|
BKE_fluid_effector_type_set(
|
|
|
|
|
object, fluid_modifier_data->effector, FLUID_EFFECTOR_TYPE_COLLISION);
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_INFLOW:
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_FLOW);
|
|
|
|
|
BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_LIQUID);
|
|
|
|
|
BKE_fluid_flow_behavior_set(object, fluid_modifier_data->flow, FLUID_FLOW_BEHAVIOR_INFLOW);
|
|
|
|
|
/* No need to emit liquid far away from surface. */
|
|
|
|
|
fluid_modifier_data->flow->surface_distance = 0.0f;
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_OUTFLOW:
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_FLOW);
|
|
|
|
|
BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_LIQUID);
|
|
|
|
|
BKE_fluid_flow_behavior_set(
|
|
|
|
|
object, fluid_modifier_data->flow, FLUID_FLOW_BEHAVIOR_OUTFLOW);
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_PARTICLE:
|
|
|
|
|
/* "Particle" type objects not being used by Mantaflow fluid simulations.
|
|
|
|
|
* Skip this object, secondary particles can only be enabled through the domain object. */
|
|
|
|
|
break;
|
|
|
|
|
case OB_FLUIDSIM_CONTROL:
|
|
|
|
|
/* "Control" type objects not being used by Mantaflow fluid simulations.
|
|
|
|
|
* Use guiding type instead which is similar. */
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_EFFEC);
|
|
|
|
|
BKE_fluid_effector_type_set(
|
|
|
|
|
object, fluid_modifier_data->effector, FLUID_EFFECTOR_TYPE_GUIDE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (old_modifier_data->type == eModifierType_Smoke) {
|
|
|
|
|
SmokeModifierData *old_smoke_modifier_data = (SmokeModifierData *)old_modifier_data;
|
|
|
|
|
modifier_ensure_type(fluid_modifier_data, old_smoke_modifier_data->type);
|
|
|
|
|
if (fluid_modifier_data->type == MOD_FLUID_TYPE_DOMAIN) {
|
|
|
|
|
BKE_fluid_domain_type_set(object, fluid_modifier_data->domain, FLUID_DOMAIN_TYPE_GAS);
|
|
|
|
|
}
|
|
|
|
|
else if (fluid_modifier_data->type == MOD_FLUID_TYPE_FLOW) {
|
|
|
|
|
BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_SMOKE);
|
|
|
|
|
}
|
|
|
|
|
else if (fluid_modifier_data->type == MOD_FLUID_TYPE_EFFEC) {
|
|
|
|
|
BKE_fluid_effector_type_set(
|
|
|
|
|
object, fluid_modifier_data->effector, FLUID_EFFECTOR_TYPE_COLLISION);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Replace modifier data in the stack. */
|
|
|
|
|
new_modifier_data->next = old_modifier_data->next;
|
|
|
|
|
new_modifier_data->prev = old_modifier_data->prev;
|
2022-09-29 16:43:09 -05:00
|
|
|
if (new_modifier_data->prev != nullptr) {
|
2020-11-06 17:13:04 +01:00
|
|
|
new_modifier_data->prev->next = new_modifier_data;
|
|
|
|
|
}
|
2022-09-29 16:43:09 -05:00
|
|
|
if (new_modifier_data->next != nullptr) {
|
2020-11-06 17:13:04 +01:00
|
|
|
new_modifier_data->next->prev = new_modifier_data;
|
|
|
|
|
}
|
|
|
|
|
if (modifiers->first == old_modifier_data) {
|
|
|
|
|
modifiers->first = new_modifier_data;
|
|
|
|
|
}
|
|
|
|
|
if (modifiers->last == old_modifier_data) {
|
|
|
|
|
modifiers->last = new_modifier_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free old modifier data. */
|
|
|
|
|
MEM_freeN(old_modifier_data);
|
|
|
|
|
|
|
|
|
|
return new_modifier_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object *ob)
|
|
|
|
|
{
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct_list(reader, ModifierData, lb);
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
LISTBASE_FOREACH (ModifierData *, md, lb) {
|
2022-09-29 16:43:09 -05:00
|
|
|
md->error = nullptr;
|
|
|
|
|
md->runtime = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
|
2023-08-14 16:45:18 +02:00
|
|
|
/* If linking from a library, clear 'local' library override flag. */
|
|
|
|
|
if (ID_IS_LINKED(ob)) {
|
|
|
|
|
md->flag &= ~eModifierFlag_OverrideLibrary_Local;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 17:13:04 +01:00
|
|
|
/* Modifier data has been allocated as a part of data migration process and
|
|
|
|
|
* no reading of nested fields from file is needed. */
|
|
|
|
|
bool is_allocated = false;
|
|
|
|
|
|
|
|
|
|
if (md->type == eModifierType_Fluidsim) {
|
|
|
|
|
BLO_reportf_wrap(
|
|
|
|
|
BLO_read_data_reports(reader),
|
|
|
|
|
RPT_WARNING,
|
2024-01-11 19:49:03 +01:00
|
|
|
RPT_("Possible data loss when saving this file! %s modifier is deprecated (Object: %s)"),
|
2020-11-06 17:13:04 +01:00
|
|
|
md->name,
|
|
|
|
|
ob->id.name + 2);
|
|
|
|
|
md = modifier_replace_with_fluid(reader, ob, lb, md);
|
|
|
|
|
is_allocated = true;
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_Smoke) {
|
|
|
|
|
BLO_reportf_wrap(
|
|
|
|
|
BLO_read_data_reports(reader),
|
|
|
|
|
RPT_WARNING,
|
2024-01-11 19:49:03 +01:00
|
|
|
RPT_("Possible data loss when saving this file! %s modifier is deprecated (Object: %s)"),
|
2020-11-06 17:13:04 +01:00
|
|
|
md->name,
|
|
|
|
|
ob->id.name + 2);
|
|
|
|
|
md = modifier_replace_with_fluid(reader, ob, lb, md);
|
|
|
|
|
is_allocated = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
/* if modifiers disappear, or for upward compatibility */
|
2022-09-29 16:43:09 -05:00
|
|
|
if (mti == nullptr) {
|
2020-11-06 17:13:04 +01:00
|
|
|
md->type = eModifierType_None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_allocated) {
|
|
|
|
|
/* All the fields has been properly allocated. */
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_Cloth) {
|
|
|
|
|
ClothModifierData *clmd = (ClothModifierData *)md;
|
|
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
clmd->clothObject = nullptr;
|
|
|
|
|
clmd->hairdata = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, ClothSimSettings, &clmd->sim_parms);
|
|
|
|
|
BLO_read_struct(reader, ClothCollSettings, &clmd->coll_parms);
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
BKE_ptcache_blend_read_data(reader, &clmd->ptcaches, &clmd->point_cache, 0);
|
|
|
|
|
|
|
|
|
|
if (clmd->sim_parms) {
|
|
|
|
|
if (clmd->sim_parms->presets > 10) {
|
|
|
|
|
clmd->sim_parms->presets = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clmd->sim_parms->reset = 0;
|
|
|
|
|
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, EffectorWeights, &clmd->sim_parms->effector_weights);
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
if (!clmd->sim_parms->effector_weights) {
|
2022-09-29 16:43:09 -05:00
|
|
|
clmd->sim_parms->effector_weights = BKE_effector_add_weights(nullptr);
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
clmd->solver_result = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_Fluid) {
|
|
|
|
|
|
|
|
|
|
FluidModifierData *fmd = (FluidModifierData *)md;
|
|
|
|
|
|
|
|
|
|
if (fmd->type == MOD_FLUID_TYPE_DOMAIN) {
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->flow = nullptr;
|
|
|
|
|
fmd->effector = nullptr;
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, FluidDomainSettings, &fmd->domain);
|
2020-11-06 17:13:04 +01:00
|
|
|
fmd->domain->fmd = fmd;
|
|
|
|
|
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->domain->fluid = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
fmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->domain->tex_density = nullptr;
|
|
|
|
|
fmd->domain->tex_color = nullptr;
|
|
|
|
|
fmd->domain->tex_shadow = nullptr;
|
|
|
|
|
fmd->domain->tex_flame = nullptr;
|
|
|
|
|
fmd->domain->tex_flame_coba = nullptr;
|
|
|
|
|
fmd->domain->tex_coba = nullptr;
|
|
|
|
|
fmd->domain->tex_field = nullptr;
|
|
|
|
|
fmd->domain->tex_velocity_x = nullptr;
|
|
|
|
|
fmd->domain->tex_velocity_y = nullptr;
|
|
|
|
|
fmd->domain->tex_velocity_z = nullptr;
|
|
|
|
|
fmd->domain->tex_wt = nullptr;
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, ColorBand, &fmd->domain->coba);
|
2020-11-06 17:13:04 +01:00
|
|
|
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, EffectorWeights, &fmd->domain->effector_weights);
|
2020-11-06 17:13:04 +01:00
|
|
|
if (!fmd->domain->effector_weights) {
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->domain->effector_weights = BKE_effector_add_weights(nullptr);
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BKE_ptcache_blend_read_data(
|
|
|
|
|
reader, &(fmd->domain->ptcaches[0]), &(fmd->domain->point_cache[0]), 1);
|
|
|
|
|
|
|
|
|
|
/* Manta sim uses only one cache from now on, so store pointer convert */
|
|
|
|
|
if (fmd->domain->ptcaches[1].first || fmd->domain->point_cache[1]) {
|
|
|
|
|
if (fmd->domain->point_cache[1]) {
|
2024-07-31 19:05:17 +02:00
|
|
|
PointCache *cache = static_cast<PointCache *>(BLO_read_get_new_data_address_no_us(
|
|
|
|
|
reader, fmd->domain->point_cache[1], sizeof(PointCache)));
|
2020-11-06 17:13:04 +01:00
|
|
|
if (cache->flag & PTCACHE_FAKE_SMOKE) {
|
|
|
|
|
/* Manta-sim/smoke was already saved in "new format" and this cache is a fake one. */
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
printf(
|
|
|
|
|
"High resolution manta cache not available due to pointcache update. Please "
|
|
|
|
|
"reset the simulation.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BLI_listbase_clear(&fmd->domain->ptcaches[1]);
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->domain->point_cache[1] = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
2023-08-18 17:23:50 +02:00
|
|
|
|
|
|
|
|
/* Flag for refreshing the simulation after loading */
|
|
|
|
|
fmd->domain->flags |= FLUID_DOMAIN_FILE_LOAD;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
else if (fmd->type == MOD_FLUID_TYPE_FLOW) {
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->domain = nullptr;
|
|
|
|
|
fmd->effector = nullptr;
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, FluidFlowSettings, &fmd->flow);
|
2020-11-06 17:13:04 +01:00
|
|
|
fmd->flow->fmd = fmd;
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->flow->mesh = nullptr;
|
|
|
|
|
fmd->flow->verts_old = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
fmd->flow->numverts = 0;
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, ParticleSystem, &fmd->flow->psys);
|
2023-08-18 17:23:50 +02:00
|
|
|
|
|
|
|
|
fmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
else if (fmd->type == MOD_FLUID_TYPE_EFFEC) {
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->flow = nullptr;
|
|
|
|
|
fmd->domain = nullptr;
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, FluidEffectorSettings, &fmd->effector);
|
2020-11-06 17:13:04 +01:00
|
|
|
if (fmd->effector) {
|
|
|
|
|
fmd->effector->fmd = fmd;
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->effector->verts_old = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
fmd->effector->numverts = 0;
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->effector->mesh = nullptr;
|
2023-08-18 17:23:50 +02:00
|
|
|
|
|
|
|
|
fmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fmd->type = 0;
|
2022-09-29 16:43:09 -05:00
|
|
|
fmd->flow = nullptr;
|
|
|
|
|
fmd->domain = nullptr;
|
|
|
|
|
fmd->effector = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (md->type == eModifierType_DynamicPaint) {
|
|
|
|
|
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
|
|
|
|
|
|
|
|
|
|
if (pmd->canvas) {
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, DynamicPaintCanvasSettings, &pmd->canvas);
|
2020-11-06 17:13:04 +01:00
|
|
|
pmd->canvas->pmd = pmd;
|
|
|
|
|
pmd->canvas->flags &= ~MOD_DPAINT_BAKING; /* just in case */
|
|
|
|
|
|
|
|
|
|
if (pmd->canvas->surfaces.first) {
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct_list(reader, DynamicPaintSurface, &pmd->canvas->surfaces);
|
2020-11-06 17:13:04 +01:00
|
|
|
|
|
|
|
|
LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
|
|
|
|
|
surface->canvas = pmd->canvas;
|
2022-09-29 16:43:09 -05:00
|
|
|
surface->data = nullptr;
|
2020-11-06 17:13:04 +01:00
|
|
|
BKE_ptcache_blend_read_data(reader, &(surface->ptcaches), &(surface->pointcache), 1);
|
|
|
|
|
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, EffectorWeights, &surface->effector_weights);
|
2022-09-29 16:43:09 -05:00
|
|
|
if (surface->effector_weights == nullptr) {
|
|
|
|
|
surface->effector_weights = BKE_effector_add_weights(nullptr);
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pmd->brush) {
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, DynamicPaintBrushSettings, &pmd->brush);
|
2020-11-06 17:13:04 +01:00
|
|
|
pmd->brush->pmd = pmd;
|
2024-04-24 17:01:22 +02:00
|
|
|
BLO_read_struct(reader, ParticleSystem, &pmd->brush->psys);
|
|
|
|
|
BLO_read_struct(reader, ColorBand, &pmd->brush->paint_ramp);
|
|
|
|
|
BLO_read_struct(reader, ColorBand, &pmd->brush->vel_ramp);
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
if ((mti != nullptr) && (mti->blend_read != nullptr)) {
|
|
|
|
|
mti->blend_read(reader, md);
|
2020-11-06 17:13:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Modifiers: measure execution time and provide Python access
The goal is to give technical artists the ability to optimize modifier usage
and/or geometry node groups for performance. In the long term, it
would be useful if Blender could provide its own UI to display profiling
information to users. However, right now, there are too many open
design questions making it infeasible to tackle this in the short term.
This commit uses a simpler approach: Instead of adding new ui for
profiling data, it exposes the execution-time of modifiers in the Python
API. This allows technical artists to access the information and to build
their own UI to display the relevant information. In the long term this
will hopefully also help us to integrate a native ui for this in Blender
by observing how users use this information.
Note: The execution time of a modifier highly depends on what other
things the CPU is doing at the same time. For example, in many more
complex files, many objects and therefore modifiers are evaluated at
the same time by multiple threads which makes the measurement
much less reliable. For best results, make sure that only one object
is evaluated at a time (e.g. by changing it in isolation) and that no
other process on the system keeps the CPU busy.
As shown below, the execution time has to be accessed on the
evaluated object, not the original object.
```lang=python
import bpy
depsgraph = bpy.context.view_layer.depsgraph
ob = bpy.context.active_object
ob_eval = ob.evaluated_get(depsgraph)
modifier_eval = ob_eval.modifiers[0]
print(modifier_eval.execution_time, "s")
```
Differential Revision: https://developer.blender.org/D17185
2023-02-06 15:39:59 +01:00
|
|
|
namespace blender::bke {
|
|
|
|
|
|
|
|
|
|
using Clock = std::chrono::high_resolution_clock;
|
|
|
|
|
|
|
|
|
|
static double get_current_time_in_seconds()
|
|
|
|
|
{
|
|
|
|
|
return std::chrono::duration<double, std::chrono::seconds::period>(
|
|
|
|
|
Clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScopedModifierTimer::ScopedModifierTimer(ModifierData &md) : md_(md)
|
|
|
|
|
{
|
|
|
|
|
start_time_ = get_current_time_in_seconds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScopedModifierTimer::~ScopedModifierTimer()
|
|
|
|
|
{
|
|
|
|
|
const double end_time = get_current_time_in_seconds();
|
|
|
|
|
const double duration = end_time - start_time_;
|
|
|
|
|
md_.execution_time = duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace blender::bke
|