Currently the shade smooth status for mesh faces is stored as part of `MPoly::flag`. As described in #95967, this moves that information to a separate boolean attribute. It also flips its status, so the attribute is now called `sharp_face`, which mirrors the existing `sharp_edge` attribute. The attribute doesn't need to be allocated when all faces are smooth. Forward compatibility is kept until 4.0 like the other mesh refactors. This will reduce memory bandwidth requirements for some operations, since the array of booleans uses 12 times less memory than `MPoly`. It also allows faces to be stored more efficiently in the future, since the flag is now unused. It's also possible to use generic functions to process the values. For example, finding whether there is a sharp face is just `sharp_faces.contains(true)`. The `shade_smooth` attribute is no longer accessible with geometry nodes. Since there were dedicated accessor nodes for that data, that shouldn't be a problem. That's difficult to version automatically since the named attribute nodes could be used in arbitrary combinations. **Implementation notes:** - The attribute and array variables in the code use the `sharp_faces` term, to be consistent with the user-facing "sharp faces" wording, and to avoid requiring many renames when #101689 is implemented. - Cycles now accesses smooth face status with the generic attribute, to avoid overhead. - Changing the zero-value from "smooth" to "flat" takes some care to make sure defaults are the same. - Versioning for the edge mode extrude node is particularly complex. New nodes are added by versioning to propagate the attribute in its old inverted state. - A lot of access is still done through the `CustomData` API rather than the attribute API because of a few functions. That can be cleaned up easily in the future. - In the future we would benefit from a way to store attributes as a single value for when all faces are sharp. Pull Request: blender/blender#104422
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 struct MLoop *mloops,
|
|
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 struct MLoop *mloop,
|
|
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
|