tornavis/source/blender/blenkernel/intern/DerivedMesh.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1718 lines
59 KiB
C++
Raw Normal View History

/* SPDX-FileCopyrightText: 2005 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
2011-02-27 21:40:57 +01:00
*/
#include <climits>
#include <cstring>
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
#include "DNA_customdata_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
2011-10-22 03:53:35 +02:00
#include "BLI_linklist.h"
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "BKE_DerivedMesh.hh"
#include "BKE_bvhutils.hh"
#include "BKE_colorband.h"
#include "BKE_deform.h"
#include "BKE_editmesh.hh"
#include "BKE_editmesh_cache.hh"
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_key.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_iterators.hh"
#include "BKE_mesh_mapping.hh"
#include "BKE_mesh_runtime.hh"
#include "BKE_mesh_tangent.hh"
#include "BKE_mesh_wrapper.hh"
2023-11-14 09:30:40 +01:00
#include "BKE_modifier.hh"
#include "BKE_multires.hh"
#include "BKE_object.hh"
#include "BKE_object_deform.h"
#include "BKE_object_types.hh"
#include "BKE_paint.hh"
#include "BKE_subdiv_modifier.hh"
#include "BLI_sys_types.h" /* for intptr_t support */
#include "BKE_shrinkwrap.h"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_query.hh"
2018-04-16 20:45:43 +02:00
#include "CLG_log.h"
#ifdef WITH_OPENSUBDIV
# include "DNA_userdef_types.h"
#endif
Curves: support deforming curves on surface Curves that are attached to a surface can now follow the surface when it is modified using shape keys or modifiers (but not when the original surface is deformed in edit or sculpt mode). The surface is allowed to be changed in any way that keeps uv maps intact. So deformation is allowed, but also some topology changes like subdivision. The following features are added: * A new `Deform Curves on Surface` node, which deforms curves with attachment information based on the surface object and uv map set in the properties panel. * A new `Add Rest Position` checkbox in the shape keys panel. When checked, a new `rest_position` vector attribute is added to the mesh before shape keys and modifiers are applied. This is necessary to support proper deformation of the curves, but can also be used for other purposes. * The `Add > Curve > Empty Hair` operator now sets up a simple geometry nodes setup that deforms the hair. It also makes sure that the rest position attribute is added to the surface. * A new `Object (Attach Curves to Surface)` operator in the `Set Parent To` (ctrl+P) menu, which attaches existing curves to the surface and sets the surface object as parent. Limitations: * Sculpting the procedurally deformed curves will be implemented separately. * The `Deform Curves on Surface` node is not generic and can only be used for one specific purpose currently. We plan to generalize this more in the future by adding support by exposing more inputs and/or by turning it into a node group. Differential Revision: https://developer.blender.org/D14864
2022-07-08 14:45:48 +02:00
using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
Mesh: Remove redundant custom data pointers For copy-on-write, we want to share attribute arrays between meshes where possible. Mutable pointers like `Mesh.mvert` make that difficult by making ownership vague. They also make code more complex by adding redundancy. The simplest solution is just removing them and retrieving layers from `CustomData` as needed. Similar changes have already been applied to curves and point clouds (e9f82d3dc7ee, 410a6efb747f). Removing use of the pointers generally makes code more obvious and more reusable. Mesh data is now accessed with a C++ API (`Mesh::edges()` or `Mesh::edges_for_write()`), and a C API (`BKE_mesh_edges(mesh)`). The CoW changes this commit makes possible are described in T95845 and T95842, and started in D14139 and D14140. The change also simplifies the ongoing mesh struct-of-array refactors from T95965. **RNA/Python Access Performance** Theoretically, accessing mesh elements with the RNA API may become slower, since the layer needs to be found on every random access. However, overhead is already high enough that this doesn't make a noticible differenc, and performance is actually improved in some cases. Random access can be up to 10% faster, but other situations might be a bit slower. Generally using `foreach_get/set` are the best way to improve performance. See the differential revision for more discussion about Python performance. Cycles has been updated to use raw pointers and the internal Blender mesh types, mostly because there is no sense in having this overhead when it's already compiled with Blender. In my tests this roughly halves the Cycles mesh creation time (0.19s to 0.10s for a 1 million face grid). Differential Revision: https://developer.blender.org/D15488
2022-09-05 18:56:34 +02:00
using blender::Span;
using blender::VArray;
using blender::bke::GeometryOwnershipType;
using blender::bke::GeometrySet;
using blender::bke::MeshComponent;
Curves: support deforming curves on surface Curves that are attached to a surface can now follow the surface when it is modified using shape keys or modifiers (but not when the original surface is deformed in edit or sculpt mode). The surface is allowed to be changed in any way that keeps uv maps intact. So deformation is allowed, but also some topology changes like subdivision. The following features are added: * A new `Deform Curves on Surface` node, which deforms curves with attachment information based on the surface object and uv map set in the properties panel. * A new `Add Rest Position` checkbox in the shape keys panel. When checked, a new `rest_position` vector attribute is added to the mesh before shape keys and modifiers are applied. This is necessary to support proper deformation of the curves, but can also be used for other purposes. * The `Add > Curve > Empty Hair` operator now sets up a simple geometry nodes setup that deforms the hair. It also makes sure that the rest position attribute is added to the surface. * A new `Object (Attach Curves to Surface)` operator in the `Set Parent To` (ctrl+P) menu, which attaches existing curves to the surface and sets the surface object as parent. Limitations: * Sculpting the procedurally deformed curves will be implemented separately. * The `Deform Curves on Surface` node is not generic and can only be used for one specific purpose currently. We plan to generalize this more in the future by adding support by exposing more inputs and/or by turning it into a node group. Differential Revision: https://developer.blender.org/D14864
2022-07-08 14:45:48 +02:00
/* very slow! enable for testing only! */
//#define USE_MODIFIER_VALIDATE
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_MESH(mesh) \
(BLI_assert((mesh == nullptr) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_MESH(mesh)
#endif
static void mesh_init_origspace(Mesh *mesh);
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final);
static void editbmesh_calc_modifier_final_normals_or_defer(Mesh *mesh_final);
/* -------------------------------------------------------------------- */
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
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 06:10:43 +01:00
static float *dm_getVertArray(DerivedMesh *dm)
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
{
float(*positions)[3] = (float(*)[3])CustomData_get_layer_named_for_write(
&dm->vertData, CD_PROP_FLOAT3, "position", dm->getNumVerts(dm));
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
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 06:10:43 +01:00
if (!positions) {
positions = (float(*)[3])CustomData_add_layer_named(
&dm->vertData, CD_PROP_FLOAT3, CD_SET_DEFAULT, dm->getNumVerts(dm), "position");
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 06:10:43 +01:00
CustomData_set_layer_flag(&dm->vertData, CD_PROP_FLOAT3, CD_FLAG_TEMPORARY);
dm->copyVertArray(dm, positions);
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
}
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 06:10:43 +01:00
return (float *)positions;
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
}
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
static vec2i *dm_getEdgeArray(DerivedMesh *dm)
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
{
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
vec2i *edge = (vec2i *)CustomData_get_layer_named_for_write(
&dm->edgeData, CD_PROP_INT32_2D, ".edge_verts", dm->getNumEdges(dm));
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
if (!edge) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
edge = (vec2i *)CustomData_add_layer_named(
&dm->edgeData, CD_PROP_INT32_2D, CD_SET_DEFAULT, dm->getNumEdges(dm), ".edge_verts");
CustomData_set_layer_flag(&dm->edgeData, CD_PROP_INT32_2D, CD_FLAG_TEMPORARY);
dm->copyEdgeArray(dm, edge);
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
}
return edge;
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
}
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
static int *dm_getCornerVertArray(DerivedMesh *dm)
{
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
int *corner_verts = (int *)CustomData_get_layer_named_for_write(
&dm->loopData, CD_PROP_INT32, ".corner_vert", dm->getNumLoops(dm));
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
if (!corner_verts) {
corner_verts = (int *)CustomData_add_layer_named(
&dm->loopData, CD_PROP_INT32, CD_SET_DEFAULT, dm->getNumLoops(dm), ".corner_vert");
dm->copyCornerVertArray(dm, corner_verts);
}
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
return corner_verts;
}
static int *dm_getCornerEdgeArray(DerivedMesh *dm)
{
int *corner_edges = (int *)CustomData_get_layer_named(
&dm->loopData, CD_PROP_INT32, ".corner_edge");
if (!corner_edges) {
corner_edges = (int *)CustomData_add_layer_named(
&dm->loopData, CD_PROP_INT32, CD_SET_DEFAULT, dm->getNumLoops(dm), ".corner_edge");
dm->copyCornerEdgeArray(dm, corner_edges);
}
return corner_edges;
}
Mesh: Replace MPoly struct with offset indices Implements #95967. Currently the `MPoly` struct is 12 bytes, and stores the index of a face's first corner and the number of corners/verts/edges. Polygons and corners are always created in order by Blender, meaning each face's corners will be after the previous face's corners. We can take advantage of this fact and eliminate the redundancy in mesh face storage by only storing a single integer corner offset for each face. The size of the face is then encoded by the offset of the next face. The size of a single integer is 4 bytes, so this reduces memory usage by 3 times. The same method is used for `CurvesGeometry`, so Blender already has an abstraction to simplify using these offsets called `OffsetIndices`. This class is used to easily retrieve a range of corner indices for each face. This also gives the opportunity for sharing some logic with curves. Another benefit of the change is that the offsets and sizes stored in `MPoly` can no longer disagree with each other. Storing faces in the order of their corners can simplify some code too. Face/polygon variables now use the `IndexRange` type, which comes with quite a few utilities that can simplify code. Some: - The offset integer array has to be one longer than the face count to avoid a branch for every face, which means the data is no longer part of the mesh's `CustomData`. - We lose the ability to "reference" an original mesh's offset array until more reusable CoW from #104478 is committed. That will be added in a separate commit. - Since they aren't part of `CustomData`, poly offsets often have to be copied manually. - To simplify using `OffsetIndices` in many places, some functions and structs in headers were moved to only compile in C++. - All meshes created by Blender use the same order for faces and face corners, but just in case, meshes with mismatched order are fixed by versioning code. - `MeshPolygon.totloop` is no longer editable in RNA. This API break is necessary here unfortunately. It should be worth it in 3.6, since that's the best way to allow loading meshes from 4.0, which is important for an LTS version. Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
static int *dm_getPolyArray(DerivedMesh *dm)
{
if (!dm->face_offsets) {
dm->face_offsets = MEM_cnew_array<int>(dm->getNumPolys(dm) + 1, __func__);
dm->copyPolyArray(dm, dm->face_offsets);
}
return dm->face_offsets;
}
void DM_init_funcs(DerivedMesh *dm)
{
/* default function implementations */
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
dm->getVertArray = dm_getVertArray;
dm->getEdgeArray = dm_getEdgeArray;
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
dm->getCornerVertArray = dm_getCornerVertArray;
dm->getCornerEdgeArray = dm_getCornerEdgeArray;
dm->getPolyArray = dm_getPolyArray;
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
dm->getPolyDataArray = DM_get_poly_data_layer;
dm->getLoopDataArray = DM_get_loop_data_layer;
}
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
int numEdges,
int numTessFaces,
int numLoops,
int numPolys)
{
dm->type = type;
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
dm->numTessFaceData = numTessFaces;
dm->numLoopData = numLoops;
dm->numPolyData = numPolys;
DM_init_funcs(dm);
/* Don't use #CustomData_reset because we don't want to touch custom-data. */
copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
void DM_from_template(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
int numVerts,
int numEdges,
int numTessFaces,
int numLoops,
int numPolys)
{
const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH;
Custom Data: support implicit sharing for custom data layers This integrates the new implicit-sharing system (from fbcddfcd68adc72f) with `CustomData`. Now the potentially long arrays referenced by custom data layers can be shared between different systems but most importantly between different geometries. This makes e.g. copying a mesh much cheaper because none of the attributes has to be copied. Only when an attribute is modified does it have to be copied. Also see the original design task: #95845. This reduces memory and improves performance by avoiding unnecessary data copies. For example, the used memory after loading a highly subdivided mesh is reduced from 2.4GB to 1.79GB. This is about 25% less which is the expected amount because in `main` there are 4 copies of the data: 1. The original data which is allocated when the file is loaded. 2. The copy for the depsgraph allocated during depsgraph evaluation. 3. The copy for the undo system allocated when the first undo step is created right after loading the file. 4. GPU buffers allocated for drawing. This patch only gets rid of copy number 2 for the depsgraph. In theory the other copies can be removed as part of follow up PRs as well though. ----- The patch has three main components: * Slightly modified `CustomData` API to make it work better with implicit sharing: * `CD_REFERENCE` and `CD_DUPLICATE` have been removed because they are meaningless when implicit-sharing is used. * `CD_ASSIGN` has been removed as well because it's not an allocation type anyway. The functionality of using existing arrays as custom data layers has not been removed though. * This can still be done with `CustomData_add_layer_with_data` which also has a new argument that allows passing in information about whether the array is shared. * `CD_FLAG_NOFREE` has been removed because it's no longer necessary. It only existed because of `CD_REFERENCE`. * `CustomData_copy` and `CustomData_merge` have been split up into a functions that do copy the actual attribute values and those that do not. The latter functions now have the `_layout` suffix (e.g. `CustomData_copy_layout`). * Changes in `customdata.cc` to make it actually use implicit-sharing. * Changes in various other files to adapt to the changes in `BKE_customdata.h`. Pull Request: https://projects.blender.org/blender/blender/pulls/106228
2023-04-13 14:57:57 +02:00
CustomData_copy_layout(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts);
CustomData_copy_layout(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges);
CustomData_copy_layout(
&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces);
CustomData_copy_layout(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops);
CustomData_copy_layout(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys);
dm->face_offsets = static_cast<int *>(MEM_dupallocN(source->face_offsets));
dm->type = type;
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
dm->numTessFaceData = numTessFaces;
dm->numLoopData = numLoops;
dm->numPolyData = numPolys;
DM_init_funcs(dm);
}
void DM_release(DerivedMesh *dm)
{
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numTessFaceData);
CustomData_free(&dm->loopData, dm->numLoopData);
CustomData_free(&dm->polyData, dm->numPolyData);
MEM_SAFE_FREE(dm->face_offsets);
}
void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
/* Just a shallow wrapper around #BKE_keyblock_convert_from_mesh,
* that ensures both evaluated mesh and original one has same number of vertices. */
const int totvert = me_deformed->totvert;
2018-06-17 17:05:51 +02:00
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
return;
}
2018-06-17 17:05:51 +02:00
BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask)
{
CustomData_set_only_copy(&dm->vertData, mask->vmask);
CustomData_set_only_copy(&dm->edgeData, mask->emask);
CustomData_set_only_copy(&dm->faceData, mask->fmask);
/* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
* weight paint mode when there are modifiers applied, needs further investigation,
* see replies to r50969, Campbell */
#if 0
CustomData_set_only_copy(&dm->loopData, mask->lmask);
Custom(&dm->polyData, mask->pmask);
#endif
}
static void mesh_set_only_copy(Mesh *mesh, const CustomData_MeshMasks *mask)
{
CustomData_set_only_copy(&mesh->vert_data, mask->vmask);
CustomData_set_only_copy(&mesh->edge_data, mask->emask);
CustomData_set_only_copy(&mesh->fdata_legacy, mask->fmask);
/* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
* weight paint mode when there are modifiers applied, needs further investigation,
* see replies to r50969, Campbell */
#if 0
CustomData_set_only_copy(&mesh->ldata, mask->lmask);
CustomData_set_only_copy(&mesh->pdata, mask->pmask);
#endif
}
void *DM_get_vert_data_layer(DerivedMesh *dm, const eCustomDataType type)
{
return CustomData_get_layer_for_write(&dm->vertData, type, dm->getNumVerts(dm));
}
void *DM_get_edge_data_layer(DerivedMesh *dm, const eCustomDataType type)
{
return CustomData_get_layer_for_write(&dm->edgeData, type, dm->getNumEdges(dm));
}
void *DM_get_poly_data_layer(DerivedMesh *dm, const eCustomDataType type)
{
return CustomData_get_layer_for_write(&dm->polyData, type, dm->getNumPolys(dm));
}
void *DM_get_loop_data_layer(DerivedMesh *dm, const eCustomDataType type)
{
return CustomData_get_layer_for_write(&dm->loopData, type, dm->getNumLoops(dm));
}
void DM_copy_vert_data(
const DerivedMesh *source, DerivedMesh *dest, int source_index, int dest_index, int count)
{
CustomData_copy_data(&source->vertData, &dest->vertData, source_index, dest_index, count);
}
void DM_interp_vert_data(const DerivedMesh *source,
DerivedMesh *dest,
int *src_indices,
float *weights,
int count,
int dest_index)
{
CustomData_interp(
&source->vertData, &dest->vertData, src_indices, weights, nullptr, count, dest_index);
}
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
{
BMIter iter;
BMVert *eve;
float(*orco)[3];
int i;
/* these may not really be the orco's, but it's only for preview.
* could be solver better once, but isn't simple */
2018-06-17 17:05:51 +02:00
orco = (float(*)[3])MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "BMEditMesh Orco");
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(orco[i], eve->co);
}
2018-06-17 17:05:51 +02:00
return orco;
}
/* orco custom data layer */
static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free))[3]
{
2012-05-12 21:18:02 +02:00
*free = 0;
if (layer == CD_ORCO) {
/* get original coordinates */
2012-05-12 21:18:02 +02:00
*free = 1;
if (em) {
return get_editbmesh_orco_verts(em);
}
return BKE_mesh_orco_verts_get(ob);
}
if (layer == CD_CLOTH_ORCO) {
/* apply shape key for cloth, this should really be solved
2012-03-09 19:28:30 +01:00
* by a more flexible customdata system, but not simple */
if (!em) {
2020-05-08 11:02:03 +02:00
ClothModifierData *clmd = (ClothModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Cloth);
if (clmd) {
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
clmd->sim_parms->shapekey_rest);
if (kb && kb->data) {
return (float(*)[3])kb->data;
}
}
}
return nullptr;
}
return nullptr;
}
static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
{
Mesh *mesh;
float(*orco)[3];
int free;
if (em) {
mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, me);
Mesh: Avoid creating incorrect original index layers Currently, whenever any BMesh is converted to a Mesh (except for edit mode switching), original index (`CD_ORIGINDEX`) layers are added. This is incorrect, because many operations just convert some Mesh into a BMesh and then back, but they shouldn't make any assumption about where their input mesh came from. It might even come from a primitive in geometry nodes, where there are no original indices at all. Conceptually, mesh original indices should be filled by the modifier stack when first creating the evaluated mesh. So that's where they're moved in this patch. A separate function now fills the indices with their default (0,1,2,3...) values. The way the mesh wrapper system defers the BMesh to Mesh conversion makes this a bit less obvious though. The old behavior is incorrect, but it's also slower, because three arrays the size of the mesh's vertices, edges, and faces had to be allocated and filled during the BMesh to Mesh conversion, which just ends up putting more pressure on the cache. In the many cases where original indices aren't used, I measured an **8% speedup** for the conversion (from 76.5ms to 70.7ms). Generally there is an assumption that BMesh is "original" and Mesh is "evaluated". After this patch, that assumption isn't quite as strong, but it still exists for two reasons. First, original indices are added whenever converting a BMesh "wrapper" to a Mesh. Second, original indices are not added to the BMesh at the beginning of evaluation, which assumes that every BMesh in the viewport is original and doesn't need the mapping. Differential Revision: https://developer.blender.org/D14018
2022-02-18 17:51:00 +01:00
BKE_mesh_ensure_default_orig_index_customdata(mesh);
}
else {
mesh = BKE_mesh_copy_for_eval(me);
}
orco = get_orco_coords(ob, em, layer, &free);
if (orco) {
BKE_mesh_vert_coords_apply(mesh, orco);
if (free) {
MEM_freeN(orco);
}
}
return mesh;
}
static MutableSpan<float3> orco_coord_layer_ensure(Mesh *mesh, const eCustomDataType layer)
{
void *data = CustomData_get_layer_for_write(&mesh->vert_data, layer, mesh->totvert);
if (!data) {
data = CustomData_add_layer(&mesh->vert_data, layer, CD_CONSTRUCT, mesh->totvert);
}
return MutableSpan(reinterpret_cast<float3 *>(data), mesh->totvert);
}
static void add_orco_mesh(
Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orco, const eCustomDataType layer)
{
const int totvert = mesh->totvert;
MutableSpan<float3> layer_orco;
if (mesh_orco) {
layer_orco = orco_coord_layer_ensure(mesh, layer);
if (mesh_orco->totvert == totvert) {
layer_orco.copy_from(mesh_orco->vert_positions());
}
else {
layer_orco.copy_from(mesh->vert_positions());
}
}
else {
/* TODO(sybren): totvert should potentially change here, as ob->data
* or em may have a different number of vertices than dm. */
int free = 0;
float(*orco)[3] = get_orco_coords(ob, em, layer, &free);
if (orco) {
layer_orco = orco_coord_layer_ensure(mesh, layer);
layer_orco.copy_from(Span<float3>(reinterpret_cast<float3 *>(orco), totvert));
}
if (free) {
MEM_freeN(orco);
}
}
if (!layer_orco.is_empty()) {
if (layer == CD_ORCO) {
BKE_mesh_orco_verts_transform(
(Mesh *)ob->data, reinterpret_cast<float(*)[3]>(layer_orco.data()), totvert, false);
}
}
}
/* Does final touches to the final evaluated mesh, making sure it is perfectly usable.
*
* This is needed because certain information is not passed along intermediate meshes allocated
* during stack evaluation.
*/
static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
{
/* Make sure the name is the same. This is because mesh allocation from template does not
* take care of naming. */
2023-05-09 04:50:37 +02:00
STRNCPY(mesh_eval->id.name, mesh_input->id.name);
/* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */
mesh_eval->edit_mesh = mesh_input->edit_mesh;
}
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval)
{
if (me_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
editbmesh_calc_modifier_final_normals(me_eval);
me_eval->runtime->wrapper_type_finalize = eMeshWrapperType(
me_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH));
}
BLI_assert(me_eval->runtime->wrapper_type_finalize == 0);
}
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
/**
* Modifies the given mesh and geometry set. The mesh is not passed as part of the mesh component
* in the \a geometry_set input, it is only passed in \a input_mesh and returned in the return
* value.
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
*
* The purpose of the geometry set is to store all geometry components that are generated
* by modifiers to allow outputting non-mesh data from modifiers.
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
*/
static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
const ModifierEvalContext &mectx,
Mesh *input_mesh,
GeometrySet &geometry_set)
{
Mesh *mesh_output = nullptr;
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->modify_geometry_set == nullptr) {
mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh);
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
}
else {
/* For performance reasons, this should be called by the modifier and/or nodes themselves at
* some point. */
BKE_mesh_wrapper_ensure_mdata(input_mesh);
/* Replace only the mesh rather than the whole component, because the entire #MeshComponent
* might have been replaced by data from a different object in the node tree, which means the
* component contains vertex group name data for that object that should not be removed. */
geometry_set.replace_mesh(input_mesh, GeometryOwnershipType::Editable);
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
/* Let the modifier change the geometry set. */
mti->modify_geometry_set(md, &mectx, &geometry_set);
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
/* Release the mesh from the geometry set again. */
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
if (mesh_component.get() != input_mesh) {
/* Make sure the mesh component actually owns the mesh before taking over ownership. */
mesh_component.ensure_owns_direct_data();
}
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
mesh_output = mesh_component.release();
}
/* Need to ensure that non-mesh data is also owned by the geometry set. Otherwise it might be
* freed while there is still a reference to it in the geometry. */
geometry_set.ensure_owns_direct_data();
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
/* Return an empty mesh instead of null. */
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
if (mesh_output == nullptr) {
mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0);
BKE_mesh_copy_parameters_for_eval(mesh_output, input_mesh);
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
}
}
return mesh_output;
}
static void set_rest_position(Mesh &mesh)
{
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh.attributes_for_write();
const AttributeReader positions = attributes.lookup<float3>("position");
attributes.remove("rest_position");
if (positions) {
if (positions.sharing_info && positions.varray.is_span()) {
attributes.add<float3>("rest_position",
ATTR_DOMAIN_POINT,
AttributeInitShared(positions.varray.get_internal_span().data(),
*positions.sharing_info));
}
else {
attributes.add<float3>(
"rest_position", ATTR_DOMAIN_POINT, AttributeInitVArray(positions.varray));
}
}
}
static void mesh_calc_modifiers(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const bool use_deform,
const bool need_mapping,
const CustomData_MeshMasks *dataMask,
const bool use_cache,
const bool allow_shared_mesh,
/* return args */
Mesh **r_deform,
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
Mesh **r_final,
GeometrySet **r_geometry_set)
{
using namespace blender::bke;
/* Input mesh shouldn't be modified. */
Mesh *mesh_input = (Mesh *)ob->data;
/* The final mesh is the result of calculating all enabled modifiers. */
Mesh *mesh_final = nullptr;
/* The result of calculating all leading deform modifiers. */
Mesh *mesh_deform = nullptr;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
GeometrySet geometry_set_final;
BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
/* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested
* for texturing. */
Mesh *mesh_orco = nullptr;
Mesh *mesh_orco_cloth = nullptr;
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
/* Sculpt can skip certain modifiers. */
const bool has_multires = BKE_sculpt_multires_active(scene, ob) != nullptr;
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
/* Modifier evaluation contexts for different types of modifiers. */
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : ModifierApplyFlag(0);
ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : ModifierApplyFlag(0);
const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache};
const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
VirtualModifierData virtual_modifier_data;
ModifierData *firstmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
ModifierData *md = firstmd;
/* Preview colors by modifiers such as dynamic paint, to show the results
* even if the resulting data is not used in a material. Only in object mode.
* TODO: this is broken, not drawn by the drawn manager. */
const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT);
ModifierData *previewmd = nullptr;
CustomData_MeshMasks previewmask = {0};
if (do_mod_mcol) {
/* Find the last active modifier generating a preview, or nullptr if none. */
/* XXX Currently, DPaint modifier just ignores this.
* Needs a stupid hack...
* The whole "modifier preview" thing has to be (re?)designed, anyway! */
previewmd = BKE_modifier_get_last_preview(scene, md, required_mode);
}
/* Compute accumulated datamasks needed by each modifier. It helps to do
* this fine grained so that for example vertex groups are preserved up to
* an armature modifier, but not through a following subsurf modifier where
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, md, &final_datamask, required_mode, previewmd, &previewmask);
CDMaskLink *md_datamask = datamasks;
/* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX;
/* Clear errors before evaluation. */
BKE_modifiers_clear_errors(ob);
Curves: support deforming curves on surface Curves that are attached to a surface can now follow the surface when it is modified using shape keys or modifiers (but not when the original surface is deformed in edit or sculpt mode). The surface is allowed to be changed in any way that keeps uv maps intact. So deformation is allowed, but also some topology changes like subdivision. The following features are added: * A new `Deform Curves on Surface` node, which deforms curves with attachment information based on the surface object and uv map set in the properties panel. * A new `Add Rest Position` checkbox in the shape keys panel. When checked, a new `rest_position` vector attribute is added to the mesh before shape keys and modifiers are applied. This is necessary to support proper deformation of the curves, but can also be used for other purposes. * The `Add > Curve > Empty Hair` operator now sets up a simple geometry nodes setup that deforms the hair. It also makes sure that the rest position attribute is added to the surface. * A new `Object (Attach Curves to Surface)` operator in the `Set Parent To` (ctrl+P) menu, which attaches existing curves to the surface and sets the surface object as parent. Limitations: * Sculpting the procedurally deformed curves will be implemented separately. * The `Deform Curves on Surface` node is not generic and can only be used for one specific purpose currently. We plan to generalize this more in the future by adding support by exposing more inputs and/or by turning it into a node group. Differential Revision: https://developer.blender.org/D14864
2022-07-08 14:45:48 +02:00
if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
if (mesh_final == nullptr) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
Curves: support deforming curves on surface Curves that are attached to a surface can now follow the surface when it is modified using shape keys or modifiers (but not when the original surface is deformed in edit or sculpt mode). The surface is allowed to be changed in any way that keeps uv maps intact. So deformation is allowed, but also some topology changes like subdivision. The following features are added: * A new `Deform Curves on Surface` node, which deforms curves with attachment information based on the surface object and uv map set in the properties panel. * A new `Add Rest Position` checkbox in the shape keys panel. When checked, a new `rest_position` vector attribute is added to the mesh before shape keys and modifiers are applied. This is necessary to support proper deformation of the curves, but can also be used for other purposes. * The `Add > Curve > Empty Hair` operator now sets up a simple geometry nodes setup that deforms the hair. It also makes sure that the rest position attribute is added to the surface. * A new `Object (Attach Curves to Surface)` operator in the `Set Parent To` (ctrl+P) menu, which attaches existing curves to the surface and sets the surface object as parent. Limitations: * Sculpting the procedurally deformed curves will be implemented separately. * The `Deform Curves on Surface` node is not generic and can only be used for one specific purpose currently. We plan to generalize this more in the future by adding support by exposing more inputs and/or by turning it into a node group. Differential Revision: https://developer.blender.org/D14864
2022-07-08 14:45:48 +02:00
ASSERT_IS_VALID_MESH(mesh_final);
}
set_rest_position(*mesh_final);
Curves: support deforming curves on surface Curves that are attached to a surface can now follow the surface when it is modified using shape keys or modifiers (but not when the original surface is deformed in edit or sculpt mode). The surface is allowed to be changed in any way that keeps uv maps intact. So deformation is allowed, but also some topology changes like subdivision. The following features are added: * A new `Deform Curves on Surface` node, which deforms curves with attachment information based on the surface object and uv map set in the properties panel. * A new `Add Rest Position` checkbox in the shape keys panel. When checked, a new `rest_position` vector attribute is added to the mesh before shape keys and modifiers are applied. This is necessary to support proper deformation of the curves, but can also be used for other purposes. * The `Add > Curve > Empty Hair` operator now sets up a simple geometry nodes setup that deforms the hair. It also makes sure that the rest position attribute is added to the surface. * A new `Object (Attach Curves to Surface)` operator in the `Set Parent To` (ctrl+P) menu, which attaches existing curves to the surface and sets the surface object as parent. Limitations: * Sculpting the procedurally deformed curves will be implemented separately. * The `Deform Curves on Surface` node is not generic and can only be used for one specific purpose currently. We plan to generalize this more in the future by adding support by exposing more inputs and/or by turning it into a node group. Differential Revision: https://developer.blender.org/D14864
2022-07-08 14:45:48 +02:00
}
/* Apply all leading deform modifiers. */
if (use_deform) {
for (; md; md = md->next, md_datamask = md_datamask->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) {
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
blender::bke::ScopedModifierTimer modifier_timer{*md};
if (!mesh_final) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
}
if (mti->required_data_mask) {
CustomData_MeshMasks mask{};
mti->required_data_mask(md, &mask);
if (mask.vmask & CD_MASK_ORCO) {
add_orco_mesh(ob, nullptr, mesh_final, nullptr, CD_ORCO);
}
}
BKE_modifier_deform_verts(md, &mectx, mesh_final, mesh_final->vert_positions_for_write());
}
else {
break;
}
}
/* Result of all leading deforming modifiers is cached for
* places that wish to use the original mesh but with deformed
* coordinates (like vertex paint). */
if (r_deform) {
mesh_deform = BKE_mesh_copy_for_eval(mesh_final ? mesh_final : mesh_input);
}
}
/* Apply all remaining constructive and deforming modifiers. */
bool have_non_onlydeform_modifiers_applied = false;
for (; md; md = md->next, md_datamask = md_datamask->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
if (mti->type == ModifierTypeType::OnlyDeform && !use_deform) {
continue;
}
if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) &&
have_non_onlydeform_modifiers_applied) {
BKE_modifier_set_error(ob, md, "Modifier requires original data, bad stack position");
continue;
}
2014-05-09 10:29:21 +02:00
if (sculpt_mode && (!has_multires || multires_applied || sculpt_dyntopo)) {
bool unsupported = false;
if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) {
/* If multires is on level 0 skip it silently without warning message. */
if (!sculpt_dyntopo) {
continue;
}
}
if (sculpt_dyntopo) {
unsupported = true;
}
if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
unsupported |= (mti->type != ModifierTypeType::OnlyDeform);
}
2012-05-12 21:18:02 +02:00
unsupported |= multires_applied;
if (unsupported) {
if (sculpt_dyntopo) {
BKE_modifier_set_error(ob, md, "Not supported in dyntopo");
}
else {
BKE_modifier_set_error(ob, md, "Not supported in sculpt mode");
}
continue;
}
}
if (need_mapping && !BKE_modifier_supports_mapping(md)) {
continue;
}
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
blender::bke::ScopedModifierTimer modifier_timer{*md};
/* Add orco mesh as layer if needed by this modifier. */
if (mesh_final && mesh_orco && mti->required_data_mask) {
CustomData_MeshMasks mask = {0};
mti->required_data_mask(md, &mask);
if (mask.vmask & CD_MASK_ORCO) {
add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO);
}
}
if (mti->type == ModifierTypeType::OnlyDeform) {
if (!mesh_final) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
}
BKE_modifier_deform_verts(md, &mectx, mesh_final, mesh_final->vert_positions_for_write());
}
else {
bool check_for_needs_mapping = false;
if (mesh_final != nullptr) {
if (have_non_onlydeform_modifiers_applied == false) {
/* If we only deformed, we won't have initialized #CD_ORIGINDEX.
* as this is the only part of the function that initializes mapping. */
check_for_needs_mapping = true;
}
}
else {
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
check_for_needs_mapping = true;
}
have_non_onlydeform_modifiers_applied = true;
/* determine which data layers are needed by following modifiers */
CustomData_MeshMasks nextmask = md_datamask->next ? md_datamask->next->mask : final_datamask;
if (check_for_needs_mapping) {
/* Initialize original indices the first time we evaluate a
* constructive modifier. Modifiers will then do mapping mostly
* automatic by copying them through CustomData_copy_data along
* with other data.
*
* These are created when either requested by evaluation, or if
* following modifiers requested them. */
if (need_mapping ||
((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) {
/* calc */
CustomData_add_layer(
&mesh_final->vert_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totvert);
CustomData_add_layer(
&mesh_final->edge_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totedge);
CustomData_add_layer(
&mesh_final->face_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->faces_num);
/* Not worth parallelizing this,
* gives less than 0.1% overall speedup in best of best cases... */
range_vn_i((int *)CustomData_get_layer_for_write(
&mesh_final->vert_data, CD_ORIGINDEX, mesh_final->totvert),
mesh_final->totvert,
0);
range_vn_i((int *)CustomData_get_layer_for_write(
&mesh_final->edge_data, CD_ORIGINDEX, mesh_final->totedge),
mesh_final->totedge,
0);
range_vn_i((int *)CustomData_get_layer_for_write(
&mesh_final->face_data, CD_ORIGINDEX, mesh_final->faces_num),
mesh_final->faces_num,
0);
}
}
/* set the Mesh to only copy needed data */
CustomData_MeshMasks mask = md_datamask->mask;
/* needMapping check here fixes bug #28112, otherwise it's
* possible that it won't be copied */
CustomData_MeshMasks_update(&mask, &append_mask);
if (need_mapping) {
mask.vmask |= CD_MASK_ORIGINDEX;
mask.emask |= CD_MASK_ORIGINDEX;
mask.pmask |= CD_MASK_ORIGINDEX;
}
mesh_set_only_copy(mesh_final, &mask);
/* add cloth rest shape key if needed */
if (mask.vmask & CD_MASK_CLOTH_ORCO) {
add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_CLOTH_ORCO);
}
/* add an origspace layer if needed */
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
if (!CustomData_has_layer(&mesh_final->loop_data, CD_ORIGSPACE_MLOOP)) {
CustomData_add_layer(
&mesh_final->loop_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh_final->totloop);
mesh_init_origspace(mesh_final);
}
}
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(
md, mectx, mesh_final, geometry_set_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
/* if the modifier returned a new mesh, release the old one */
if (mesh_final != mesh_next) {
BLI_assert(mesh_final != mesh_input);
BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_next;
}
/* create an orco mesh in parallel */
if (nextmask.vmask & CD_MASK_ORCO) {
if (!mesh_orco) {
mesh_orco = create_orco_mesh(ob, mesh_input, nullptr, CD_ORCO);
}
nextmask.vmask &= ~CD_MASK_ORCO;
CustomData_MeshMasks temp_cddata_masks = {0};
temp_cddata_masks.vmask = CD_MASK_ORIGINDEX;
temp_cddata_masks.emask = CD_MASK_ORIGINDEX;
temp_cddata_masks.fmask = CD_MASK_ORIGINDEX;
temp_cddata_masks.pmask = CD_MASK_ORIGINDEX;
if (mti->required_data_mask != nullptr) {
mti->required_data_mask(md, &temp_cddata_masks);
}
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
/* if the modifier returned a new mesh, release the old one */
if (mesh_orco != mesh_next) {
BLI_assert(mesh_orco != mesh_input);
BKE_id_free(nullptr, mesh_orco);
}
mesh_orco = mesh_next;
}
}
/* create cloth orco mesh in parallel */
if (nextmask.vmask & CD_MASK_CLOTH_ORCO) {
if (!mesh_orco_cloth) {
mesh_orco_cloth = create_orco_mesh(ob, mesh_input, nullptr, CD_CLOTH_ORCO);
}
nextmask.vmask &= ~CD_MASK_CLOTH_ORCO;
nextmask.vmask |= CD_MASK_ORIGINDEX;
nextmask.emask |= CD_MASK_ORIGINDEX;
nextmask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
/* if the modifier returned a new mesh, release the old one */
if (mesh_orco_cloth != mesh_next) {
BLI_assert(mesh_orco != mesh_input);
BKE_id_free(nullptr, mesh_orco_cloth);
}
mesh_orco_cloth = mesh_next;
}
}
/* in case of dynamic paint, make sure preview mask remains for following modifiers */
/* XXX Temp and hackish solution! */
if (md->type == eModifierType_DynamicPaint) {
append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL;
}
mesh_final->runtime->deformed_only = false;
}
if (sculpt_mode && md->type == eModifierType_Multires) {
multires_applied = true;
}
}
BLI_linklist_free((LinkNode *)datamasks, nullptr);
for (md = firstmd; md; md = md->next) {
BKE_modifier_free_temporary_data(md);
}
if (mesh_final == nullptr) {
if (allow_shared_mesh) {
mesh_final = mesh_input;
}
else {
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
}
}
/* Denotes whether the object which the modifier stack came from owns the mesh or whether the
* mesh is shared across multiple objects since there are no effective modifiers. */
const bool is_own_mesh = (mesh_final != mesh_input);
/* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) {
/* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case
* matches input mesh. */
if (is_own_mesh) {
add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO);
}
if (mesh_deform) {
add_orco_mesh(ob, nullptr, mesh_deform, nullptr, CD_ORCO);
}
}
if (mesh_orco) {
BKE_id_free(nullptr, mesh_orco);
}
if (mesh_orco_cloth) {
BKE_id_free(nullptr, mesh_orco_cloth);
}
/* Remove temporary data layer only needed for modifier evaluation.
* Save some memory, and ensure GPU subdivision does not need to deal with this. */
CustomData_free_layers(&mesh_final->vert_data, CD_CLOTH_ORCO, mesh_final->totvert);
/* Compute normals. */
if (is_own_mesh) {
mesh_calc_finalize(mesh_input, mesh_final);
}
else {
blender::bke::MeshRuntime *runtime = mesh_input->runtime;
if (runtime->mesh_eval == nullptr) {
std::lock_guard lock{mesh_input->runtime->eval_mutex};
if (runtime->mesh_eval == nullptr) {
/* Not yet finalized by any instance, do it now
* Isolate since computing normals is multithreaded and we are holding a lock. */
blender::threading::isolate_task([&] {
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
mesh_calc_finalize(mesh_input, mesh_final);
runtime->mesh_eval = mesh_final;
});
}
else {
/* Already finalized by another instance, reuse. */
mesh_final = runtime->mesh_eval;
}
}
else {
/* Already finalized by another instance, reuse. */
mesh_final = runtime->mesh_eval;
}
}
/* Return final mesh */
*r_final = mesh_final;
if (r_deform) {
*r_deform = mesh_deform;
}
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
if (r_geometry_set) {
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
}
}
static blender::Array<float3> editbmesh_vert_coords_alloc(const BMEditMesh *em)
- added data arguments to deformer modifiers, in case someone wants to write one that is based on geometry (and not just vertex position) - added editmode versions of modifier deform/apply calls and flag to tag modifiers that support editmode - added isFinalCalc param to applyModifier, basically a switch to let subsurf know if it is calc'ng orco or not (so it can deal with cache appropriately). This is kinda hacky and perhaps I can come up with a better solution (its also a waste to do a complete subdivide just to get vertex locations). - changed ccgsubsurf to not preallocate hash's to be approximately correct size... this was probably not a big performance savings but means that the order of faces returned by the iterator can vary after the first call, this messes up orco calculation so dropped for time being. - minor bug fix, meshes with only key didn't get vertex normals correctly calc'd - updated editmesh derivedmesh to support auxiliary locations - changed mesh_calc_modifiers to alloc deformVerts on demand - added editmesh_calc_modifiers for calculating editmesh cage and final derivedmesh's - bug fix, update shadedisplist to always calc colors (even if totvert==0) - changed load_editMesh and make_edge to build me->medge even if totedge==0 (incremental subsurf checks this) todo: add drawFacesTex for ccgderivedmesh So, modifiers in editmode are back (which means auto-mirror in edit mode works now) although still not finished. Currently no cage is computed, the cage is always the base mesh (in other words, Optimal edge style editing is off), and the final mesh currently includes all modifiers that work in edit mode (including lattice and curve). At some point there will be toggles for which modifiers affect the final/cage editmode derivedmesh's. Also, very nice new feature is that incremental subsurf in object mode returns a ccgderivedmesh object instead of copying to a new displistmesh. This can make a *huge* speed difference, and is very nice for working with deformed armatures (esp. with only small per frame changes).
2005-07-22 09:37:15 +02:00
{
blender::Array<float3> cos(em->bm->totvert);
BMIter iter;
BMVert *eve;
int i;
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
cos[i] = eve->co;
- added data arguments to deformer modifiers, in case someone wants to write one that is based on geometry (and not just vertex position) - added editmode versions of modifier deform/apply calls and flag to tag modifiers that support editmode - added isFinalCalc param to applyModifier, basically a switch to let subsurf know if it is calc'ng orco or not (so it can deal with cache appropriately). This is kinda hacky and perhaps I can come up with a better solution (its also a waste to do a complete subdivide just to get vertex locations). - changed ccgsubsurf to not preallocate hash's to be approximately correct size... this was probably not a big performance savings but means that the order of faces returned by the iterator can vary after the first call, this messes up orco calculation so dropped for time being. - minor bug fix, meshes with only key didn't get vertex normals correctly calc'd - updated editmesh derivedmesh to support auxiliary locations - changed mesh_calc_modifiers to alloc deformVerts on demand - added editmesh_calc_modifiers for calculating editmesh cage and final derivedmesh's - bug fix, update shadedisplist to always calc colors (even if totvert==0) - changed load_editMesh and make_edge to build me->medge even if totedge==0 (incremental subsurf checks this) todo: add drawFacesTex for ccgderivedmesh So, modifiers in editmode are back (which means auto-mirror in edit mode works now) although still not finished. Currently no cage is computed, the cage is always the base mesh (in other words, Optimal edge style editing is off), and the final mesh currently includes all modifiers that work in edit mode (including lattice and curve). At some point there will be toggles for which modifiers affect the final/cage editmode derivedmesh's. Also, very nice new feature is that incremental subsurf in object mode returns a ccgderivedmesh object instead of copying to a new displistmesh. This can make a *huge* speed difference, and is very nice for working with deformed armatures (esp. with only small per frame changes).
2005-07-22 09:37:15 +02:00
}
2005-10-09 18:59:10 +02:00
return cos;
- added data arguments to deformer modifiers, in case someone wants to write one that is based on geometry (and not just vertex position) - added editmode versions of modifier deform/apply calls and flag to tag modifiers that support editmode - added isFinalCalc param to applyModifier, basically a switch to let subsurf know if it is calc'ng orco or not (so it can deal with cache appropriately). This is kinda hacky and perhaps I can come up with a better solution (its also a waste to do a complete subdivide just to get vertex locations). - changed ccgsubsurf to not preallocate hash's to be approximately correct size... this was probably not a big performance savings but means that the order of faces returned by the iterator can vary after the first call, this messes up orco calculation so dropped for time being. - minor bug fix, meshes with only key didn't get vertex normals correctly calc'd - updated editmesh derivedmesh to support auxiliary locations - changed mesh_calc_modifiers to alloc deformVerts on demand - added editmesh_calc_modifiers for calculating editmesh cage and final derivedmesh's - bug fix, update shadedisplist to always calc colors (even if totvert==0) - changed load_editMesh and make_edge to build me->medge even if totedge==0 (incremental subsurf checks this) todo: add drawFacesTex for ccgderivedmesh So, modifiers in editmode are back (which means auto-mirror in edit mode works now) although still not finished. Currently no cage is computed, the cage is always the base mesh (in other words, Optimal edge style editing is off), and the final mesh currently includes all modifiers that work in edit mode (including lattice and curve). At some point there will be toggles for which modifiers affect the final/cage editmode derivedmesh's. Also, very nice new feature is that incremental subsurf in object mode returns a ccgderivedmesh object instead of copying to a new displistmesh. This can make a *huge* speed difference, and is very nice for working with deformed armatures (esp. with only small per frame changes).
2005-07-22 09:37:15 +02:00
}
bool editbmesh_modifier_is_enabled(const Scene *scene,
const Object *ob,
ModifierData *md,
bool has_prev_mesh)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
return false;
}
if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
BKE_modifier_set_error(ob, md, "Modifier requires original data, bad stack position");
2014-12-01 17:11:18 +01:00
return false;
}
2014-12-01 17:11:18 +01:00
return true;
}
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final)
{
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
switch (mesh_final->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
break;
case ME_WRAPPER_TYPE_BMESH: {
BMEditMesh *em = mesh_final->edit_mesh;
blender::bke::EditMeshData *emd = mesh_final->runtime->edit_data;
if (!emd->vertexCos.is_empty()) {
BKE_editmesh_cache_ensure_vert_normals(em, emd);
BKE_editmesh_cache_ensure_face_normals(em, emd);
}
return;
}
}
}
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
static void editbmesh_calc_modifier_final_normals_or_defer(Mesh *mesh_final)
{
if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) {
/* Generated at draw time. */
mesh_final->runtime->wrapper_type_finalize = eMeshWrapperType(
1 << mesh_final->runtime->wrapper_type);
return;
}
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
editbmesh_calc_modifier_final_normals(mesh_final);
}
static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
{
switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data->vertexCos.is_empty()) {
mesh->runtime->edit_data->vertexCos = editbmesh_vert_coords_alloc(mesh->edit_mesh);
}
return mesh->runtime->edit_data->vertexCos;
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD:
return mesh->vert_positions_for_write();
}
BLI_assert_unreachable();
return {};
}
static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
BMEditMesh *em_input,
const CustomData_MeshMasks *dataMask,
/* return args */
Mesh **r_cage,
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
Mesh **r_final,
GeometrySet **r_geometry_set)
{
Mesh *mesh_input = (Mesh *)ob->data;
Mesh *mesh_cage = nullptr;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
GeometrySet geometry_set_final;
/* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested
* for texturing. */
Mesh *mesh_orco = nullptr;
/* Modifier evaluation modes. */
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
/* Modifier evaluation contexts for different types of modifiers. */
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : ModifierApplyFlag(0);
const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | apply_render};
const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
VirtualModifierData virtual_modifier_data;
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data);
/* Compute accumulated datamasks needed by each modifier. It helps to do
* this fine grained so that for example vertex groups are preserved up to
* an armature modifier, but not through a following subsurf modifier where
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, md, &final_datamask, required_mode, nullptr, nullptr);
CDMaskLink *md_datamask = datamasks;
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
Mesh *mesh_final = BKE_mesh_wrapper_from_editmesh(em_input, &final_datamask, mesh_input);
int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true);
if (r_cage && cageIndex == -1) {
mesh_cage = mesh_final;
}
Mesh: Avoid creating incorrect original index layers Currently, whenever any BMesh is converted to a Mesh (except for edit mode switching), original index (`CD_ORIGINDEX`) layers are added. This is incorrect, because many operations just convert some Mesh into a BMesh and then back, but they shouldn't make any assumption about where their input mesh came from. It might even come from a primitive in geometry nodes, where there are no original indices at all. Conceptually, mesh original indices should be filled by the modifier stack when first creating the evaluated mesh. So that's where they're moved in this patch. A separate function now fills the indices with their default (0,1,2,3...) values. The way the mesh wrapper system defers the BMesh to Mesh conversion makes this a bit less obvious though. The old behavior is incorrect, but it's also slower, because three arrays the size of the mesh's vertices, edges, and faces had to be allocated and filled during the BMesh to Mesh conversion, which just ends up putting more pressure on the cache. In the many cases where original indices aren't used, I measured an **8% speedup** for the conversion (from 76.5ms to 70.7ms). Generally there is an assumption that BMesh is "original" and Mesh is "evaluated". After this patch, that assumption isn't quite as strong, but it still exists for two reasons. First, original indices are added whenever converting a BMesh "wrapper" to a Mesh. Second, original indices are not added to the BMesh at the beginning of evaluation, which assumes that every BMesh in the viewport is original and doesn't need the mapping. Differential Revision: https://developer.blender.org/D14018
2022-02-18 17:51:00 +01:00
/* The mesh from edit mode should not have any original index layers already, since those
* are added during evaluation when necessary and are redundant on an original mesh. */
BLI_assert(CustomData_get_layer(&em_input->bm->pdata, CD_ORIGINDEX) == nullptr &&
CustomData_get_layer(&em_input->bm->edata, CD_ORIGINDEX) == nullptr &&
CustomData_get_layer(&em_input->bm->pdata, CD_ORIGINDEX) == nullptr);
/* Clear errors before evaluation. */
BKE_modifiers_clear_errors(ob);
if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
BKE_mesh_wrapper_ensure_mdata(mesh_final);
set_rest_position(*mesh_final);
}
bool non_deform_modifier_applied = false;
for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (!editbmesh_modifier_is_enabled(scene, ob, md, non_deform_modifier_applied)) {
continue;
}
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
blender::bke::ScopedModifierTimer modifier_timer{*md};
/* Add an orco mesh as layer if needed by this modifier. */
if (mesh_orco && mti->required_data_mask) {
CustomData_MeshMasks mask = {0};
mti->required_data_mask(md, &mask);
if (mask.vmask & CD_MASK_ORCO) {
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
}
}
if (mesh_final == mesh_cage) {
/* If the cage mesh has already been assigned, we have passed the cage index in the modifier
* list. If the cage and final meshes are still the same, duplicate the final mesh so the
* cage mesh isn't modified anymore. */
mesh_final = BKE_mesh_copy_for_eval(mesh_final);
if (mesh_cage->edit_mesh) {
mesh_final->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(mesh_cage->edit_mesh));
mesh_final->edit_mesh->is_shallow_copy = true;
mesh_final->runtime->is_original_bmesh = true;
BKE_mesh_runtime_ensure_edit_data(mesh_final);
}
}
if (mti->type == ModifierTypeType::OnlyDeform) {
if (mti->deform_verts_EM) {
BKE_modifier_deform_vertsEM(md,
&mectx,
em_input,
mesh_final,
mesh_wrapper_vert_coords_ensure_for_write(mesh_final));
BKE_mesh_wrapper_tag_positions_changed(mesh_final);
}
else {
BKE_mesh_wrapper_ensure_mdata(mesh_final);
BKE_modifier_deform_verts(md, &mectx, mesh_final, mesh_final->vert_positions_for_write());
BKE_mesh_tag_positions_changed(mesh_final);
}
}
else {
non_deform_modifier_applied = true;
/* create an orco derivedmesh in parallel */
CustomData_MeshMasks mask = md_datamask->mask;
if (mask.vmask & CD_MASK_ORCO) {
if (!mesh_orco) {
mesh_orco = create_orco_mesh(ob, mesh_input, em_input, CD_ORCO);
}
mask.vmask &= ~CD_MASK_ORCO;
mask.vmask |= CD_MASK_ORIGINDEX;
mask.emask |= CD_MASK_ORIGINDEX;
mask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco, &mask);
Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
/* if the modifier returned a new dm, release the old one */
if (mesh_orco && mesh_orco != mesh_next) {
BKE_id_free(nullptr, mesh_orco);
}
mesh_orco = mesh_next;
}
}
/* set the DerivedMesh to only copy needed data */
CustomData_MeshMasks_update(&mask, &append_mask);
/* XXX WHAT? overwrites mask ??? */
/* CD_MASK_ORCO may have been cleared above */
mask = md_datamask->mask;
mask.vmask |= CD_MASK_ORIGINDEX;
mask.emask |= CD_MASK_ORIGINDEX;
mask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_final, &mask);
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
if (!CustomData_has_layer(&mesh_final->loop_data, CD_ORIGSPACE_MLOOP)) {
CustomData_add_layer(
&mesh_final->loop_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh_final->totloop);
mesh_init_origspace(mesh_final);
}
}
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(
md, mectx, mesh_final, geometry_set_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
if (mesh_final != mesh_next) {
BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_next;
}
mesh_final->runtime->deformed_only = false;
}
if (r_cage && i == cageIndex) {
mesh_cage = mesh_final;
- added data arguments to deformer modifiers, in case someone wants to write one that is based on geometry (and not just vertex position) - added editmode versions of modifier deform/apply calls and flag to tag modifiers that support editmode - added isFinalCalc param to applyModifier, basically a switch to let subsurf know if it is calc'ng orco or not (so it can deal with cache appropriately). This is kinda hacky and perhaps I can come up with a better solution (its also a waste to do a complete subdivide just to get vertex locations). - changed ccgsubsurf to not preallocate hash's to be approximately correct size... this was probably not a big performance savings but means that the order of faces returned by the iterator can vary after the first call, this messes up orco calculation so dropped for time being. - minor bug fix, meshes with only key didn't get vertex normals correctly calc'd - updated editmesh derivedmesh to support auxiliary locations - changed mesh_calc_modifiers to alloc deformVerts on demand - added editmesh_calc_modifiers for calculating editmesh cage and final derivedmesh's - bug fix, update shadedisplist to always calc colors (even if totvert==0) - changed load_editMesh and make_edge to build me->medge even if totedge==0 (incremental subsurf checks this) todo: add drawFacesTex for ccgderivedmesh So, modifiers in editmode are back (which means auto-mirror in edit mode works now) although still not finished. Currently no cage is computed, the cage is always the base mesh (in other words, Optimal edge style editing is off), and the final mesh currently includes all modifiers that work in edit mode (including lattice and curve). At some point there will be toggles for which modifiers affect the final/cage editmode derivedmesh's. Also, very nice new feature is that incremental subsurf in object mode returns a ccgderivedmesh object instead of copying to a new displistmesh. This can make a *huge* speed difference, and is very nice for working with deformed armatures (esp. with only small per frame changes).
2005-07-22 09:37:15 +02:00
}
}
BLI_linklist_free((LinkNode *)datamasks, nullptr);
/* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) {
/* FIXME(@ideasman42): avoid the need to convert to mesh data just to add an orco layer. */
BKE_mesh_wrapper_ensure_mdata(mesh_final);
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
}
if (mesh_orco) {
BKE_id_free(nullptr, mesh_orco);
}
/* Compute normals. */
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
editbmesh_calc_modifier_final_normals_or_defer(mesh_final);
if (mesh_cage && (mesh_cage != mesh_final)) {
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
editbmesh_calc_modifier_final_normals_or_defer(mesh_cage);
}
/* Return final mesh. */
*r_final = mesh_final;
if (r_cage) {
*r_cage = mesh_cage;
}
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
if (r_geometry_set) {
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
}
- added data arguments to deformer modifiers, in case someone wants to write one that is based on geometry (and not just vertex position) - added editmode versions of modifier deform/apply calls and flag to tag modifiers that support editmode - added isFinalCalc param to applyModifier, basically a switch to let subsurf know if it is calc'ng orco or not (so it can deal with cache appropriately). This is kinda hacky and perhaps I can come up with a better solution (its also a waste to do a complete subdivide just to get vertex locations). - changed ccgsubsurf to not preallocate hash's to be approximately correct size... this was probably not a big performance savings but means that the order of faces returned by the iterator can vary after the first call, this messes up orco calculation so dropped for time being. - minor bug fix, meshes with only key didn't get vertex normals correctly calc'd - updated editmesh derivedmesh to support auxiliary locations - changed mesh_calc_modifiers to alloc deformVerts on demand - added editmesh_calc_modifiers for calculating editmesh cage and final derivedmesh's - bug fix, update shadedisplist to always calc colors (even if totvert==0) - changed load_editMesh and make_edge to build me->medge even if totedge==0 (incremental subsurf checks this) todo: add drawFacesTex for ccgderivedmesh So, modifiers in editmode are back (which means auto-mirror in edit mode works now) although still not finished. Currently no cage is computed, the cage is always the base mesh (in other words, Optimal edge style editing is off), and the final mesh currently includes all modifiers that work in edit mode (including lattice and curve). At some point there will be toggles for which modifiers affect the final/cage editmode derivedmesh's. Also, very nice new feature is that incremental subsurf in object mode returns a ccgderivedmesh object instead of copying to a new displistmesh. This can make a *huge* speed difference, and is very nice for working with deformed armatures (esp. with only small per frame changes).
2005-07-22 09:37:15 +02:00
}
static void mesh_build_extra_data(Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval)
{
uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
BKE_shrinkwrap_compute_boundary_data(mesh_eval);
}
}
static void mesh_build_data(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask,
const bool need_mapping)
- 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 22:30:33 +02:00
{
#if 0 /* XXX This is already taken care of in #mesh_calc_modifiers... */
if (need_mapping) {
/* Also add the flag so that it is recorded in lastDataMask. */
dataMask->vmask |= CD_MASK_ORIGINDEX;
dataMask->emask |= CD_MASK_ORIGINDEX;
dataMask->pmask |= CD_MASK_ORIGINDEX;
}
#endif
Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
GeometrySet *geometry_set_eval = nullptr;
mesh_calc_modifiers(depsgraph,
scene,
ob,
2021-07-01 02:08:24 +02:00
true,
need_mapping,
dataMask,
true,
true,
&mesh_deform_eval,
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
&mesh_eval,
&geometry_set_eval);
/* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result
* is not guaranteed to be owned by object.
*
* Check ownership now, since later on we can not go to a mesh owned by someone else via
* object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns
* the final result might be freed prior to object). */
Mesh *mesh = (Mesh *)ob->data;
const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime->mesh_eval);
BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned);
/* Add the final mesh as a non-owning component to the geometry set. */
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>();
mesh_component.replace(mesh_eval, GeometryOwnershipType::Editable);
ob->runtime->geometry_set_eval = geometry_set_eval;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
ob->runtime->mesh_deform_eval = mesh_deform_eval;
ob->runtime->last_data_mask = *dataMask;
ob->runtime->last_need_mapping = need_mapping;
BKE_object_boundbox_calc_from_mesh(ob, mesh_eval);
/* Make sure that drivers can target shapekey properties.
* Note that this causes a potential inconsistency, as the shapekey may have a
* different topology than the evaluated mesh. */
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
mesh_eval->key = mesh->key;
if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
if (DEG_is_active(depsgraph)) {
BKE_sculpt_update_object_after_eval(depsgraph, ob);
}
}
mesh_build_extra_data(depsgraph, ob, mesh_eval);
- 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 22:30:33 +02:00
}
static void editbmesh_build_data(Depsgraph *depsgraph,
const Scene *scene,
Object *obedit,
BMEditMesh *em,
CustomData_MeshMasks *dataMask)
- 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 22:30:33 +02:00
{
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
Mesh *mesh = static_cast<Mesh *>(obedit->data);
Mesh *me_cage;
Mesh *me_final;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
GeometrySet *non_mesh_components;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
editbmesh_calc_modifiers(
depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
/* The modifier stack result is expected to share edit mesh pointer with the input.
* This is similar `mesh_calc_finalize()`. */
BKE_mesh_free_editmesh(me_final);
BKE_mesh_free_editmesh(me_cage);
me_final->edit_mesh = me_cage->edit_mesh = em;
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
* with is in edit mode).
* Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
* edit mode. */
if (!(obedit->mode & OB_MODE_EDIT)) {
BKE_mesh_wrapper_ensure_mdata(me_final);
if (me_final != me_cage) {
BKE_mesh_wrapper_ensure_mdata(me_cage);
}
}
const bool is_mesh_eval_owned = (me_final != mesh->runtime->mesh_eval);
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
/* Make sure that drivers can target shapekey properties.
* Note that this causes a potential inconsistency, as the shapekey may have a
* different topology than the evaluated mesh. */
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
me_final->key = mesh->key;
obedit->runtime->editmesh_eval_cage = me_cage;
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
obedit->runtime->geometry_set_eval = non_mesh_components;
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
BKE_object_boundbox_calc_from_mesh(obedit, me_final);
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 05:28:02 +01:00
obedit->runtime->last_data_mask = *dataMask;
}
static void object_get_datamask(const Depsgraph *depsgraph,
Object *ob,
CustomData_MeshMasks *r_mask,
bool *r_need_mapping)
{
ViewLayer: Lazy sync of scene data. When a change happens which invalidates view layers the syncing will be postponed until the first usage. This will improve importing or adding many objects in a single operation/script. `BKE_view_layer_need_resync_tag` is used to tag the view layer to be out of sync. Before accessing `BKE_view_layer_active_base_get`, `BKE_view_layer_active_object_get`, `BKE_view_layer_active_collection` or `BKE_view_layer_object_bases` the caller should call `BKE_view_layer_synced_ensure`. Having two functions ensures that partial syncing could be added as smaller patches in the future. Tagging a view layer out of sync could be replaced with a partial sync. Eventually the number of full resyncs could be reduced. After all tagging has been replaced with partial syncs the ensure_sync could be phased out. This patch has been added to discuss the details and consequences of the current approach. For clarity the call to BKE_view_layer_ensure_sync is placed close to the getters. In the future this could be placed in more strategical places to reduce the number of calls or improve performance. Finding those strategical places isn't that clear. When multiple operations are grouped in a single script you might want to always check for resync. Some areas found that can be improved. This list isn't complete. These areas aren't addressed by this patch as these changes would be hard to detect to the reviewer. The idea is to add changes to these areas as a separate patch. It might be that the initial commit would reduce performance compared to master, but will be fixed by the additional patches. **Object duplication** During object duplication the syncing is temporarily disabled. With this patch this isn't useful as when disabled the view_layer is accessed to locate bases. This can be improved by first locating the source bases, then duplicate and sync and locate the new bases. Will be solved in a separate patch for clarity reasons ({D15886}). **Object add** `BKE_object_add` not only adds a new object, but also selects and activates the new base. This requires the view_layer to be resynced. Some callers reverse the selection and activation (See `get_new_constraint_target`). We should make the selection and activation optional. This would make it possible to add multiple objects without having to resync per object. **Postpone Activate Base** Setting the basact is done in many locations. They follow a rule as after an action find the base and set the basact. Finding the base could require a resync. The idea is to store in the view_layer the object which base will be set in the basact during the next sync, reducing the times resyncing needs to happen. Reviewed By: mont29 Maniphest Tasks: T73411 Differential Revision: https://developer.blender.org/D15885
2022-09-14 21:33:51 +02:00
Scene *scene = DEG_get_evaluated_scene(depsgraph);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
DEG_get_customdata_mask_for_object(depsgraph, ob, r_mask);
if (r_need_mapping) {
*r_need_mapping = false;
}
/* Must never access original objects when dependency graph is not active: it might be already
* freed. */
if (!DEG_is_active(depsgraph)) {
return;
}
ViewLayer: Lazy sync of scene data. When a change happens which invalidates view layers the syncing will be postponed until the first usage. This will improve importing or adding many objects in a single operation/script. `BKE_view_layer_need_resync_tag` is used to tag the view layer to be out of sync. Before accessing `BKE_view_layer_active_base_get`, `BKE_view_layer_active_object_get`, `BKE_view_layer_active_collection` or `BKE_view_layer_object_bases` the caller should call `BKE_view_layer_synced_ensure`. Having two functions ensures that partial syncing could be added as smaller patches in the future. Tagging a view layer out of sync could be replaced with a partial sync. Eventually the number of full resyncs could be reduced. After all tagging has been replaced with partial syncs the ensure_sync could be phased out. This patch has been added to discuss the details and consequences of the current approach. For clarity the call to BKE_view_layer_ensure_sync is placed close to the getters. In the future this could be placed in more strategical places to reduce the number of calls or improve performance. Finding those strategical places isn't that clear. When multiple operations are grouped in a single script you might want to always check for resync. Some areas found that can be improved. This list isn't complete. These areas aren't addressed by this patch as these changes would be hard to detect to the reviewer. The idea is to add changes to these areas as a separate patch. It might be that the initial commit would reduce performance compared to master, but will be fixed by the additional patches. **Object duplication** During object duplication the syncing is temporarily disabled. With this patch this isn't useful as when disabled the view_layer is accessed to locate bases. This can be improved by first locating the source bases, then duplicate and sync and locate the new bases. Will be solved in a separate patch for clarity reasons ({D15886}). **Object add** `BKE_object_add` not only adds a new object, but also selects and activates the new base. This requires the view_layer to be resynced. Some callers reverse the selection and activation (See `get_new_constraint_target`). We should make the selection and activation optional. This would make it possible to add multiple objects without having to resync per object. **Postpone Activate Base** Setting the basact is done in many locations. They follow a rule as after an action find the base and set the basact. Finding the base could require a resync. The idea is to store in the view_layer the object which base will be set in the basact during the next sync, reducing the times resyncing needs to happen. Reviewed By: mont29 Maniphest Tasks: T73411 Differential Revision: https://developer.blender.org/D15885
2022-09-14 21:33:51 +02:00
BKE_view_layer_synced_ensure(scene, view_layer);
Object *actob = BKE_view_layer_active_object_get(view_layer);
if (actob) {
actob = DEG_get_original_object(actob);
}
if (DEG_get_original_object(ob) == actob) {
bool editing = BKE_paint_select_face_test(actob);
/* weight paint and face select need original indices because of selection buffer drawing */
if (r_need_mapping) {
*r_need_mapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)));
}
2023-11-09 23:24:19 +01:00
/* Check if we need #MTFace & loop-color due to face select or texture paint. */
if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
Mesh: Move UV layers to generic attributes Currently the `MLoopUV` struct stores UV coordinates and flags related to editing UV maps in the UV editor. This patch changes the coordinates to use the generic 2D vector type, and moves the flags into three separate boolean attributes. This follows the design in T95965, with the ultimate intention of simplifying code and improving performance. Importantly, the change allows exporters and renderers to use UVs "touched" by geometry nodes, which only creates generic attributes. It also allows geometry nodes to create "proper" UV maps from scratch, though only with the Store Named Attribute node for now. The new design considers any 2D vector attribute on the corner domain to be a UV map. In the future, they might be distinguished from regular 2D vectors with attribute metadata, which may be helpful because they are often interpolated differently. Most of the code changes deal with passing around UV BMesh custom data offsets and tracking the boolean "sublayers". The boolean layers are use the following prefixes for attribute names: vert selection: `.vs.`, edge selection: `.es.`, pinning: `.pn.`. Currently these are short to avoid using up the maximum length of attribute names. To accommodate for these 4 extra characters, the name length limit is enlarged to 68 bytes, while the maximum user settable name length is still 64 bytes. Unfortunately Python/RNA API access to the UV flag data becomes slower. Accessing the boolean layers directly is be better for performance in general. Like the other mesh SoA refactors, backward and forward compatibility aren't affected, and won't be changed until 4.0. We pay for that by making mesh reading and writing more expensive with conversions. Resolves T85962 Differential Revision: https://developer.blender.org/D14365
2023-01-10 06:47:04 +01:00
r_mask->lmask |= CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_BYTE_COLOR;
r_mask->fmask |= CD_MASK_MTFACE;
}
/* Check if we need mcols due to vertex paint or weight-paint. */
if (ob->mode & OB_MODE_VERTEX_PAINT) {
r_mask->lmask |= CD_MASK_PROP_BYTE_COLOR;
}
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
r_mask->vmask |= CD_MASK_MDEFORMVERT;
}
if (ob->mode & OB_MODE_EDIT) {
r_mask->vmask |= CD_MASK_MVERT_SKIN;
}
}
}
void makeDerivedMesh(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
BLI_assert(ob->type == OB_MESH);
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
* they aren't cleaned up properly on mode switch, causing crashes, e.g #58150. */
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
BKE_object_free_derived_caches(ob);
if (DEG_is_active(depsgraph)) {
BKE_sculpt_update_object_before_eval(ob);
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
}
/* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
* to the pre-evaluated state. This is because the evaluated state is not necessarily sharing the
* `edit_mesh` pointer with the input. For example, if the object is first evaluated in the
* object mode, and then user in another scene moves object to edit mode. */
BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
bool need_mapping;
CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
if (em) {
editbmesh_build_data(depsgraph, scene, ob, em, &cddata_masks);
}
else {
mesh_build_data(depsgraph, scene, ob, &cddata_masks, need_mapping);
- 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 22:30:33 +02:00
}
}
/***/
Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
if (em != nullptr) {
/* There is no such a concept as deformed mesh in edit mode.
* Explicitly disallow this request so that the evaluated result is not modified with evaluated
* result from the wrong mode. */
BLI_assert_msg(0, "Request of derformed mesh of object which is in edit mode");
return nullptr;
}
/* This function isn't thread-safe and can't be used during evaluation. */
BLI_assert(DEG_is_evaluating(depsgraph) == false);
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
* they aren't cleaned up properly on mode switch, causing crashes, e.g #58150. */
BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
if (!ob->runtime->mesh_deform_eval ||
!CustomData_MeshMasks_are_matching(&(ob->runtime->last_data_mask), &cddata_masks) ||
(need_mapping && !ob->runtime->last_need_mapping))
{
CustomData_MeshMasks_update(&cddata_masks, &ob->runtime->last_data_mask);
mesh_build_data(
depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime->last_need_mapping);
}
return ob->runtime->mesh_deform_eval;
}
Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
const Scene *scene,
2020-08-20 08:09:48 +02:00
Object *ob,
const CustomData_MeshMasks *dataMask)
{
Mesh *result;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
mesh_calc_modifiers(
depsgraph, scene, ob, true, false, dataMask, false, false, nullptr, &result, nullptr);
return result;
}
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
Mesh *result;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
mesh_calc_modifiers(
depsgraph, scene, ob, false, false, dataMask, false, false, nullptr, &result, nullptr);
return result;
}
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
Mesh *result;
Geometry Nodes: support evaluating mesh object to geometry set This implements the design proposed in T83357. The goal is to allow the geometry nodes modifier on mesh objects to output instances and potentially other geometry types. Both problems are tackled by allowing mesh objects to evaluate to a geometry set, instead of just a single mesh id data block. The geometry set can contain a mesh but also other data like instances and a point cloud. I can't say that I'm sure that this commit won't introduce bugs. Mainly the temporary object creation during rendering seems a bit brittle. BUT, we can be reasonably sure that this commit will not introduce regressions (at least not ones, that are hard to fix). This is because the code has been written in a way that minimizes changes for existing functionality. Given that we intend to hide the point cloud object for the next release, we won't even have to worry about temporary object creation for now. An important part of the technical design is to make sure that `ObjectRuntime->data_eval` contains the same data before and after this patch. This helps to make sure, that existing code paths are impacted as little as possible. Instead of fully replacing `data_eval`, there is `geometry_set_eval`, which contains all the geometry components an object evaluated to (including the data referenced by `data_eval`). For now, not much code has to be aware of `geometry_set_eval`. Mainly the depsgraph object iterator and the instances system have to know about it. Reviewers: brecht Differential Revision: https://developer.blender.org/D9851
2020-12-15 12:42:10 +01:00
mesh_calc_modifiers(
depsgraph, scene, ob, false, false, dataMask, false, false, nullptr, &result, nullptr);
return result;
}
/***/
Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
const Scene *scene,
Object *obedit,
BMEditMesh *em,
const CustomData_MeshMasks *dataMask)
{
CustomData_MeshMasks cddata_masks = *dataMask;
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
if (!obedit->runtime->editmesh_eval_cage ||
!CustomData_MeshMasks_are_matching(&(obedit->runtime->last_data_mask), &cddata_masks))
Fix depsgraphs sharing IDs via evaluated edit mesh The evaluated mesh is a result of evaluated modifiers, and referencing other evaluated IDs such as materials. It can not be stored in the EditMesh structure which is intended to be re-used by many areas. Such sharing was causing ownership errors causing bugs like T93855: Cycles crash with edit mode and simultaneous viewport and final render The proposed solution is to store the evaluated edit mesh and its cage in the object's runtime field. The motivation goes as following: - It allows to avoid ownership problems like the ones in the linked report. - Object level is chosen over mesh level is because the evaluated mesh is affected by modifiers, which are on the object level. This patch allows to have modifier stack of an object which shares mesh with an object which is in edit mode to be properly taken into account (before the change the modifier stack from the active object will be used for all objects which share the mesh). There is a change in the way how copy-on-write is handled in the edit mode to allow proper state update when changing active scene (or having two windows with different scenes). Previously, the copt-on-write would have been ignored by skipping tagging CoW component. Now it is ignored from within the CoW operation callback. This allows to update edit pointers for objects which are not from the current depsgraph and where the edit_mesh was never assigned in the case when the depsgraph was evaluated prior the active depsgraph. There is no user level changes changes expected with the CoW handling changes: should not affect on neither performance, nor memory consumption. Tested scenarios: - Various modifiers configurations of objects sharing mesh and be part of the same scene. - Steps from the reports: T93855, T82952, T77359 This also fixes T76609, T72733 and perhaps other reports. Differential Revision: https://developer.blender.org/D13824
2022-01-11 15:42:07 +01:00
{
editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
}
return obedit->runtime->editmesh_eval_cage;
}
Mesh *editbmesh_get_eval_cage_from_orig(Depsgraph *depsgraph,
const Scene *scene,
Object *obedit,
const CustomData_MeshMasks *dataMask)
{
BLI_assert((obedit->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
const Scene *scene_eval = (const Scene *)DEG_get_evaluated_id(depsgraph, (ID *)&scene->id);
Object *obedit_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obedit->id);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
return editbmesh_get_eval_cage(depsgraph, scene_eval, obedit_eval, em_eval, dataMask);
}
/***/
/* same as above but for vert coords */
struct MappedUserData {
float (*vertexcos)[3];
BLI_bitmap *vertex_visit;
};
static void make_vertexcos__mapFunc(void *user_data,
int index,
const float co[3],
const float /*no*/[3])
{
MappedUserData *mappedData = (MappedUserData *)user_data;
if (BLI_BITMAP_TEST(mappedData->vertex_visit, index) == 0) {
/* we need coord from prototype vertex, not from copies,
* assume they stored in the beginning of vertex array stored in DM
* (mirror modifier for eg does this) */
copy_v3_v3(mappedData->vertexcos[index], co);
BLI_BITMAP_ENABLE(mappedData->vertex_visit, index);
}
}
void mesh_get_mapped_verts_coords(Mesh *me_eval, blender::MutableSpan<blender::float3> r_cos)
{
if (me_eval->runtime->deformed_only == false) {
MappedUserData user_data;
r_cos.fill(float3(0));
user_data.vertexcos = reinterpret_cast<float(*)[3]>(r_cos.data());
user_data.vertex_visit = BLI_BITMAP_NEW(r_cos.size(), "vertexcos flags");
BKE_mesh_foreach_mapped_vert(me_eval, make_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP);
MEM_freeN(user_data.vertex_visit);
}
else {
r_cos.copy_from(me_eval->vert_positions());
}
}
static void mesh_init_origspace(Mesh *mesh)
{
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
OrigSpaceLoop *lof_array = (OrigSpaceLoop *)CustomData_get_layer_for_write(
&mesh->loop_data, CD_ORIGSPACE_MLOOP, mesh->totloop);
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 06:10:43 +01:00
const Span<float3> positions = mesh->vert_positions();
const blender::OffsetIndices faces = mesh->faces();
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
const Span<int> corner_verts = mesh->corner_verts();
Mesh: Remove redundant custom data pointers For copy-on-write, we want to share attribute arrays between meshes where possible. Mutable pointers like `Mesh.mvert` make that difficult by making ownership vague. They also make code more complex by adding redundancy. The simplest solution is just removing them and retrieving layers from `CustomData` as needed. Similar changes have already been applied to curves and point clouds (e9f82d3dc7ee, 410a6efb747f). Removing use of the pointers generally makes code more obvious and more reusable. Mesh data is now accessed with a C++ API (`Mesh::edges()` or `Mesh::edges_for_write()`), and a C API (`BKE_mesh_edges(mesh)`). The CoW changes this commit makes possible are described in T95845 and T95842, and started in D14139 and D14140. The change also simplifies the ongoing mesh struct-of-array refactors from T95965. **RNA/Python Access Performance** Theoretically, accessing mesh elements with the RNA API may become slower, since the layer needs to be found on every random access. However, overhead is already high enough that this doesn't make a noticible differenc, and performance is actually improved in some cases. Random access can be up to 10% faster, but other situations might be a bit slower. Generally using `foreach_get/set` are the best way to improve performance. See the differential revision for more discussion about Python performance. Cycles has been updated to use raw pointers and the internal Blender mesh types, mostly because there is no sense in having this overhead when it's already compiled with Blender. In my tests this roughly halves the Cycles mesh creation time (0.19s to 0.10s for a 1 million face grid). Differential Revision: https://developer.blender.org/D15488
2022-09-05 18:56:34 +02:00
int j, k;
blender::Vector<blender::float2, 64> vcos_2d;
for (const int i : faces.index_range()) {
const blender::IndexRange face = faces[i];
OrigSpaceLoop *lof = lof_array + face.start();
if (ELEM(face.size(), 3, 4)) {
for (j = 0; j < face.size(); j++, lof++) {
copy_v2_v2(lof->uv, default_osf[j]);
}
}
else {
float co[3];
float mat[3][3];
float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
float translate[2], scale[2];
const float3 p_nor = blender::bke::mesh::face_normal_calc(positions,
corner_verts.slice(face));
axis_dominant_v3_to_m3(mat, p_nor);
vcos_2d.resize(face.size());
for (j = 0; j < face.size(); j++) {
mul_v3_m3v3(co, mat, positions[corner_verts[face[j]]]);
copy_v2_v2(vcos_2d[j], co);
for (k = 0; k < 2; k++) {
if (co[k] > max[k]) {
max[k] = co[k];
}
else if (co[k] < min[k]) {
min[k] = co[k];
}
}
}
/* Brings min to (0, 0). */
negate_v2_v2(translate, min);
/* Scale will bring max to (1, 1). */
sub_v2_v2v2(scale, max, min);
if (scale[0] == 0.0f) {
scale[0] = 1e-9f;
}
if (scale[1] == 0.0f) {
scale[1] = 1e-9f;
}
invert_v2(scale);
/* Finally, transform all vcos_2d into ((0, 0), (1, 1))
* square and assign them as origspace. */
for (j = 0; j < face.size(); j++, lof++) {
add_v2_v2v2(lof->uv, vcos_2d[j], translate);
mul_v2_v2(lof->uv, scale);
}
}
}
BKE_mesh_tessface_clear(mesh);
}