2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2018-05-25 22:24:24 +05:30
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup modifiers
|
2018-05-25 22:24:24 +05:30
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2020-02-26 14:24:57 +11:00
|
|
|
#include "BLI_bitmap.h"
|
2019-02-25 11:39:14 +01:00
|
|
|
#include "BLI_linklist.h"
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
|
|
2020-06-05 10:41:03 -04:00
|
|
|
#include "BLT_translation.h"
|
|
|
|
|
|
2020-10-01 09:38:00 -05:00
|
|
|
#include "DNA_defaults.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
#include "DNA_mesh_types.h"
|
2020-02-26 14:24:57 +11:00
|
|
|
#include "DNA_meshdata_types.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
2020-06-05 10:41:03 -04:00
|
|
|
#include "DNA_screen_types.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
|
2020-06-05 10:41:03 -04:00
|
|
|
#include "BKE_context.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
#include "BKE_deform.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_id.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
#include "BKE_mesh.h"
|
2020-06-05 10:41:03 -04:00
|
|
|
#include "BKE_screen.h"
|
|
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
|
|
|
|
#include "UI_resources.h"
|
|
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
2022-03-14 16:54:46 +01:00
|
|
|
#include "RNA_prototypes.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
#include "MOD_modifiertypes.h"
|
2020-06-05 10:41:03 -04:00
|
|
|
#include "MOD_ui_common.h"
|
2018-05-25 22:24:24 +05:30
|
|
|
#include "MOD_util.h"
|
|
|
|
|
|
2019-05-20 08:51:18 -04:00
|
|
|
#include "bmesh.h"
|
|
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
#define CLNORS_VALID_VEC_LEN (1e-6f)
|
|
|
|
|
|
|
|
|
|
typedef struct ModePair {
|
|
|
|
|
float val; /* Contains mode based value (face area / corner angle). */
|
|
|
|
|
int index; /* Index value per poly or per loop. */
|
|
|
|
|
} ModePair;
|
|
|
|
|
|
|
|
|
|
/* Sorting function used in modifier, sorts in decreasing order. */
|
|
|
|
|
static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
|
|
|
|
|
{
|
|
|
|
|
ModePair *r1 = (ModePair *)p1;
|
|
|
|
|
ModePair *r2 = (ModePair *)p2;
|
|
|
|
|
|
|
|
|
|
return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 07:40:07 +10:00
|
|
|
/* There will be one of those per vertex
|
|
|
|
|
* (simple case, computing one normal per vertex), or per smooth fan. */
|
2018-05-25 22:24:24 +05:30
|
|
|
typedef struct WeightedNormalDataAggregateItem {
|
|
|
|
|
float normal[3];
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
int loops_num; /* Count number of loops using this item so far. */
|
2018-05-25 22:24:24 +05:30
|
|
|
float curr_val; /* Current max val for this item. */
|
|
|
|
|
int curr_strength; /* Current max strength encountered for this item. */
|
|
|
|
|
} WeightedNormalDataAggregateItem;
|
|
|
|
|
|
|
|
|
|
#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
|
|
|
|
|
|
|
|
|
|
typedef struct WeightedNormalData {
|
2022-03-28 12:29:47 +11:00
|
|
|
const int verts_num;
|
|
|
|
|
const int edges_num;
|
|
|
|
|
const int loops_num;
|
|
|
|
|
const int polys_num;
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
MVert *mvert;
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
const float (*vert_normals)[3];
|
2018-05-25 22:24:24 +05:30
|
|
|
MEdge *medge;
|
|
|
|
|
|
|
|
|
|
MLoop *mloop;
|
|
|
|
|
short (*clnors)[2];
|
|
|
|
|
const bool has_clnors; /* True if clnors already existed, false if we had to create them. */
|
|
|
|
|
const float split_angle;
|
|
|
|
|
|
|
|
|
|
MPoly *mpoly;
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
const float (*polynors)[3];
|
2022-05-13 18:31:29 +02:00
|
|
|
const int *poly_strength;
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
MDeformVert *dvert;
|
|
|
|
|
const int defgrp_index;
|
|
|
|
|
const bool use_invert_vgroup;
|
|
|
|
|
|
|
|
|
|
const float weight;
|
|
|
|
|
const short mode;
|
|
|
|
|
|
|
|
|
|
/* Lower-level, internal processing data. */
|
|
|
|
|
float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT];
|
|
|
|
|
|
|
|
|
|
WeightedNormalDataAggregateItem *items_data;
|
|
|
|
|
|
|
|
|
|
ModePair *mode_pair;
|
|
|
|
|
|
|
|
|
|
int *loop_to_poly;
|
|
|
|
|
} WeightedNormalData;
|
|
|
|
|
|
2019-05-01 07:40:07 +10:00
|
|
|
/**
|
|
|
|
|
* Check strength of given poly compared to those found so far for that given item
|
|
|
|
|
* (vertex or smooth fan), and reset matching item_data in case we get a stronger new strength.
|
|
|
|
|
*/
|
2018-05-25 22:24:24 +05:30
|
|
|
static bool check_item_poly_strength(WeightedNormalData *wn_data,
|
|
|
|
|
WeightedNormalDataAggregateItem *item_data,
|
|
|
|
|
const int mp_index)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(wn_data->poly_strength != NULL);
|
|
|
|
|
|
|
|
|
|
const int mp_strength = wn_data->poly_strength[mp_index];
|
|
|
|
|
|
|
|
|
|
if (mp_strength > item_data->curr_strength) {
|
|
|
|
|
item_data->curr_strength = mp_strength;
|
|
|
|
|
item_data->curr_val = 0.0f;
|
2022-03-28 12:29:47 +11:00
|
|
|
item_data->loops_num = 0;
|
2018-05-25 22:24:24 +05:30
|
|
|
zero_v3(item_data->normal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mp_strength == item_data->curr_strength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aggregate_item_normal(WeightedNormalModifierData *wnmd,
|
|
|
|
|
WeightedNormalData *wn_data,
|
|
|
|
|
WeightedNormalDataAggregateItem *item_data,
|
|
|
|
|
const int mv_index,
|
|
|
|
|
const int mp_index,
|
|
|
|
|
const float curr_val,
|
|
|
|
|
const bool use_face_influence)
|
|
|
|
|
{
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
const float(*polynors)[3] = wn_data->polynors;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MDeformVert *dvert = wn_data->dvert;
|
|
|
|
|
const int defgrp_index = wn_data->defgrp_index;
|
|
|
|
|
const bool use_invert_vgroup = wn_data->use_invert_vgroup;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
const float weight = wn_data->weight;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
const bool has_vgroup = dvert != NULL;
|
|
|
|
|
const bool vert_of_group = has_vgroup &&
|
2020-03-06 12:50:56 +11:00
|
|
|
BKE_defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
if (has_vgroup &&
|
|
|
|
|
((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
/* If item's curr_val is 0 init it to present value. */
|
|
|
|
|
if (item_data->curr_val == 0.0f) {
|
|
|
|
|
item_data->curr_val = curr_val;
|
|
|
|
|
}
|
|
|
|
|
if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
|
|
|
|
|
/* item's curr_val and present value differ more than threshold, update. */
|
2022-03-28 12:29:47 +11:00
|
|
|
item_data->loops_num++;
|
2018-05-25 22:24:24 +05:30
|
|
|
item_data->curr_val = curr_val;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:40:07 +10:00
|
|
|
/* Exponentially divided weight for each normal
|
|
|
|
|
* (since a few values will be used by most cases, we cache those). */
|
2022-03-28 12:29:47 +11:00
|
|
|
const int loops_num = item_data->loops_num;
|
|
|
|
|
if (loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT &&
|
|
|
|
|
cached_inverse_powers_of_weight[loops_num] == 0.0f) {
|
|
|
|
|
cached_inverse_powers_of_weight[loops_num] = 1.0f / powf(weight, loops_num);
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
2022-03-28 12:29:47 +11:00
|
|
|
const float inverted_n_weight = loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
|
|
|
|
|
cached_inverse_powers_of_weight[loops_num] :
|
|
|
|
|
1.0f / powf(weight, loops_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
|
|
|
|
WeightedNormalData *wn_data)
|
|
|
|
|
{
|
2022-03-28 12:29:47 +11:00
|
|
|
const int verts_num = wn_data->verts_num;
|
|
|
|
|
const int edges_num = wn_data->edges_num;
|
|
|
|
|
const int loops_num = wn_data->loops_num;
|
|
|
|
|
const int polys_num = wn_data->polys_num;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MVert *mvert = wn_data->mvert;
|
|
|
|
|
MEdge *medge = wn_data->medge;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MLoop *mloop = wn_data->mloop;
|
|
|
|
|
short(*clnors)[2] = wn_data->clnors;
|
|
|
|
|
int *loop_to_poly = wn_data->loop_to_poly;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MPoly *mpoly = wn_data->mpoly;
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
const float(*polynors)[3] = wn_data->polynors;
|
2022-05-13 18:31:29 +02:00
|
|
|
const int *poly_strength = wn_data->poly_strength;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MDeformVert *dvert = wn_data->dvert;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
const short mode = wn_data->mode;
|
|
|
|
|
ModePair *mode_pair = wn_data->mode_pair;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
const bool has_clnors = wn_data->has_clnors;
|
|
|
|
|
const float split_angle = wn_data->split_angle;
|
|
|
|
|
MLoopNorSpaceArray lnors_spacearr = {NULL};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
|
|
|
|
|
const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 &&
|
|
|
|
|
poly_strength != NULL;
|
|
|
|
|
const bool has_vgroup = dvert != NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
float(*loop_normals)[3] = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
WeightedNormalDataAggregateItem *items_data = NULL;
|
2022-03-28 12:29:47 +11:00
|
|
|
int items_num = 0;
|
2018-05-25 22:24:24 +05:30
|
|
|
if (keep_sharp) {
|
2022-03-28 12:29:47 +11:00
|
|
|
BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_num, __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:40:07 +10:00
|
|
|
/* This will give us loop normal spaces,
|
|
|
|
|
* we do not actually care about computed loop_normals for now... */
|
2022-03-28 12:29:47 +11:00
|
|
|
loop_normals = MEM_calloc_arrayN((size_t)loops_num, sizeof(*loop_normals), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
BKE_mesh_normals_loop_split(mvert,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
wn_data->vert_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
verts_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
medge,
|
2022-03-28 12:29:47 +11:00
|
|
|
edges_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mloop,
|
|
|
|
|
loop_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
loops_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mpoly,
|
|
|
|
|
polynors,
|
2022-03-28 12:29:47 +11:00
|
|
|
polys_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
true,
|
|
|
|
|
split_angle,
|
|
|
|
|
&lnors_spacearr,
|
|
|
|
|
has_clnors ? clnors : NULL,
|
|
|
|
|
loop_to_poly);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
items_num = lnors_spacearr.spaces_num;
|
|
|
|
|
items_data = MEM_calloc_arrayN((size_t)items_num, sizeof(*items_data), __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-05 08:39:20 +05:30
|
|
|
/* In this first loop, we assign each WeightedNormalDataAggregateItem
|
2018-09-02 18:28:27 +10:00
|
|
|
* to its smooth fan of loops (aka lnor space). */
|
2018-05-25 22:24:24 +05:30
|
|
|
MPoly *mp;
|
|
|
|
|
int mp_index;
|
|
|
|
|
int item_index;
|
2022-03-28 12:29:47 +11:00
|
|
|
for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < polys_num; mp++, mp_index++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
int ml_index = mp->loopstart;
|
|
|
|
|
const int ml_end_index = ml_index + mp->totloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
for (; ml_index < ml_end_index; ml_index++) {
|
|
|
|
|
if (BLI_BITMAP_TEST(done_loops, ml_index)) {
|
|
|
|
|
/* Smooth fan of this loop has already been processed, skip it. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-03-28 12:29:47 +11:00
|
|
|
BLI_assert(item_index < items_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
|
|
|
|
|
itdt->curr_strength = FACE_STRENGTH_WEAK;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
|
|
|
|
|
lnor_space->user_data = itdt;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
|
|
|
|
|
for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
|
2018-09-19 12:14:36 +10:00
|
|
|
const int ml_fan_index = POINTER_AS_INT(lnode->link);
|
2018-05-25 22:24:24 +05:30
|
|
|
BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_BITMAP_ENABLE(done_loops, ml_index);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
item_index++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MEM_freeN(done_loops);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-03-28 12:29:47 +11:00
|
|
|
items_num = verts_num;
|
|
|
|
|
items_data = MEM_calloc_arrayN((size_t)items_num, sizeof(*items_data), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
if (use_face_influence) {
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int item_index = 0; item_index < items_num; item_index++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
|
|
|
|
wn_data->items_data = items_data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
switch (mode) {
|
|
|
|
|
case MOD_WEIGHTEDNORMAL_MODE_FACE:
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int i = 0; i < polys_num; i++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
const int mp_index = mode_pair[i].index;
|
|
|
|
|
const float mp_val = mode_pair[i].val;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
int ml_index = mpoly[mp_index].loopstart;
|
|
|
|
|
const int ml_index_end = ml_index + mpoly[mp_index].totloop;
|
|
|
|
|
for (; ml_index < ml_index_end; ml_index++) {
|
|
|
|
|
const int mv_index = mloop[ml_index].v;
|
|
|
|
|
WeightedNormalDataAggregateItem *item_data =
|
|
|
|
|
keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
aggregate_item_normal(
|
|
|
|
|
wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2018-05-25 22:24:24 +05:30
|
|
|
case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
|
|
|
|
|
case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
|
|
|
|
|
BLI_assert(loop_to_poly != NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int i = 0; i < loops_num; i++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
const int ml_index = mode_pair[i].index;
|
|
|
|
|
const float ml_val = mode_pair[i].val;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
const int mp_index = loop_to_poly[ml_index];
|
|
|
|
|
const int mv_index = mloop[ml_index].v;
|
|
|
|
|
WeightedNormalDataAggregateItem *item_data =
|
|
|
|
|
keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
aggregate_item_normal(
|
|
|
|
|
wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2022-05-17 15:12:12 +02:00
|
|
|
BLI_assert_unreachable();
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
/* Validate computed weighted normals. */
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int item_index = 0; item_index < items_num; item_index++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
|
|
|
|
|
zero_v3(items_data[item_index].normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
if (keep_sharp) {
|
|
|
|
|
/* Set loop normals for normal computed for each lnor space (smooth fan).
|
2019-05-01 07:40:07 +10:00
|
|
|
* Note that loop_normals is already populated with clnors
|
|
|
|
|
* (before this modifier is applied, at start of this function),
|
|
|
|
|
* so no need to recompute them here. */
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int ml_index = 0; ml_index < loops_num; ml_index++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
|
|
|
|
|
if (!is_zero_v3(item_data->normal)) {
|
|
|
|
|
copy_v3_v3(loop_normals[ml_index], item_data->normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
BKE_mesh_normals_loop_custom_set(mvert,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
wn_data->vert_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
verts_num,
|
2019-04-17 06:17:24 +02:00
|
|
|
medge,
|
2022-03-28 12:29:47 +11:00
|
|
|
edges_num,
|
2019-04-17 06:17:24 +02:00
|
|
|
mloop,
|
2018-05-25 22:24:24 +05:30
|
|
|
loop_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
loops_num,
|
2019-04-17 06:17:24 +02:00
|
|
|
mpoly,
|
2018-05-25 22:24:24 +05:30
|
|
|
polynors,
|
2022-03-28 12:29:47 +11:00
|
|
|
polys_num,
|
2019-04-17 06:17:24 +02:00
|
|
|
clnors);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-05-01 07:40:07 +10:00
|
|
|
/* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set()
|
2020-02-13 14:01:52 +11:00
|
|
|
* to keep current clnors instead of resetting them to default auto-computed ones,
|
2019-05-01 07:40:07 +10:00
|
|
|
* when given new custom normal is zero-vec.
|
2018-05-25 22:24:24 +05:30
|
|
|
* But this is not exactly trivial change, better to keep this optimization for later...
|
|
|
|
|
*/
|
|
|
|
|
if (!has_vgroup) {
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: in theory, we could avoid this extra allocation & copying...
|
2019-05-01 07:40:07 +10:00
|
|
|
* But think we can live with it for now,
|
2018-05-25 22:24:24 +05:30
|
|
|
* and it makes code simpler & cleaner. */
|
|
|
|
|
float(*vert_normals)[3] = MEM_calloc_arrayN(
|
2022-03-28 12:29:47 +11:00
|
|
|
(size_t)verts_num, sizeof(*loop_normals), __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int ml_index = 0; ml_index < loops_num; ml_index++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
const int mv_index = mloop[ml_index].v;
|
|
|
|
|
copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
BKE_mesh_normals_loop_custom_from_vertices_set(mvert,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
wn_data->vert_normals,
|
2018-05-25 22:24:24 +05:30
|
|
|
vert_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
verts_num,
|
2019-04-17 06:17:24 +02:00
|
|
|
medge,
|
2022-03-28 12:29:47 +11:00
|
|
|
edges_num,
|
2019-04-17 06:17:24 +02:00
|
|
|
mloop,
|
2022-03-28 12:29:47 +11:00
|
|
|
loops_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mpoly,
|
|
|
|
|
polynors,
|
2022-03-28 12:29:47 +11:00
|
|
|
polys_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
clnors);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
MEM_freeN(vert_normals);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-05-25 22:24:24 +05:30
|
|
|
else {
|
2022-03-28 12:29:47 +11:00
|
|
|
loop_normals = MEM_calloc_arrayN((size_t)loops_num, sizeof(*loop_normals), __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
BKE_mesh_normals_loop_split(mvert,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
wn_data->vert_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
verts_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
medge,
|
2022-03-28 12:29:47 +11:00
|
|
|
edges_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mloop,
|
|
|
|
|
loop_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
loops_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mpoly,
|
|
|
|
|
polynors,
|
2022-03-28 12:29:47 +11:00
|
|
|
polys_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
true,
|
|
|
|
|
split_angle,
|
|
|
|
|
NULL,
|
|
|
|
|
has_clnors ? clnors : NULL,
|
|
|
|
|
loop_to_poly);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
for (int ml_index = 0; ml_index < loops_num; ml_index++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
const int item_index = mloop[ml_index].v;
|
|
|
|
|
if (!is_zero_v3(items_data[item_index].normal)) {
|
|
|
|
|
copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
BKE_mesh_normals_loop_custom_set(mvert,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
wn_data->vert_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
verts_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
medge,
|
2022-03-28 12:29:47 +11:00
|
|
|
edges_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mloop,
|
|
|
|
|
loop_normals,
|
2022-03-28 12:29:47 +11:00
|
|
|
loops_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
mpoly,
|
|
|
|
|
polynors,
|
2022-03-28 12:29:47 +11:00
|
|
|
polys_num,
|
2018-05-25 22:24:24 +05:30
|
|
|
clnors);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
if (keep_sharp) {
|
|
|
|
|
BKE_lnor_spacearr_free(&lnors_spacearr);
|
|
|
|
|
}
|
|
|
|
|
MEM_SAFE_FREE(loop_normals);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
|
|
|
|
{
|
2022-03-28 12:29:47 +11:00
|
|
|
const int polys_num = wn_data->polys_num;
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
MVert *mvert = wn_data->mvert;
|
|
|
|
|
MLoop *mloop = wn_data->mloop;
|
|
|
|
|
MPoly *mpoly = wn_data->mpoly;
|
|
|
|
|
|
|
|
|
|
MPoly *mp;
|
|
|
|
|
int mp_index;
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
ModePair *face_area = MEM_malloc_arrayN((size_t)polys_num, sizeof(*face_area), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
ModePair *f_area = face_area;
|
2022-03-28 12:29:47 +11:00
|
|
|
for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++, f_area++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
|
|
|
|
|
f_area->index = mp_index;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
qsort(face_area, polys_num, sizeof(*face_area), modepair_cmp_by_val_inverse);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
wn_data->mode_pair = face_area;
|
|
|
|
|
apply_weights_vertex_normal(wnmd, wn_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
|
|
|
|
{
|
2022-03-28 12:29:47 +11:00
|
|
|
const int loops_num = wn_data->loops_num;
|
|
|
|
|
const int polys_num = wn_data->polys_num;
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
MVert *mvert = wn_data->mvert;
|
|
|
|
|
MLoop *mloop = wn_data->mloop;
|
|
|
|
|
MPoly *mpoly = wn_data->mpoly;
|
|
|
|
|
|
|
|
|
|
MPoly *mp;
|
|
|
|
|
int mp_index;
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
int *loop_to_poly = MEM_malloc_arrayN((size_t)loops_num, sizeof(*loop_to_poly), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
ModePair *corner_angle = MEM_malloc_arrayN((size_t)loops_num, sizeof(*corner_angle), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
MLoop *ml_start = &mloop[mp->loopstart];
|
|
|
|
|
|
|
|
|
|
float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
|
|
|
|
|
BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
|
|
|
|
|
|
|
|
|
|
ModePair *c_angl = &corner_angle[mp->loopstart];
|
|
|
|
|
float *angl = index_angle;
|
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop;
|
|
|
|
|
ml_index++, c_angl++, angl++) {
|
|
|
|
|
c_angl->val = (float)M_PI - *angl;
|
|
|
|
|
c_angl->index = ml_index;
|
|
|
|
|
|
|
|
|
|
loop_to_poly[ml_index] = mp_index;
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(index_angle);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
qsort(corner_angle, loops_num, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
wn_data->loop_to_poly = loop_to_poly;
|
|
|
|
|
wn_data->mode_pair = corner_angle;
|
|
|
|
|
apply_weights_vertex_normal(wnmd, wn_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
|
|
|
|
{
|
2022-03-28 12:29:47 +11:00
|
|
|
const int loops_num = wn_data->loops_num;
|
|
|
|
|
const int polys_num = wn_data->polys_num;
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
MVert *mvert = wn_data->mvert;
|
|
|
|
|
MLoop *mloop = wn_data->mloop;
|
|
|
|
|
MPoly *mpoly = wn_data->mpoly;
|
|
|
|
|
|
|
|
|
|
MPoly *mp;
|
|
|
|
|
int mp_index;
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
int *loop_to_poly = MEM_malloc_arrayN((size_t)loops_num, sizeof(*loop_to_poly), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
ModePair *combined = MEM_malloc_arrayN((size_t)loops_num, sizeof(*combined), __func__);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) {
|
2018-05-25 22:24:24 +05:30
|
|
|
MLoop *ml_start = &mloop[mp->loopstart];
|
|
|
|
|
|
|
|
|
|
float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
|
|
|
|
|
float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
|
|
|
|
|
BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
|
|
|
|
|
|
|
|
|
|
ModePair *cmbnd = &combined[mp->loopstart];
|
|
|
|
|
float *angl = index_angle;
|
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop;
|
|
|
|
|
ml_index++, cmbnd++, angl++) {
|
|
|
|
|
/* In this case val is product of corner angle and face area. */
|
|
|
|
|
cmbnd->val = ((float)M_PI - *angl) * face_area;
|
|
|
|
|
cmbnd->index = ml_index;
|
|
|
|
|
|
|
|
|
|
loop_to_poly[ml_index] = mp_index;
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(index_angle);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
qsort(combined, loops_num, sizeof(*combined), modepair_cmp_by_val_inverse);
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
|
wn_data->loop_to_poly = loop_to_poly;
|
|
|
|
|
wn_data->mode_pair = combined;
|
|
|
|
|
apply_weights_vertex_normal(wnmd, wn_data);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-21 13:09:41 +02:00
|
|
|
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
2018-05-25 22:24:24 +05:30
|
|
|
{
|
|
|
|
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
|
|
|
|
Object *ob = ctx->object;
|
|
|
|
|
|
2019-05-01 07:40:07 +10:00
|
|
|
/* XXX TODO(Rohan Rathi):
|
|
|
|
|
* Once we fully switch to Mesh evaluation of modifiers,
|
|
|
|
|
* we can expect to get that flag from the COW copy.
|
|
|
|
|
* But for now, it is lost in the DM intermediate step,
|
|
|
|
|
* so we need to directly check orig object's data. */
|
2018-05-25 22:24:24 +05:30
|
|
|
#if 0
|
2019-05-01 07:34:41 +10:00
|
|
|
if (!(mesh->flag & ME_AUTOSMOOTH))
|
2018-05-25 22:24:24 +05:30
|
|
|
#else
|
2019-05-01 07:34:41 +10:00
|
|
|
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
|
2018-05-25 22:24:24 +05:30
|
|
|
#endif
|
2019-05-01 07:34:41 +10:00
|
|
|
{
|
2020-10-26 17:07:58 +11:00
|
|
|
BKE_modifier_set_error(
|
|
|
|
|
ctx->object, (ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
|
2019-05-01 07:34:41 +10:00
|
|
|
return mesh;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
Mesh *result;
|
2020-10-07 14:27:33 +02:00
|
|
|
result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-28 12:29:47 +11:00
|
|
|
const int verts_num = result->totvert;
|
|
|
|
|
const int edges_num = result->totedge;
|
|
|
|
|
const int loops_num = result->totloop;
|
|
|
|
|
const int polys_num = result->totpoly;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
MEdge *medge = result->medge;
|
|
|
|
|
MPoly *mpoly = result->mpoly;
|
|
|
|
|
MVert *mvert = result->mvert;
|
|
|
|
|
MLoop *mloop = result->mloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
/* Right now:
|
2019-05-01 07:40:07 +10:00
|
|
|
* If weight = 50 then all faces are given equal weight.
|
|
|
|
|
* If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
|
|
|
|
|
* If weight < 50 then more weight given to faces with lesser vals. However current calculation
|
|
|
|
|
* does not converge to min/max.
|
|
|
|
|
*/
|
2019-05-01 07:34:41 +10:00
|
|
|
float weight = ((float)wnmd->weight) / 50.0f;
|
|
|
|
|
if (wnmd->weight == 100) {
|
|
|
|
|
weight = (float)SHRT_MAX;
|
|
|
|
|
}
|
|
|
|
|
else if (wnmd->weight == 1) {
|
|
|
|
|
weight = 1 / (float)SHRT_MAX;
|
|
|
|
|
}
|
|
|
|
|
else if ((weight - 1) * 25 > 1) {
|
|
|
|
|
weight = (weight - 1) * 25;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
const float split_angle = mesh->smoothresh;
|
2022-05-13 18:31:29 +02:00
|
|
|
short(*clnors)[2] = CustomData_get_layer(&result->ldata, CD_CUSTOMLOOPNORMAL);
|
2019-05-01 07:34:41 +10:00
|
|
|
|
2021-07-23 16:56:00 +10:00
|
|
|
/* Keep info whether we had clnors,
|
2019-05-01 07:40:07 +10:00
|
|
|
* it helps when generating clnor spaces and default normals. */
|
2019-05-01 07:34:41 +10:00
|
|
|
const bool has_clnors = clnors != NULL;
|
|
|
|
|
if (!clnors) {
|
2022-05-13 18:31:29 +02:00
|
|
|
clnors = CustomData_add_layer(&result->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num);
|
2019-05-01 07:34:41 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
MDeformVert *dvert;
|
|
|
|
|
int defgrp_index;
|
|
|
|
|
MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
|
|
|
|
|
|
|
|
|
|
WeightedNormalData wn_data = {
|
2022-03-28 12:29:47 +11:00
|
|
|
.verts_num = verts_num,
|
|
|
|
|
.edges_num = edges_num,
|
|
|
|
|
.loops_num = loops_num,
|
|
|
|
|
.polys_num = polys_num,
|
2019-05-01 07:34:41 +10:00
|
|
|
|
|
|
|
|
.mvert = mvert,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
.vert_normals = BKE_mesh_vertex_normals_ensure(result),
|
2019-05-01 07:34:41 +10:00
|
|
|
.medge = medge,
|
|
|
|
|
|
|
|
|
|
.mloop = mloop,
|
|
|
|
|
.clnors = clnors,
|
|
|
|
|
.has_clnors = has_clnors,
|
|
|
|
|
.split_angle = split_angle,
|
|
|
|
|
|
|
|
|
|
.mpoly = mpoly,
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
.polynors = BKE_mesh_poly_normals_ensure(mesh),
|
2019-05-01 07:34:41 +10:00
|
|
|
.poly_strength = CustomData_get_layer_named(
|
2020-06-10 15:47:31 +02:00
|
|
|
&result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
|
2019-05-01 07:34:41 +10:00
|
|
|
|
|
|
|
|
.dvert = dvert,
|
|
|
|
|
.defgrp_index = defgrp_index,
|
|
|
|
|
.use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
|
|
|
|
|
|
|
|
|
|
.weight = weight,
|
|
|
|
|
.mode = wnmd->mode,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (wnmd->mode) {
|
|
|
|
|
case MOD_WEIGHTEDNORMAL_MODE_FACE:
|
|
|
|
|
wn_face_area(wnmd, &wn_data);
|
|
|
|
|
break;
|
|
|
|
|
case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
|
|
|
|
|
wn_corner_angle(wnmd, &wn_data);
|
|
|
|
|
break;
|
|
|
|
|
case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
|
|
|
|
|
wn_face_with_angle(wnmd, &wn_data);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
MEM_SAFE_FREE(wn_data.loop_to_poly);
|
|
|
|
|
MEM_SAFE_FREE(wn_data.mode_pair);
|
|
|
|
|
MEM_SAFE_FREE(wn_data.items_data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-11 21:46:06 +10:00
|
|
|
result->runtime.is_original = false;
|
|
|
|
|
|
2019-05-01 07:34:41 +10:00
|
|
|
return result;
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void initData(ModifierData *md)
|
|
|
|
|
{
|
|
|
|
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
2020-10-01 09:38:00 -05:00
|
|
|
|
|
|
|
|
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wnmd, modifier));
|
|
|
|
|
|
|
|
|
|
MEMCPY_STRUCT_AFTER(wnmd, DNA_struct_default_get(WeightedNormalModifierData), modifier);
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
|
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
static void requiredDataMask(Object *UNUSED(ob),
|
|
|
|
|
ModifierData *md,
|
|
|
|
|
CustomData_MeshMasks *r_cddata_masks)
|
2018-05-25 22:24:24 +05:30
|
|
|
{
|
|
|
|
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
|
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
r_cddata_masks->lmask = CD_MASK_CUSTOMLOOPNORMAL;
|
|
|
|
|
|
|
|
|
|
if (wnmd->defgrp_name[0] != '\0') {
|
|
|
|
|
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) {
|
2020-06-10 15:47:31 +02:00
|
|
|
r_cddata_masks->pmask |= CD_MASK_PROP_INT32;
|
2018-05-25 22:24:24 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool dependsOnNormals(ModifierData *UNUSED(md))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-02 14:13:26 -05:00
|
|
|
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
|
2020-06-05 10:41:03 -04:00
|
|
|
{
|
UI: Small Tweaks to Modifier Layouts for Consistency
These changes are smaller, made based on feedback and a pass on all
the layouts for clarity and consistency. The Multires modifier UI will
be addressed in a separate patch. Here is an overview of the changes:
Renaming Options:
- Build: "Start" -> "Start Frame"
- Curve: "From Radius" -> "Size from Radius"
- Screw: "Calc Order" -> "Calculate Order"
- Displace, Warp, Wave: "Texture Coordinates Object" -> "Object"
Move Mode Toggle to Top & Expand:
- Bevel, Boolean, Normal Edit, Subdivision
Use Columns for Tighter Spacing:
- Displace, Explode, Ocean, Particle Instance, Remesh, Shrinkwrap,
Solidify, Warp, Weighted Normal, Wave
Misc:
- Bevel: Set inactive properties for vertex bevel
- Mesh Sequence Cache: Remove box for cache file
- Skin: Don't align "Mark Loose" and "Clear Loose"
- Array: Expand relative offset subpanel by default
- Array: Move start cap, end cap to a new subpanel
- Bevel: Move width type above width
Differential Revision: https://developer.blender.org/D8115
2020-07-02 10:47:02 -04:00
|
|
|
uiLayout *col;
|
2020-06-05 10:41:03 -04:00
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
PointerRNA ob_ptr;
|
2020-09-02 14:13:26 -05:00
|
|
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
2020-06-05 10:41:03 -04:00
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
|
|
|
|
|
2020-09-02 14:13:26 -05:00
|
|
|
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
|
2020-06-05 10:41:03 -04:00
|
|
|
|
2020-09-02 14:13:26 -05:00
|
|
|
uiItemR(layout, ptr, "weight", 0, IFACE_("Weight"), ICON_NONE);
|
|
|
|
|
uiItemR(layout, ptr, "thresh", 0, IFACE_("Threshold"), ICON_NONE);
|
2020-06-05 10:41:03 -04:00
|
|
|
|
UI: Small Tweaks to Modifier Layouts for Consistency
These changes are smaller, made based on feedback and a pass on all
the layouts for clarity and consistency. The Multires modifier UI will
be addressed in a separate patch. Here is an overview of the changes:
Renaming Options:
- Build: "Start" -> "Start Frame"
- Curve: "From Radius" -> "Size from Radius"
- Screw: "Calc Order" -> "Calculate Order"
- Displace, Warp, Wave: "Texture Coordinates Object" -> "Object"
Move Mode Toggle to Top & Expand:
- Bevel, Boolean, Normal Edit, Subdivision
Use Columns for Tighter Spacing:
- Displace, Explode, Ocean, Particle Instance, Remesh, Shrinkwrap,
Solidify, Warp, Weighted Normal, Wave
Misc:
- Bevel: Set inactive properties for vertex bevel
- Mesh Sequence Cache: Remove box for cache file
- Skin: Don't align "Mark Loose" and "Clear Loose"
- Array: Expand relative offset subpanel by default
- Array: Move start cap, end cap to a new subpanel
- Bevel: Move width type above width
Differential Revision: https://developer.blender.org/D8115
2020-07-02 10:47:02 -04:00
|
|
|
col = uiLayoutColumn(layout, false);
|
2020-09-02 14:13:26 -05:00
|
|
|
uiItemR(col, ptr, "keep_sharp", 0, NULL, ICON_NONE);
|
2020-09-30 15:01:12 +10:00
|
|
|
uiItemR(col, ptr, "use_face_influence", 0, NULL, ICON_NONE);
|
2020-06-05 10:41:03 -04:00
|
|
|
|
2020-09-02 14:13:26 -05:00
|
|
|
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
|
2020-06-05 10:41:03 -04:00
|
|
|
|
2020-09-02 14:13:26 -05:00
|
|
|
modifier_panel_end(layout, ptr);
|
2020-06-05 10:41:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void panelRegister(ARegionType *region_type)
|
|
|
|
|
{
|
|
|
|
|
modifier_panel_register(region_type, eModifierType_WeightedNormal, panel_draw);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
ModifierTypeInfo modifierType_WeightedNormal = {
|
2020-06-05 10:41:03 -04:00
|
|
|
/* name */ "WeightedNormal",
|
2018-05-25 22:24:24 +05:30
|
|
|
/* structName */ "WeightedNormalModifierData",
|
|
|
|
|
/* structSize */ sizeof(WeightedNormalModifierData),
|
2020-09-25 12:49:18 +02:00
|
|
|
/* srna */ &RNA_WeightedNormalModifier,
|
2018-05-25 22:24:24 +05:30
|
|
|
/* type */ eModifierTypeType_Constructive,
|
|
|
|
|
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
|
|
|
|
|
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
|
2020-09-25 12:45:30 +02:00
|
|
|
/* icon */ ICON_MOD_VERTEX_WEIGHT,
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
/* copyData */ BKE_modifier_copydata_generic,
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
/* deformVerts */ NULL,
|
|
|
|
|
/* deformMatrices */ NULL,
|
|
|
|
|
/* deformVertsEM */ NULL,
|
|
|
|
|
/* deformMatricesEM */ NULL,
|
2020-04-21 13:09:41 +02:00
|
|
|
/* modifyMesh */ modifyMesh,
|
2020-12-10 14:35:02 +01:00
|
|
|
/* modifyGeometrySet */ NULL,
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-25 22:24:24 +05:30
|
|
|
/* initData */ initData,
|
|
|
|
|
/* requiredDataMask */ requiredDataMask,
|
|
|
|
|
/* freeData */ NULL,
|
|
|
|
|
/* isDisabled */ NULL,
|
|
|
|
|
/* updateDepsgraph */ NULL,
|
|
|
|
|
/* dependsOnTime */ NULL,
|
|
|
|
|
/* dependsOnNormals */ dependsOnNormals,
|
|
|
|
|
/* foreachIDLink */ NULL,
|
|
|
|
|
/* foreachTexLink */ NULL,
|
2019-03-18 15:56:16 +01:00
|
|
|
/* freeRuntimeData */ NULL,
|
2020-06-05 10:41:03 -04:00
|
|
|
/* panelRegister */ panelRegister,
|
2020-06-15 17:37:07 +02:00
|
|
|
/* blendWrite */ NULL,
|
|
|
|
|
/* blendRead */ NULL,
|
2018-05-25 22:24:24 +05:30
|
|
|
};
|