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: blender/blender#104424
99 lines
4.3 KiB
C++
99 lines
4.3 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#pragma once
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
struct ReportList;
|
|
|
|
/**
|
|
* Compute simplified tangent space normals, i.e.
|
|
* tangent vector + sign of bi-tangent one, which combined with
|
|
* split normals can be used to recreate the full tangent space.
|
|
*
|
|
* \note The mesh should be made of only triangles and quads!
|
|
*/
|
|
void BKE_mesh_calc_loop_tangent_single_ex(const float (*vert_positions)[3],
|
|
int numVerts,
|
|
const int *corner_verts,
|
|
float (*r_looptangent)[4],
|
|
const float (*loop_normals)[3],
|
|
const float (*loopuv)[2],
|
|
int numLoops,
|
|
const struct MPoly *polys,
|
|
int numPolys,
|
|
struct ReportList *reports);
|
|
/**
|
|
* Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boilerplate code.
|
|
* \note
|
|
* - There must be a valid loop's CD_NORMALS available.
|
|
* - The mesh should be made of only triangles and quads!
|
|
*/
|
|
void BKE_mesh_calc_loop_tangent_single(struct Mesh *mesh,
|
|
const char *uvmap,
|
|
float (*r_looptangents)[4],
|
|
struct ReportList *reports);
|
|
|
|
/**
|
|
* See: #BKE_editmesh_loop_tangent_calc (matching logic).
|
|
*/
|
|
void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
|
|
const struct MPoly *polys,
|
|
uint polys_len,
|
|
const int *corner_verts,
|
|
const struct MLoopTri *looptri,
|
|
uint looptri_len,
|
|
const bool *sharp_faces,
|
|
|
|
struct CustomData *loopdata,
|
|
bool calc_active_tangent,
|
|
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
|
|
int tangent_names_len,
|
|
const float (*vert_normals)[3],
|
|
const float (*poly_normals)[3],
|
|
const float (*loop_normals)[3],
|
|
const float (*vert_orco)[3],
|
|
/* result */
|
|
struct CustomData *loopdata_out,
|
|
uint loopdata_out_len,
|
|
short *tangent_mask_curr_p);
|
|
|
|
void BKE_mesh_calc_loop_tangents(struct Mesh *me_eval,
|
|
bool calc_active_tangent,
|
|
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
|
|
int tangent_names_len);
|
|
|
|
/* Helpers */
|
|
void BKE_mesh_add_loop_tangent_named_layer_for_uv(struct CustomData *uv_data,
|
|
struct CustomData *tan_data,
|
|
int numLoopData,
|
|
const char *layer_name);
|
|
|
|
#define DM_TANGENT_MASK_ORCO (1 << 9)
|
|
/**
|
|
* Here we get some useful information such as active uv layer name and
|
|
* search if it is already in tangent_names.
|
|
* Also, we calculate tangent_mask that works as a descriptor of tangents state.
|
|
* If tangent_mask has changed, then recalculate tangents.
|
|
*/
|
|
void BKE_mesh_calc_loop_tangent_step_0(const struct CustomData *loopData,
|
|
bool calc_active_tangent,
|
|
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
|
|
int tangent_names_count,
|
|
bool *rcalc_act,
|
|
bool *rcalc_ren,
|
|
int *ract_uv_n,
|
|
int *rren_uv_n,
|
|
char *ract_uv_name,
|
|
char *rren_uv_name,
|
|
short *rtangent_mask);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|