Mesh: Replace auto smooth with node group #108014
|
@ -816,9 +816,10 @@ static void create_mesh(Scene *scene,
|
||||||
const blender::OffsetIndices faces = b_mesh.faces();
|
const blender::OffsetIndices faces = b_mesh.faces();
|
||||||
const blender::Span<int> corner_verts = b_mesh.corner_verts();
|
const blender::Span<int> corner_verts = b_mesh.corner_verts();
|
||||||
const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
|
const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
|
||||||
|
const blender::bke::MeshNormalDomain normals_domain = b_mesh.normals_domain();
|
||||||
int numfaces = (!subdivision) ? b_mesh.looptris().size() : faces.size();
|
int numfaces = (!subdivision) ? b_mesh.looptris().size() : faces.size();
|
||||||
|
|
||||||
bool use_loop_normals = (b_mesh.flag & ME_AUTOSMOOTH) &&
|
bool use_loop_normals = normals_domain == blender::bke::MeshNormalDomain::Corner &&
|
||||||
(mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
|
(mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
|
||||||
|
|
||||||
/* If no faces, create empty mesh. */
|
/* If no faces, create empty mesh. */
|
||||||
|
@ -832,9 +833,7 @@ static void create_mesh(Scene *scene,
|
||||||
ATTR_DOMAIN_FACE);
|
ATTR_DOMAIN_FACE);
|
||||||
blender::Span<blender::float3> corner_normals;
|
blender::Span<blender::float3> corner_normals;
|
||||||
if (use_loop_normals) {
|
if (use_loop_normals) {
|
||||||
corner_normals = {
|
corner_normals = b_mesh.corner_normals();
|
||||||
static_cast<const blender::float3 *>(CustomData_get_layer(&b_mesh.loop_data, CD_NORMAL)),
|
|
||||||
corner_verts.size()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int numngons = 0;
|
int numngons = 0;
|
||||||
|
@ -939,7 +938,8 @@ static void create_mesh(Scene *scene,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::fill(smooth, smooth + numtris, true);
|
/* If only face normals are needed, all faces are sharp. */
|
||||||
|
std::fill(smooth, smooth + numtris, normals_domain != blender::bke::MeshNormalDomain::Face);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_loop_normals && !corner_normals.is_empty()) {
|
if (use_loop_normals && !corner_normals.is_empty()) {
|
||||||
|
|
|
@ -95,7 +95,9 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||||
* Also in edit mode do we need to make a copy, to ensure data layers like
|
* Also in edit mode do we need to make a copy, to ensure data layers like
|
||||||
* UV are not empty. */
|
* UV are not empty. */
|
||||||
if (mesh.is_editmode() ||
|
if (mesh.is_editmode() ||
|
||||||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
|
(mesh.normals_domain() == BL::Mesh::normals_domain_CORNER &&
|
||||||
|
subdivision_type == Mesh::SUBDIVISION_NONE))
|
||||||
|
{
|
||||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||||
}
|
}
|
||||||
|
@ -119,8 +121,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
|
if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
|
||||||
if (mesh.use_auto_smooth()) {
|
if (mesh.normals_domain() == BL::Mesh::normals_domain_CORNER) {
|
||||||
mesh.calc_normals_split();
|
|
||||||
mesh.split_faces();
|
mesh.split_faces();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,33 +183,6 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel):
|
||||||
layout.template_ID(space, "pin_id")
|
layout.template_ID(space, "pin_id")
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_normals(MeshButtonsPanel, Panel):
|
|
||||||
bl_label = "Normals"
|
|
||||||
bl_options = {'DEFAULT_CLOSED'}
|
|
||||||
COMPAT_ENGINES = {
|
|
||||||
'BLENDER_RENDER',
|
|
||||||
'BLENDER_EEVEE',
|
|
||||||
'BLENDER_EEVEE_NEXT',
|
|
||||||
'BLENDER_WORKBENCH',
|
|
||||||
}
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
layout = self.layout
|
|
||||||
layout.use_property_split = True
|
|
||||||
|
|
||||||
mesh = context.mesh
|
|
||||||
|
|
||||||
col = layout.column(align=False, heading="Auto Smooth")
|
|
||||||
col.use_property_decorate = False
|
|
||||||
row = col.row(align=True)
|
|
||||||
sub = row.row(align=True)
|
|
||||||
sub.prop(mesh, "use_auto_smooth", text="")
|
|
||||||
sub = sub.row(align=True)
|
|
||||||
sub.active = mesh.use_auto_smooth and not mesh.has_custom_normals
|
|
||||||
sub.prop(mesh, "auto_smooth_angle", text="")
|
|
||||||
row.prop_decorator(mesh, "auto_smooth_angle")
|
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_texture_space(MeshButtonsPanel, Panel):
|
class DATA_PT_texture_space(MeshButtonsPanel, Panel):
|
||||||
bl_label = "Texture Space"
|
bl_label = "Texture Space"
|
||||||
bl_options = {'DEFAULT_CLOSED'}
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
@ -728,7 +701,6 @@ classes = (
|
||||||
DATA_PT_uv_texture,
|
DATA_PT_uv_texture,
|
||||||
DATA_PT_vertex_colors,
|
DATA_PT_vertex_colors,
|
||||||
DATA_PT_mesh_attributes,
|
DATA_PT_mesh_attributes,
|
||||||
DATA_PT_normals,
|
|
||||||
DATA_PT_texture_space,
|
DATA_PT_texture_space,
|
||||||
DATA_PT_remesh,
|
DATA_PT_remesh,
|
||||||
DATA_PT_customdata,
|
DATA_PT_customdata,
|
||||||
|
|
|
@ -2723,7 +2723,8 @@ class VIEW3D_MT_object(Menu):
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
layout.operator("object.shade_smooth")
|
layout.operator("object.shade_smooth")
|
||||||
layout.operator("object.shade_smooth", text="Shade Auto Smooth").use_auto_smooth = True
|
if context.object and context.object.type == 'MESH':
|
||||||
|
layout.operator("object.shade_smooth_by_angle")
|
||||||
layout.operator("object.shade_flat")
|
layout.operator("object.shade_flat")
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
@ -2967,8 +2968,9 @@ class VIEW3D_MT_object_context_menu(Menu):
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
if obj.type in {'MESH', 'CURVE', 'SURFACE'}:
|
if obj.type in {'MESH', 'CURVE', 'SURFACE'}:
|
||||||
layout.operator("object.shade_smooth")
|
layout.operator("object.shade_smooth")
|
||||||
layout.operator("object.shade_smooth", text="Shade Auto Smooth").use_auto_smooth = True
|
if obj.type == 'MESH':
|
||||||
layout.operator("object.shade_flat", text="Shade Flat")
|
layout.operator("object.shade_smooth_by_angle")
|
||||||
|
layout.operator("object.shade_flat")
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
||||||
|
|
||||||
/* Blender file format version. */
|
/* Blender file format version. */
|
||||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||||
#define BLENDER_FILE_SUBVERSION 1
|
#define BLENDER_FILE_SUBVERSION 2
|
||||||
|
|
||||||
/* Minimum Blender version that supports reading file written with the current
|
/* Minimum Blender version that supports reading file written with the current
|
||||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||||
|
|
|
@ -120,11 +120,7 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
|
||||||
int *r_vert_len,
|
int *r_vert_len,
|
||||||
bool *r_is_alloc))[3];
|
bool *r_is_alloc))[3];
|
||||||
|
|
||||||
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
|
void BKE_editmesh_lnorspace_update(BMEditMesh *em);
|
||||||
/**
|
|
||||||
* If auto-smooth not already set, set it.
|
|
||||||
*/
|
|
||||||
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
|
|
||||||
struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
|
struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -77,6 +77,9 @@ void BKE_mesh_tag_topology_changed(struct Mesh *mesh);
|
||||||
*/
|
*/
|
||||||
void BKE_mesh_tag_edges_split(struct Mesh *mesh);
|
void BKE_mesh_tag_edges_split(struct Mesh *mesh);
|
||||||
|
|
||||||
|
/** Call when changing "sharp_face" or "sharp_edge" data. */
|
||||||
|
void BKE_mesh_tag_sharpness_changed(struct Mesh *mesh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call when face vertex order has changed but positions and faces haven't changed
|
* Call when face vertex order has changed but positions and faces haven't changed
|
||||||
*/
|
*/
|
||||||
|
@ -224,7 +227,7 @@ bool BKE_mesh_material_index_used(struct Mesh *me, short index);
|
||||||
void BKE_mesh_material_index_clear(struct Mesh *me);
|
void BKE_mesh_material_index_clear(struct Mesh *me);
|
||||||
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
|
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
|
||||||
void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth);
|
void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth);
|
||||||
void BKE_mesh_auto_smooth_flag_set(struct Mesh *me, bool use_auto_smooth, float auto_smooth_angle);
|
void BKE_mesh_sharp_edges_set_from_angle(struct Mesh *me, float angle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for unit testing; compares two meshes, checking only
|
* Used for unit testing; compares two meshes, checking only
|
||||||
|
@ -328,11 +331,6 @@ bool BKE_mesh_vert_normals_are_dirty(const struct Mesh *mesh);
|
||||||
/** Return true if the mesh face normals either are not stored or are dirty. */
|
/** Return true if the mesh face normals either are not stored or are dirty. */
|
||||||
bool BKE_mesh_face_normals_are_dirty(const struct Mesh *mesh);
|
bool BKE_mesh_face_normals_are_dirty(const struct Mesh *mesh);
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after calculating all modifiers.
|
|
||||||
*/
|
|
||||||
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* References a contiguous loop-fan with normal offset vars.
|
* References a contiguous loop-fan with normal offset vars.
|
||||||
*/
|
*/
|
||||||
|
@ -456,18 +454,6 @@ void BKE_mesh_normals_loop_to_vertex(int numVerts,
|
||||||
*/
|
*/
|
||||||
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
|
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
|
||||||
|
|
||||||
void BKE_mesh_calc_normals_split(struct Mesh *mesh);
|
|
||||||
/**
|
|
||||||
* Compute 'split' (aka loop, or per face corner's) normals.
|
|
||||||
*
|
|
||||||
* \param r_lnors_spacearr: Allows to get computed loop normal space array.
|
|
||||||
* That data, among other things, contains 'smooth fan' info, useful e.g.
|
|
||||||
* to split geometry along sharp edges.
|
|
||||||
*/
|
|
||||||
void BKE_mesh_calc_normals_split_ex(const struct Mesh *mesh,
|
|
||||||
struct MLoopNorSpaceArray *r_lnors_spacearr,
|
|
||||||
float (*r_corner_normals)[3]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Higher level functions hiding most of the code needed around call to
|
* Higher level functions hiding most of the code needed around call to
|
||||||
* #normals_loop_custom_set().
|
* #normals_loop_custom_set().
|
||||||
|
@ -650,8 +636,7 @@ void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool selec
|
||||||
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
|
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
|
||||||
|
|
||||||
/* In DerivedMesh.cc */
|
/* In DerivedMesh.cc */
|
||||||
void BKE_mesh_wrapper_deferred_finalize_mdata(struct Mesh *me_eval,
|
void BKE_mesh_wrapper_deferred_finalize_mdata(struct Mesh *me_eval);
|
||||||
const struct CustomData_MeshMasks *cd_mask_finalize);
|
|
||||||
|
|
||||||
/* **** Depsgraph evaluation **** */
|
/* **** Depsgraph evaluation **** */
|
||||||
|
|
||||||
|
|
|
@ -162,8 +162,6 @@ void normals_calc_loop(Span<float3> vert_positions,
|
||||||
const bool *sharp_edges,
|
const bool *sharp_edges,
|
||||||
const bool *sharp_faces,
|
const bool *sharp_faces,
|
||||||
const short2 *clnors_data,
|
const short2 *clnors_data,
|
||||||
bool use_split_normals,
|
|
||||||
float split_angle,
|
|
||||||
CornerNormalSpaceArray *r_lnors_spacearr,
|
CornerNormalSpaceArray *r_lnors_spacearr,
|
||||||
MutableSpan<float3> r_loop_normals);
|
MutableSpan<float3> r_loop_normals);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
struct CustomData;
|
struct CustomData;
|
||||||
|
struct Main;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
struct MFace;
|
struct MFace;
|
||||||
|
|
||||||
|
@ -108,6 +109,8 @@ void BKE_mesh_calc_edges_legacy(Mesh *me);
|
||||||
|
|
||||||
void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh);
|
void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh);
|
||||||
|
|
||||||
|
void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain);
|
||||||
|
|
||||||
/* Inlines */
|
/* Inlines */
|
||||||
|
|
||||||
/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
|
/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
|
||||||
|
|
|
@ -144,9 +144,6 @@ enum {
|
||||||
MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY,
|
MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY,
|
||||||
};
|
};
|
||||||
|
|
||||||
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
|
|
||||||
int vert_mode, int edge_mode, int loop_mode, int face_mode, CustomData_MeshMasks *cddata_mask);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute a value of the difference between both given meshes.
|
* Compute a value of the difference between both given meshes.
|
||||||
* The smaller the result, the better the match.
|
* The smaller the result, the better the match.
|
||||||
|
@ -176,7 +173,6 @@ void BKE_mesh_remap_calc_verts_from_mesh(int mode,
|
||||||
float ray_radius,
|
float ray_radius,
|
||||||
const float (*vert_positions_dst)[3],
|
const float (*vert_positions_dst)[3],
|
||||||
int numverts_dst,
|
int numverts_dst,
|
||||||
bool dirty_nors_dst,
|
|
||||||
const Mesh *me_src,
|
const Mesh *me_src,
|
||||||
Mesh *me_dst,
|
Mesh *me_dst,
|
||||||
MeshPairRemap *r_map);
|
MeshPairRemap *r_map);
|
||||||
|
@ -189,7 +185,6 @@ void BKE_mesh_remap_calc_edges_from_mesh(int mode,
|
||||||
int numverts_dst,
|
int numverts_dst,
|
||||||
const blender::int2 *edges_dst,
|
const blender::int2 *edges_dst,
|
||||||
int numedges_dst,
|
int numedges_dst,
|
||||||
bool dirty_nors_dst,
|
|
||||||
const Mesh *me_src,
|
const Mesh *me_src,
|
||||||
Mesh *me_dst,
|
Mesh *me_dst,
|
||||||
MeshPairRemap *r_map);
|
MeshPairRemap *r_map);
|
||||||
|
@ -198,19 +193,12 @@ void BKE_mesh_remap_calc_loops_from_mesh(int mode,
|
||||||
const SpaceTransform *space_transform,
|
const SpaceTransform *space_transform,
|
||||||
float max_dist,
|
float max_dist,
|
||||||
float ray_radius,
|
float ray_radius,
|
||||||
Mesh *mesh_dst,
|
const Mesh *mesh_dst,
|
||||||
const float (*vert_positions_dst)[3],
|
const float (*vert_positions_dst)[3],
|
||||||
int numverts_dst,
|
int numverts_dst,
|
||||||
const blender::int2 *edges_dst,
|
|
||||||
int numedges_dst,
|
|
||||||
const int *corner_verts_dst,
|
const int *corner_verts_dst,
|
||||||
const int *corner_edges_dst,
|
|
||||||
int numloops_dst,
|
int numloops_dst,
|
||||||
const blender::OffsetIndices<int> faces_dst,
|
const blender::OffsetIndices<int> faces_dst,
|
||||||
CustomData *ldata_dst,
|
|
||||||
bool use_split_nors_dst,
|
|
||||||
float split_angle_dst,
|
|
||||||
bool dirty_nors_dst,
|
|
||||||
const Mesh *me_src,
|
const Mesh *me_src,
|
||||||
MeshRemapIslandsCalc gen_islands_src,
|
MeshRemapIslandsCalc gen_islands_src,
|
||||||
float islands_precision_src,
|
float islands_precision_src,
|
||||||
|
|
|
@ -33,8 +33,7 @@ bool BKE_mesh_runtime_ensure_edit_data(Mesh *mesh);
|
||||||
* For "smaller" changes to meshes like updating positions, consider calling a more specific update
|
* For "smaller" changes to meshes like updating positions, consider calling a more specific update
|
||||||
* function like #BKE_mesh_tag_positions_changed.
|
* function like #BKE_mesh_tag_positions_changed.
|
||||||
*
|
*
|
||||||
* Also note that some derived caches like #CD_NORMAL and #CD_TANGENT are stored directly in
|
* Also note that some derived caches like #CD_TANGENT are stored directly in #CustomData.
|
||||||
* #CustomData.
|
|
||||||
*/
|
*/
|
||||||
void BKE_mesh_runtime_clear_geometry(Mesh *mesh);
|
void BKE_mesh_runtime_clear_geometry(Mesh *mesh);
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,31 @@ enum eMeshWrapperType {
|
||||||
|
|
||||||
namespace blender::bke {
|
namespace blender::bke {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The complexity requirement of attribute domains needed to process normals.
|
||||||
|
* See #Mesh::normals_domain().
|
||||||
|
*/
|
||||||
|
enum class MeshNormalDomain : int8_t {
|
||||||
|
/**
|
||||||
|
* The mesh is completely smooth shaded; either all faces or edges are sharp.
|
||||||
|
* Only #Mesh::face_normals() is necessary. This case is generally the best
|
||||||
|
* for performance, since no mixing is necessary and multithreading is simple.
|
||||||
|
*/
|
||||||
|
Face,
|
||||||
|
/**
|
||||||
|
* The mesh is completely smooth shaded; there are no sharp face or edges. Only
|
||||||
|
* #Mesh::vert_normals() is necessary. Calculating face normals is still necessary though,
|
||||||
|
* since they have to be mixed to become vertex normals.
|
||||||
|
*/
|
||||||
|
Point,
|
||||||
|
/**
|
||||||
|
* The mesh has mixed smooth and sharp shading. In order to split the normals on each side of
|
||||||
|
* sharp edges, they need to be processed per-face-corner. Normals can be retrieved with
|
||||||
|
* #Mesh::corner_normals().
|
||||||
|
*/
|
||||||
|
Corner,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of a mesh's loose edges, accessed with #Mesh::loose_edges(). *
|
* Cache of a mesh's loose edges, accessed with #Mesh::loose_edges(). *
|
||||||
*/
|
*/
|
||||||
|
@ -136,9 +161,10 @@ struct MeshRuntime {
|
||||||
*/
|
*/
|
||||||
SubsurfRuntimeData *subsurf_runtime_data = nullptr;
|
SubsurfRuntimeData *subsurf_runtime_data = nullptr;
|
||||||
|
|
||||||
/** Caches for lazily computed vertex and face normals. */
|
/** Caches for lazily computed normals. */
|
||||||
SharedCache<Vector<float3>> vert_normals_cache;
|
SharedCache<Vector<float3>> vert_normals_cache;
|
||||||
SharedCache<Vector<float3>> face_normals_cache;
|
SharedCache<Vector<float3>> face_normals_cache;
|
||||||
|
SharedCache<Vector<float3>> corner_normals_cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of offsets for vert to face/corner maps. The same offsets array is used to group
|
* Cache of offsets for vert to face/corner maps. The same offsets array is used to group
|
||||||
|
|
|
@ -45,7 +45,6 @@ struct SubsurfRuntimeData {
|
||||||
bool has_gpu_subdiv;
|
bool has_gpu_subdiv;
|
||||||
int resolution;
|
int resolution;
|
||||||
bool use_optimal_display;
|
bool use_optimal_display;
|
||||||
bool calc_loop_normals;
|
|
||||||
bool use_loop_normals;
|
bool use_loop_normals;
|
||||||
|
|
||||||
/* Cached from the draw code for stats display. */
|
/* Cached from the draw code for stats display. */
|
||||||
|
|
|
@ -89,10 +89,8 @@ using blender::bke::MeshComponent;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void mesh_init_origspace(Mesh *mesh);
|
static void mesh_init_origspace(Mesh *mesh);
|
||||||
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
|
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final);
|
||||||
const CustomData_MeshMasks *final_datamask);
|
static void editbmesh_calc_modifier_final_normals_or_defer(Mesh *mesh_final);
|
||||||
static void editbmesh_calc_modifier_final_normals_or_defer(
|
|
||||||
Mesh *mesh_final, const CustomData_MeshMasks *final_datamask);
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -448,60 +446,6 @@ static void add_orco_mesh(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
|
|
||||||
const CustomData_MeshMasks *final_datamask,
|
|
||||||
Mesh *mesh_final)
|
|
||||||
{
|
|
||||||
/* Test if mesh has the required loop normals, in case an additional modifier
|
|
||||||
* evaluation from another instance or from an operator requests it but the
|
|
||||||
* initial normals were not loop normals. */
|
|
||||||
const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
|
|
||||||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
|
|
||||||
|
|
||||||
return (!calc_loop_normals || CustomData_has_layer(&mesh_final->loop_data, CD_NORMAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
|
|
||||||
const CustomData_MeshMasks *final_datamask,
|
|
||||||
const bool sculpt_dyntopo,
|
|
||||||
Mesh *mesh_final)
|
|
||||||
{
|
|
||||||
/* Compute normals. */
|
|
||||||
const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
|
|
||||||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
|
|
||||||
|
|
||||||
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
|
|
||||||
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
|
|
||||||
if (subsurf_runtime_data) {
|
|
||||||
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (calc_loop_normals) {
|
|
||||||
/* Compute loop normals (NOTE: will compute face and vert normals as well, if needed!). In case
|
|
||||||
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
|
|
||||||
if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
|
|
||||||
BKE_mesh_calc_normals_split(mesh_final);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (sculpt_dyntopo == false) {
|
|
||||||
/* without this, drawing ngon tri's faces will show ugly tessellated face
|
|
||||||
* normals and will also have to calculate normals on the fly, try avoid
|
|
||||||
* this where possible since calculating face normals isn't fast,
|
|
||||||
* note that this isn't a problem for subsurf (only quads) or edit-mode
|
|
||||||
* which deals with drawing differently. */
|
|
||||||
BKE_mesh_ensure_normals_for_display(mesh_final);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Some modifiers, like data-transfer, may generate those data as temp layer,
|
|
||||||
* we do not want to keep them, as they are used by display code when available
|
|
||||||
* (i.e. even if auto-smooth is disabled). */
|
|
||||||
if (CustomData_has_layer(&mesh_final->loop_data, CD_NORMAL)) {
|
|
||||||
CustomData_free_layers(&mesh_final->loop_data, CD_NORMAL, mesh_final->totloop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Does final touches to the final evaluated mesh, making sure it is perfectly usable.
|
/* 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
|
* This is needed because certain information is not passed along intermediate meshes allocated
|
||||||
|
@ -516,11 +460,10 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
|
||||||
mesh_eval->edit_mesh = mesh_input->edit_mesh;
|
mesh_eval->edit_mesh = mesh_input->edit_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval,
|
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval)
|
||||||
const CustomData_MeshMasks *cd_mask_finalize)
|
|
||||||
{
|
{
|
||||||
if (me_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
|
if (me_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
|
||||||
editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
|
editbmesh_calc_modifier_final_normals(me_eval);
|
||||||
me_eval->runtime->wrapper_type_finalize = eMeshWrapperType(
|
me_eval->runtime->wrapper_type_finalize = eMeshWrapperType(
|
||||||
me_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH));
|
me_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH));
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +967,6 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
||||||
|
|
||||||
/* Compute normals. */
|
/* Compute normals. */
|
||||||
if (is_own_mesh) {
|
if (is_own_mesh) {
|
||||||
mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
|
|
||||||
mesh_calc_finalize(mesh_input, mesh_final);
|
mesh_calc_finalize(mesh_input, mesh_final);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1036,8 +978,6 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
||||||
* Isolate since computing normals is multithreaded and we are holding a lock. */
|
* Isolate since computing normals is multithreaded and we are holding a lock. */
|
||||||
blender::threading::isolate_task([&] {
|
blender::threading::isolate_task([&] {
|
||||||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||||
mesh_calc_modifier_final_normals(
|
|
||||||
mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
|
|
||||||
mesh_calc_finalize(mesh_input, mesh_final);
|
mesh_calc_finalize(mesh_input, mesh_final);
|
||||||
runtime->mesh_eval = mesh_final;
|
runtime->mesh_eval = mesh_final;
|
||||||
});
|
});
|
||||||
|
@ -1047,13 +987,6 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
||||||
mesh_final = runtime->mesh_eval;
|
mesh_final = runtime->mesh_eval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) {
|
|
||||||
/* Modifier stack was (re-)evaluated with a request for additional normals
|
|
||||||
* different than the instanced mesh, can't instance anymore now. */
|
|
||||||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
|
||||||
mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
|
|
||||||
mesh_calc_finalize(mesh_input, mesh_final);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
/* Already finalized by another instance, reuse. */
|
/* Already finalized by another instance, reuse. */
|
||||||
mesh_final = runtime->mesh_eval;
|
mesh_final = runtime->mesh_eval;
|
||||||
|
@ -1102,39 +1035,25 @@ bool editbmesh_modifier_is_enabled(const Scene *scene,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
|
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final)
|
||||||
const CustomData_MeshMasks *final_datamask)
|
|
||||||
{
|
{
|
||||||
const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
|
switch (mesh_final->runtime->wrapper_type) {
|
||||||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
|
case ME_WRAPPER_TYPE_SUBD:
|
||||||
|
case ME_WRAPPER_TYPE_MDATA:
|
||||||
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
|
break;
|
||||||
if (subsurf_runtime_data) {
|
case ME_WRAPPER_TYPE_BMESH: {
|
||||||
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
|
BMEditMesh *em = mesh_final->edit_mesh;
|
||||||
}
|
blender::bke::EditMeshData *emd = mesh_final->runtime->edit_data;
|
||||||
|
if (!emd->vertexCos.is_empty()) {
|
||||||
if (calc_loop_normals) {
|
BKE_editmesh_cache_ensure_vert_normals(em, emd);
|
||||||
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
|
BKE_editmesh_cache_ensure_face_normals(em, emd);
|
||||||
* wrapper is generated. */
|
}
|
||||||
if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
|
return;
|
||||||
BKE_mesh_calc_normals_split(mesh_final);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Same as #mesh_calc_modifiers.
|
|
||||||
* If using loop normals, face normals have already been computed. */
|
|
||||||
BKE_mesh_ensure_normals_for_display(mesh_final);
|
|
||||||
|
|
||||||
/* Some modifiers, like data-transfer, may generate those data, we do not want to keep them,
|
|
||||||
* as they are used by display code when available (i.e. even if auto-smooth is disabled). */
|
|
||||||
if (CustomData_has_layer(&mesh_final->loop_data, CD_NORMAL)) {
|
|
||||||
CustomData_free_layers(&mesh_final->loop_data, CD_NORMAL, mesh_final->totloop);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void editbmesh_calc_modifier_final_normals_or_defer(
|
static void editbmesh_calc_modifier_final_normals_or_defer(Mesh *mesh_final)
|
||||||
Mesh *mesh_final, const CustomData_MeshMasks *final_datamask)
|
|
||||||
{
|
{
|
||||||
if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) {
|
if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) {
|
||||||
/* Generated at draw time. */
|
/* Generated at draw time. */
|
||||||
|
@ -1143,7 +1062,7 @@ static void editbmesh_calc_modifier_final_normals_or_defer(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editbmesh_calc_modifier_final_normals(mesh_final, final_datamask);
|
editbmesh_calc_modifier_final_normals(mesh_final);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
|
static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
|
||||||
|
@ -1361,9 +1280,9 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute normals. */
|
/* Compute normals. */
|
||||||
editbmesh_calc_modifier_final_normals_or_defer(mesh_final, &final_datamask);
|
editbmesh_calc_modifier_final_normals_or_defer(mesh_final);
|
||||||
if (mesh_cage && (mesh_cage != mesh_final)) {
|
if (mesh_cage && (mesh_cage != mesh_final)) {
|
||||||
editbmesh_calc_modifier_final_normals_or_defer(mesh_cage, &final_datamask);
|
editbmesh_calc_modifier_final_normals_or_defer(mesh_cage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return final mesh. */
|
/* Return final mesh. */
|
||||||
|
|
|
@ -796,8 +796,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
|
||||||
CustomData_free_layer_named(&mesh->vert_data, "position", 0);
|
CustomData_free_layer_named(&mesh->vert_data, "position", 0);
|
||||||
mesh->totvert = offsets.vert.last();
|
mesh->totvert = offsets.vert.last();
|
||||||
|
|
||||||
mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
mesh->smoothresh = DEG2RADF(180.0f);
|
|
||||||
MutableSpan<int2> edges = mesh->edges_for_write();
|
MutableSpan<int2> edges = mesh->edges_for_write();
|
||||||
MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
|
MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
|
||||||
MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
|
MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
|
||||||
|
|
|
@ -70,7 +70,7 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
|
||||||
r_data_masks->lmask |= CD_MASK_PROP_FLOAT2;
|
r_data_masks->lmask |= CD_MASK_PROP_FLOAT2;
|
||||||
}
|
}
|
||||||
else if (cddata_type == CD_FAKE_LNOR) {
|
else if (cddata_type == CD_FAKE_LNOR) {
|
||||||
r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
|
r_data_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,60 +353,6 @@ static void data_transfer_mesh_attributes_transfer_default_color_string(
|
||||||
|
|
||||||
/* ********** */
|
/* ********** */
|
||||||
|
|
||||||
/* Generic pre/post processing, only used by custom loop normals currently. */
|
|
||||||
|
|
||||||
static void data_transfer_dtdata_type_preprocess(const Mesh *me_src,
|
|
||||||
Mesh *me_dst,
|
|
||||||
const int dtdata_type,
|
|
||||||
const bool dirty_nors_dst)
|
|
||||||
{
|
|
||||||
if (dtdata_type == DT_TYPE_LNOR) {
|
|
||||||
/* Compute custom normals into regular loop normals, which will be used for the transfer. */
|
|
||||||
CustomData *ldata_dst = &me_dst->loop_data;
|
|
||||||
|
|
||||||
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
|
|
||||||
const float split_angle_dst = me_dst->smoothresh;
|
|
||||||
|
|
||||||
/* This should be ensured by cddata_masks we pass to code generating/giving us me_src now. */
|
|
||||||
BLI_assert(CustomData_get_layer(&me_src->loop_data, CD_NORMAL) != nullptr);
|
|
||||||
(void)me_src;
|
|
||||||
|
|
||||||
const blender::short2 *custom_nors_dst = static_cast<const blender::short2 *>(
|
|
||||||
CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL));
|
|
||||||
|
|
||||||
/* Cache loop nors into a temp CDLayer. */
|
|
||||||
blender::float3 *loop_nors_dst = static_cast<blender::float3 *>(
|
|
||||||
CustomData_get_layer_for_write(ldata_dst, CD_NORMAL, me_dst->totloop));
|
|
||||||
const bool do_loop_nors_dst = (loop_nors_dst == nullptr);
|
|
||||||
if (do_loop_nors_dst) {
|
|
||||||
loop_nors_dst = static_cast<blender::float3 *>(
|
|
||||||
CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, me_dst->totloop));
|
|
||||||
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
|
||||||
if (dirty_nors_dst || do_loop_nors_dst) {
|
|
||||||
const bool *sharp_edges = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&me_dst->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
|
||||||
const bool *sharp_faces = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&me_dst->face_data, CD_PROP_BOOL, "sharp_face"));
|
|
||||||
blender::bke::mesh::normals_calc_loop(me_dst->vert_positions(),
|
|
||||||
me_dst->edges(),
|
|
||||||
me_dst->faces(),
|
|
||||||
me_dst->corner_verts(),
|
|
||||||
me_dst->corner_edges(),
|
|
||||||
me_dst->corner_to_face_map(),
|
|
||||||
me_dst->vert_normals(),
|
|
||||||
me_dst->face_normals(),
|
|
||||||
sharp_edges,
|
|
||||||
sharp_faces,
|
|
||||||
custom_nors_dst,
|
|
||||||
use_split_nors_dst,
|
|
||||||
split_angle_dst,
|
|
||||||
nullptr,
|
|
||||||
{loop_nors_dst, me_dst->totloop});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void data_transfer_dtdata_type_postprocess(Mesh *me_dst,
|
static void data_transfer_dtdata_type_postprocess(Mesh *me_dst,
|
||||||
const int dtdata_type,
|
const int dtdata_type,
|
||||||
const bool changed)
|
const bool changed)
|
||||||
|
@ -1352,8 +1298,6 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
SpaceTransform auto_space_transform;
|
SpaceTransform auto_space_transform;
|
||||||
|
|
||||||
const Mesh *me_src;
|
const Mesh *me_src;
|
||||||
/* Assumed always true if not using an evaluated mesh as destination. */
|
|
||||||
bool dirty_nors_dst = true;
|
|
||||||
|
|
||||||
const MDeformVert *mdef = nullptr;
|
const MDeformVert *mdef = nullptr;
|
||||||
int vg_idx = -1;
|
int vg_idx = -1;
|
||||||
|
@ -1370,7 +1314,6 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
|
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
|
||||||
|
|
||||||
if (me_dst) {
|
if (me_dst) {
|
||||||
dirty_nors_dst = BKE_mesh_vert_normals_are_dirty(me_dst);
|
|
||||||
/* Never create needed custom layers on passed destination mesh
|
/* Never create needed custom layers on passed destination mesh
|
||||||
* (assumed to *not* be ob_dst->data, aka modifier case). */
|
* (assumed to *not* be ob_dst->data, aka modifier case). */
|
||||||
use_create = false;
|
use_create = false;
|
||||||
|
@ -1424,8 +1367,6 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
|
|
||||||
|
|
||||||
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
|
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
|
||||||
|
|
||||||
fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
|
fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
|
||||||
|
@ -1480,7 +1421,6 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
ray_radius,
|
ray_radius,
|
||||||
reinterpret_cast<const float(*)[3]>(positions_dst.data()),
|
reinterpret_cast<const float(*)[3]>(positions_dst.data()),
|
||||||
num_verts_dst,
|
num_verts_dst,
|
||||||
dirty_nors_dst,
|
|
||||||
me_src,
|
me_src,
|
||||||
me_dst,
|
me_dst,
|
||||||
&geom_map[VDATA]);
|
&geom_map[VDATA]);
|
||||||
|
@ -1560,7 +1500,6 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
num_verts_dst,
|
num_verts_dst,
|
||||||
edges_dst.data(),
|
edges_dst.data(),
|
||||||
edges_dst.size(),
|
edges_dst.size(),
|
||||||
dirty_nors_dst,
|
|
||||||
me_src,
|
me_src,
|
||||||
me_dst,
|
me_dst,
|
||||||
&geom_map[EDATA]);
|
&geom_map[EDATA]);
|
||||||
|
@ -1608,11 +1547,8 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
|
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
|
||||||
const blender::Span<blender::float3> positions_dst = me_dst->vert_positions();
|
const blender::Span<blender::float3> positions_dst = me_dst->vert_positions();
|
||||||
const int num_verts_dst = me_dst->totvert;
|
const int num_verts_dst = me_dst->totvert;
|
||||||
const blender::Span<blender::int2> edges_dst = me_dst->edges();
|
|
||||||
const blender::OffsetIndices faces_dst = me_dst->faces();
|
const blender::OffsetIndices faces_dst = me_dst->faces();
|
||||||
const blender::Span<int> corner_verts_dst = me_dst->corner_verts();
|
const blender::Span<int> corner_verts_dst = me_dst->corner_verts();
|
||||||
const blender::Span<int> corner_edges_dst = me_dst->corner_edges();
|
|
||||||
CustomData *ldata_dst = &me_dst->loop_data;
|
|
||||||
|
|
||||||
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
|
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
|
||||||
|
|
||||||
|
@ -1650,16 +1586,9 @@ bool BKE_object_data_transfer_ex(Depsgraph *depsgraph,
|
||||||
me_dst,
|
me_dst,
|
||||||
reinterpret_cast<const float(*)[3]>(positions_dst.data()),
|
reinterpret_cast<const float(*)[3]>(positions_dst.data()),
|
||||||
num_verts_dst,
|
num_verts_dst,
|
||||||
edges_dst.data(),
|
|
||||||
edges_dst.size(),
|
|
||||||
corner_verts_dst.data(),
|
corner_verts_dst.data(),
|
||||||
corner_edges_dst.data(),
|
|
||||||
corner_verts_dst.size(),
|
corner_verts_dst.size(),
|
||||||
faces_dst,
|
faces_dst,
|
||||||
ldata_dst,
|
|
||||||
(me_dst->flag & ME_AUTOSMOOTH) != 0,
|
|
||||||
me_dst->smoothresh,
|
|
||||||
dirty_nors_dst,
|
|
||||||
me_src,
|
me_src,
|
||||||
island_callback,
|
island_callback,
|
||||||
islands_handling_precision,
|
islands_handling_precision,
|
||||||
|
|
|
@ -758,9 +758,6 @@ static blender::bke::GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
|
||||||
|
|
||||||
if (geometry_set.has_mesh()) {
|
if (geometry_set.has_mesh()) {
|
||||||
Mesh *final_mesh = geometry_set.get_mesh_for_write();
|
Mesh *final_mesh = geometry_set.get_mesh_for_write();
|
||||||
|
|
||||||
BKE_mesh_ensure_normals_for_display(final_mesh);
|
|
||||||
|
|
||||||
STRNCPY(final_mesh->id.name, cu->id.name);
|
STRNCPY(final_mesh->id.name, cu->id.name);
|
||||||
*((short *)final_mesh->id.name) = ID_ME;
|
*((short *)final_mesh->id.name) = ID_ME;
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,33 +252,9 @@ float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
|
||||||
return BM_mesh_vert_coords_alloc(em->bm, r_vert_len);
|
return BM_mesh_vert_coords_alloc(em->bm, r_vert_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
|
void BKE_editmesh_lnorspace_update(BMEditMesh *em)
|
||||||
{
|
{
|
||||||
BMesh *bm = em->bm;
|
BM_lnorspace_update(em->bm);
|
||||||
|
|
||||||
/* We need to create custom-loop-normals (CLNORS) data if none exist yet,
|
|
||||||
* otherwise there is no way to edit them.
|
|
||||||
* Similar code to #MESH_OT_customdata_custom_splitnormals_add operator,
|
|
||||||
* we want to keep same shading in case we were using auto-smooth so far.
|
|
||||||
* NOTE: there is a problem here, which is that if someone starts a normal editing operation on
|
|
||||||
* previously auto-smooth-ed mesh, and cancel that operation, generated CLNORS data remain,
|
|
||||||
* with related sharp edges (and hence auto-smooth is 'lost').
|
|
||||||
* Not sure how critical this is, and how to fix that issue? */
|
|
||||||
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
|
|
||||||
if (me->flag & ME_AUTOSMOOTH) {
|
|
||||||
BM_edges_sharp_from_angle_set(bm, me->smoothresh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BM_lnorspace_update(bm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
|
|
||||||
{
|
|
||||||
if (!(me->flag & ME_AUTOSMOOTH)) {
|
|
||||||
me->flag |= ME_AUTOSMOOTH;
|
|
||||||
BKE_editmesh_lnorspace_update(em, me);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundBox *BKE_editmesh_cage_boundbox_get(Object *object, BMEditMesh * /*em*/)
|
BoundBox *BKE_editmesh_cage_boundbox_get(Object *object, BMEditMesh * /*em*/)
|
||||||
|
|
|
@ -858,6 +858,13 @@ static void tag_component_positions_changed(void *owner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tag_component_sharpness_changed(void *owner)
|
||||||
|
{
|
||||||
|
if (Mesh *mesh = static_cast<Mesh *>(owner)) {
|
||||||
|
BKE_mesh_tag_sharpness_changed(mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This provider makes vertex groups available as float attributes.
|
* This provider makes vertex groups available as float attributes.
|
||||||
*/
|
*/
|
||||||
|
@ -1075,7 +1082,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||||
BuiltinAttributeProvider::Creatable,
|
BuiltinAttributeProvider::Creatable,
|
||||||
BuiltinAttributeProvider::Deletable,
|
BuiltinAttributeProvider::Deletable,
|
||||||
face_access,
|
face_access,
|
||||||
nullptr);
|
tag_component_sharpness_changed);
|
||||||
|
|
||||||
static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge",
|
static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge",
|
||||||
ATTR_DOMAIN_EDGE,
|
ATTR_DOMAIN_EDGE,
|
||||||
|
@ -1084,7 +1091,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||||
BuiltinAttributeProvider::Creatable,
|
BuiltinAttributeProvider::Creatable,
|
||||||
BuiltinAttributeProvider::Deletable,
|
BuiltinAttributeProvider::Deletable,
|
||||||
edge_access,
|
edge_access,
|
||||||
nullptr);
|
tag_component_sharpness_changed);
|
||||||
|
|
||||||
static MeshVertexGroupsAttributeProvider vertex_groups;
|
static MeshVertexGroupsAttributeProvider vertex_groups;
|
||||||
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
|
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
|
||||||
|
|
|
@ -2287,8 +2287,6 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
|
||||||
sharp_edges,
|
sharp_edges,
|
||||||
sharp_faces,
|
sharp_faces,
|
||||||
clnors,
|
clnors,
|
||||||
(mesh->flag & ME_AUTOSMOOTH) != 0,
|
|
||||||
mesh->smoothresh,
|
|
||||||
nullptr,
|
nullptr,
|
||||||
{reinterpret_cast<blender::float3 *>(r_loop_normals), corner_verts.size()});
|
{reinterpret_cast<blender::float3 *>(r_loop_normals), corner_verts.size()});
|
||||||
}
|
}
|
||||||
|
|
|
@ -972,7 +972,6 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
|
||||||
/* Copy general settings. */
|
/* Copy general settings. */
|
||||||
me_dst->editflag = me_src->editflag;
|
me_dst->editflag = me_src->editflag;
|
||||||
me_dst->flag = me_src->flag;
|
me_dst->flag = me_src->flag;
|
||||||
me_dst->smoothresh = me_src->smoothresh;
|
|
||||||
me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
|
me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
|
||||||
me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
|
me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
|
||||||
me_dst->remesh_mode = me_src->remesh_mode;
|
me_dst->remesh_mode = me_src->remesh_mode;
|
||||||
|
@ -1429,9 +1428,11 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
|
||||||
using namespace blender::bke;
|
using namespace blender::bke;
|
||||||
MutableAttributeAccessor attributes = me->attributes_for_write();
|
MutableAttributeAccessor attributes = me->attributes_for_write();
|
||||||
if (use_smooth) {
|
if (use_smooth) {
|
||||||
|
attributes.remove("sharp_edge");
|
||||||
attributes.remove("sharp_face");
|
attributes.remove("sharp_face");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
attributes.remove("sharp_edge");
|
||||||
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_only_span<bool>(
|
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_only_span<bool>(
|
||||||
"sharp_face", ATTR_DOMAIN_FACE);
|
"sharp_face", ATTR_DOMAIN_FACE);
|
||||||
sharp_faces.span.fill(true);
|
sharp_faces.span.fill(true);
|
||||||
|
@ -1439,17 +1440,33 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_mesh_auto_smooth_flag_set(Mesh *me,
|
void BKE_mesh_sharp_edges_set_from_angle(Mesh *me, const float angle)
|
||||||
const bool use_auto_smooth,
|
|
||||||
const float auto_smooth_angle)
|
|
||||||
{
|
{
|
||||||
if (use_auto_smooth) {
|
using namespace blender;
|
||||||
me->flag |= ME_AUTOSMOOTH;
|
using namespace blender::bke;
|
||||||
me->smoothresh = auto_smooth_angle;
|
bke::MutableAttributeAccessor attributes = me->attributes_for_write();
|
||||||
|
if (angle >= M_PI) {
|
||||||
|
attributes.remove("sharp_edge");
|
||||||
|
attributes.remove("sharp_face");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
if (angle == 0.0f) {
|
||||||
me->flag &= ~ME_AUTOSMOOTH;
|
BKE_mesh_smooth_flag_set(me, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
|
||||||
|
"sharp_edge", ATTR_DOMAIN_EDGE);
|
||||||
|
const bool *sharp_faces = static_cast<const bool *>(
|
||||||
|
CustomData_get_layer_named(&me->face_data, CD_PROP_BOOL, "sharp_face"));
|
||||||
|
bke::mesh::edges_sharp_from_angle_set(me->faces(),
|
||||||
|
me->corner_verts(),
|
||||||
|
me->corner_edges(),
|
||||||
|
me->face_normals(),
|
||||||
|
me->corner_to_face_map(),
|
||||||
|
sharp_faces,
|
||||||
|
angle,
|
||||||
|
sharp_edges.span);
|
||||||
|
sharp_edges.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_mesh_looptri_get_real_edges(const blender::int2 *edges,
|
void BKE_mesh_looptri_get_real_edges(const blender::int2 *edges,
|
||||||
|
@ -1506,20 +1523,6 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't update normals, caller can do this explicitly.
|
|
||||||
* We do update loop normals though, those may not be auto-generated
|
|
||||||
* (see e.g. STL import script)! */
|
|
||||||
float(*lnors)[3] = (float(*)[3])CustomData_get_layer_for_write(
|
|
||||||
&me->loop_data, CD_NORMAL, me->totloop);
|
|
||||||
if (lnors) {
|
|
||||||
float m3[3][3];
|
|
||||||
|
|
||||||
copy_m3_m4(m3, mat);
|
|
||||||
normalize_m3(m3);
|
|
||||||
for (int i = 0; i < me->totloop; i++, lnors++) {
|
|
||||||
mul_m3_v3(m3, *lnors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BKE_mesh_tag_positions_changed(me);
|
BKE_mesh_tag_positions_changed(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1731,63 +1734,6 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
|
||||||
BKE_mesh_tag_positions_changed(mesh);
|
BKE_mesh_tag_positions_changed(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float (*ensure_corner_normal_layer(Mesh &mesh))[3]
|
|
||||||
{
|
|
||||||
float(*r_loop_normals)[3];
|
|
||||||
if (CustomData_has_layer(&mesh.loop_data, CD_NORMAL)) {
|
|
||||||
r_loop_normals = (float(*)[3])CustomData_get_layer_for_write(
|
|
||||||
&mesh.loop_data, CD_NORMAL, mesh.totloop);
|
|
||||||
memset(r_loop_normals, 0, sizeof(float[3]) * mesh.totloop);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
r_loop_normals = (float(*)[3])CustomData_add_layer(
|
|
||||||
&mesh.loop_data, CD_NORMAL, CD_SET_DEFAULT, mesh.totloop);
|
|
||||||
CustomData_set_layer_flag(&mesh.loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
|
||||||
return r_loop_normals;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BKE_mesh_calc_normals_split_ex(const Mesh *mesh,
|
|
||||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
|
||||||
float (*r_corner_normals)[3])
|
|
||||||
{
|
|
||||||
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
|
|
||||||
* However, we obviously only use the auto-smooth angle threshold
|
|
||||||
* only in case auto-smooth is enabled. */
|
|
||||||
const bool use_split_normals = (r_lnors_spacearr != nullptr) ||
|
|
||||||
((mesh->flag & ME_AUTOSMOOTH) != 0);
|
|
||||||
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : float(M_PI);
|
|
||||||
|
|
||||||
const blender::short2 *clnors = static_cast<const blender::short2 *>(
|
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL));
|
|
||||||
const bool *sharp_edges = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&mesh->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
|
||||||
const bool *sharp_faces = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
|
|
||||||
|
|
||||||
blender::bke::mesh::normals_calc_loop(
|
|
||||||
mesh->vert_positions(),
|
|
||||||
mesh->edges(),
|
|
||||||
mesh->faces(),
|
|
||||||
mesh->corner_verts(),
|
|
||||||
mesh->corner_edges(),
|
|
||||||
mesh->corner_to_face_map(),
|
|
||||||
mesh->vert_normals(),
|
|
||||||
mesh->face_normals(),
|
|
||||||
sharp_edges,
|
|
||||||
sharp_faces,
|
|
||||||
clnors,
|
|
||||||
use_split_normals,
|
|
||||||
split_angle,
|
|
||||||
nullptr,
|
|
||||||
{reinterpret_cast<float3 *>(r_corner_normals), mesh->totloop});
|
|
||||||
}
|
|
||||||
|
|
||||||
void BKE_mesh_calc_normals_split(Mesh *mesh)
|
|
||||||
{
|
|
||||||
BKE_mesh_calc_normals_split_ex(mesh, nullptr, ensure_corner_normal_layer(*mesh));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* **** Depsgraph evaluation **** */
|
/* **** Depsgraph evaluation **** */
|
||||||
|
|
||||||
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
|
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
|
||||||
|
|
|
@ -167,9 +167,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
|
||||||
/* XXX: investigate using EditMesh data. */
|
/* XXX: investigate using EditMesh data. */
|
||||||
blender::Span<blender::float3> corner_normals;
|
blender::Span<blender::float3> corner_normals;
|
||||||
if (flag & MESH_FOREACH_USE_NORMAL) {
|
if (flag & MESH_FOREACH_USE_NORMAL) {
|
||||||
corner_normals = {
|
corner_normals = mesh->corner_normals();
|
||||||
static_cast<const blender::float3 *>(CustomData_get_layer(&mesh->loop_data, CD_NORMAL)),
|
|
||||||
mesh->totloop};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int f_idx;
|
int f_idx;
|
||||||
|
@ -194,9 +192,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
|
||||||
else {
|
else {
|
||||||
blender::Span<blender::float3> corner_normals;
|
blender::Span<blender::float3> corner_normals;
|
||||||
if (flag & MESH_FOREACH_USE_NORMAL) {
|
if (flag & MESH_FOREACH_USE_NORMAL) {
|
||||||
corner_normals = {
|
corner_normals = mesh->corner_normals();
|
||||||
static_cast<const blender::float3 *>(CustomData_get_layer(&mesh->loop_data, CD_NORMAL)),
|
|
||||||
mesh->totloop};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const blender::Span<blender::float3> positions = mesh->vert_positions();
|
const blender::Span<blender::float3> positions = mesh->vert_positions();
|
||||||
|
|
|
@ -33,10 +33,17 @@
|
||||||
#include "BKE_attribute.hh"
|
#include "BKE_attribute.hh"
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
|
#include "BKE_idprop.hh"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_mesh.hh"
|
#include "BKE_mesh.hh"
|
||||||
#include "BKE_mesh_legacy_convert.hh"
|
#include "BKE_mesh_legacy_convert.hh"
|
||||||
|
#include "BKE_modifier.h"
|
||||||
#include "BKE_multires.hh"
|
#include "BKE_multires.hh"
|
||||||
|
#include "BKE_node.hh"
|
||||||
|
#include "BKE_node_runtime.hh"
|
||||||
|
#include "BKE_node_tree_update.h"
|
||||||
|
|
||||||
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
using blender::MutableSpan;
|
using blender::MutableSpan;
|
||||||
using blender::Span;
|
using blender::Span;
|
||||||
|
@ -2116,3 +2123,168 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Auto Smooth Conversion
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
|
||||||
|
{
|
||||||
|
bNodeTree *group = ntreeAddTree(&bmain, DATA_("Auto Smooth"), "GeometryNodeTree");
|
||||||
|
|
||||||
|
group->tree_interface.add_socket(DATA_("Geometry"),
|
||||||
|
"",
|
||||||
|
"NodeSocketGeometry",
|
||||||
|
NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT,
|
||||||
|
nullptr);
|
||||||
|
group->tree_interface.add_socket(
|
||||||
|
DATA_("Angle"), "", "NodeSocketFloatAngle", NODE_INTERFACE_SOCKET_INPUT, nullptr);
|
||||||
|
|
||||||
|
bNode *group_output = nodeAddNode(nullptr, group, "NodeGroupOutput");
|
||||||
|
group_output->locx = 480.0f;
|
||||||
|
group_output->locy = -100.0f;
|
||||||
|
bNode *group_input_angle = nodeAddNode(nullptr, group, "NodeGroupInput");
|
||||||
|
group_input_angle->locx = -420.0f;
|
||||||
|
group_input_angle->locy = -300.0f;
|
||||||
|
LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_angle->outputs) {
|
||||||
|
if (!STREQ(socket->identifier, "Socket_1")) {
|
||||||
|
socket->flag |= SOCK_HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bNode *group_input_mesh = nodeAddNode(nullptr, group, "NodeGroupInput");
|
||||||
|
group_input_mesh->locx = -60.0f;
|
||||||
|
group_input_mesh->locy = -100.0f;
|
||||||
|
LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_mesh->outputs) {
|
||||||
|
if (!STREQ(socket->identifier, "Socket_0")) {
|
||||||
|
socket->flag |= SOCK_HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bNode *shade_smooth_edge = nodeAddNode(nullptr, group, "GeometryNodeSetShadeSmooth");
|
||||||
|
shade_smooth_edge->custom1 = ATTR_DOMAIN_EDGE;
|
||||||
|
shade_smooth_edge->locx = 120.0f;
|
||||||
|
shade_smooth_edge->locy = -100.0f;
|
||||||
|
bNode *shade_smooth_face = nodeAddNode(nullptr, group, "GeometryNodeSetShadeSmooth");
|
||||||
|
shade_smooth_face->custom1 = ATTR_DOMAIN_FACE;
|
||||||
|
shade_smooth_face->locx = 300.0f;
|
||||||
|
shade_smooth_face->locy = -100.0f;
|
||||||
|
bNode *edge_angle = nodeAddNode(nullptr, group, "GeometryNodeInputMeshEdgeAngle");
|
||||||
|
edge_angle->locx = -420.0f;
|
||||||
|
edge_angle->locy = -220.0f;
|
||||||
|
bNode *edge_smooth = nodeAddNode(nullptr, group, "GeometryNodeInputEdgeSmooth");
|
||||||
|
edge_smooth->locx = -60.0f;
|
||||||
|
edge_smooth->locy = -160.0f;
|
||||||
|
bNode *face_smooth = nodeAddNode(nullptr, group, "GeometryNodeInputShadeSmooth");
|
||||||
|
face_smooth->locx = -240.0f;
|
||||||
|
face_smooth->locy = -340.0f;
|
||||||
|
bNode *boolean_and = nodeAddNode(nullptr, group, "FunctionNodeBooleanMath");
|
||||||
|
boolean_and->custom1 = NODE_BOOLEAN_MATH_AND;
|
||||||
|
boolean_and->locx = -60.0f;
|
||||||
|
boolean_and->locy = -220.0f;
|
||||||
|
bNode *less_than_or_equal = nodeAddNode(nullptr, group, "FunctionNodeCompare");
|
||||||
|
static_cast<NodeFunctionCompare *>(less_than_or_equal->storage)->operation =
|
||||||
|
NODE_COMPARE_LESS_EQUAL;
|
||||||
|
less_than_or_equal->locx = -240.0f;
|
||||||
|
less_than_or_equal->locy = -180.0f;
|
||||||
|
|
||||||
|
nodeAddLink(group,
|
||||||
|
edge_angle,
|
||||||
|
nodeFindSocket(edge_angle, SOCK_OUT, "Unsigned Angle"),
|
||||||
|
less_than_or_equal,
|
||||||
|
nodeFindSocket(less_than_or_equal, SOCK_IN, "A"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
shade_smooth_face,
|
||||||
|
nodeFindSocket(shade_smooth_face, SOCK_OUT, "Geometry"),
|
||||||
|
group_output,
|
||||||
|
nodeFindSocket(group_output, SOCK_IN, "Socket_0"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
group_input_angle,
|
||||||
|
nodeFindSocket(group_input_angle, SOCK_OUT, "Socket_1"),
|
||||||
|
less_than_or_equal,
|
||||||
|
nodeFindSocket(less_than_or_equal, SOCK_IN, "B"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
less_than_or_equal,
|
||||||
|
nodeFindSocket(less_than_or_equal, SOCK_OUT, "Result"),
|
||||||
|
boolean_and,
|
||||||
|
nodeFindSocket(boolean_and, SOCK_IN, "Boolean"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
face_smooth,
|
||||||
|
nodeFindSocket(face_smooth, SOCK_OUT, "Smooth"),
|
||||||
|
boolean_and,
|
||||||
|
nodeFindSocket(boolean_and, SOCK_IN, "Boolean_001"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
group_input_mesh,
|
||||||
|
nodeFindSocket(group_input_mesh, SOCK_OUT, "Socket_0"),
|
||||||
|
shade_smooth_edge,
|
||||||
|
nodeFindSocket(shade_smooth_edge, SOCK_IN, "Geometry"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
edge_smooth,
|
||||||
|
nodeFindSocket(edge_smooth, SOCK_OUT, "Smooth"),
|
||||||
|
shade_smooth_edge,
|
||||||
|
nodeFindSocket(shade_smooth_edge, SOCK_IN, "Selection"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
shade_smooth_edge,
|
||||||
|
nodeFindSocket(shade_smooth_edge, SOCK_OUT, "Geometry"),
|
||||||
|
shade_smooth_face,
|
||||||
|
nodeFindSocket(shade_smooth_face, SOCK_IN, "Geometry"));
|
||||||
|
nodeAddLink(group,
|
||||||
|
boolean_and,
|
||||||
|
nodeFindSocket(boolean_and, SOCK_OUT, "Boolean"),
|
||||||
|
shade_smooth_edge,
|
||||||
|
nodeFindSocket(shade_smooth_edge, SOCK_IN, "Shade Smooth"));
|
||||||
|
|
||||||
|
LISTBASE_FOREACH (bNode *, node, &group->nodes) {
|
||||||
|
nodeSetSelected(node, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain)
|
||||||
|
{
|
||||||
|
using namespace blender;
|
||||||
|
bNodeTree *auto_smooth_node_tree = nullptr;
|
||||||
|
LISTBASE_FOREACH (Object *, object, &bmain.objects) {
|
||||||
|
if (object->type != OB_MESH) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Mesh *mesh = static_cast<Mesh *>(object->data);
|
||||||
|
if (!(mesh->flag & ME_AUTOSMOOTH_LEGACY)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!auto_smooth_node_tree) {
|
||||||
|
auto_smooth_node_tree = add_auto_smooth_node_tree(bmain);
|
||||||
|
BKE_ntree_update_main_tree(&bmain, auto_smooth_node_tree, nullptr);
|
||||||
|
}
|
||||||
|
auto *md = reinterpret_cast<NodesModifierData *>(BKE_modifier_new(eModifierType_Nodes));
|
||||||
|
STRNCPY(md->modifier.name, DATA_("Auto Smooth"));
|
||||||
|
BKE_modifier_unique_name(&object->modifiers, &md->modifier);
|
||||||
|
md->node_group = auto_smooth_node_tree;
|
||||||
|
if (!BLI_listbase_is_empty(&object->modifiers) &&
|
||||||
|
static_cast<ModifierData *>(object->modifiers.last)->type == eModifierType_Subsurf)
|
||||||
|
{
|
||||||
|
/* Add the auto smooth node group before the last subdivision surface modifier if possible.
|
||||||
|
* Subdivision surface modifiers have special handling for interpolating face corner normals,
|
||||||
|
* and recalculating them afterwards isn't usually helpful and can be much slower. */
|
||||||
|
BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, md);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_addtail(&object->modifiers, md);
|
||||||
|
}
|
||||||
|
|
||||||
|
md->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release();
|
||||||
|
IDProperty *angle_prop =
|
||||||
|
bke::idprop::create(DATA_("Socket_1"), mesh->smoothresh_legacy).release();
|
||||||
|
auto *ui_data = reinterpret_cast<IDPropertyUIDataFloat *>(IDP_ui_data_ensure(angle_prop));
|
||||||
|
ui_data->base.rna_subtype = PROP_ANGLE;
|
||||||
|
IDP_AddToGroup(md->settings.properties, angle_prop);
|
||||||
|
IDP_AddToGroup(md->settings.properties,
|
||||||
|
bke::idprop::create(DATA_("Input_1_use_attribute"), 0).release());
|
||||||
|
IDP_AddToGroup(md->settings.properties,
|
||||||
|
bke::idprop::create(DATA_("Input_1_attribute_name"), "").release());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "DNA_meshdata_types.h"
|
#include "DNA_meshdata_types.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
|
#include "BKE_attribute.hh"
|
||||||
#include "BKE_deform.h"
|
#include "BKE_deform.h"
|
||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_lib_query.h"
|
#include "BKE_lib_query.h"
|
||||||
|
@ -389,8 +390,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle custom split normals */
|
/* handle custom split normals */
|
||||||
if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
|
if (ob->type == OB_MESH && CustomData_has_layer(&result->loop_data, CD_CUSTOMLOOPNORMAL) &&
|
||||||
CustomData_has_layer(&result->loop_data, CD_CUSTOMLOOPNORMAL) && result->faces_num > 0)
|
result->faces_num > 0)
|
||||||
{
|
{
|
||||||
blender::Array<blender::float3> loop_normals(result_corner_verts.size());
|
blender::Array<blender::float3> loop_normals(result_corner_verts.size());
|
||||||
blender::short2 *clnors = static_cast<blender::short2 *>(
|
blender::short2 *clnors = static_cast<blender::short2 *>(
|
||||||
|
@ -420,8 +421,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
|
||||||
sharp_edges,
|
sharp_edges,
|
||||||
sharp_faces,
|
sharp_faces,
|
||||||
clnors,
|
clnors,
|
||||||
true,
|
|
||||||
result->smoothresh,
|
|
||||||
&lnors_spacearr,
|
&lnors_spacearr,
|
||||||
loop_normals);
|
loop_normals);
|
||||||
|
|
||||||
|
|
|
@ -299,6 +299,42 @@ static void normals_calc_faces_and_verts(const Span<float3> positions,
|
||||||
/** \name Mesh Normal Calculation
|
/** \name Mesh Normal Calculation
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
blender::bke::MeshNormalDomain Mesh::normals_domain() const
|
||||||
|
{
|
||||||
|
using namespace blender;
|
||||||
|
using namespace blender::bke;
|
||||||
|
if (this->faces_num == 0) {
|
||||||
|
return MeshNormalDomain::Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CustomData_has_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
return MeshNormalDomain::Corner;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AttributeAccessor attributes = this->attributes();
|
||||||
|
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
||||||
|
"sharp_face", ATTR_DOMAIN_FACE, false);
|
||||||
|
|
||||||
|
const array_utils::BooleanMix face_mix = array_utils::booleans_mix_calc(sharp_faces);
|
||||||
|
if (face_mix == array_utils::BooleanMix::AllTrue) {
|
||||||
|
return MeshNormalDomain::Face;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VArray<bool> sharp_edges = *attributes.lookup_or_default<bool>(
|
||||||
|
"sharp_edge", ATTR_DOMAIN_EDGE, false);
|
||||||
|
const array_utils::BooleanMix edge_mix = array_utils::booleans_mix_calc(sharp_edges);
|
||||||
|
if (edge_mix == array_utils::BooleanMix::AllTrue) {
|
||||||
|
return MeshNormalDomain::Face;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edge_mix == array_utils::BooleanMix::AllFalse &&
|
||||||
|
face_mix == array_utils::BooleanMix::AllFalse) {
|
||||||
|
return MeshNormalDomain::Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MeshNormalDomain::Corner;
|
||||||
|
}
|
||||||
|
|
||||||
blender::Span<blender::float3> Mesh::vert_normals() const
|
blender::Span<blender::float3> Mesh::vert_normals() const
|
||||||
{
|
{
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
|
@ -348,25 +384,52 @@ blender::Span<blender::float3> Mesh::face_normals() const
|
||||||
return this->runtime->face_normals_cache.data();
|
return this->runtime->face_normals_cache.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
|
blender::Span<blender::float3> Mesh::corner_normals() const
|
||||||
{
|
{
|
||||||
switch (mesh->runtime->wrapper_type) {
|
using namespace blender;
|
||||||
case ME_WRAPPER_TYPE_SUBD:
|
using namespace blender::bke;
|
||||||
case ME_WRAPPER_TYPE_MDATA:
|
this->runtime->corner_normals_cache.ensure([&](Vector<float3> &r_data) {
|
||||||
mesh->vert_normals();
|
r_data.reinitialize(this->totloop);
|
||||||
mesh->face_normals();
|
const OffsetIndices<int> faces = this->faces();
|
||||||
break;
|
switch (this->normals_domain()) {
|
||||||
case ME_WRAPPER_TYPE_BMESH: {
|
case MeshNormalDomain::Point: {
|
||||||
BMEditMesh *em = mesh->edit_mesh;
|
array_utils::gather(this->vert_normals(), this->corner_verts(), r_data.as_mutable_span());
|
||||||
if (blender::bke::EditMeshData *emd = mesh->runtime->edit_data) {
|
break;
|
||||||
if (!emd->vertexCos.is_empty()) {
|
}
|
||||||
BKE_editmesh_cache_ensure_vert_normals(em, emd);
|
case MeshNormalDomain::Face: {
|
||||||
BKE_editmesh_cache_ensure_face_normals(em, emd);
|
const Span<float3> face_normals = this->face_normals();
|
||||||
}
|
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
||||||
|
for (const int i : range) {
|
||||||
|
r_data.as_mutable_span().slice(faces[i]).fill(face_normals[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MeshNormalDomain::Corner: {
|
||||||
|
const bool *sharp_edges = static_cast<const bool *>(
|
||||||
|
CustomData_get_layer_named(&this->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
||||||
|
const bool *sharp_faces = static_cast<const bool *>(
|
||||||
|
CustomData_get_layer_named(&this->face_data, CD_PROP_BOOL, "sharp_face"));
|
||||||
|
const short2 *custom_normals = static_cast<const short2 *>(
|
||||||
|
CustomData_get_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL));
|
||||||
|
mesh::normals_calc_loop(this->vert_positions(),
|
||||||
|
this->edges(),
|
||||||
|
this->faces(),
|
||||||
|
this->corner_verts(),
|
||||||
|
this->corner_edges(),
|
||||||
|
this->corner_to_face_map(),
|
||||||
|
this->vert_normals(),
|
||||||
|
this->face_normals(),
|
||||||
|
sharp_edges,
|
||||||
|
sharp_faces,
|
||||||
|
custom_normals,
|
||||||
|
nullptr,
|
||||||
|
r_data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
return this->runtime->corner_normals_cache.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
|
void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
|
||||||
|
@ -764,7 +827,7 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> faces,
|
||||||
|
|
||||||
/* We want to avoid tagging edges as sharp when it is already defined as such by
|
/* We want to avoid tagging edges as sharp when it is already defined as such by
|
||||||
* other causes than angle threshold. */
|
* other causes than angle threshold. */
|
||||||
if (!r_sharp_edges.is_empty() && is_angle_sharp) {
|
if (is_angle_sharp) {
|
||||||
r_sharp_edges[edge_i] = true;
|
r_sharp_edges[edge_i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -778,9 +841,60 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> faces,
|
||||||
|
|
||||||
/* We want to avoid tagging edges as sharp when it is already defined as such by
|
/* We want to avoid tagging edges as sharp when it is already defined as such by
|
||||||
* other causes than angle threshold. */
|
* other causes than angle threshold. */
|
||||||
if (!r_sharp_edges.is_empty()) {
|
r_sharp_edges[edge_i] = false;
|
||||||
r_sharp_edges[edge_i] = false;
|
}
|
||||||
|
/* Else, edge is already 'disqualified' (i.e. sharp)! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a simplified map from edges to face corners, marking special values when
|
||||||
|
* it encounters sharp edges or borders between faces with flipped winding orders.
|
||||||
|
*/
|
||||||
|
static void build_edge_to_loop_map_with_flip_and_sharp(const OffsetIndices<int> faces,
|
||||||
|
const Span<int> corner_verts,
|
||||||
|
const Span<int> corner_edges,
|
||||||
|
const Span<bool> sharp_faces,
|
||||||
|
const Span<bool> sharp_edges,
|
||||||
|
MutableSpan<int2> edge_to_loops)
|
||||||
|
{
|
||||||
|
auto face_is_smooth = [&](const int face_i) {
|
||||||
|
return sharp_faces.is_empty() || !sharp_faces[face_i];
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const int face_i : faces.index_range()) {
|
||||||
|
for (const int loop_index : faces[face_i]) {
|
||||||
|
const int vert_i = corner_verts[loop_index];
|
||||||
|
const int edge_i = corner_edges[loop_index];
|
||||||
|
|
||||||
|
int2 &e2l = edge_to_loops[edge_i];
|
||||||
|
|
||||||
|
/* Check whether current edge might be smooth or sharp */
|
||||||
|
if ((e2l[0] | e2l[1]) == 0) {
|
||||||
|
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
|
||||||
|
e2l[0] = loop_index;
|
||||||
|
/* We have to check this here too, else we might miss some flat faces!!! */
|
||||||
|
e2l[1] = !face_is_smooth(face_i) ? INDEX_INVALID : INDEX_UNSET;
|
||||||
|
}
|
||||||
|
else if (e2l[1] == INDEX_UNSET) {
|
||||||
|
/* Second loop using this edge, time to test its sharpness.
|
||||||
|
* An edge is sharp if it is tagged as such, or its face is not smooth,
|
||||||
|
* or both face have opposed (flipped) normals, i.e. both loops on the same edge share the
|
||||||
|
* same vertex. */
|
||||||
|
if (!face_is_smooth(face_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
|
||||||
|
vert_i == corner_verts[e2l[0]])
|
||||||
|
{
|
||||||
|
/* NOTE: we are sure that loop != 0 here ;). */
|
||||||
|
e2l[1] = INDEX_INVALID;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
e2l[1] = loop_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!IS_EDGE_SHARP(e2l)) {
|
||||||
|
/* More than two loops using this edge, tag as sharp if not yet done. */
|
||||||
|
e2l[1] = INDEX_INVALID;
|
||||||
}
|
}
|
||||||
/* Else, edge is already 'disqualified' (i.e. sharp)! */
|
/* Else, edge is already 'disqualified' (i.e. sharp)! */
|
||||||
}
|
}
|
||||||
|
@ -1209,36 +1323,9 @@ void normals_calc_loop(const Span<float3> vert_positions,
|
||||||
const bool *sharp_edges,
|
const bool *sharp_edges,
|
||||||
const bool *sharp_faces,
|
const bool *sharp_faces,
|
||||||
const short2 *clnors_data,
|
const short2 *clnors_data,
|
||||||
bool use_split_normals,
|
|
||||||
float split_angle,
|
|
||||||
CornerNormalSpaceArray *r_lnors_spacearr,
|
CornerNormalSpaceArray *r_lnors_spacearr,
|
||||||
MutableSpan<float3> r_loop_normals)
|
MutableSpan<float3> r_loop_normals)
|
||||||
{
|
{
|
||||||
/* For now this is not supported.
|
|
||||||
* If we do not use split normals, we do not generate anything fancy! */
|
|
||||||
BLI_assert(use_split_normals || !(r_lnors_spacearr));
|
|
||||||
|
|
||||||
if (!use_split_normals) {
|
|
||||||
/* In this case, simply fill `r_loop_normals` with `vert_normals`
|
|
||||||
* (or `face_normals` for flat faces), quite simple!
|
|
||||||
* Note this is done here to keep some logic and consistency in this quite complex code,
|
|
||||||
* since we may want to use loop_normals even when mesh's 'autosmooth' is disabled
|
|
||||||
* (see e.g. mesh mapping code). As usual, we could handle that on case-by-case basis,
|
|
||||||
* but simpler to keep it well confined here. */
|
|
||||||
for (const int face_index : faces.index_range()) {
|
|
||||||
const bool is_face_flat = sharp_faces && sharp_faces[face_index];
|
|
||||||
for (const int corner : faces[face_index]) {
|
|
||||||
if (is_face_flat) {
|
|
||||||
copy_v3_v3(r_loop_normals[corner], face_normals[face_index]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
copy_v3_v3(r_loop_normals[corner], vert_normals[corner_verts[corner]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping edge -> loops.
|
* Mapping edge -> loops.
|
||||||
* If that edge is used by more than two loops (faces),
|
* If that edge is used by more than two loops (faces),
|
||||||
|
@ -1255,9 +1342,6 @@ void normals_calc_loop(const Span<float3> vert_positions,
|
||||||
* Note also that loose edges always have both values set to 0! */
|
* Note also that loose edges always have both values set to 0! */
|
||||||
Array<int2> edge_to_loops(edges.size(), int2(0));
|
Array<int2> edge_to_loops(edges.size(), int2(0));
|
||||||
|
|
||||||
/* When using custom loop normals, disable the angle feature! */
|
|
||||||
const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr);
|
|
||||||
|
|
||||||
CornerNormalSpaceArray _lnors_spacearr;
|
CornerNormalSpaceArray _lnors_spacearr;
|
||||||
|
|
||||||
#ifdef DEBUG_TIME
|
#ifdef DEBUG_TIME
|
||||||
|
@ -1289,17 +1373,13 @@ void normals_calc_loop(const Span<float3> vert_positions,
|
||||||
array_utils::gather(vert_normals, corner_verts, r_loop_normals, 1024);
|
array_utils::gather(vert_normals, corner_verts, r_loop_normals, 1024);
|
||||||
|
|
||||||
/* This first loop check which edges are actually smooth, and compute edge vectors. */
|
/* This first loop check which edges are actually smooth, and compute edge vectors. */
|
||||||
mesh_edges_sharp_tag(faces,
|
build_edge_to_loop_map_with_flip_and_sharp(
|
||||||
corner_verts,
|
faces,
|
||||||
corner_edges,
|
corner_verts,
|
||||||
loop_to_face_map,
|
corner_edges,
|
||||||
face_normals,
|
Span<bool>(sharp_faces, sharp_faces ? faces.size() : 0),
|
||||||
Span<bool>(sharp_faces, sharp_faces ? faces.size() : 0),
|
Span<bool>(sharp_edges, sharp_edges ? edges.size() : 0),
|
||||||
Span<bool>(sharp_edges, sharp_edges ? edges.size() : 0),
|
edge_to_loops);
|
||||||
check_angle,
|
|
||||||
split_angle,
|
|
||||||
edge_to_loops,
|
|
||||||
{});
|
|
||||||
|
|
||||||
Vector<int> single_corners;
|
Vector<int> single_corners;
|
||||||
Vector<int> fan_corners;
|
Vector<int> fan_corners;
|
||||||
|
@ -1367,10 +1447,6 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
||||||
BitVector<> done_loops(corner_verts.size(), false);
|
BitVector<> done_loops(corner_verts.size(), false);
|
||||||
Array<float3> loop_normals(corner_verts.size());
|
Array<float3> loop_normals(corner_verts.size());
|
||||||
const Array<int> loop_to_face = build_loop_to_face_map(faces);
|
const Array<int> loop_to_face = build_loop_to_face_map(faces);
|
||||||
/* In this case we always consider split nors as ON,
|
|
||||||
* and do not want to use angle to define smooth fans! */
|
|
||||||
const bool use_split_normals = true;
|
|
||||||
const float split_angle = float(M_PI);
|
|
||||||
|
|
||||||
/* Compute current lnor spacearr. */
|
/* Compute current lnor spacearr. */
|
||||||
normals_calc_loop(positions,
|
normals_calc_loop(positions,
|
||||||
|
@ -1384,8 +1460,6 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
||||||
sharp_edges.data(),
|
sharp_edges.data(),
|
||||||
sharp_faces,
|
sharp_faces,
|
||||||
r_clnors_data.data(),
|
r_clnors_data.data(),
|
||||||
use_split_normals,
|
|
||||||
split_angle,
|
|
||||||
&lnors_spacearr,
|
&lnors_spacearr,
|
||||||
loop_normals);
|
loop_normals);
|
||||||
|
|
||||||
|
@ -1507,8 +1581,6 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
||||||
sharp_edges.data(),
|
sharp_edges.data(),
|
||||||
sharp_faces,
|
sharp_faces,
|
||||||
r_clnors_data.data(),
|
r_clnors_data.data(),
|
||||||
use_split_normals,
|
|
||||||
split_angle,
|
|
||||||
&lnors_spacearr,
|
&lnors_spacearr,
|
||||||
loop_normals);
|
loop_normals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,20 +303,6 @@ void BKE_mesh_remap_find_best_match_from_mesh(const float (*vert_positions_dst)[
|
||||||
/** \name Mesh to Mesh Mapping
|
/** \name Mesh to Mesh Mapping
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int /*vert_mode*/,
|
|
||||||
const int /*edge_mode*/,
|
|
||||||
const int loop_mode,
|
|
||||||
const int /*face_mode*/,
|
|
||||||
CustomData_MeshMasks *r_cddata_mask)
|
|
||||||
{
|
|
||||||
/* vert, edge and face mapping modes never need extra cddata from source object. */
|
|
||||||
const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL);
|
|
||||||
|
|
||||||
if (need_lnors_src) {
|
|
||||||
r_cddata_mask->lmask |= CD_MASK_NORMAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
|
void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
|
||||||
{
|
{
|
||||||
MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||||
|
@ -469,7 +455,6 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
|
||||||
const float ray_radius,
|
const float ray_radius,
|
||||||
const float (*vert_positions_dst)[3],
|
const float (*vert_positions_dst)[3],
|
||||||
const int numverts_dst,
|
const int numverts_dst,
|
||||||
const bool /*dirty_nors_dst*/,
|
|
||||||
const Mesh *me_src,
|
const Mesh *me_src,
|
||||||
Mesh *me_dst,
|
Mesh *me_dst,
|
||||||
MeshPairRemap *r_map)
|
MeshPairRemap *r_map)
|
||||||
|
@ -695,7 +680,6 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
|
||||||
const int numverts_dst,
|
const int numverts_dst,
|
||||||
const blender::int2 *edges_dst,
|
const blender::int2 *edges_dst,
|
||||||
const int numedges_dst,
|
const int numedges_dst,
|
||||||
const bool /*dirty_nors_dst*/,
|
|
||||||
const Mesh *me_src,
|
const Mesh *me_src,
|
||||||
Mesh *me_dst,
|
Mesh *me_dst,
|
||||||
MeshPairRemap *r_map)
|
MeshPairRemap *r_map)
|
||||||
|
@ -1228,19 +1212,12 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
||||||
const SpaceTransform *space_transform,
|
const SpaceTransform *space_transform,
|
||||||
const float max_dist,
|
const float max_dist,
|
||||||
const float ray_radius,
|
const float ray_radius,
|
||||||
Mesh *mesh_dst,
|
const Mesh *mesh_dst,
|
||||||
const float (*vert_positions_dst)[3],
|
const float (*vert_positions_dst)[3],
|
||||||
const int numverts_dst,
|
const int numverts_dst,
|
||||||
const blender::int2 *edges_dst,
|
|
||||||
const int numedges_dst,
|
|
||||||
const int *corner_verts_dst,
|
const int *corner_verts_dst,
|
||||||
const int *corner_edges_dst,
|
|
||||||
const int numloops_dst,
|
const int numloops_dst,
|
||||||
const blender::OffsetIndices<int> faces_dst,
|
const blender::OffsetIndices<int> faces_dst,
|
||||||
CustomData *ldata_dst,
|
|
||||||
const bool use_split_nors_dst,
|
|
||||||
const float split_angle_dst,
|
|
||||||
const bool dirty_nors_dst,
|
|
||||||
const Mesh *me_src,
|
const Mesh *me_src,
|
||||||
MeshRemapIslandsCalc gen_islands_src,
|
MeshRemapIslandsCalc gen_islands_src,
|
||||||
const float islands_precision_src,
|
const float islands_precision_src,
|
||||||
|
@ -1286,7 +1263,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
||||||
blender::Span<blender::float3> loop_normals_src;
|
blender::Span<blender::float3> loop_normals_src;
|
||||||
|
|
||||||
blender::Span<blender::float3> face_normals_dst;
|
blender::Span<blender::float3> face_normals_dst;
|
||||||
blender::float3 *loop_normals_dst;
|
blender::Span<blender::float3> loop_normals_dst;
|
||||||
|
|
||||||
blender::Array<blender::float3> face_cents_src;
|
blender::Array<blender::float3> face_cents_src;
|
||||||
|
|
||||||
|
@ -1342,52 +1319,13 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
||||||
face_normals_dst = mesh_dst->face_normals();
|
face_normals_dst = mesh_dst->face_normals();
|
||||||
}
|
}
|
||||||
if (need_lnors_dst) {
|
if (need_lnors_dst) {
|
||||||
const blender::short2 *custom_nors_dst = static_cast<const blender::short2 *>(
|
loop_normals_dst = mesh_dst->corner_normals();
|
||||||
CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL));
|
|
||||||
|
|
||||||
/* Cache loop normals into a temporary custom data layer. */
|
|
||||||
loop_normals_dst = static_cast<blender::float3 *>(
|
|
||||||
CustomData_get_layer_for_write(ldata_dst, CD_NORMAL, numloops_dst));
|
|
||||||
|
|
||||||
const bool do_loop_normals_dst = (loop_normals_dst == nullptr);
|
|
||||||
if (!loop_normals_dst) {
|
|
||||||
loop_normals_dst = static_cast<blender::float3 *>(
|
|
||||||
CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, numloops_dst));
|
|
||||||
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
|
||||||
if (dirty_nors_dst || do_loop_normals_dst) {
|
|
||||||
const bool *sharp_edges = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&mesh_dst->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
|
||||||
const bool *sharp_faces = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&mesh_dst->face_data, CD_PROP_BOOL, "sharp_face"));
|
|
||||||
blender::bke::mesh::normals_calc_loop(
|
|
||||||
{reinterpret_cast<const blender::float3 *>(vert_positions_dst), numverts_dst},
|
|
||||||
{edges_dst, numedges_dst},
|
|
||||||
faces_dst,
|
|
||||||
{corner_verts_dst, numloops_dst},
|
|
||||||
{corner_edges_dst, numloops_dst},
|
|
||||||
mesh_dst->corner_to_face_map(),
|
|
||||||
mesh_dst->vert_normals(),
|
|
||||||
mesh_dst->face_normals(),
|
|
||||||
sharp_edges,
|
|
||||||
sharp_faces,
|
|
||||||
custom_nors_dst,
|
|
||||||
use_split_nors_dst,
|
|
||||||
split_angle_dst,
|
|
||||||
nullptr,
|
|
||||||
{loop_normals_dst, numloops_dst});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (need_pnors_src || need_lnors_src) {
|
if (need_pnors_src) {
|
||||||
if (need_pnors_src) {
|
face_normals_src = me_src->face_normals();
|
||||||
face_normals_src = me_src->face_normals();
|
}
|
||||||
}
|
if (need_lnors_src) {
|
||||||
if (need_lnors_src) {
|
loop_normals_src = me_src->corner_normals();
|
||||||
loop_normals_src = {static_cast<const blender::float3 *>(
|
|
||||||
CustomData_get_layer(&me_src->loop_data, CD_NORMAL)),
|
|
||||||
me_src->totloop};
|
|
||||||
BLI_assert(loop_normals_src.data() != nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -355,10 +355,16 @@ void BKE_mesh_tag_edges_split(Mesh *mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BKE_mesh_tag_sharpness_changed(Mesh *mesh)
|
||||||
|
{
|
||||||
|
mesh->runtime->corner_normals_cache.tag_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
void BKE_mesh_tag_face_winding_changed(Mesh *mesh)
|
void BKE_mesh_tag_face_winding_changed(Mesh *mesh)
|
||||||
{
|
{
|
||||||
mesh->runtime->vert_normals_cache.tag_dirty();
|
mesh->runtime->vert_normals_cache.tag_dirty();
|
||||||
mesh->runtime->face_normals_cache.tag_dirty();
|
mesh->runtime->face_normals_cache.tag_dirty();
|
||||||
|
mesh->runtime->corner_normals_cache.tag_dirty();
|
||||||
mesh->runtime->vert_to_corner_map_cache.tag_dirty();
|
mesh->runtime->vert_to_corner_map_cache.tag_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +372,7 @@ void BKE_mesh_tag_positions_changed(Mesh *mesh)
|
||||||
{
|
{
|
||||||
mesh->runtime->vert_normals_cache.tag_dirty();
|
mesh->runtime->vert_normals_cache.tag_dirty();
|
||||||
mesh->runtime->face_normals_cache.tag_dirty();
|
mesh->runtime->face_normals_cache.tag_dirty();
|
||||||
|
mesh->runtime->corner_normals_cache.tag_dirty();
|
||||||
BKE_mesh_tag_positions_changed_no_normals(mesh);
|
BKE_mesh_tag_positions_changed_no_normals(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,20 +138,12 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float(*loop_normals)[3] = static_cast<const float(*)[3]>(
|
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_NORMAL));
|
|
||||||
if (!loop_normals) {
|
|
||||||
BKE_report(
|
|
||||||
reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BKE_mesh_calc_loop_tangent_single_ex(
|
BKE_mesh_calc_loop_tangent_single_ex(
|
||||||
reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()),
|
reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()),
|
||||||
mesh->totvert,
|
mesh->totvert,
|
||||||
mesh->corner_verts().data(),
|
mesh->corner_verts().data(),
|
||||||
r_looptangents,
|
r_looptangents,
|
||||||
loop_normals,
|
reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data()),
|
||||||
reinterpret_cast<const float(*)[2]>(uv_map.data()),
|
reinterpret_cast<const float(*)[2]>(uv_map.data()),
|
||||||
mesh->totloop,
|
mesh->totloop,
|
||||||
mesh->faces(),
|
mesh->faces(),
|
||||||
|
@ -606,7 +598,7 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
|
||||||
tangent_names_len,
|
tangent_names_len,
|
||||||
reinterpret_cast<const float(*)[3]>(me_eval->vert_normals().data()),
|
reinterpret_cast<const float(*)[3]>(me_eval->vert_normals().data()),
|
||||||
reinterpret_cast<const float(*)[3]>(me_eval->face_normals().data()),
|
reinterpret_cast<const float(*)[3]>(me_eval->face_normals().data()),
|
||||||
static_cast<const float(*)[3]>(CustomData_get_layer(&me_eval->loop_data, CD_NORMAL)),
|
reinterpret_cast<const float(*)[3]>(me_eval->corner_normals().data()),
|
||||||
/* may be nullptr */
|
/* may be nullptr */
|
||||||
static_cast<const float(*)[3]>(CustomData_get_layer(&me_eval->vert_data, CD_ORCO)),
|
static_cast<const float(*)[3]>(CustomData_get_layer(&me_eval->vert_data, CD_ORCO)),
|
||||||
/* result */
|
/* result */
|
||||||
|
|
|
@ -130,16 +130,17 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
|
||||||
me->vert_positions_for_write().copy_from(edit_data->vertexCos);
|
me->vert_positions_for_write().copy_from(edit_data->vertexCos);
|
||||||
me->runtime->is_original_bmesh = false;
|
me->runtime->is_original_bmesh = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (me->runtime->wrapper_type_finalize) {
|
||||||
|
BKE_mesh_wrapper_deferred_finalize_mdata(me);
|
||||||
|
}
|
||||||
|
|
||||||
MEM_delete(me->runtime->edit_data);
|
MEM_delete(me->runtime->edit_data);
|
||||||
me->runtime->edit_data = nullptr;
|
me->runtime->edit_data = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me->runtime->wrapper_type_finalize) {
|
|
||||||
BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime->cd_mask_extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep type assignment last, so that read-only access only uses the mdata code paths after all
|
/* Keep type assignment last, so that read-only access only uses the mdata code paths after all
|
||||||
* the underlying data has been initialized. */
|
* the underlying data has been initialized. */
|
||||||
me->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA;
|
me->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA;
|
||||||
|
@ -384,22 +385,17 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
|
||||||
if (use_clnors) {
|
if (use_clnors) {
|
||||||
/* If custom normals are present and the option is turned on calculate the split
|
/* If custom normals are present and the option is turned on calculate the split
|
||||||
* normals and clear flag so the normals get interpolated to the result mesh. */
|
* normals and clear flag so the normals get interpolated to the result mesh. */
|
||||||
BKE_mesh_calc_normals_split(me);
|
void *data = CustomData_add_layer(&me->loop_data, CD_NORMAL, CD_CONSTRUCT, me->totloop);
|
||||||
CustomData_clear_layer_flag(&me->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
memcpy(data, me->corner_normals().data(), me->corner_normals().size_in_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me);
|
Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me);
|
||||||
|
|
||||||
if (use_clnors) {
|
if (use_clnors) {
|
||||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
BKE_mesh_set_custom_normals(subdiv_mesh,
|
||||||
CustomData_get_layer_for_write(&subdiv_mesh->loop_data, CD_NORMAL, subdiv_mesh->totloop));
|
static_cast<float(*)[3]>(CustomData_get_layer_for_write(
|
||||||
BLI_assert(lnors != nullptr);
|
&subdiv_mesh->loop_data, CD_NORMAL, me->totloop)));
|
||||||
BKE_mesh_set_custom_normals(subdiv_mesh, lnors);
|
CustomData_free_layers(&subdiv_mesh->loop_data, CD_NORMAL, me->totloop);
|
||||||
CustomData_set_layer_flag(&me->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
CustomData_set_layer_flag(&subdiv_mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
|
||||||
else if (runtime_data->calc_loop_normals) {
|
|
||||||
BKE_mesh_calc_normals_split(subdiv_mesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "BKE_DerivedMesh.h"
|
#include "BKE_DerivedMesh.h"
|
||||||
|
#include "BKE_attribute.h"
|
||||||
#include "BKE_cdderivedmesh.h"
|
#include "BKE_cdderivedmesh.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_lattice.h"
|
#include "BKE_lattice.h"
|
||||||
|
@ -141,9 +142,8 @@ bool BKE_shrinkwrap_init_tree(
|
||||||
|
|
||||||
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
|
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
|
||||||
data->face_normals = reinterpret_cast<const float(*)[3]>(mesh->face_normals().data());
|
data->face_normals = reinterpret_cast<const float(*)[3]>(mesh->face_normals().data());
|
||||||
if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
|
if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
data->clnors = static_cast<const float(*)[3]>(
|
data->clnors = reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data());
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_NORMAL));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "BKE_attribute.h"
|
||||||
#include "BKE_subdiv_modifier.hh"
|
#include "BKE_subdiv_modifier.hh"
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
@ -85,14 +86,8 @@ static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
|
||||||
|
|
||||||
bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd, const Mesh *mesh)
|
bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd, const Mesh *mesh)
|
||||||
{
|
{
|
||||||
return (smd->flags & eSubsurfModifierFlag_UseCustomNormals) && (mesh->flag & ME_AUTOSMOOTH) &&
|
return smd->flags & eSubsurfModifierFlag_UseCustomNormals &&
|
||||||
CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL);
|
mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner;
|
||||||
}
|
|
||||||
|
|
||||||
static bool subsurf_modifier_use_autosmooth_or_split_normals(const SubsurfModifierData *smd,
|
|
||||||
const Mesh *mesh)
|
|
||||||
{
|
|
||||||
return (mesh->flag & ME_AUTOSMOOTH) || BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_subdivision_evaluation_possible_on_gpu()
|
static bool is_subdivision_evaluation_possible_on_gpu()
|
||||||
|
@ -126,7 +121,7 @@ bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfMod
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh);
|
return BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
|
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
|
||||||
|
@ -141,7 +136,7 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
|
||||||
|
|
||||||
/* Deactivate GPU subdivision if autosmooth or custom split normals are used as those are
|
/* Deactivate GPU subdivision if autosmooth or custom split normals are used as those are
|
||||||
* complicated to support on GPU, and should really be separate workflows. */
|
* complicated to support on GPU, and should really be separate workflows. */
|
||||||
if (subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh)) {
|
if (BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -529,9 +529,9 @@ void blo_do_versions_270(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 270, 2)) {
|
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 270, 2)) {
|
||||||
/* Mesh smoothresh deg->rad. */
|
/* Mesh smoothresh_legacy deg->rad. */
|
||||||
LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
|
LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
|
||||||
me->smoothresh = DEG2RADF(me->smoothresh);
|
me->smoothresh_legacy = DEG2RADF(me->smoothresh_legacy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "BKE_lib_override.hh"
|
#include "BKE_lib_override.hh"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_main_namemap.h"
|
#include "BKE_main_namemap.h"
|
||||||
|
#include "BKE_mesh_legacy_convert.hh"
|
||||||
#include "BKE_node.hh"
|
#include "BKE_node.hh"
|
||||||
#include "BKE_node_runtime.hh"
|
#include "BKE_node_runtime.hh"
|
||||||
|
|
||||||
|
@ -526,4 +527,8 @@ void do_versions_after_setup(Main *new_bmain, BlendFileReadReport *reports)
|
||||||
/* Does not add any new IDs, but needs the full Main data-base. */
|
/* Does not add any new IDs, but needs the full Main data-base. */
|
||||||
BKE_lib_override_library_main_hierarchy_root_ensure(new_bmain);
|
BKE_lib_override_library_main_hierarchy_root_ensure(new_bmain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!blendfile_or_libraries_versions_atleast(new_bmain, 401, 2)) {
|
||||||
|
BKE_main_mesh_legacy_convert_auto_smooth(*new_bmain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
* To update preference defaults see `userdef_default.c`.
|
* To update preference defaults see `userdef_default.c`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define DNA_DEPRECATED_ALLOW
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
|
@ -591,7 +593,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
|
||||||
|
|
||||||
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
|
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
|
||||||
/* Match default for new meshes. */
|
/* Match default for new meshes. */
|
||||||
mesh->smoothresh = DEG2RADF(30);
|
mesh->smoothresh_legacy = DEG2RADF(30);
|
||||||
/* Match voxel remesher options for all existing meshes in templates. */
|
/* Match voxel remesher options for all existing meshes in templates. */
|
||||||
mesh->flag |= ME_REMESH_REPROJECT_VOLUME | ME_REMESH_REPROJECT_PAINT_MASK |
|
mesh->flag |= ME_REMESH_REPROJECT_VOLUME | ME_REMESH_REPROJECT_PAINT_MASK |
|
||||||
ME_REMESH_REPROJECT_SCULPT_FACE_SETS | ME_REMESH_REPROJECT_VERTEX_COLORS;
|
ME_REMESH_REPROJECT_SCULPT_FACE_SETS | ME_REMESH_REPROJECT_VERTEX_COLORS;
|
||||||
|
|
|
@ -635,7 +635,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
|
||||||
if (bmain->versionfile <= 164) {
|
if (bmain->versionfile <= 164) {
|
||||||
Mesh *me = static_cast<Mesh *>(bmain->meshes.first);
|
Mesh *me = static_cast<Mesh *>(bmain->meshes.first);
|
||||||
while (me) {
|
while (me) {
|
||||||
me->smoothresh = 30;
|
me->smoothresh_legacy = 30;
|
||||||
me = static_cast<Mesh *>(me->id.next);
|
me = static_cast<Mesh *>(me->id.next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1697,14 +1697,12 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||||
const float (*vnos)[3],
|
const float (*vnos)[3],
|
||||||
const float (*fnos)[3],
|
const float (*fnos)[3],
|
||||||
const bool use_split_normals,
|
const bool use_split_normals,
|
||||||
const float split_angle,
|
|
||||||
float (*r_lnos)[3],
|
float (*r_lnos)[3],
|
||||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||||
short (*clnors_data)[2],
|
short (*clnors_data)[2],
|
||||||
const int cd_loop_clnors_offset,
|
const int cd_loop_clnors_offset,
|
||||||
const bool do_rebuild)
|
const bool do_rebuild)
|
||||||
{
|
{
|
||||||
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
|
|
||||||
|
|
||||||
if (use_split_normals) {
|
if (use_split_normals) {
|
||||||
bm_mesh_loops_calc_normals(bm,
|
bm_mesh_loops_calc_normals(bm,
|
||||||
|
@ -1715,7 +1713,7 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||||
clnors_data,
|
clnors_data,
|
||||||
cd_loop_clnors_offset,
|
cd_loop_clnors_offset,
|
||||||
do_rebuild,
|
do_rebuild,
|
||||||
has_clnors ? -1.0f : cosf(split_angle));
|
-1.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BLI_assert(!r_lnors_spacearr);
|
BLI_assert(!r_lnors_spacearr);
|
||||||
|
@ -1744,7 +1742,6 @@ void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3])
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
true,
|
true,
|
||||||
M_PI,
|
|
||||||
r_lnors,
|
r_lnors,
|
||||||
bm->lnor_spacearr,
|
bm->lnor_spacearr,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -1871,7 +1868,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
true,
|
true,
|
||||||
M_PI,
|
|
||||||
r_lnors,
|
r_lnors,
|
||||||
bm->lnor_spacearr,
|
bm->lnor_spacearr,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -1947,17 +1943,8 @@ void BM_lnorspace_err(BMesh *bm)
|
||||||
|
|
||||||
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
float(*lnors)[3] = static_cast<float(*)[3]>(MEM_callocN(sizeof(*lnors) * bm->totloop, __func__));
|
float(*lnors)[3] = static_cast<float(*)[3]>(MEM_callocN(sizeof(*lnors) * bm->totloop, __func__));
|
||||||
BM_loops_calc_normal_vcos(bm,
|
BM_loops_calc_normal_vcos(
|
||||||
nullptr,
|
bm, nullptr, nullptr, nullptr, true, lnors, temp, nullptr, cd_loop_clnors_offset, true);
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
true,
|
|
||||||
M_PI,
|
|
||||||
lnors,
|
|
||||||
temp,
|
|
||||||
nullptr,
|
|
||||||
cd_loop_clnors_offset,
|
|
||||||
true);
|
|
||||||
|
|
||||||
for (int i = 0; i < bm->totloop; i++) {
|
for (int i = 0; i < bm->totloop; i++) {
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
|
@ -62,7 +62,6 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||||
const float (*vnos)[3],
|
const float (*vnos)[3],
|
||||||
const float (*fnos)[3],
|
const float (*fnos)[3],
|
||||||
bool use_split_normals,
|
bool use_split_normals,
|
||||||
float split_angle,
|
|
||||||
float (*r_lnos)[3],
|
float (*r_lnos)[3],
|
||||||
struct MLoopNorSpaceArray *r_lnors_spacearr,
|
struct MLoopNorSpaceArray *r_lnors_spacearr,
|
||||||
short (*clnors_data)[2],
|
short (*clnors_data)[2],
|
||||||
|
|
|
@ -1816,7 +1816,6 @@ static BMOpDefine bmo_bevel_def = {
|
||||||
{"miter_inner", BMO_OP_SLOT_INT, to_subtype_union(BMO_OP_SLOT_SUBTYPE_INT_ENUM),
|
{"miter_inner", BMO_OP_SLOT_INT, to_subtype_union(BMO_OP_SLOT_SUBTYPE_INT_ENUM),
|
||||||
bmo_enum_bevel_miter_type}, /* outer miter kind */
|
bmo_enum_bevel_miter_type}, /* outer miter kind */
|
||||||
{"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */
|
{"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */
|
||||||
{"smoothresh", BMO_OP_SLOT_FLT}, /* for passing mesh's smoothresh, used in hardening */
|
|
||||||
{"custom_profile", BMO_OP_SLOT_PTR, to_subtype_union(BMO_OP_SLOT_SUBTYPE_PTR_STRUCT)}, /* CurveProfile, if None ignored */
|
{"custom_profile", BMO_OP_SLOT_PTR, to_subtype_union(BMO_OP_SLOT_SUBTYPE_PTR_STRUCT)}, /* CurveProfile, if None ignored */
|
||||||
{"vmesh_method", BMO_OP_SLOT_INT, to_subtype_union(BMO_OP_SLOT_SUBTYPE_INT_ENUM),
|
{"vmesh_method", BMO_OP_SLOT_INT, to_subtype_union(BMO_OP_SLOT_SUBTYPE_INT_ENUM),
|
||||||
bmo_enum_bevel_vmesh_method}, /* The method to use to create meshes at intersections. */
|
bmo_enum_bevel_vmesh_method}, /* The method to use to create meshes at intersections. */
|
||||||
|
|
|
@ -35,7 +35,6 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
|
||||||
const int miter_outer = BMO_slot_int_get(op->slots_in, "miter_outer");
|
const int miter_outer = BMO_slot_int_get(op->slots_in, "miter_outer");
|
||||||
const int miter_inner = BMO_slot_int_get(op->slots_in, "miter_inner");
|
const int miter_inner = BMO_slot_int_get(op->slots_in, "miter_inner");
|
||||||
const float spread = BMO_slot_float_get(op->slots_in, "spread");
|
const float spread = BMO_slot_float_get(op->slots_in, "spread");
|
||||||
const float smoothresh = BMO_slot_float_get(op->slots_in, "smoothresh");
|
|
||||||
const CurveProfile *custom_profile = static_cast<const CurveProfile *>(
|
const CurveProfile *custom_profile = static_cast<const CurveProfile *>(
|
||||||
BMO_slot_ptr_get(op->slots_in, "custom_profile"));
|
BMO_slot_ptr_get(op->slots_in, "custom_profile"));
|
||||||
const int vmesh_method = BMO_slot_int_get(op->slots_in, "vmesh_method");
|
const int vmesh_method = BMO_slot_int_get(op->slots_in, "vmesh_method");
|
||||||
|
@ -82,7 +81,6 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
|
||||||
miter_outer,
|
miter_outer,
|
||||||
miter_inner,
|
miter_inner,
|
||||||
spread,
|
spread,
|
||||||
smoothresh,
|
|
||||||
custom_profile,
|
custom_profile,
|
||||||
vmesh_method);
|
vmesh_method);
|
||||||
|
|
||||||
|
|
|
@ -378,8 +378,6 @@ struct BevelParams {
|
||||||
int vmesh_method;
|
int vmesh_method;
|
||||||
/** Amount to spread when doing inside miter. */
|
/** Amount to spread when doing inside miter. */
|
||||||
float spread;
|
float spread;
|
||||||
/** Mesh's smoothresh, used if hardening. */
|
|
||||||
float smoothresh;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// #pragma GCC diagnostic ignored "-Wpadded"
|
// #pragma GCC diagnostic ignored "-Wpadded"
|
||||||
|
@ -2497,7 +2495,6 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm)
|
||||||
* To get that to happen, we have to mark the sharpen the edges that are only sharp because
|
* To get that to happen, we have to mark the sharpen the edges that are only sharp because
|
||||||
* of the angle test -- otherwise would be smooth. */
|
* of the angle test -- otherwise would be smooth. */
|
||||||
if (cd_clnors_offset == -1) {
|
if (cd_clnors_offset == -1) {
|
||||||
BM_edges_sharp_from_angle_set(bm, bp->smoothresh);
|
|
||||||
bevel_edges_sharp_boundary(bm, bp);
|
bevel_edges_sharp_boundary(bm, bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7725,7 +7722,6 @@ void BM_mesh_bevel(BMesh *bm,
|
||||||
const int miter_outer,
|
const int miter_outer,
|
||||||
const int miter_inner,
|
const int miter_inner,
|
||||||
const float spread,
|
const float spread,
|
||||||
const float smoothresh,
|
|
||||||
const CurveProfile *custom_profile,
|
const CurveProfile *custom_profile,
|
||||||
const int vmesh_method)
|
const int vmesh_method)
|
||||||
{
|
{
|
||||||
|
@ -7762,7 +7758,6 @@ void BM_mesh_bevel(BMesh *bm,
|
||||||
bp.miter_outer = miter_outer;
|
bp.miter_outer = miter_outer;
|
||||||
bp.miter_inner = miter_inner;
|
bp.miter_inner = miter_inner;
|
||||||
bp.spread = spread;
|
bp.spread = spread;
|
||||||
bp.smoothresh = smoothresh;
|
|
||||||
bp.face_hash = nullptr;
|
bp.face_hash = nullptr;
|
||||||
bp.profile_type = profile_type;
|
bp.profile_type = profile_type;
|
||||||
bp.custom_profile = custom_profile;
|
bp.custom_profile = custom_profile;
|
||||||
|
|
|
@ -47,7 +47,6 @@ void BM_mesh_bevel(BMesh *bm,
|
||||||
int miter_outer,
|
int miter_outer,
|
||||||
int miter_inner,
|
int miter_inner,
|
||||||
float spread,
|
float spread,
|
||||||
float smoothresh,
|
|
||||||
const struct CurveProfile *custom_profile,
|
const struct CurveProfile *custom_profile,
|
||||||
int vmesh_method);
|
int vmesh_method);
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,12 @@
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "BLI_array.hh"
|
#include "BLI_array.hh"
|
||||||
|
#include "BLI_array_utils.hh"
|
||||||
#include "BLI_enumerable_thread_specific.hh"
|
#include "BLI_enumerable_thread_specific.hh"
|
||||||
|
#include "BLI_index_mask.hh"
|
||||||
#include "BLI_math_matrix.h"
|
#include "BLI_math_matrix.h"
|
||||||
#include "BLI_task.hh"
|
#include "BLI_task.hh"
|
||||||
|
#include "BLI_virtual_array.hh"
|
||||||
|
|
||||||
#include "BKE_attribute.hh"
|
#include "BKE_attribute.hh"
|
||||||
#include "BKE_editmesh.h"
|
#include "BKE_editmesh.h"
|
||||||
|
@ -352,39 +355,70 @@ void mesh_render_data_update_looptris(MeshRenderData &mr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bm_edge_is_sharp(const BMEdge *const &edge)
|
||||||
|
{
|
||||||
|
return !BM_elem_flag_test(edge, BM_ELEM_SMOOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bm_face_is_sharp(const BMFace *const &face)
|
||||||
|
{
|
||||||
|
return !BM_elem_flag_test(face, BM_ELEM_SMOOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether loop normals are required because of mixed sharp and smooth flags.
|
||||||
|
* Similar to #Mesh::normals_domain().
|
||||||
|
*/
|
||||||
|
static bool bm_loop_normals_required(BMesh *bm)
|
||||||
|
{
|
||||||
|
using namespace blender;
|
||||||
|
using namespace blender::bke;
|
||||||
|
if (bm->totface == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||||
|
const VArray<bool> sharp_faces = VArray<bool>::ForDerivedSpan<const BMFace *, bm_face_is_sharp>(
|
||||||
|
Span(bm->ftable, bm->totface));
|
||||||
|
const array_utils::BooleanMix face_mix = array_utils::booleans_mix_calc(sharp_faces);
|
||||||
|
if (face_mix == array_utils::BooleanMix::AllTrue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BM_mesh_elem_table_ensure(bm, BM_EDGE);
|
||||||
|
const VArray<bool> sharp_edges = VArray<bool>::ForDerivedSpan<const BMEdge *, bm_edge_is_sharp>(
|
||||||
|
Span(bm->etable, bm->totedge));
|
||||||
|
const array_utils::BooleanMix edge_mix = array_utils::booleans_mix_calc(sharp_edges);
|
||||||
|
if (edge_mix == array_utils::BooleanMix::AllTrue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edge_mix == array_utils::BooleanMix::AllFalse &&
|
||||||
|
face_mix == array_utils::BooleanMix::AllFalse) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_flag)
|
void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_flag)
|
||||||
{
|
{
|
||||||
Mesh *me = mr.me;
|
|
||||||
const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
|
|
||||||
const float split_angle = is_auto_smooth ? me->smoothresh : float(M_PI);
|
|
||||||
|
|
||||||
if (mr.extract_type != MR_EXTRACT_BMESH) {
|
if (mr.extract_type != MR_EXTRACT_BMESH) {
|
||||||
/* Mesh */
|
/* Mesh */
|
||||||
mr.vert_normals = mr.me->vert_normals();
|
mr.vert_normals = mr.me->vert_normals();
|
||||||
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
|
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
|
||||||
mr.face_normals = mr.me->face_normals();
|
mr.face_normals = mr.me->face_normals();
|
||||||
}
|
}
|
||||||
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
|
if (((data_flag & MR_DATA_LOOP_NOR) && ELEM(mr.me->normals_domain(),
|
||||||
mr.loop_normals.reinitialize(mr.corner_verts.size());
|
blender::bke::MeshNormalDomain::Corner,
|
||||||
const blender::short2 *clnors = static_cast<const blender::short2 *>(
|
blender::bke::MeshNormalDomain::Face)) ||
|
||||||
CustomData_get_layer(&mr.me->loop_data, CD_CUSTOMLOOPNORMAL));
|
(data_flag & MR_DATA_TAN_LOOP_NOR))
|
||||||
const bool *sharp_edges = static_cast<const bool *>(
|
{
|
||||||
CustomData_get_layer_named(&mr.me->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
mr.loop_normals = mr.me->corner_normals();
|
||||||
blender::bke::mesh::normals_calc_loop(mr.vert_positions,
|
|
||||||
mr.edges,
|
|
||||||
mr.faces,
|
|
||||||
mr.corner_verts,
|
|
||||||
mr.corner_edges,
|
|
||||||
mr.me->corner_to_face_map(),
|
|
||||||
mr.vert_normals,
|
|
||||||
mr.face_normals,
|
|
||||||
sharp_edges,
|
|
||||||
mr.sharp_faces,
|
|
||||||
clnors,
|
|
||||||
is_auto_smooth,
|
|
||||||
split_angle,
|
|
||||||
nullptr,
|
|
||||||
mr.loop_normals);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -392,7 +426,9 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_
|
||||||
if (data_flag & MR_DATA_POLY_NOR) {
|
if (data_flag & MR_DATA_POLY_NOR) {
|
||||||
/* Use #BMFace.no instead. */
|
/* Use #BMFace.no instead. */
|
||||||
}
|
}
|
||||||
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
|
if (((data_flag & MR_DATA_LOOP_NOR) && bm_loop_normals_required(mr.bm)) ||
|
||||||
|
(data_flag & MR_DATA_TAN_LOOP_NOR))
|
||||||
|
{
|
||||||
|
|
||||||
const float(*vert_coords)[3] = nullptr;
|
const float(*vert_coords)[3] = nullptr;
|
||||||
const float(*vert_normals)[3] = nullptr;
|
const float(*vert_normals)[3] = nullptr;
|
||||||
|
@ -404,19 +440,19 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_
|
||||||
face_normals = reinterpret_cast<const float(*)[3]>(mr.bm_face_normals.data());
|
face_normals = reinterpret_cast<const float(*)[3]>(mr.bm_face_normals.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
mr.loop_normals.reinitialize(mr.loop_len);
|
mr.bm_loop_normals.reinitialize(mr.loop_len);
|
||||||
const int clnors_offset = CustomData_get_offset(&mr.bm->ldata, CD_CUSTOMLOOPNORMAL);
|
const int clnors_offset = CustomData_get_offset(&mr.bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
BM_loops_calc_normal_vcos(mr.bm,
|
BM_loops_calc_normal_vcos(mr.bm,
|
||||||
vert_coords,
|
vert_coords,
|
||||||
vert_normals,
|
vert_normals,
|
||||||
face_normals,
|
face_normals,
|
||||||
is_auto_smooth,
|
true,
|
||||||
split_angle,
|
reinterpret_cast<float(*)[3]>(mr.bm_loop_normals.data()),
|
||||||
reinterpret_cast<float(*)[3]>(mr.loop_normals.data()),
|
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
clnors_offset,
|
clnors_offset,
|
||||||
false);
|
false);
|
||||||
|
mr.loop_normals = mr.bm_loop_normals;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2152,9 +2152,8 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
|
||||||
runtime_data->stats_totloop = draw_cache.num_subdiv_loops;
|
runtime_data->stats_totloop = draw_cache.num_subdiv_loops;
|
||||||
|
|
||||||
draw_cache.use_custom_loop_normals = (runtime_data->use_loop_normals) &&
|
draw_cache.use_custom_loop_normals = (runtime_data->use_loop_normals) &&
|
||||||
(mesh_eval->flag & ME_AUTOSMOOTH) &&
|
mesh_eval->normals_domain() ==
|
||||||
CustomData_has_layer(&mesh_eval->loop_data,
|
blender::bke::MeshNormalDomain::Corner;
|
||||||
CD_CUSTOMLOOPNORMAL);
|
|
||||||
|
|
||||||
if (DRW_ibo_requested(mbc.buff.ibo.tris)) {
|
if (DRW_ibo_requested(mbc.buff.ibo.tris)) {
|
||||||
draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache.mat_len);
|
draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache.mat_len);
|
||||||
|
|
|
@ -67,6 +67,7 @@ struct MeshRenderData {
|
||||||
blender::Span<blender::float3> bm_vert_normals;
|
blender::Span<blender::float3> bm_vert_normals;
|
||||||
blender::Span<blender::float3> bm_face_normals;
|
blender::Span<blender::float3> bm_face_normals;
|
||||||
blender::Span<blender::float3> bm_face_centers;
|
blender::Span<blender::float3> bm_face_centers;
|
||||||
|
blender::Array<blender::float3> bm_loop_normals;
|
||||||
|
|
||||||
const int *v_origindex, *e_origindex, *p_origindex;
|
const int *v_origindex, *e_origindex, *p_origindex;
|
||||||
int edge_crease_ofs;
|
int edge_crease_ofs;
|
||||||
|
@ -91,6 +92,7 @@ struct MeshRenderData {
|
||||||
const int *material_indices;
|
const int *material_indices;
|
||||||
blender::Span<blender::float3> vert_normals;
|
blender::Span<blender::float3> vert_normals;
|
||||||
blender::Span<blender::float3> face_normals;
|
blender::Span<blender::float3> face_normals;
|
||||||
|
blender::Span<blender::float3> loop_normals;
|
||||||
const bool *hide_vert;
|
const bool *hide_vert;
|
||||||
const bool *hide_edge;
|
const bool *hide_edge;
|
||||||
const bool *hide_poly;
|
const bool *hide_poly;
|
||||||
|
@ -98,7 +100,6 @@ struct MeshRenderData {
|
||||||
const bool *select_edge;
|
const bool *select_edge;
|
||||||
const bool *select_poly;
|
const bool *select_poly;
|
||||||
const bool *sharp_faces;
|
const bool *sharp_faces;
|
||||||
blender::Array<blender::float3> loop_normals;
|
|
||||||
|
|
||||||
blender::Span<int> loose_verts;
|
blender::Span<int> loose_verts;
|
||||||
blender::Span<int> loose_edges;
|
blender::Span<int> loose_edges;
|
||||||
|
|
|
@ -258,18 +258,16 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache &subdiv_cache,
|
||||||
draw_subdiv_extract_pos_nor(subdiv_cache, flags_buffer, vbo, orco_vbo);
|
draw_subdiv_extract_pos_nor(subdiv_cache, flags_buffer, vbo, orco_vbo);
|
||||||
|
|
||||||
if (subdiv_cache.use_custom_loop_normals) {
|
if (subdiv_cache.use_custom_loop_normals) {
|
||||||
Mesh *coarse_mesh = subdiv_cache.mesh;
|
const Mesh *coarse_mesh = subdiv_cache.mesh;
|
||||||
const float(*loop_normals)[3] = static_cast<const float(*)[3]>(
|
const Span<float3> corner_normals = coarse_mesh->corner_normals();
|
||||||
CustomData_get_layer(&coarse_mesh->loop_data, CD_NORMAL));
|
|
||||||
BLI_assert(loop_normals != nullptr);
|
|
||||||
|
|
||||||
GPUVertBuf *src_custom_normals = GPU_vertbuf_calloc();
|
GPUVertBuf *src_custom_normals = GPU_vertbuf_calloc();
|
||||||
GPU_vertbuf_init_with_format(src_custom_normals, get_custom_normals_format());
|
GPU_vertbuf_init_with_format(src_custom_normals, get_custom_normals_format());
|
||||||
GPU_vertbuf_data_alloc(src_custom_normals, coarse_mesh->totloop);
|
GPU_vertbuf_data_alloc(src_custom_normals, coarse_mesh->totloop);
|
||||||
|
|
||||||
memcpy(GPU_vertbuf_get_data(src_custom_normals),
|
memcpy(GPU_vertbuf_get_data(src_custom_normals),
|
||||||
loop_normals,
|
corner_normals.data(),
|
||||||
sizeof(float[3]) * coarse_mesh->totloop);
|
corner_normals.size_in_bytes());
|
||||||
|
|
||||||
GPUVertBuf *dst_custom_normals = GPU_vertbuf_calloc();
|
GPUVertBuf *dst_custom_normals = GPU_vertbuf_calloc();
|
||||||
GPU_vertbuf_init_build_on_device(
|
GPU_vertbuf_init_build_on_device(
|
||||||
|
|
|
@ -543,7 +543,6 @@ bool ED_operator_editable_mesh(bContext *C);
|
||||||
bool ED_operator_editmesh(bContext *C);
|
bool ED_operator_editmesh(bContext *C);
|
||||||
bool ED_operator_editmesh_view3d(bContext *C);
|
bool ED_operator_editmesh_view3d(bContext *C);
|
||||||
bool ED_operator_editmesh_region_view3d(bContext *C);
|
bool ED_operator_editmesh_region_view3d(bContext *C);
|
||||||
bool ED_operator_editmesh_auto_smooth(bContext *C);
|
|
||||||
bool ED_operator_editarmature(bContext *C);
|
bool ED_operator_editarmature(bContext *C);
|
||||||
bool ED_operator_editcurve(bContext *C);
|
bool ED_operator_editcurve(bContext *C);
|
||||||
bool ED_operator_editcurve_3d(bContext *C);
|
bool ED_operator_editcurve_3d(bContext *C);
|
||||||
|
|
|
@ -336,20 +336,13 @@ static bool edbm_bevel_calc(wmOperator *op)
|
||||||
|
|
||||||
const int material = CLAMPIS(material_init, -1, obedit->totcol - 1);
|
const int material = CLAMPIS(material_init, -1, obedit->totcol - 1);
|
||||||
|
|
||||||
Mesh *me = static_cast<Mesh *>(obedit->data);
|
|
||||||
|
|
||||||
if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) {
|
|
||||||
/* `harden_normals` only has a visible effect if auto-smooth is on, so turn it on. */
|
|
||||||
me->flag |= ME_AUTOSMOOTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
EDBM_op_init(em,
|
EDBM_op_init(em,
|
||||||
&bmop,
|
&bmop,
|
||||||
op,
|
op,
|
||||||
"bevel geom=%hev offset=%f segments=%i affect=%i offset_type=%i "
|
"bevel geom=%hev offset=%f segments=%i affect=%i offset_type=%i "
|
||||||
"profile_type=%i profile=%f clamp_overlap=%b material=%i loop_slide=%b "
|
"profile_type=%i profile=%f clamp_overlap=%b material=%i loop_slide=%b "
|
||||||
"mark_seam=%b mark_sharp=%b harden_normals=%b face_strength_mode=%i "
|
"mark_seam=%b mark_sharp=%b harden_normals=%b face_strength_mode=%i "
|
||||||
"miter_outer=%i miter_inner=%i spread=%f smoothresh=%f custom_profile=%p "
|
"miter_outer=%i miter_inner=%i spread=%f custom_profile=%p "
|
||||||
"vmesh_method=%i",
|
"vmesh_method=%i",
|
||||||
BM_ELEM_SELECT,
|
BM_ELEM_SELECT,
|
||||||
offset,
|
offset,
|
||||||
|
@ -368,7 +361,6 @@ static bool edbm_bevel_calc(wmOperator *op)
|
||||||
miter_outer,
|
miter_outer,
|
||||||
miter_inner,
|
miter_inner,
|
||||||
spread,
|
spread,
|
||||||
me->smoothresh,
|
|
||||||
opdata->custom_profile,
|
opdata->custom_profile,
|
||||||
vmesh_method);
|
vmesh_method);
|
||||||
|
|
||||||
|
|
|
@ -8449,8 +8449,7 @@ static bool point_normals_init(bContext *C, wmOperator *op)
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
BMesh *bm = em->bm;
|
BMesh *bm = em->bm;
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
|
||||||
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
|
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
|
||||||
|
|
||||||
op->customdata = lnors_ed_arr;
|
op->customdata = lnors_ed_arr;
|
||||||
|
@ -9075,8 +9074,7 @@ static int normals_split_merge(bContext *C, const bool do_merge)
|
||||||
BMEdge *e;
|
BMEdge *e;
|
||||||
BMIter eiter;
|
BMIter eiter;
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
|
||||||
|
|
||||||
/* Note that we need temp lnor editing data for all loops of all affected vertices, since by
|
/* Note that we need temp lnor editing data for all loops of all affected vertices, since by
|
||||||
* setting some faces/edges as smooth we are going to change clnors spaces... See also #65809.
|
* setting some faces/edges as smooth we are going to change clnors spaces... See also #65809.
|
||||||
|
@ -9094,7 +9092,7 @@ static int normals_split_merge(bContext *C, const bool do_merge)
|
||||||
}
|
}
|
||||||
|
|
||||||
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
|
|
||||||
if (do_merge) {
|
if (do_merge) {
|
||||||
normals_merge(bm, lnors_ed_arr);
|
normals_merge(bm, lnors_ed_arr);
|
||||||
|
@ -9214,9 +9212,8 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
|
||||||
BMLoop *l, *l_curr, *l_first;
|
BMLoop *l, *l_curr, *l_first;
|
||||||
BMIter fiter;
|
BMIter fiter;
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
|
|
||||||
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
|
|
||||||
const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
|
||||||
|
@ -9466,8 +9463,7 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
|
||||||
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
|
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
|
||||||
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
|
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
|
||||||
|
|
||||||
|
@ -9690,8 +9686,7 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
|
||||||
|
|
||||||
const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
|
const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
|
||||||
|
|
||||||
float(*vert_normals)[3] = static_cast<float(*)[3]>(
|
float(*vert_normals)[3] = static_cast<float(*)[3]>(
|
||||||
MEM_mallocN(sizeof(*vert_normals) * bm->totvert, __func__));
|
MEM_mallocN(sizeof(*vert_normals) * bm->totvert, __func__));
|
||||||
|
@ -9799,8 +9794,7 @@ static int edbm_smooth_normals_exec(bContext *C, wmOperator *op)
|
||||||
BMLoop *l;
|
BMLoop *l;
|
||||||
BMIter fiter, liter;
|
BMIter fiter, liter;
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
|
|
||||||
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
|
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
|
||||||
|
|
||||||
float(*smooth_normal)[3] = static_cast<float(*)[3]>(
|
float(*smooth_normal)[3] = static_cast<float(*)[3]>(
|
||||||
|
|
|
@ -723,34 +723,9 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
|
||||||
|
|
||||||
if (me->edit_mesh) {
|
if (me->edit_mesh) {
|
||||||
BMesh &bm = *me->edit_mesh->bm;
|
BMesh &bm = *me->edit_mesh->bm;
|
||||||
/* Tag edges as sharp according to smooth threshold if needed,
|
|
||||||
* to preserve auto-smooth shading. */
|
|
||||||
if (me->flag & ME_AUTOSMOOTH) {
|
|
||||||
BM_edges_sharp_from_angle_set(&bm, me->smoothresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
BM_data_layer_add(&bm, &bm.ldata, CD_CUSTOMLOOPNORMAL);
|
BM_data_layer_add(&bm, &bm.ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Tag edges as sharp according to smooth threshold if needed,
|
|
||||||
* to preserve auto-smooth shading. */
|
|
||||||
if (me->flag & ME_AUTOSMOOTH) {
|
|
||||||
bke::MutableAttributeAccessor attributes = me->attributes_for_write();
|
|
||||||
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
|
|
||||||
"sharp_edge", ATTR_DOMAIN_EDGE);
|
|
||||||
const bool *sharp_faces = static_cast<const bool *>(
|
|
||||||
CustomData_get_layer_named(&me->face_data, CD_PROP_BOOL, "sharp_face"));
|
|
||||||
bke::mesh::edges_sharp_from_angle_set(me->faces(),
|
|
||||||
me->corner_verts(),
|
|
||||||
me->corner_edges(),
|
|
||||||
me->face_normals(),
|
|
||||||
me->corner_to_face_map(),
|
|
||||||
sharp_faces,
|
|
||||||
me->smoothresh,
|
|
||||||
sharp_edges.span);
|
|
||||||
sharp_edges.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomData_add_layer(&me->loop_data, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, me->totloop);
|
CustomData_add_layer(&me->loop_data, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, me->totloop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,9 +1129,7 @@ void ED_mesh_split_faces(Mesh *mesh)
|
||||||
{
|
{
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
const OffsetIndices polys = mesh->faces();
|
const OffsetIndices polys = mesh->faces();
|
||||||
const Span<int> corner_verts = mesh->corner_verts();
|
|
||||||
const Span<int> corner_edges = mesh->corner_edges();
|
const Span<int> corner_edges = mesh->corner_edges();
|
||||||
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : float(M_PI);
|
|
||||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||||
const VArray<bool> mesh_sharp_edges = *attributes.lookup_or_default<bool>(
|
const VArray<bool> mesh_sharp_edges = *attributes.lookup_or_default<bool>(
|
||||||
"sharp_edge", ATTR_DOMAIN_EDGE, false);
|
"sharp_edge", ATTR_DOMAIN_EDGE, false);
|
||||||
|
@ -1166,15 +1139,6 @@ void ED_mesh_split_faces(Mesh *mesh)
|
||||||
Array<bool> sharp_edges(mesh->totedge);
|
Array<bool> sharp_edges(mesh->totedge);
|
||||||
mesh_sharp_edges.materialize(sharp_edges);
|
mesh_sharp_edges.materialize(sharp_edges);
|
||||||
|
|
||||||
bke::mesh::edges_sharp_from_angle_set(polys,
|
|
||||||
corner_verts,
|
|
||||||
corner_edges,
|
|
||||||
mesh->face_normals(),
|
|
||||||
mesh->corner_to_face_map(),
|
|
||||||
sharp_faces,
|
|
||||||
split_angle,
|
|
||||||
sharp_edges);
|
|
||||||
|
|
||||||
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
|
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
|
||||||
for (const int face_i : range) {
|
for (const int face_i : range) {
|
||||||
if (sharp_faces && sharp_faces[face_i]) {
|
if (sharp_faces && sharp_faces[face_i]) {
|
||||||
|
|
|
@ -712,9 +712,8 @@ static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph,
|
||||||
{
|
{
|
||||||
Mesh *me = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex);
|
Mesh *me = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex);
|
||||||
|
|
||||||
if (me->flag & ME_AUTOSMOOTH) {
|
if (me->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
ED_mesh_split_faces(me);
|
ED_mesh_split_faces(me);
|
||||||
CustomData_free_layers(&me->loop_data, CD_NORMAL, me->totloop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
|
|
|
@ -522,11 +522,6 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
|
||||||
false,
|
false,
|
||||||
op->reports))
|
op->reports))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (data_type == DT_TYPE_LNOR && use_create) {
|
|
||||||
((Mesh *)ob_dst->data)->flag |= ME_AUTOSMOOTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
|
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1567,6 +1567,7 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
|
||||||
static int shade_smooth_exec(bContext *C, wmOperator *op)
|
static int shade_smooth_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
|
const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
|
||||||
|
const bool use_smooth_by_angle = STREQ(op->idname, "OBJECT_OT_shade_smooth_by_angle");
|
||||||
bool changed_multi = false;
|
bool changed_multi = false;
|
||||||
bool has_linked_data = false;
|
bool has_linked_data = false;
|
||||||
|
|
||||||
|
@ -1615,12 +1616,12 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (ob->type == OB_MESH) {
|
if (ob->type == OB_MESH) {
|
||||||
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), use_smooth);
|
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), use_smooth || use_smooth_by_angle);
|
||||||
if (use_smooth) {
|
if (use_smooth || use_smooth_by_angle) {
|
||||||
const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
|
if (use_smooth_by_angle) {
|
||||||
const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
|
const float angle = RNA_float_get(op->ptr, "angle");
|
||||||
BKE_mesh_auto_smooth_flag_set(
|
BKE_mesh_sharp_edges_set_from_angle(static_cast<Mesh *>(ob->data), angle);
|
||||||
static_cast<Mesh *>(ob->data), use_auto_smooth, auto_smooth_angle);
|
}
|
||||||
}
|
}
|
||||||
BKE_mesh_batch_cache_dirty_tag(static_cast<Mesh *>(ob->data), BKE_MESH_BATCH_DIRTY_ALL);
|
BKE_mesh_batch_cache_dirty_tag(static_cast<Mesh *>(ob->data), BKE_MESH_BATCH_DIRTY_ALL);
|
||||||
changed = true;
|
changed = true;
|
||||||
|
@ -1694,25 +1695,25 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
|
||||||
/* properties */
|
void OBJECT_OT_shade_smooth_by_angle(wmOperatorType *ot)
|
||||||
PropertyRNA *prop;
|
{
|
||||||
|
ot->name = "Shade Smooth by Angle";
|
||||||
|
ot->description =
|
||||||
|
"Set the sharpness of mesh edges based on the angle between the neighboring faces";
|
||||||
|
ot->idname = "OBJECT_OT_shade_smooth_by_angle";
|
||||||
|
|
||||||
prop = RNA_def_boolean(
|
ot->poll = shade_poll;
|
||||||
ot->srna,
|
ot->exec = shade_smooth_exec;
|
||||||
"use_auto_smooth",
|
|
||||||
false,
|
|
||||||
"Auto Smooth",
|
|
||||||
"Enable automatic smooth based on smooth/sharp faces/edges and angle between faces");
|
|
||||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
||||||
|
|
||||||
prop = RNA_def_property(ot->srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
|
PropertyRNA *prop = RNA_def_property(ot->srna, "angle", PROP_FLOAT, PROP_ANGLE);
|
||||||
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
|
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
|
||||||
RNA_def_property_float_default(prop, DEG2RADF(30.0f));
|
RNA_def_property_float_default(prop, DEG2RADF(30.0f));
|
||||||
RNA_def_property_ui_text(prop,
|
RNA_def_property_ui_text(
|
||||||
"Angle",
|
prop, "Angle", "Maximum angle between face normals that will be considered as smooth");
|
||||||
"Maximum angle between face normals that will be considered as smooth "
|
|
||||||
"(unused if custom split normals data are available)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
|
@ -83,6 +83,7 @@ void OBJECT_OT_mode_set_with_submode(struct wmOperatorType *ot);
|
||||||
void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot);
|
void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot);
|
||||||
void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot);
|
void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot);
|
||||||
void OBJECT_OT_shade_smooth(struct wmOperatorType *ot);
|
void OBJECT_OT_shade_smooth(struct wmOperatorType *ot);
|
||||||
|
void OBJECT_OT_shade_smooth_by_angle(struct wmOperatorType *ot);
|
||||||
void OBJECT_OT_shade_flat(struct wmOperatorType *ot);
|
void OBJECT_OT_shade_flat(struct wmOperatorType *ot);
|
||||||
void OBJECT_OT_paths_calculate(struct wmOperatorType *ot);
|
void OBJECT_OT_paths_calculate(struct wmOperatorType *ot);
|
||||||
void OBJECT_OT_paths_update(struct wmOperatorType *ot);
|
void OBJECT_OT_paths_update(struct wmOperatorType *ot);
|
||||||
|
|
|
@ -45,6 +45,7 @@ void ED_operatortypes_object()
|
||||||
WM_operatortype_append(OBJECT_OT_editmode_toggle);
|
WM_operatortype_append(OBJECT_OT_editmode_toggle);
|
||||||
WM_operatortype_append(OBJECT_OT_posemode_toggle);
|
WM_operatortype_append(OBJECT_OT_posemode_toggle);
|
||||||
WM_operatortype_append(OBJECT_OT_shade_smooth);
|
WM_operatortype_append(OBJECT_OT_shade_smooth);
|
||||||
|
WM_operatortype_append(OBJECT_OT_shade_smooth_by_angle);
|
||||||
WM_operatortype_append(OBJECT_OT_shade_flat);
|
WM_operatortype_append(OBJECT_OT_shade_flat);
|
||||||
WM_operatortype_append(OBJECT_OT_paths_calculate);
|
WM_operatortype_append(OBJECT_OT_paths_calculate);
|
||||||
WM_operatortype_append(OBJECT_OT_paths_update);
|
WM_operatortype_append(OBJECT_OT_paths_update);
|
||||||
|
|
|
@ -482,15 +482,6 @@ bool ED_operator_editmesh_region_view3d(bContext *C)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ED_operator_editmesh_auto_smooth(bContext *C)
|
|
||||||
{
|
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
|
||||||
if (obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)) {
|
|
||||||
return nullptr != BKE_editmesh_from_object(obedit);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ED_operator_editarmature(bContext *C)
|
bool ED_operator_editarmature(bContext *C)
|
||||||
{
|
{
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
|
|
|
@ -128,7 +128,7 @@ struct AddOperationExecutor {
|
||||||
transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
|
transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
|
||||||
|
|
||||||
Object &surface_ob_orig = *curves_id_orig_->surface;
|
Object &surface_ob_orig = *curves_id_orig_->surface;
|
||||||
Mesh &surface_orig = *static_cast<Mesh *>(surface_ob_orig.data);
|
const Mesh &surface_orig = *static_cast<const Mesh *>(surface_ob_orig.data);
|
||||||
if (surface_orig.faces_num == 0) {
|
if (surface_orig.faces_num == 0) {
|
||||||
report_empty_original_surface(stroke_extension.reports);
|
report_empty_original_surface(stroke_extension.reports);
|
||||||
return;
|
return;
|
||||||
|
@ -207,15 +207,7 @@ struct AddOperationExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Span<MLoopTri> surface_looptris_orig = surface_orig.looptris();
|
const Span<MLoopTri> surface_looptris_orig = surface_orig.looptris();
|
||||||
|
const Span<float3> corner_normals_su = surface_orig.corner_normals();
|
||||||
/* Find normals. */
|
|
||||||
if (!CustomData_has_layer(&surface_orig.loop_data, CD_NORMAL)) {
|
|
||||||
BKE_mesh_calc_normals_split(&surface_orig);
|
|
||||||
}
|
|
||||||
const Span<float3> corner_normals_su = {
|
|
||||||
reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig.loop_data, CD_NORMAL)),
|
|
||||||
surface_orig.totloop};
|
|
||||||
|
|
||||||
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
|
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
|
||||||
|
|
||||||
geometry::AddCurvesOnMeshInputs add_inputs;
|
geometry::AddCurvesOnMeshInputs add_inputs;
|
||||||
|
|
|
@ -76,7 +76,7 @@ struct DensityAddOperationExecutor {
|
||||||
CurvesGeometry *curves_orig_ = nullptr;
|
CurvesGeometry *curves_orig_ = nullptr;
|
||||||
|
|
||||||
Object *surface_ob_orig_ = nullptr;
|
Object *surface_ob_orig_ = nullptr;
|
||||||
Mesh *surface_orig_ = nullptr;
|
const Mesh *surface_orig_ = nullptr;
|
||||||
|
|
||||||
Object *surface_ob_eval_ = nullptr;
|
Object *surface_ob_eval_ = nullptr;
|
||||||
Mesh *surface_eval_ = nullptr;
|
Mesh *surface_eval_ = nullptr;
|
||||||
|
@ -115,7 +115,7 @@ struct DensityAddOperationExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
surface_ob_orig_ = curves_id_orig_->surface;
|
surface_ob_orig_ = curves_id_orig_->surface;
|
||||||
surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
|
surface_orig_ = static_cast<const Mesh *>(surface_ob_orig_->data);
|
||||||
if (surface_orig_->faces_num == 0) {
|
if (surface_orig_->faces_num == 0) {
|
||||||
report_empty_original_surface(stroke_extension.reports);
|
report_empty_original_surface(stroke_extension.reports);
|
||||||
return;
|
return;
|
||||||
|
@ -257,14 +257,7 @@ struct DensityAddOperationExecutor {
|
||||||
}
|
}
|
||||||
self_->new_deformed_root_positions_.extend(new_positions_cu);
|
self_->new_deformed_root_positions_.extend(new_positions_cu);
|
||||||
|
|
||||||
/* Find normals. */
|
const Span<float3> corner_normals_su = surface_orig_->corner_normals();
|
||||||
if (!CustomData_has_layer(&surface_orig_->loop_data, CD_NORMAL)) {
|
|
||||||
BKE_mesh_calc_normals_split(surface_orig_);
|
|
||||||
}
|
|
||||||
const Span<float3> corner_normals_su = {reinterpret_cast<const float3 *>(CustomData_get_layer(
|
|
||||||
&surface_orig_->loop_data, CD_NORMAL)),
|
|
||||||
surface_orig_->totloop};
|
|
||||||
|
|
||||||
const Span<MLoopTri> surface_looptris_orig = surface_orig_->looptris();
|
const Span<MLoopTri> surface_looptris_orig = surface_orig_->looptris();
|
||||||
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
|
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,8 @@ struct PuffOperationExecutor {
|
||||||
|
|
||||||
CurvesSurfaceTransforms transforms_;
|
CurvesSurfaceTransforms transforms_;
|
||||||
|
|
||||||
Object *surface_ob_ = nullptr;
|
const Object *surface_ob_ = nullptr;
|
||||||
Mesh *surface_ = nullptr;
|
const Mesh *surface_ = nullptr;
|
||||||
Span<float3> surface_positions_;
|
Span<float3> surface_positions_;
|
||||||
Span<int> surface_corner_verts_;
|
Span<int> surface_corner_verts_;
|
||||||
Span<MLoopTri> surface_looptris_;
|
Span<MLoopTri> surface_looptris_;
|
||||||
|
@ -113,20 +113,14 @@ struct PuffOperationExecutor {
|
||||||
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
|
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
|
||||||
|
|
||||||
surface_ob_ = curves_id_->surface;
|
surface_ob_ = curves_id_->surface;
|
||||||
surface_ = static_cast<Mesh *>(surface_ob_->data);
|
surface_ = static_cast<const Mesh *>(surface_ob_->data);
|
||||||
|
|
||||||
transforms_ = CurvesSurfaceTransforms(*object_, surface_ob_);
|
transforms_ = CurvesSurfaceTransforms(*object_, surface_ob_);
|
||||||
|
|
||||||
if (!CustomData_has_layer(&surface_->loop_data, CD_NORMAL)) {
|
|
||||||
BKE_mesh_calc_normals_split(surface_);
|
|
||||||
}
|
|
||||||
corner_normals_su_ = {
|
|
||||||
reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->loop_data, CD_NORMAL)),
|
|
||||||
surface_->totloop};
|
|
||||||
|
|
||||||
surface_positions_ = surface_->vert_positions();
|
surface_positions_ = surface_->vert_positions();
|
||||||
surface_corner_verts_ = surface_->corner_verts();
|
surface_corner_verts_ = surface_->corner_verts();
|
||||||
surface_looptris_ = surface_->looptris();
|
surface_looptris_ = surface_->looptris();
|
||||||
|
corner_normals_su_ = surface_->corner_normals();
|
||||||
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
|
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
|
||||||
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
|
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ struct SlideOperationExecutor {
|
||||||
CurvesGeometry *curves_orig_ = nullptr;
|
CurvesGeometry *curves_orig_ = nullptr;
|
||||||
|
|
||||||
Object *surface_ob_orig_ = nullptr;
|
Object *surface_ob_orig_ = nullptr;
|
||||||
Mesh *surface_orig_ = nullptr;
|
const Mesh *surface_orig_ = nullptr;
|
||||||
Span<MLoopTri> surface_looptris_orig_;
|
Span<MLoopTri> surface_looptris_orig_;
|
||||||
VArraySpan<float2> surface_uv_map_orig_;
|
VArraySpan<float2> surface_uv_map_orig_;
|
||||||
Span<float3> corner_normals_orig_su_;
|
Span<float3> corner_normals_orig_su_;
|
||||||
|
@ -166,25 +166,19 @@ struct SlideOperationExecutor {
|
||||||
transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
|
transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
|
||||||
|
|
||||||
surface_ob_orig_ = curves_id_orig_->surface;
|
surface_ob_orig_ = curves_id_orig_->surface;
|
||||||
surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
|
surface_orig_ = static_cast<const Mesh *>(surface_ob_orig_->data);
|
||||||
if (surface_orig_->faces_num == 0) {
|
if (surface_orig_->faces_num == 0) {
|
||||||
report_empty_original_surface(stroke_extension.reports);
|
report_empty_original_surface(stroke_extension.reports);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
surface_looptris_orig_ = surface_orig_->looptris();
|
surface_looptris_orig_ = surface_orig_->looptris();
|
||||||
|
corner_normals_orig_su_ = surface_orig_->corner_normals();
|
||||||
surface_uv_map_orig_ = *surface_orig_->attributes().lookup<float2>(uv_map_name,
|
surface_uv_map_orig_ = *surface_orig_->attributes().lookup<float2>(uv_map_name,
|
||||||
ATTR_DOMAIN_CORNER);
|
ATTR_DOMAIN_CORNER);
|
||||||
if (surface_uv_map_orig_.is_empty()) {
|
if (surface_uv_map_orig_.is_empty()) {
|
||||||
report_missing_uv_map_on_original_surface(stroke_extension.reports);
|
report_missing_uv_map_on_original_surface(stroke_extension.reports);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!CustomData_has_layer(&surface_orig_->loop_data, CD_NORMAL)) {
|
|
||||||
BKE_mesh_calc_normals_split(surface_orig_);
|
|
||||||
}
|
|
||||||
corner_normals_orig_su_ = {reinterpret_cast<const float3 *>(
|
|
||||||
CustomData_get_layer(&surface_orig_->loop_data, CD_NORMAL)),
|
|
||||||
surface_orig_->totloop};
|
|
||||||
|
|
||||||
surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
|
surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
|
||||||
if (surface_ob_eval_ == nullptr) {
|
if (surface_ob_eval_ == nullptr) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2094,32 +2094,30 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
||||||
if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
|
if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
|
||||||
|
|
||||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||||
if (((Mesh *)(tc->obedit->data))->flag & ME_AUTOSMOOTH) {
|
BMEditMesh *em = nullptr; /* BKE_editmesh_from_object(t->obedit); */
|
||||||
BMEditMesh *em = nullptr; /* BKE_editmesh_from_object(t->obedit); */
|
bool do_skip = false;
|
||||||
bool do_skip = false;
|
|
||||||
|
|
||||||
/* Currently only used for two of three most frequent transform ops,
|
/* Currently only used for two of three most frequent transform ops,
|
||||||
* can include more ops.
|
* can include more ops.
|
||||||
* Note that scaling cannot be included here,
|
* Note that scaling cannot be included here,
|
||||||
* non-uniform scaling will affect normals. */
|
* non-uniform scaling will affect normals. */
|
||||||
if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) {
|
if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) {
|
||||||
if (em->bm->totvertsel == em->bm->totvert) {
|
if (em->bm->totvertsel == em->bm->totvert) {
|
||||||
/* No need to invalidate if whole mesh is selected. */
|
/* No need to invalidate if whole mesh is selected. */
|
||||||
do_skip = true;
|
do_skip = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (t->flag & T_MODAL) {
|
if (t->flag & T_MODAL) {
|
||||||
RNA_property_boolean_set(op->ptr, prop, false);
|
RNA_property_boolean_set(op->ptr, prop, false);
|
||||||
}
|
}
|
||||||
else if (!do_skip) {
|
else if (!do_skip) {
|
||||||
const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
|
const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
|
||||||
if (preserve_clnor) {
|
if (preserve_clnor) {
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(tc->obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
t->flag |= T_CLNOR_REBUILD;
|
t->flag |= T_CLNOR_REBUILD;
|
||||||
}
|
|
||||||
BM_lnorspace_invalidate(em->bm, true);
|
|
||||||
}
|
}
|
||||||
|
BM_lnorspace_invalidate(em->bm, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,8 +131,7 @@ static void initNormalRotation(TransInfo *t, wmOperator * /*op*/)
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
||||||
BMesh *bm = em->bm;
|
BMesh *bm = em->bm;
|
||||||
|
|
||||||
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(tc->obedit->data));
|
BKE_editmesh_lnorspace_update(em);
|
||||||
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(tc->obedit->data));
|
|
||||||
|
|
||||||
storeCustomLNorValue(tc, bm);
|
storeCustomLNorValue(tc, bm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,14 +422,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
|
||||||
MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__);
|
MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__);
|
||||||
blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, corner_verts, {mlooptri, tottri});
|
blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, corner_verts, {mlooptri, tottri});
|
||||||
const blender::Span<int> looptri_faces = me->looptri_faces();
|
const blender::Span<int> looptri_faces = me->looptri_faces();
|
||||||
|
const blender::Span<blender::float3> lnors = me->corner_normals();
|
||||||
// Compute loop normals
|
|
||||||
BKE_mesh_calc_normals_split(me);
|
|
||||||
const float(*lnors)[3] = nullptr;
|
|
||||||
|
|
||||||
if (CustomData_has_layer(&me->loop_data, CD_NORMAL)) {
|
|
||||||
lnors = (const float(*)[3])CustomData_get_layer(&me->loop_data, CD_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get other mesh data
|
// Get other mesh data
|
||||||
const FreestyleEdge *fed = (const FreestyleEdge *)CustomData_get_layer(&me->edge_data,
|
const FreestyleEdge *fed = (const FreestyleEdge *)CustomData_get_layer(&me->edge_data,
|
||||||
|
@ -546,7 +539,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
|
||||||
v2[2] += _z_offset;
|
v2[2] += _z_offset;
|
||||||
v3[2] += _z_offset;
|
v3[2] += _z_offset;
|
||||||
|
|
||||||
if (_smooth && (!sharp_faces[poly_i]) && lnors) {
|
if (_smooth && (!sharp_faces[poly_i])) {
|
||||||
copy_v3_v3(n1, lnors[lt->tri[0]]);
|
copy_v3_v3(n1, lnors[lt->tri[0]]);
|
||||||
copy_v3_v3(n2, lnors[lt->tri[1]]);
|
copy_v3_v3(n2, lnors[lt->tri[1]]);
|
||||||
copy_v3_v3(n3, lnors[lt->tri[2]]);
|
copy_v3_v3(n3, lnors[lt->tri[2]]);
|
||||||
|
|
|
@ -206,7 +206,7 @@ static void update_depsgraph(GpencilModifierData *md,
|
||||||
CustomData_MeshMasks mask = {0};
|
CustomData_MeshMasks mask = {0};
|
||||||
|
|
||||||
if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) {
|
if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) {
|
||||||
mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
|
mask.lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mmd->target != nullptr) {
|
if (mmd->target != nullptr) {
|
||||||
|
|
|
@ -2006,10 +2006,6 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
|
||||||
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
|
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
|
||||||
crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold);
|
crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold);
|
||||||
}
|
}
|
||||||
else if (ob_info->original_me->flag & ME_AUTOSMOOTH) {
|
|
||||||
crease_angle = cosf(ob_info->original_me->smoothresh);
|
|
||||||
use_auto_smooth = true;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
crease_angle = la_data->conf.crease_threshold;
|
crease_angle = la_data->conf.crease_threshold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "abc_hierarchy_iterator.h"
|
#include "abc_hierarchy_iterator.h"
|
||||||
#include "intern/abc_axis_conversion.h"
|
#include "intern/abc_axis_conversion.h"
|
||||||
|
|
||||||
|
#include "BLI_array_utils.hh"
|
||||||
#include "BLI_assert.h"
|
#include "BLI_assert.h"
|
||||||
#include "BLI_math_vector.h"
|
#include "BLI_math_vector.h"
|
||||||
|
|
||||||
|
@ -63,8 +64,7 @@ namespace blender::io::alembic {
|
||||||
static void get_vertices(Mesh *mesh, std::vector<Imath::V3f> &points);
|
static void get_vertices(Mesh *mesh, std::vector<Imath::V3f> &points);
|
||||||
static void get_topology(Mesh *mesh,
|
static void get_topology(Mesh *mesh,
|
||||||
std::vector<int32_t> &face_verts,
|
std::vector<int32_t> &face_verts,
|
||||||
std::vector<int32_t> &loop_counts,
|
std::vector<int32_t> &loop_counts);
|
||||||
bool &r_has_flat_shaded_face);
|
|
||||||
static void get_edge_creases(Mesh *mesh,
|
static void get_edge_creases(Mesh *mesh,
|
||||||
std::vector<int32_t> &indices,
|
std::vector<int32_t> &indices,
|
||||||
std::vector<int32_t> &lengths,
|
std::vector<int32_t> &lengths,
|
||||||
|
@ -72,9 +72,7 @@ static void get_edge_creases(Mesh *mesh,
|
||||||
static void get_vert_creases(Mesh *mesh,
|
static void get_vert_creases(Mesh *mesh,
|
||||||
std::vector<int32_t> &indices,
|
std::vector<int32_t> &indices,
|
||||||
std::vector<float> &sharpnesses);
|
std::vector<float> &sharpnesses);
|
||||||
static void get_loop_normals(Mesh *mesh,
|
static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals);
|
||||||
std::vector<Imath::V3f> &normals,
|
|
||||||
bool has_flat_shaded_poly);
|
|
||||||
|
|
||||||
ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args)
|
ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args)
|
||||||
: ABCAbstractWriter(args), is_subd_(false)
|
: ABCAbstractWriter(args), is_subd_(false)
|
||||||
|
@ -215,10 +213,9 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
||||||
std::vector<Imath::V3f> points, normals;
|
std::vector<Imath::V3f> points, normals;
|
||||||
std::vector<int32_t> face_verts, loop_counts;
|
std::vector<int32_t> face_verts, loop_counts;
|
||||||
std::vector<Imath::V3f> velocities;
|
std::vector<Imath::V3f> velocities;
|
||||||
bool has_flat_shaded_poly = false;
|
|
||||||
|
|
||||||
get_vertices(mesh, points);
|
get_vertices(mesh, points);
|
||||||
get_topology(mesh, face_verts, loop_counts, has_flat_shaded_poly);
|
get_topology(mesh, face_verts, loop_counts);
|
||||||
|
|
||||||
if (!frame_has_been_written_ && args_.export_params->face_sets) {
|
if (!frame_has_been_written_ && args_.export_params->face_sets) {
|
||||||
write_face_sets(context.object, mesh, abc_poly_mesh_schema_);
|
write_face_sets(context.object, mesh, abc_poly_mesh_schema_);
|
||||||
|
@ -249,7 +246,7 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_.export_params->normals) {
|
if (args_.export_params->normals) {
|
||||||
get_loop_normals(mesh, normals, has_flat_shaded_poly);
|
get_loop_normals(mesh, normals);
|
||||||
|
|
||||||
ON3fGeomParam::Sample normals_sample;
|
ON3fGeomParam::Sample normals_sample;
|
||||||
if (!normals.empty()) {
|
if (!normals.empty()) {
|
||||||
|
@ -282,10 +279,9 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, Mesh *mesh)
|
||||||
std::vector<Imath::V3f> points;
|
std::vector<Imath::V3f> points;
|
||||||
std::vector<int32_t> face_verts, loop_counts;
|
std::vector<int32_t> face_verts, loop_counts;
|
||||||
std::vector<int32_t> edge_crease_indices, edge_crease_lengths, vert_crease_indices;
|
std::vector<int32_t> edge_crease_indices, edge_crease_lengths, vert_crease_indices;
|
||||||
bool has_flat_poly = false;
|
|
||||||
|
|
||||||
get_vertices(mesh, points);
|
get_vertices(mesh, points);
|
||||||
get_topology(mesh, face_verts, loop_counts, has_flat_poly);
|
get_topology(mesh, face_verts, loop_counts);
|
||||||
get_edge_creases(mesh, edge_crease_indices, edge_crease_lengths, edge_crease_sharpness);
|
get_edge_creases(mesh, edge_crease_indices, edge_crease_lengths, edge_crease_sharpness);
|
||||||
get_vert_creases(mesh, vert_crease_indices, vert_crease_sharpness);
|
get_vert_creases(mesh, vert_crease_indices, vert_crease_sharpness);
|
||||||
|
|
||||||
|
@ -450,20 +446,10 @@ static void get_vertices(Mesh *mesh, std::vector<Imath::V3f> &points)
|
||||||
|
|
||||||
static void get_topology(Mesh *mesh,
|
static void get_topology(Mesh *mesh,
|
||||||
std::vector<int32_t> &face_verts,
|
std::vector<int32_t> &face_verts,
|
||||||
std::vector<int32_t> &loop_counts,
|
std::vector<int32_t> &loop_counts)
|
||||||
bool &r_has_flat_shaded_face)
|
|
||||||
{
|
{
|
||||||
const OffsetIndices faces = mesh->faces();
|
const OffsetIndices faces = mesh->faces();
|
||||||
const Span<int> corner_verts = mesh->corner_verts();
|
const Span<int> corner_verts = mesh->corner_verts();
|
||||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
|
||||||
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
|
||||||
"sharp_face", ATTR_DOMAIN_FACE, false);
|
|
||||||
for (const int i : sharp_faces.index_range()) {
|
|
||||||
if (sharp_faces[i]) {
|
|
||||||
r_has_flat_shaded_face = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
face_verts.clear();
|
face_verts.clear();
|
||||||
loop_counts.clear();
|
loop_counts.clear();
|
||||||
|
@ -535,36 +521,47 @@ static void get_vert_creases(Mesh *mesh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_loop_normals(Mesh *mesh,
|
static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals)
|
||||||
std::vector<Imath::V3f> &normals,
|
|
||||||
bool has_flat_shaded_poly)
|
|
||||||
{
|
{
|
||||||
normals.clear();
|
normals.clear();
|
||||||
|
|
||||||
/* If all polygons are smooth shaded, and there are no custom normals, we don't need to export
|
switch (mesh->normals_domain()) {
|
||||||
* normals at all. This is also done by other software, see #71246. */
|
case blender::bke::MeshNormalDomain::Point: {
|
||||||
if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL) &&
|
/* If all faces are smooth shaded, and there are no custom normals, we don't need to
|
||||||
(mesh->flag & ME_AUTOSMOOTH) == 0)
|
* export normals at all. This is also done by other software, see #71246. */
|
||||||
{
|
break;
|
||||||
return;
|
}
|
||||||
}
|
case blender::bke::MeshNormalDomain::Face: {
|
||||||
|
normals.resize(mesh->totloop);
|
||||||
|
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
|
||||||
|
|
||||||
BKE_mesh_calc_normals_split(mesh);
|
const OffsetIndices faces = mesh->faces();
|
||||||
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
const Span<float3> face_normals = mesh->face_normals();
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_NORMAL));
|
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
||||||
BLI_assert_msg(lnors != nullptr, "BKE_mesh_calc_normals_split() should have computed CD_NORMAL");
|
for (const int i : range) {
|
||||||
|
float3 y_up;
|
||||||
|
copy_yup_from_zup(y_up, face_normals[i]);
|
||||||
|
dst_normals.slice(faces[i]).fill(y_up);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case blender::bke::MeshNormalDomain::Corner: {
|
||||||
|
normals.resize(mesh->totloop);
|
||||||
|
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
|
||||||
|
|
||||||
normals.resize(mesh->totloop);
|
/* NOTE: data needs to be written in the reverse order. */
|
||||||
|
const OffsetIndices faces = mesh->faces();
|
||||||
/* NOTE: data needs to be written in the reverse order. */
|
const Span<float3> corner_normals = mesh->corner_normals();
|
||||||
int abc_index = 0;
|
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
||||||
const OffsetIndices faces = mesh->faces();
|
for (const int i : range) {
|
||||||
|
const IndexRange face = faces[i];
|
||||||
for (const int i : faces.index_range()) {
|
for (const int i : face.index_range()) {
|
||||||
const IndexRange face = faces[i];
|
copy_yup_from_zup(dst_normals[face.last(i)], corner_normals[face[i]]);
|
||||||
for (int j = face.size() - 1; j >= 0; j--, abc_index++) {
|
}
|
||||||
int blender_index = face[j];
|
}
|
||||||
copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]);
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,7 +289,6 @@ static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
BKE_mesh_set_custom_normals(mesh, lnors);
|
BKE_mesh_set_custom_normals(mesh, lnors);
|
||||||
|
|
||||||
MEM_freeN(lnors);
|
MEM_freeN(lnors);
|
||||||
|
@ -312,7 +311,6 @@ static void process_vertex_normals(CDStreamConfig &config,
|
||||||
copy_zup_from_yup(vert_normals[index], vertex_normals[index].getValue());
|
copy_zup_from_yup(vert_normals[index], vertex_normals[index].getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
config.mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
BKE_mesh_set_custom_normals_from_verts(config.mesh, vert_normals);
|
BKE_mesh_set_custom_normals_from_verts(config.mesh, vert_normals);
|
||||||
MEM_freeN(vert_normals);
|
MEM_freeN(vert_normals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -620,22 +620,19 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
|
||||||
const Span<float3> vert_normals = me->vert_normals();
|
const Span<float3> vert_normals = me->vert_normals();
|
||||||
const blender::OffsetIndices faces = me->faces();
|
const blender::OffsetIndices faces = me->faces();
|
||||||
const Span<int> corner_verts = me->corner_verts();
|
const Span<int> corner_verts = me->corner_verts();
|
||||||
const float(*lnors)[3] = nullptr;
|
|
||||||
bool use_custom_normals = false;
|
|
||||||
|
|
||||||
const bke::AttributeAccessor attributes = me->attributes();
|
const bke::AttributeAccessor attributes = me->attributes();
|
||||||
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
||||||
"sharp_face", ATTR_DOMAIN_FACE, false);
|
"sharp_face", ATTR_DOMAIN_FACE, false);
|
||||||
|
|
||||||
BKE_mesh_calc_normals_split(me);
|
blender::Span<blender::float3> corner_normals;
|
||||||
if (CustomData_has_layer(&me->loop_data, CD_NORMAL)) {
|
if (me->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
lnors = (float(*)[3])CustomData_get_layer(&me->loop_data, CD_NORMAL);
|
corner_normals = me->corner_normals();
|
||||||
use_custom_normals = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const int face_index : faces.index_range()) {
|
for (const int face_index : faces.index_range()) {
|
||||||
const IndexRange face = faces[face_index];
|
const IndexRange face = faces[face_index];
|
||||||
bool use_vert_normals = use_custom_normals || !sharp_faces[face_index];
|
bool use_vert_normals = !corner_normals.is_empty() || !sharp_faces[face_index];
|
||||||
|
|
||||||
if (!use_vert_normals) {
|
if (!use_vert_normals) {
|
||||||
/* For flat faces use face normal as vertex normal: */
|
/* For flat faces use face normal as vertex normal: */
|
||||||
|
@ -653,8 +650,8 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
|
||||||
if (use_vert_normals) {
|
if (use_vert_normals) {
|
||||||
float normalized[3];
|
float normalized[3];
|
||||||
|
|
||||||
if (use_custom_normals) {
|
if (!corner_normals.is_empty()) {
|
||||||
normalize_v3_v3(normalized, lnors[corner]);
|
normalize_v3_v3(normalized, corner_normals[corner]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
copy_v3_v3(normalized, vert_normals[corner_verts[corner]]);
|
copy_v3_v3(normalized, vert_normals[corner_verts[corner]]);
|
||||||
|
|
|
@ -1173,7 +1173,6 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BKE_mesh_set_custom_normals(me, reinterpret_cast<float(*)[3]>(loop_normals.data()));
|
BKE_mesh_set_custom_normals(me, reinterpret_cast<float(*)[3]>(loop_normals.data()));
|
||||||
me->flag |= ME_AUTOSMOOTH;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,6 @@ Mesh *STLMeshHelper::to_mesh()
|
||||||
|
|
||||||
if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
|
if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
|
||||||
BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
|
BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
|
||||||
mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "BLI_string.h"
|
#include "BLI_string.h"
|
||||||
|
|
||||||
|
#include "BKE_attribute.h"
|
||||||
#include "BKE_material.h"
|
#include "BKE_material.h"
|
||||||
#include "BKE_mesh.hh"
|
#include "BKE_mesh.hh"
|
||||||
#include "BKE_mesh_runtime.hh"
|
#include "BKE_mesh_runtime.hh"
|
||||||
|
@ -231,9 +232,10 @@ void MeshData::write_submeshes(const Mesh *mesh)
|
||||||
const Span<int> corner_verts = mesh->corner_verts();
|
const Span<int> corner_verts = mesh->corner_verts();
|
||||||
const Span<MLoopTri> looptris = mesh->looptris();
|
const Span<MLoopTri> looptris = mesh->looptris();
|
||||||
|
|
||||||
Array<float3> corner_normals(mesh->totloop);
|
Span<float3> corner_normals;
|
||||||
BKE_mesh_calc_normals_split_ex(
|
if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
mesh, nullptr, reinterpret_cast<float(*)[3]>(corner_normals.data()));
|
corner_normals = mesh->corner_normals();
|
||||||
|
}
|
||||||
|
|
||||||
const float2 *uv_map = static_cast<const float2 *>(
|
const float2 *uv_map = static_cast<const float2 *>(
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_PROP_FLOAT2));
|
CustomData_get_layer(&mesh->loop_data, CD_PROP_FLOAT2));
|
||||||
|
|
|
@ -773,8 +773,6 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
|
|
||||||
long int loop_count = normals_.size();
|
long int loop_count = normals_.size();
|
||||||
|
|
||||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
float(*lnors)[3] = static_cast<float(*)[3]>(
|
||||||
|
@ -828,7 +826,6 @@ void USDMeshReader::process_normals_uniform(Mesh *mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
BKE_mesh_set_custom_normals(mesh, lnors);
|
BKE_mesh_set_custom_normals(mesh, lnors);
|
||||||
|
|
||||||
MEM_freeN(lnors);
|
MEM_freeN(lnors);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <pxr/usd/usdShade/material.h>
|
#include <pxr/usd/usdShade/material.h>
|
||||||
#include <pxr/usd/usdShade/materialBindingAPI.h>
|
#include <pxr/usd/usdShade/materialBindingAPI.h>
|
||||||
|
|
||||||
|
#include "BLI_array_utils.hh"
|
||||||
#include "BLI_assert.h"
|
#include "BLI_assert.h"
|
||||||
#include "BLI_math_color.hh"
|
#include "BLI_math_color.hh"
|
||||||
#include "BLI_math_quaternion_types.hh"
|
#include "BLI_math_quaternion_types.hh"
|
||||||
|
@ -648,42 +649,28 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
|
||||||
void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
|
void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
|
||||||
{
|
{
|
||||||
pxr::UsdTimeCode timecode = get_export_time_code();
|
pxr::UsdTimeCode timecode = get_export_time_code();
|
||||||
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_NORMAL));
|
|
||||||
const OffsetIndices faces = mesh->faces();
|
|
||||||
const Span<int> corner_verts = mesh->corner_verts();
|
|
||||||
|
|
||||||
pxr::VtVec3fArray loop_normals;
|
pxr::VtVec3fArray loop_normals;
|
||||||
loop_normals.reserve(mesh->totloop);
|
loop_normals.resize(mesh->totloop);
|
||||||
|
|
||||||
if (lnors != nullptr) {
|
MutableSpan dst_normals(reinterpret_cast<float3 *>(loop_normals.data()), loop_normals.size());
|
||||||
/* Export custom loop normals. */
|
|
||||||
for (int loop_idx = 0, totloop = mesh->totloop; loop_idx < totloop; ++loop_idx) {
|
switch (mesh->normals_domain()) {
|
||||||
loop_normals.push_back(pxr::GfVec3f(lnors[loop_idx]));
|
case bke::MeshNormalDomain::Point: {
|
||||||
|
array_utils::gather(mesh->vert_normals(), mesh->corner_verts(), dst_normals);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
case bke::MeshNormalDomain::Face: {
|
||||||
else {
|
const OffsetIndices faces = mesh->faces();
|
||||||
/* Compute the loop normals based on the 'smooth' flag. */
|
const Span<float3> face_normals = mesh->face_normals();
|
||||||
bke::AttributeAccessor attributes = mesh->attributes();
|
for (const int i : faces.index_range()) {
|
||||||
const Span<float3> vert_normals = mesh->vert_normals();
|
dst_normals.slice(faces[i]).fill(face_normals[i]);
|
||||||
const Span<float3> face_normals = mesh->face_normals();
|
|
||||||
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
|
||||||
"sharp_face", ATTR_DOMAIN_FACE, false);
|
|
||||||
for (const int i : faces.index_range()) {
|
|
||||||
const IndexRange face = faces[i];
|
|
||||||
if (sharp_faces[i]) {
|
|
||||||
/* Flat shaded, use common normal for all verts. */
|
|
||||||
pxr::GfVec3f pxr_normal(&face_normals[i].x);
|
|
||||||
for (int loop_idx = 0; loop_idx < face.size(); ++loop_idx) {
|
|
||||||
loop_normals.push_back(pxr_normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Smooth shaded, use individual vert normals. */
|
|
||||||
for (const int vert : corner_verts.slice(face)) {
|
|
||||||
loop_normals.push_back(pxr::GfVec3f(&vert_normals[vert].x));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bke::MeshNormalDomain::Corner: {
|
||||||
|
array_utils::copy(mesh->corner_normals(), dst_normals);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,12 +192,6 @@ int OBJMesh::ith_smooth_group(const int face_index) const
|
||||||
return poly_smooth_groups_[face_index];
|
return poly_smooth_groups_[face_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBJMesh::ensure_mesh_normals() const
|
|
||||||
{
|
|
||||||
/* Constant cast can be removed when calculating face corner normals lazily is possible. */
|
|
||||||
BKE_mesh_calc_normals_split(const_cast<Mesh *>(export_mesh_));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
||||||
{
|
{
|
||||||
const bool *sharp_edges = static_cast<const bool *>(
|
const bool *sharp_edges = static_cast<const bool *>(
|
||||||
|
@ -372,16 +366,23 @@ void OBJMesh::store_normal_coords_and_indices()
|
||||||
normal_to_index.reserve(export_mesh_->faces_num);
|
normal_to_index.reserve(export_mesh_->faces_num);
|
||||||
loop_to_normal_index_.resize(export_mesh_->totloop);
|
loop_to_normal_index_.resize(export_mesh_->totloop);
|
||||||
loop_to_normal_index_.fill(-1);
|
loop_to_normal_index_.fill(-1);
|
||||||
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
|
||||||
CustomData_get_layer(&export_mesh_->loop_data, CD_NORMAL));
|
Span<float3> corner_normals;
|
||||||
|
if (ELEM(export_mesh_->normals_domain(),
|
||||||
|
bke::MeshNormalDomain::Point,
|
||||||
|
bke::MeshNormalDomain::Corner))
|
||||||
|
{
|
||||||
|
corner_normals = export_mesh_->corner_normals();
|
||||||
|
}
|
||||||
|
|
||||||
for (int face_index = 0; face_index < export_mesh_->faces_num; ++face_index) {
|
for (int face_index = 0; face_index < export_mesh_->faces_num; ++face_index) {
|
||||||
const IndexRange face = mesh_faces_[face_index];
|
const IndexRange face = mesh_faces_[face_index];
|
||||||
bool need_per_loop_normals = lnors != nullptr || !(sharp_faces_[face_index]);
|
bool need_per_loop_normals = !corner_normals.is_empty() || !(sharp_faces_[face_index]);
|
||||||
if (need_per_loop_normals) {
|
if (need_per_loop_normals) {
|
||||||
for (const int corner : face) {
|
for (const int corner : face) {
|
||||||
float3 loop_normal;
|
float3 loop_normal;
|
||||||
BLI_assert(corner < export_mesh_->totloop);
|
BLI_assert(corner < export_mesh_->totloop);
|
||||||
copy_v3_v3(loop_normal, lnors[corner]);
|
copy_v3_v3(loop_normal, corner_normals[corner]);
|
||||||
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
||||||
normalize_v3(loop_normal);
|
normalize_v3(loop_normal);
|
||||||
float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
|
float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
|
||||||
|
|
|
@ -119,8 +119,6 @@ class OBJMesh : NonCopyable {
|
||||||
*/
|
*/
|
||||||
const Material *get_object_material(int16_t mat_nr) const;
|
const Material *get_object_material(int16_t mat_nr) const;
|
||||||
|
|
||||||
void ensure_mesh_normals() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate smooth groups of a smooth-shaded object.
|
* Calculate smooth groups of a smooth-shaded object.
|
||||||
* \return A polygon aligned array of smooth group numbers.
|
* \return A polygon aligned array of smooth group numbers.
|
||||||
|
|
|
@ -160,9 +160,6 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
|
||||||
if (mtl_writer) {
|
if (mtl_writer) {
|
||||||
mtlindices.append(mtl_writer->add_materials(obj));
|
mtlindices.append(mtl_writer->add_materials(obj));
|
||||||
}
|
}
|
||||||
if (export_params.export_normals) {
|
|
||||||
obj.ensure_mesh_normals();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parallel over meshes: store normal coords & indices, uv coords and indices. */
|
/* Parallel over meshes: store normal coords & indices, uv coords and indices. */
|
||||||
|
|
|
@ -384,7 +384,6 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
|
||||||
tot_loop_idx++;
|
tot_loop_idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mesh->flag |= ME_AUTOSMOOTH;
|
|
||||||
BKE_mesh_set_custom_normals(mesh, loop_normals);
|
BKE_mesh_set_custom_normals(mesh, loop_normals);
|
||||||
MEM_freeN(loop_normals);
|
MEM_freeN(loop_normals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,9 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
|
||||||
const Span<float3> positions = mesh->vert_positions();
|
const Span<float3> positions = mesh->vert_positions();
|
||||||
EXPECT_V3_NEAR(positions.first(), exp.vert_first, 0.0001f);
|
EXPECT_V3_NEAR(positions.first(), exp.vert_first, 0.0001f);
|
||||||
EXPECT_V3_NEAR(positions.last(), exp.vert_last, 0.0001f);
|
EXPECT_V3_NEAR(positions.last(), exp.vert_last, 0.0001f);
|
||||||
const float3 *lnors = (const float3 *)CustomData_get_layer(&mesh->loop_data, CD_NORMAL);
|
const float3 *lnors = mesh->normals_domain() == bke::MeshNormalDomain::Corner ?
|
||||||
|
mesh->corner_normals().data() :
|
||||||
|
nullptr;
|
||||||
float3 normal_first = lnors != nullptr ? lnors[0] : float3(0, 0, 0);
|
float3 normal_first = lnors != nullptr ? lnors[0] : float3(0, 0, 0);
|
||||||
EXPECT_V3_NEAR(normal_first, exp.normal_first, 0.0001f);
|
EXPECT_V3_NEAR(normal_first, exp.normal_first, 0.0001f);
|
||||||
const float2 *mloopuv = static_cast<const float2 *>(
|
const float2 *mloopuv = static_cast<const float2 *>(
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#define _DNA_DEFAULT_Mesh \
|
#define _DNA_DEFAULT_Mesh \
|
||||||
{ \
|
{ \
|
||||||
.texspace_size = {1.0f, 1.0f, 1.0f}, \
|
.texspace_size = {1.0f, 1.0f, 1.0f}, \
|
||||||
.smoothresh = DEG2RADF(30), \
|
|
||||||
.texspace_flag = ME_TEXSPACE_FLAG_AUTO, \
|
.texspace_flag = ME_TEXSPACE_FLAG_AUTO, \
|
||||||
.remesh_voxel_size = 0.1f, \
|
.remesh_voxel_size = 0.1f, \
|
||||||
.remesh_voxel_adaptivity = 0.0f, \
|
.remesh_voxel_adaptivity = 0.0f, \
|
||||||
|
|
|
@ -32,6 +32,7 @@ class AttributeAccessor;
|
||||||
class MutableAttributeAccessor;
|
class MutableAttributeAccessor;
|
||||||
struct LooseVertCache;
|
struct LooseVertCache;
|
||||||
struct LooseEdgeCache;
|
struct LooseEdgeCache;
|
||||||
|
enum class MeshNormalDomain : int8_t;
|
||||||
} // namespace bke
|
} // namespace bke
|
||||||
} // namespace blender
|
} // namespace blender
|
||||||
using MeshRuntimeHandle = blender::bke::MeshRuntime;
|
using MeshRuntimeHandle = blender::bke::MeshRuntime;
|
||||||
|
@ -149,10 +150,7 @@ typedef struct Mesh {
|
||||||
/** Mostly more flags used when editing or displaying the mesh. */
|
/** Mostly more flags used when editing or displaying the mesh. */
|
||||||
uint16_t flag;
|
uint16_t flag;
|
||||||
|
|
||||||
/**
|
float smoothresh_legacy DNA_DEPRECATED;
|
||||||
* The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
|
|
||||||
*/
|
|
||||||
float smoothresh;
|
|
||||||
|
|
||||||
/** Per-mesh settings for voxel remesh. */
|
/** Per-mesh settings for voxel remesh. */
|
||||||
float remesh_voxel_size;
|
float remesh_voxel_size;
|
||||||
|
@ -359,6 +357,17 @@ typedef struct Mesh {
|
||||||
*/
|
*/
|
||||||
void tag_loose_verts_none() const;
|
void tag_loose_verts_none() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the least complex attribute domain needed to store normals encoding all relevant mesh
|
||||||
|
* data. When all edges or faces are sharp, face normals are enough. When all are smooth, vertex
|
||||||
|
* normals are enough. With a combination of sharp and smooth, normals may be "split",
|
||||||
|
* requiring face corner storage.
|
||||||
|
*
|
||||||
|
* When possible, it's preferred to use face normals over vertex normals and vertex normals over
|
||||||
|
* face corner normals, since there is a 2-4x performance cost increase for each more complex
|
||||||
|
* domain.
|
||||||
|
*/
|
||||||
|
blender::bke::MeshNormalDomain normals_domain() const;
|
||||||
/**
|
/**
|
||||||
* Normal direction of polygons, defined by positions and the winding direction of face corners.
|
* Normal direction of polygons, defined by positions and the winding direction of face corners.
|
||||||
*/
|
*/
|
||||||
|
@ -368,6 +377,14 @@ typedef struct Mesh {
|
||||||
* surrounding each vertex and the normalized position for loose vertices.
|
* surrounding each vertex and the normalized position for loose vertices.
|
||||||
*/
|
*/
|
||||||
blender::Span<blender::float3> vert_normals() const;
|
blender::Span<blender::float3> vert_normals() const;
|
||||||
|
/**
|
||||||
|
* Normal direction at each face corner. Defined by a combination of face normals, vertex
|
||||||
|
* normals, the `sharp_edge` and `sharp_face` attributes, and potentially by custom normals.
|
||||||
|
*
|
||||||
|
* \note Because of the large memory requirements of storing normals per face corner, prefer
|
||||||
|
* using #face_normals() or #vert_normals() when possible (see #normals_domain()).
|
||||||
|
*/
|
||||||
|
blender::Span<blender::float3> corner_normals() const;
|
||||||
#endif
|
#endif
|
||||||
} Mesh;
|
} Mesh;
|
||||||
|
|
||||||
|
@ -422,9 +439,9 @@ enum {
|
||||||
ME_FLAG_DEPRECATED_2 = 1 << 2, /* deprecated */
|
ME_FLAG_DEPRECATED_2 = 1 << 2, /* deprecated */
|
||||||
ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */
|
ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */
|
||||||
ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */
|
ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */
|
||||||
ME_AUTOSMOOTH = 1 << 5,
|
ME_AUTOSMOOTH_LEGACY = 1 << 5, /* deprecated */
|
||||||
ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */
|
ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */
|
||||||
ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */
|
ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */
|
||||||
ME_REMESH_REPROJECT_VERTEX_COLORS = 1 << 8,
|
ME_REMESH_REPROJECT_VERTEX_COLORS = 1 << 8,
|
||||||
ME_DS_EXPAND = 1 << 9,
|
ME_DS_EXPAND = 1 << 9,
|
||||||
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
|
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
|
||||||
|
|
|
@ -116,6 +116,7 @@ DNA_STRUCT_RENAME_ELEM(Mesh, loc, texspace_location)
|
||||||
DNA_STRUCT_RENAME_ELEM(Mesh, pdata, face_data)
|
DNA_STRUCT_RENAME_ELEM(Mesh, pdata, face_data)
|
||||||
DNA_STRUCT_RENAME_ELEM(Mesh, poly_offset_indices, face_offset_indices)
|
DNA_STRUCT_RENAME_ELEM(Mesh, poly_offset_indices, face_offset_indices)
|
||||||
DNA_STRUCT_RENAME_ELEM(Mesh, size, texspace_size)
|
DNA_STRUCT_RENAME_ELEM(Mesh, size, texspace_size)
|
||||||
|
DNA_STRUCT_RENAME_ELEM(Mesh, smoothresh, smoothresh_legacy)
|
||||||
DNA_STRUCT_RENAME_ELEM(Mesh, texflag, texspace_flag)
|
DNA_STRUCT_RENAME_ELEM(Mesh, texflag, texspace_flag)
|
||||||
DNA_STRUCT_RENAME_ELEM(Mesh, totface, totface_legacy)
|
DNA_STRUCT_RENAME_ELEM(Mesh, totface, totface_legacy)
|
||||||
DNA_STRUCT_RENAME_ELEM(Mesh, totpoly, faces_num)
|
DNA_STRUCT_RENAME_ELEM(Mesh, totpoly, faces_num)
|
||||||
|
|
|
@ -225,6 +225,8 @@ DEF_ENUM(rna_enum_attribute_type_with_auto_items)
|
||||||
DEF_ENUM(rna_enum_attribute_domain_items)
|
DEF_ENUM(rna_enum_attribute_domain_items)
|
||||||
DEF_ENUM(rna_enum_attribute_domain_edge_face_items)
|
DEF_ENUM(rna_enum_attribute_domain_edge_face_items)
|
||||||
DEF_ENUM(rna_enum_attribute_domain_only_mesh_items)
|
DEF_ENUM(rna_enum_attribute_domain_only_mesh_items)
|
||||||
|
DEF_ENUM(rna_enum_attribute_domain_only_mesh_no_edge_items)
|
||||||
|
DEF_ENUM(rna_enum_attribute_domain_point_face_curve_items)
|
||||||
DEF_ENUM(rna_enum_attribute_domain_point_edge_face_curve_items)
|
DEF_ENUM(rna_enum_attribute_domain_point_edge_face_curve_items)
|
||||||
DEF_ENUM(rna_enum_attribute_curves_domain_items)
|
DEF_ENUM(rna_enum_attribute_curves_domain_items)
|
||||||
DEF_ENUM(rna_enum_color_attribute_domain_items)
|
DEF_ENUM(rna_enum_color_attribute_domain_items)
|
||||||
|
|
|
@ -100,6 +100,20 @@ const EnumPropertyItem rna_enum_attribute_domain_only_mesh_items[] = {
|
||||||
{0, nullptr, 0, nullptr, nullptr},
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const EnumPropertyItem rna_enum_attribute_domain_only_mesh_no_edge_items[] = {
|
||||||
|
{ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
|
||||||
|
{ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"},
|
||||||
|
{ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EnumPropertyItem rna_enum_attribute_domain_point_face_curve_items[] = {
|
||||||
|
{ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
|
||||||
|
{ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"},
|
||||||
|
{ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
const EnumPropertyItem rna_enum_attribute_domain_point_edge_face_curve_items[] = {
|
const EnumPropertyItem rna_enum_attribute_domain_point_edge_face_curve_items[] = {
|
||||||
{ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
|
{ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
|
||||||
{ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"},
|
{ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"},
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "BKE_attribute.h"
|
#include "BKE_attribute.h"
|
||||||
#include "BKE_editmesh.h"
|
#include "BKE_editmesh.h"
|
||||||
|
#include "BKE_mesh_types.hh"
|
||||||
|
|
||||||
#include "RNA_access.hh"
|
#include "RNA_access.hh"
|
||||||
#include "RNA_define.hh"
|
#include "RNA_define.hh"
|
||||||
|
@ -478,27 +479,7 @@ static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values)
|
||||||
{
|
{
|
||||||
Mesh *me = rna_mesh(ptr);
|
Mesh *me = rna_mesh(ptr);
|
||||||
const int index = rna_MeshLoop_index_get(ptr);
|
const int index = rna_MeshLoop_index_get(ptr);
|
||||||
const float(*layer)[3] = static_cast<const float(*)[3]>(
|
copy_v3_v3(values, me->corner_normals()[index]);
|
||||||
CustomData_get_layer(&me->loop_data, CD_NORMAL));
|
|
||||||
|
|
||||||
if (!layer) {
|
|
||||||
zero_v3(values);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
copy_v3_v3(values, layer[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rna_MeshLoop_normal_set(PointerRNA *ptr, const float *values)
|
|
||||||
{
|
|
||||||
Mesh *me = rna_mesh(ptr);
|
|
||||||
const int index = rna_MeshLoop_index_get(ptr);
|
|
||||||
float(*layer)[3] = static_cast<float(*)[3]>(
|
|
||||||
CustomData_get_layer_for_write(&me->loop_data, CD_NORMAL, me->totloop));
|
|
||||||
|
|
||||||
if (layer) {
|
|
||||||
normalize_v3_v3(layer[index], values);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_MeshLoop_tangent_get(PointerRNA *ptr, float *values)
|
static void rna_MeshLoop_tangent_get(PointerRNA *ptr, float *values)
|
||||||
|
@ -530,13 +511,11 @@ static void rna_MeshLoop_bitangent_get(PointerRNA *ptr, float *values)
|
||||||
{
|
{
|
||||||
Mesh *me = rna_mesh(ptr);
|
Mesh *me = rna_mesh(ptr);
|
||||||
const int index = rna_MeshLoop_index_get(ptr);
|
const int index = rna_MeshLoop_index_get(ptr);
|
||||||
const float(*nor)[3] = static_cast<const float(*)[3]>(
|
|
||||||
CustomData_get_layer(&me->loop_data, CD_NORMAL));
|
|
||||||
const float(*vec)[4] = static_cast<const float(*)[4]>(
|
const float(*vec)[4] = static_cast<const float(*)[4]>(
|
||||||
CustomData_get_layer(&me->loop_data, CD_MLOOPTANGENT));
|
CustomData_get_layer(&me->loop_data, CD_MLOOPTANGENT));
|
||||||
|
|
||||||
if (nor && vec) {
|
if (vec) {
|
||||||
cross_v3_v3v3(values, nor[index], vec[index]);
|
cross_v3_v3v3(values, me->corner_normals()[index], vec[index]);
|
||||||
mul_v3_fl(values, vec[index][3]);
|
mul_v3_fl(values, vec[index][3]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -604,7 +583,10 @@ static void rna_MeshPolygon_use_smooth_set(PointerRNA *ptr, bool value)
|
||||||
&mesh->face_data, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->faces_num, "sharp_face"));
|
&mesh->face_data, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->faces_num, "sharp_face"));
|
||||||
}
|
}
|
||||||
const int index = rna_MeshPolygon_index_get(ptr);
|
const int index = rna_MeshPolygon_index_get(ptr);
|
||||||
sharp_faces[index] = !value;
|
if (value != sharp_faces[index]) {
|
||||||
|
sharp_faces[index] = value;
|
||||||
|
BKE_mesh_tag_sharpness_changed(mesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rna_MeshPolygon_select_get(PointerRNA *ptr)
|
static bool rna_MeshPolygon_select_get(PointerRNA *ptr)
|
||||||
|
@ -706,20 +688,11 @@ static void rna_MeshLoopTriangle_normal_get(PointerRNA *ptr, float *values)
|
||||||
static void rna_MeshLoopTriangle_split_normals_get(PointerRNA *ptr, float *values)
|
static void rna_MeshLoopTriangle_split_normals_get(PointerRNA *ptr, float *values)
|
||||||
{
|
{
|
||||||
Mesh *me = rna_mesh(ptr);
|
Mesh *me = rna_mesh(ptr);
|
||||||
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
const blender::Span<blender::float3> loop_normals = me->corner_normals();
|
||||||
CustomData_get_layer(&me->loop_data, CD_NORMAL));
|
const MLoopTri *lt = (const MLoopTri *)ptr->data;
|
||||||
|
copy_v3_v3(values + 0, loop_normals[lt->tri[0]]);
|
||||||
if (!lnors) {
|
copy_v3_v3(values + 3, loop_normals[lt->tri[1]]);
|
||||||
zero_v3(values + 0);
|
copy_v3_v3(values + 6, loop_normals[lt->tri[2]]);
|
||||||
zero_v3(values + 3);
|
|
||||||
zero_v3(values + 6);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MLoopTri *lt = (MLoopTri *)ptr->data;
|
|
||||||
copy_v3_v3(values + 0, lnors[lt->tri[0]]);
|
|
||||||
copy_v3_v3(values + 3, lnors[lt->tri[1]]);
|
|
||||||
copy_v3_v3(values + 6, lnors[lt->tri[2]]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static float rna_MeshLoopTriangle_area_get(PointerRNA *ptr)
|
static float rna_MeshLoopTriangle_area_get(PointerRNA *ptr)
|
||||||
|
@ -1399,7 +1372,10 @@ static void rna_MeshEdge_use_edge_sharp_set(PointerRNA *ptr, bool value)
|
||||||
&mesh->edge_data, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totedge, "sharp_edge"));
|
&mesh->edge_data, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totedge, "sharp_edge"));
|
||||||
}
|
}
|
||||||
const int index = rna_MeshEdge_index_get(ptr);
|
const int index = rna_MeshEdge_index_get(ptr);
|
||||||
sharp_edge[index] = value;
|
if (value != sharp_edge[index]) {
|
||||||
|
sharp_edge[index] = value;
|
||||||
|
BKE_mesh_tag_sharpness_changed(mesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rna_MeshEdge_use_seam_get(PointerRNA *ptr)
|
static bool rna_MeshEdge_use_seam_get(PointerRNA *ptr)
|
||||||
|
@ -1642,6 +1618,11 @@ int rna_Mesh_loops_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rna_Mesh_normals_domain_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
return int(rna_mesh(ptr)->normals_domain());
|
||||||
|
}
|
||||||
|
|
||||||
static void rna_Mesh_vertex_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
static void rna_Mesh_vertex_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
const Mesh *mesh = rna_mesh(ptr);
|
const Mesh *mesh = rna_mesh(ptr);
|
||||||
|
@ -1707,41 +1688,32 @@ int rna_Mesh_poly_normals_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_p
|
||||||
static void rna_Mesh_corner_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
static void rna_Mesh_corner_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
const Mesh *mesh = rna_mesh(ptr);
|
const Mesh *mesh = rna_mesh(ptr);
|
||||||
const blender::float3 *normals = static_cast<const blender::float3 *>(
|
const blender::Span<blender::float3> normals = mesh->corner_normals();
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_NORMAL));
|
if (normals.is_empty()) {
|
||||||
if (!normals) {
|
|
||||||
iter->valid = false;
|
iter->valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rna_iterator_array_begin(iter,
|
rna_iterator_array_begin(
|
||||||
const_cast<blender::float3 *>(normals),
|
iter, (void *)normals.data(), sizeof(float[3]), mesh->totloop, false, nullptr);
|
||||||
sizeof(float[3]),
|
|
||||||
mesh->totloop,
|
|
||||||
false,
|
|
||||||
nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rna_Mesh_corner_normals_length(PointerRNA *ptr)
|
static int rna_Mesh_corner_normals_length(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
const Mesh *mesh = rna_mesh(ptr);
|
const Mesh *mesh = rna_mesh(ptr);
|
||||||
if (!CustomData_has_layer(&mesh->loop_data, CD_NORMAL)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mesh->totloop;
|
return mesh->totloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rna_Mesh_corner_normals_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
|
int rna_Mesh_corner_normals_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
|
||||||
{
|
{
|
||||||
const Mesh *mesh = rna_mesh(ptr);
|
const Mesh *mesh = rna_mesh(ptr);
|
||||||
const blender::float3 *normals = static_cast<const blender::float3 *>(
|
const blender::Span<blender::float3> normals = mesh->corner_normals();
|
||||||
CustomData_get_layer(&mesh->loop_data, CD_NORMAL));
|
if (index < 0 || index >= mesh->totloop || normals.is_empty()) {
|
||||||
if (index < 0 || index >= mesh->totloop || !normals) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Casting away const is okay because this RNA type doesn't allow changing the value. */
|
/* Casting away const is okay because this RNA type doesn't allow changing the value. */
|
||||||
r_ptr->owner_id = (ID *)&mesh->id;
|
r_ptr->owner_id = (ID *)&mesh->id;
|
||||||
r_ptr->type = &RNA_MeshNormalValue;
|
r_ptr->type = &RNA_MeshNormalValue;
|
||||||
r_ptr->data = const_cast<blender::float3 *>(&normals[index]);
|
r_ptr->data = (float *)&normals[index];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2193,8 +2165,7 @@ static void rna_def_mlooptri(BlenderRNA *brna)
|
||||||
RNA_def_property_ui_text(
|
RNA_def_property_ui_text(
|
||||||
prop,
|
prop,
|
||||||
"Split Normals",
|
"Split Normals",
|
||||||
"Local space unit length split normals vectors of the vertices of this triangle "
|
"Local space unit length split normal vectors of the face corners of this triangle");
|
||||||
"(must be computed beforehand using calc_normals_split or calc_tangents)");
|
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED);
|
prop = RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED);
|
||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
@ -2243,15 +2214,14 @@ static void rna_def_mloop(BlenderRNA *brna)
|
||||||
RNA_def_property_ui_text(prop, "Index", "Index of this loop");
|
RNA_def_property_ui_text(prop, "Index", "Index of this loop");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
|
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_array(prop, 3);
|
RNA_def_property_array(prop, 3);
|
||||||
RNA_def_property_range(prop, -1.0f, 1.0f);
|
RNA_def_property_range(prop, -1.0f, 1.0f);
|
||||||
RNA_def_property_float_funcs(
|
RNA_def_property_float_funcs(prop, "rna_MeshLoop_normal_get", nullptr, nullptr);
|
||||||
prop, "rna_MeshLoop_normal_get", "rna_MeshLoop_normal_set", nullptr);
|
RNA_def_property_ui_text(prop,
|
||||||
RNA_def_property_ui_text(
|
"Normal",
|
||||||
prop,
|
"The normal direction of the face corner, taking into account sharp "
|
||||||
"Normal",
|
"faces, sharp edges, and custom normal data");
|
||||||
"Local space unit length split normal vector of this vertex for this face "
|
|
||||||
"(must be computed beforehand using calc_normals_split or calc_tangents)");
|
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "tangent", PROP_FLOAT, PROP_DIRECTION);
|
prop = RNA_def_property(srna, "tangent", PROP_FLOAT, PROP_DIRECTION);
|
||||||
RNA_def_property_array(prop, 3);
|
RNA_def_property_array(prop, 3);
|
||||||
|
@ -3030,6 +3000,22 @@ static void rna_def_mesh(BlenderRNA *brna)
|
||||||
|
|
||||||
rna_def_normal_layer_value(brna);
|
rna_def_normal_layer_value(brna);
|
||||||
|
|
||||||
|
static const EnumPropertyItem normal_domain_items[] = {
|
||||||
|
{int(blender::bke::MeshNormalDomain::Point), "POINT", 0, "Point", ""},
|
||||||
|
{int(blender::bke::MeshNormalDomain::Face), "FACE", 0, "Face", ""},
|
||||||
|
{int(blender::bke::MeshNormalDomain::Corner), "CORNER", 0, "Corner", ""},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "normals_domain", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, normal_domain_items);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop,
|
||||||
|
"Normal Domain",
|
||||||
|
"The attribute domain that gives enough information to represent the mesh's normals");
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
RNA_def_property_enum_funcs(prop, "rna_Mesh_normals_domain_get", NULL, NULL);
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "vertex_normals", PROP_COLLECTION, PROP_NONE);
|
prop = RNA_def_property(srna, "vertex_normals", PROP_COLLECTION, PROP_NONE);
|
||||||
RNA_def_property_struct_type(prop, "MeshNormalValue");
|
RNA_def_property_struct_type(prop, "MeshNormalValue");
|
||||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||||
|
@ -3325,24 +3311,6 @@ static void rna_def_mesh(BlenderRNA *brna)
|
||||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
|
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
|
||||||
/* End Symmetry */
|
/* End Symmetry */
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
|
|
||||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", ME_AUTOSMOOTH);
|
|
||||||
RNA_def_property_ui_text(
|
|
||||||
prop,
|
|
||||||
"Auto Smooth",
|
|
||||||
"Auto smooth (based on smooth/sharp faces/edges and angle between faces), "
|
|
||||||
"or use custom split normals data if available");
|
|
||||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
|
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
|
|
||||||
RNA_def_property_float_sdna(prop, nullptr, "smoothresh");
|
|
||||||
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
|
|
||||||
RNA_def_property_ui_text(prop,
|
|
||||||
"Auto Smooth Angle",
|
|
||||||
"Maximum angle between face normals that will be considered as smooth "
|
|
||||||
"(unused if custom split normals data are available)");
|
|
||||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
|
|
||||||
|
|
||||||
RNA_define_verify_sdna(false);
|
RNA_define_verify_sdna(false);
|
||||||
prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE);
|
prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE);
|
||||||
RNA_def_property_boolean_sdna(prop, nullptr, "", 0);
|
RNA_def_property_boolean_sdna(prop, nullptr, "", 0);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "DNA_customdata_types.h"
|
#include "DNA_customdata_types.h"
|
||||||
|
|
||||||
|
#include "BLI_math_base.h"
|
||||||
#include "BLI_sys_types.h"
|
#include "BLI_sys_types.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
|
@ -23,6 +24,8 @@
|
||||||
# include "DNA_mesh_types.h"
|
# include "DNA_mesh_types.h"
|
||||||
|
|
||||||
# include "BKE_anim_data.h"
|
# include "BKE_anim_data.h"
|
||||||
|
# include "BKE_attribute.hh"
|
||||||
|
# include "BKE_mesh.h"
|
||||||
# include "BKE_mesh.hh"
|
# include "BKE_mesh.hh"
|
||||||
# include "BKE_mesh_mapping.hh"
|
# include "BKE_mesh_mapping.hh"
|
||||||
# include "BKE_mesh_runtime.hh"
|
# include "BKE_mesh_runtime.hh"
|
||||||
|
@ -46,17 +49,12 @@ static const char *rna_Mesh_unit_test_compare(Mesh *mesh, Mesh *mesh2, float thr
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_Mesh_create_normals_split(Mesh *mesh)
|
static void rna_Mesh_sharp_from_angle_set(Mesh *mesh, const float angle)
|
||||||
{
|
{
|
||||||
if (!CustomData_has_layer(&mesh->loop_data, CD_NORMAL)) {
|
mesh->attributes_for_write().remove("sharp_edge");
|
||||||
CustomData_add_layer(&mesh->loop_data, CD_NORMAL, CD_SET_DEFAULT, mesh->totloop);
|
mesh->attributes_for_write().remove("sharp_face");
|
||||||
CustomData_set_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
BKE_mesh_sharp_edges_set_from_angle(mesh, angle);
|
||||||
}
|
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
|
||||||
}
|
|
||||||
|
|
||||||
static void rna_Mesh_free_normals_split(Mesh *mesh)
|
|
||||||
{
|
|
||||||
CustomData_free_layers(&mesh->loop_data, CD_NORMAL, mesh->totloop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *uvmap)
|
static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *uvmap)
|
||||||
|
@ -74,11 +72,6 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
|
||||||
CustomData_set_layer_flag(&mesh->loop_data, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
|
CustomData_set_layer_flag(&mesh->loop_data, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute loop normals if needed. */
|
|
||||||
if (!CustomData_has_layer(&mesh->loop_data, CD_NORMAL)) {
|
|
||||||
BKE_mesh_calc_normals_split(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
BKE_mesh_calc_loop_tangent_single(mesh, uvmap, r_looptangents, reports);
|
BKE_mesh_calc_loop_tangent_single(mesh, uvmap, r_looptangents, reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +178,7 @@ static void rna_Mesh_update(Mesh *mesh,
|
||||||
|
|
||||||
mesh->runtime->vert_normals_cache.tag_dirty();
|
mesh->runtime->vert_normals_cache.tag_dirty();
|
||||||
mesh->runtime->face_normals_cache.tag_dirty();
|
mesh->runtime->face_normals_cache.tag_dirty();
|
||||||
|
mesh->runtime->corner_normals_cache.tag_dirty();
|
||||||
|
|
||||||
DEG_id_tag_update(&mesh->id, 0);
|
DEG_id_tag_update(&mesh->id, 0);
|
||||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh);
|
WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh);
|
||||||
|
@ -230,15 +224,19 @@ void RNA_api_mesh(StructRNA *srna)
|
||||||
"Invert winding of all polygons "
|
"Invert winding of all polygons "
|
||||||
"(clears tessellation, does not handle custom normals)");
|
"(clears tessellation, does not handle custom normals)");
|
||||||
|
|
||||||
func = RNA_def_function(srna, "create_normals_split", "rna_Mesh_create_normals_split");
|
func = RNA_def_function(srna, "set_sharp_from_angle", "rna_Mesh_sharp_from_angle_set");
|
||||||
RNA_def_function_ui_description(func, "Empty split vertex normals");
|
|
||||||
|
|
||||||
func = RNA_def_function(srna, "calc_normals_split", "BKE_mesh_calc_normals_split");
|
|
||||||
RNA_def_function_ui_description(func,
|
RNA_def_function_ui_description(func,
|
||||||
"Calculate split vertex normals, which preserve sharp edges");
|
"Reset and fill the \"sharp_edge\" attribute based on the angle "
|
||||||
|
"of faces neighboring manifold edges");
|
||||||
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
|
RNA_def_float(func,
|
||||||
RNA_def_function_ui_description(func, "Free split vertex normals");
|
"angle",
|
||||||
|
M_PI,
|
||||||
|
0.0f,
|
||||||
|
M_PI,
|
||||||
|
"Angle",
|
||||||
|
"Angle between faces beyond which edges are marked sharp",
|
||||||
|
0.0f,
|
||||||
|
M_PI);
|
||||||
|
|
||||||
func = RNA_def_function(srna, "split_faces", "ED_mesh_split_faces");
|
func = RNA_def_function(srna, "split_faces", "ED_mesh_split_faces");
|
||||||
RNA_def_function_ui_description(func, "Split faces based on the edge angle");
|
RNA_def_function_ui_description(func, "Split faces based on the edge angle");
|
||||||
|
|
|
@ -193,13 +193,6 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *ob = ctx->object;
|
|
||||||
|
|
||||||
if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
|
|
||||||
BKE_modifier_set_error(ob, md, "Enable 'Auto Smooth' in Object Data Properties");
|
|
||||||
harden_normals = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BM_mesh_bevel(bm,
|
BM_mesh_bevel(bm,
|
||||||
value,
|
value,
|
||||||
offset_type,
|
offset_type,
|
||||||
|
@ -220,7 +213,6 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
miter_outer,
|
miter_outer,
|
||||||
miter_inner,
|
miter_inner,
|
||||||
spread,
|
spread,
|
||||||
mesh->smoothresh,
|
|
||||||
bmd->custom_profile,
|
bmd->custom_profile,
|
||||||
bmd->vmesh_method);
|
bmd->vmesh_method);
|
||||||
|
|
||||||
|
|
|
@ -117,8 +117,6 @@ static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphCont
|
||||||
if (dtmd->ob_source != nullptr) {
|
if (dtmd->ob_source != nullptr) {
|
||||||
CustomData_MeshMasks cddata_masks = {0};
|
CustomData_MeshMasks cddata_masks = {0};
|
||||||
BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks);
|
BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks);
|
||||||
BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
|
|
||||||
dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, &cddata_masks);
|
|
||||||
|
|
||||||
DEG_add_object_relation(
|
DEG_add_object_relation(
|
||||||
ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
|
ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
|
||||||
|
@ -222,10 +220,6 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
BKE_modifier_set_error(ctx->object, md, "%s", report_str);
|
BKE_modifier_set_error(ctx->object, md, "%s", report_str);
|
||||||
MEM_freeN((void *)report_str);
|
MEM_freeN((void *)report_str);
|
||||||
}
|
}
|
||||||
else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
|
|
||||||
BKE_modifier_set_error(
|
|
||||||
ctx->object, (ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties");
|
|
||||||
}
|
|
||||||
|
|
||||||
BKE_reports_free(&reports);
|
BKE_reports_free(&reports);
|
||||||
|
|
||||||
|
|
|
@ -302,22 +302,15 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction == MOD_DISP_DIR_CLNOR) {
|
if (direction == MOD_DISP_DIR_CLNOR) {
|
||||||
CustomData *ldata = &mesh->loop_data;
|
if (CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
|
||||||
if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) {
|
|
||||||
if (!CustomData_has_layer(ldata, CD_NORMAL)) {
|
|
||||||
BKE_mesh_calc_normals_split(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
float(*clnors)[3] = static_cast<float(*)[3]>(
|
|
||||||
CustomData_get_layer_for_write(ldata, CD_NORMAL, mesh->totloop));
|
|
||||||
vert_clnors = static_cast<float(*)[3]>(
|
vert_clnors = static_cast<float(*)[3]>(
|
||||||
MEM_malloc_arrayN(verts_num, sizeof(*vert_clnors), __func__));
|
MEM_malloc_arrayN(verts_num, sizeof(*vert_clnors), __func__));
|
||||||
BKE_mesh_normals_loop_to_vertex(verts_num,
|
BKE_mesh_normals_loop_to_vertex(
|
||||||
mesh->corner_verts().data(),
|
verts_num,
|
||||||
mesh->totloop,
|
mesh->corner_verts().data(),
|
||||||
(const float(*)[3])clnors,
|
mesh->totloop,
|
||||||
vert_clnors);
|
reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data()),
|
||||||
|
vert_clnors);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
direction = MOD_DISP_DIR_NOR;
|
direction = MOD_DISP_DIR_NOR;
|
||||||
|
|
|
@ -67,7 +67,6 @@ static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_
|
||||||
{
|
{
|
||||||
MultiresModifierData *mmd = (MultiresModifierData *)md;
|
MultiresModifierData *mmd = (MultiresModifierData *)md;
|
||||||
if (mmd->flags & eMultiresModifierFlag_UseCustomNormals) {
|
if (mmd->flags & eMultiresModifierFlag_UseCustomNormals) {
|
||||||
r_cddata_masks->lmask |= CD_MASK_NORMAL;
|
|
||||||
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,8 +216,7 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const bool use_clnors = mmd->flags & eMultiresModifierFlag_UseCustomNormals &&
|
const bool use_clnors = mmd->flags & eMultiresModifierFlag_UseCustomNormals &&
|
||||||
mesh->flag & ME_AUTOSMOOTH &&
|
mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner;
|
||||||
CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL);
|
|
||||||
/* NOTE: Orco needs final coordinates on CPU side, which are expected to be
|
/* NOTE: Orco needs final coordinates on CPU side, which are expected to be
|
||||||
* accessible via mesh vertices. For this reason we do not evaluate multires to
|
* accessible via mesh vertices. For this reason we do not evaluate multires to
|
||||||
* grids when orco is requested. */
|
* grids when orco is requested. */
|
||||||
|
@ -253,10 +251,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (use_clnors) {
|
if (use_clnors) {
|
||||||
/* If custom normals are present and the option is turned on calculate the split
|
void *data = CustomData_add_layer(&mesh->loop_data, CD_NORMAL, CD_CONSTRUCT, mesh->totloop);
|
||||||
* normals and clear flag so the normals get interpolated to the result mesh. */
|
memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
|
||||||
BKE_mesh_calc_normals_split(mesh);
|
|
||||||
CustomData_clear_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = multires_as_mesh(mmd, ctx, mesh, subdiv);
|
result = multires_as_mesh(mmd, ctx, mesh, subdiv);
|
||||||
|
@ -264,10 +260,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
if (use_clnors) {
|
if (use_clnors) {
|
||||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
float(*lnors)[3] = static_cast<float(*)[3]>(
|
||||||
CustomData_get_layer_for_write(&result->loop_data, CD_NORMAL, result->totloop));
|
CustomData_get_layer_for_write(&result->loop_data, CD_NORMAL, result->totloop));
|
||||||
BLI_assert(lnors != nullptr);
|
|
||||||
BKE_mesh_set_custom_normals(result, lnors);
|
BKE_mesh_set_custom_normals(result, lnors);
|
||||||
CustomData_set_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
CustomData_free_layers(&result->loop_data, CD_NORMAL, result->totloop);
|
||||||
CustomData_set_layer_flag(&result->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
}
|
||||||
// BKE_subdiv_stats_print(&subdiv->stats);
|
// BKE_subdiv_stats_print(&subdiv->stats);
|
||||||
if (subdiv != runtime_data->subdiv) {
|
if (subdiv != runtime_data->subdiv) {
|
||||||
|
|
|
@ -477,22 +477,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
#if 0
|
|
||||||
if (!(mesh->flag & ME_AUTOSMOOTH))
|
|
||||||
#else
|
|
||||||
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
BKE_modifier_set_error(
|
|
||||||
ob, (ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties");
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh *result;
|
Mesh *result;
|
||||||
if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) {
|
if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) {
|
||||||
/* We need to duplicate data here, otherwise setting custom normals
|
/* We need to duplicate data here, otherwise setting custom normals
|
||||||
|
@ -540,8 +524,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
|
||||||
sharp_edges.span.data(),
|
sharp_edges.span.data(),
|
||||||
sharp_faces,
|
sharp_faces,
|
||||||
clnors,
|
clnors,
|
||||||
true,
|
|
||||||
result->smoothresh,
|
|
||||||
nullptr,
|
nullptr,
|
||||||
loop_normals);
|
loop_normals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphCont
|
||||||
CustomData_MeshMasks mask = {0};
|
CustomData_MeshMasks mask = {0};
|
||||||
|
|
||||||
if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) {
|
if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) {
|
||||||
mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
|
mask.lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smd->target != nullptr) {
|
if (smd->target != nullptr) {
|
||||||
|
|
|
@ -66,7 +66,6 @@ static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_
|
||||||
{
|
{
|
||||||
SubsurfModifierData *smd = (SubsurfModifierData *)md;
|
SubsurfModifierData *smd = (SubsurfModifierData *)md;
|
||||||
if (smd->flags & eSubsurfModifierFlag_UseCustomNormals) {
|
if (smd->flags & eSubsurfModifierFlag_UseCustomNormals) {
|
||||||
r_cddata_masks->lmask |= CD_MASK_NORMAL;
|
|
||||||
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +205,6 @@ static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
|
||||||
runtime_data->has_gpu_subdiv = true;
|
runtime_data->has_gpu_subdiv = true;
|
||||||
runtime_data->resolution = mesh_settings.resolution;
|
runtime_data->resolution = mesh_settings.resolution;
|
||||||
runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
|
runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
|
||||||
runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
|
|
||||||
runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
|
runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
|
||||||
|
|
||||||
mesh->runtime->subsurf_runtime_data = runtime_data;
|
mesh->runtime->subsurf_runtime_data = runtime_data;
|
||||||
|
@ -260,10 +258,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
}
|
}
|
||||||
const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
|
const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
|
||||||
if (use_clnors) {
|
if (use_clnors) {
|
||||||
/* If custom normals are present and the option is turned on calculate the split
|
void *data = CustomData_add_layer(&mesh->loop_data, CD_NORMAL, CD_CONSTRUCT, mesh->totloop);
|
||||||
* normals and clear flag so the normals get interpolated to the result mesh. */
|
memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
|
||||||
BKE_mesh_calc_normals_split(mesh);
|
|
||||||
CustomData_clear_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
}
|
||||||
/* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
|
/* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
|
||||||
* maybe when it is a last modifier in the stack? */
|
* maybe when it is a last modifier in the stack? */
|
||||||
|
@ -275,12 +271,10 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_clnors) {
|
if (use_clnors) {
|
||||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
BKE_mesh_set_custom_normals(result,
|
||||||
CustomData_get_layer_for_write(&result->loop_data, CD_NORMAL, result->totloop));
|
static_cast<float(*)[3]>(CustomData_get_layer_for_write(
|
||||||
BLI_assert(lnors != nullptr);
|
&result->loop_data, CD_NORMAL, result->totloop)));
|
||||||
BKE_mesh_set_custom_normals(result, lnors);
|
CustomData_free_layers(&result->loop_data, CD_NORMAL, result->totloop);
|
||||||
CustomData_set_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
CustomData_set_layer_flag(&result->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
}
|
||||||
// BKE_subdiv_stats_print(&subdiv->stats);
|
// BKE_subdiv_stats_print(&subdiv->stats);
|
||||||
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
||||||
|
|
|
@ -53,9 +53,8 @@ static Mesh *triangulate_mesh(Mesh *mesh,
|
||||||
bool keep_clnors = (flag & MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS) != 0;
|
bool keep_clnors = (flag & MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS) != 0;
|
||||||
|
|
||||||
if (keep_clnors) {
|
if (keep_clnors) {
|
||||||
BKE_mesh_calc_normals_split(mesh);
|
void *data = CustomData_add_layer(&mesh->loop_data, CD_NORMAL, CD_CONSTRUCT, mesh->totloop);
|
||||||
/* We need that one to 'survive' to/from BMesh conversions. */
|
memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
|
||||||
CustomData_clear_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
cd_mask_extra.lmask |= CD_MASK_NORMAL;
|
cd_mask_extra.lmask |= CD_MASK_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,13 +75,8 @@ static Mesh *triangulate_mesh(Mesh *mesh,
|
||||||
if (keep_clnors) {
|
if (keep_clnors) {
|
||||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
float(*lnors)[3] = static_cast<float(*)[3]>(
|
||||||
CustomData_get_layer_for_write(&result->loop_data, CD_NORMAL, result->totloop));
|
CustomData_get_layer_for_write(&result->loop_data, CD_NORMAL, result->totloop));
|
||||||
BLI_assert(lnors != nullptr);
|
|
||||||
|
|
||||||
BKE_mesh_set_custom_normals(result, lnors);
|
BKE_mesh_set_custom_normals(result, lnors);
|
||||||
|
CustomData_free_layers(&result->loop_data, CD_NORMAL, result->totloop);
|
||||||
/* Do some cleanup, we do not want those temp data to stay around. */
|
|
||||||
CustomData_set_layer_flag(&mesh->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
CustomData_set_layer_flag(&result->loop_data, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -83,7 +83,6 @@ struct WeightedNormalData {
|
||||||
blender::Span<int> loop_to_face;
|
blender::Span<int> loop_to_face;
|
||||||
blender::MutableSpan<blender::short2> clnors;
|
blender::MutableSpan<blender::short2> clnors;
|
||||||
bool has_clnors; /* True if clnors already existed, false if we had to create them. */
|
bool has_clnors; /* True if clnors already existed, false if we had to create them. */
|
||||||
float split_angle;
|
|
||||||
|
|
||||||
blender::OffsetIndices<int> faces;
|
blender::OffsetIndices<int> faces;
|
||||||
blender::Span<blender::float3> face_normals;
|
blender::Span<blender::float3> face_normals;
|
||||||
|
@ -207,7 +206,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||||
ModePair *mode_pair = wn_data->mode_pair;
|
ModePair *mode_pair = wn_data->mode_pair;
|
||||||
|
|
||||||
const bool has_clnors = wn_data->has_clnors;
|
const bool has_clnors = wn_data->has_clnors;
|
||||||
const float split_angle = wn_data->split_angle;
|
|
||||||
bke::mesh::CornerNormalSpaceArray lnors_spacearr;
|
bke::mesh::CornerNormalSpaceArray lnors_spacearr;
|
||||||
|
|
||||||
const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
|
const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
|
||||||
|
@ -233,8 +231,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||||
wn_data->sharp_edges.data(),
|
wn_data->sharp_edges.data(),
|
||||||
wn_data->sharp_faces,
|
wn_data->sharp_faces,
|
||||||
has_clnors ? clnors.data() : nullptr,
|
has_clnors ? clnors.data() : nullptr,
|
||||||
true,
|
|
||||||
split_angle,
|
|
||||||
&lnors_spacearr,
|
&lnors_spacearr,
|
||||||
loop_normals);
|
loop_normals);
|
||||||
|
|
||||||
|
@ -363,8 +359,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||||
wn_data->sharp_edges.data(),
|
wn_data->sharp_edges.data(),
|
||||||
wn_data->sharp_faces,
|
wn_data->sharp_faces,
|
||||||
has_clnors ? clnors.data() : nullptr,
|
has_clnors ? clnors.data() : nullptr,
|
||||||
true,
|
|
||||||
split_angle,
|
|
||||||
nullptr,
|
nullptr,
|
||||||
loop_normals);
|
loop_normals);
|
||||||
|
|
||||||
|
@ -482,23 +476,6 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
{
|
{
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
||||||
Object *ob = ctx->object;
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
#if 0
|
|
||||||
if (!(mesh->flag & ME_AUTOSMOOTH))
|
|
||||||
#else
|
|
||||||
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
BKE_modifier_set_error(
|
|
||||||
ctx->object, (ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh *result;
|
Mesh *result;
|
||||||
result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
|
result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
|
||||||
|
@ -527,7 +504,6 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
weight = (weight - 1) * 25;
|
weight = (weight - 1) * 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float split_angle = mesh->smoothresh;
|
|
||||||
blender::short2 *clnors = static_cast<blender::short2 *>(
|
blender::short2 *clnors = static_cast<blender::short2 *>(
|
||||||
CustomData_get_layer_for_write(&result->loop_data, CD_CUSTOMLOOPNORMAL, mesh->totloop));
|
CustomData_get_layer_for_write(&result->loop_data, CD_CUSTOMLOOPNORMAL, mesh->totloop));
|
||||||
|
|
||||||
|
@ -562,7 +538,6 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||||
wn_data.loop_to_face = loop_to_face_map;
|
wn_data.loop_to_face = loop_to_face_map;
|
||||||
wn_data.clnors = {clnors, mesh->totloop};
|
wn_data.clnors = {clnors, mesh->totloop};
|
||||||
wn_data.has_clnors = has_clnors;
|
wn_data.has_clnors = has_clnors;
|
||||||
wn_data.split_angle = split_angle;
|
|
||||||
|
|
||||||
wn_data.faces = faces;
|
wn_data.faces = faces;
|
||||||
wn_data.face_normals = mesh->face_normals();
|
wn_data.face_normals = mesh->face_normals();
|
||||||
|
|
|
@ -316,14 +316,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||||
|
|
||||||
/* Retrieve face corner normals from each mesh. It's necessary to use face corner normals
|
/* Retrieve face corner normals from each mesh. It's necessary to use face corner normals
|
||||||
* because face normals or vertex normals may lose information (custom normals, auto smooth) in
|
* because face normals or vertex normals may lose information (custom normals, auto smooth) in
|
||||||
* some cases. It isn't yet possible to retrieve lazily calculated face corner normals from a
|
* some cases. */
|
||||||
* const mesh, so they are calculated here every time. */
|
const Span<float3> corner_normals_orig = surface_mesh_orig->corner_normals();
|
||||||
Array<float3> corner_normals_orig(surface_mesh_orig->totloop);
|
const Span<float3> corner_normals_eval = surface_mesh_eval->corner_normals();
|
||||||
Array<float3> corner_normals_eval(surface_mesh_eval->totloop);
|
|
||||||
BKE_mesh_calc_normals_split_ex(
|
|
||||||
surface_mesh_orig, nullptr, reinterpret_cast<float(*)[3]>(corner_normals_orig.data()));
|
|
||||||
BKE_mesh_calc_normals_split_ex(
|
|
||||||
surface_mesh_eval, nullptr, reinterpret_cast<float(*)[3]>(corner_normals_eval.data()));
|
|
||||||
|
|
||||||
std::atomic<int> invalid_uv_count = 0;
|
std::atomic<int> invalid_uv_count = 0;
|
||||||
|
|
||||||
|
|
|
@ -338,15 +338,36 @@ static void compute_normal_outputs(const Mesh &mesh,
|
||||||
const Span<int> looptri_indices,
|
const Span<int> looptri_indices,
|
||||||
MutableSpan<float3> r_normals)
|
MutableSpan<float3> r_normals)
|
||||||
{
|
{
|
||||||
Array<float3> corner_normals(mesh.totloop);
|
switch (mesh.normals_domain()) {
|
||||||
BKE_mesh_calc_normals_split_ex(
|
case bke::MeshNormalDomain::Point: {
|
||||||
&mesh, nullptr, reinterpret_cast<float(*)[3]>(corner_normals.data()));
|
const Span<int> corner_verts = mesh.corner_verts();
|
||||||
|
const Span<MLoopTri> looptris = mesh.looptris();
|
||||||
const Span<MLoopTri> looptris = mesh.looptris();
|
const Span<float3> vert_normals = mesh.vert_normals();
|
||||||
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
||||||
bke::mesh_surface_sample::sample_corner_normals(
|
bke::mesh_surface_sample::sample_point_normals(
|
||||||
looptris, looptri_indices, bary_coords, corner_normals, range, r_normals);
|
corner_verts, looptris, looptri_indices, bary_coords, vert_normals, range, r_normals);
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bke::MeshNormalDomain::Face: {
|
||||||
|
const Span<int> looptri_faces = mesh.looptri_faces();
|
||||||
|
VArray<float3> face_normals = VArray<float3>::ForSpan(mesh.face_normals());
|
||||||
|
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
||||||
|
bke::mesh_surface_sample::sample_face_attribute(
|
||||||
|
looptri_faces, looptri_indices, face_normals, range, r_normals);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bke::MeshNormalDomain::Corner: {
|
||||||
|
const Span<MLoopTri> looptris = mesh.looptris();
|
||||||
|
const Span<float3> corner_normals = mesh.corner_normals();
|
||||||
|
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
||||||
|
bke::mesh_surface_sample::sample_corner_normals(
|
||||||
|
looptris, looptri_indices, bary_coords, corner_normals, range, r_normals);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compute_legacy_normal_outputs(const Mesh &mesh,
|
static void compute_legacy_normal_outputs(const Mesh &mesh,
|
||||||
|
|
|
@ -148,7 +148,6 @@ static void expand_mesh(Mesh &mesh,
|
||||||
mesh.face_offset_indices[mesh.faces_num] = mesh.totloop + loop_expand;
|
mesh.face_offset_indices[mesh.faces_num] = mesh.totloop + loop_expand;
|
||||||
}
|
}
|
||||||
if (loop_expand != 0) {
|
if (loop_expand != 0) {
|
||||||
CustomData_free_layers(&mesh.loop_data, CD_NORMAL, mesh.totloop);
|
|
||||||
CustomData_free_layers(&mesh.loop_data, CD_MDISPS, mesh.totloop);
|
CustomData_free_layers(&mesh.loop_data, CD_MDISPS, mesh.totloop);
|
||||||
CustomData_free_layers(&mesh.loop_data, CD_TANGENT, mesh.totloop);
|
CustomData_free_layers(&mesh.loop_data, CD_TANGENT, mesh.totloop);
|
||||||
CustomData_free_layers(&mesh.loop_data, CD_PAINT_MASK, mesh.totloop);
|
CustomData_free_layers(&mesh.loop_data, CD_PAINT_MASK, mesh.totloop);
|
||||||
|
|
|
@ -491,17 +491,14 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
|
||||||
}
|
}
|
||||||
|
|
||||||
const TSpace *tspace = nullptr;
|
const TSpace *tspace = nullptr;
|
||||||
const float(*loop_normals)[3] = nullptr;
|
blender::Span<blender::float3> corner_normals;
|
||||||
if (tangent) {
|
if (tangent) {
|
||||||
BKE_mesh_ensure_normals_for_display(me_eval);
|
|
||||||
BKE_mesh_calc_normals_split(me_eval);
|
|
||||||
BKE_mesh_calc_loop_tangents(me_eval, true, nullptr, 0);
|
BKE_mesh_calc_loop_tangents(me_eval, true, nullptr, 0);
|
||||||
|
|
||||||
tspace = static_cast<const TSpace *>(CustomData_get_layer(&me_eval->loop_data, CD_TANGENT));
|
tspace = static_cast<const TSpace *>(CustomData_get_layer(&me_eval->loop_data, CD_TANGENT));
|
||||||
BLI_assert(tspace);
|
BLI_assert(tspace);
|
||||||
|
|
||||||
loop_normals = static_cast<const float(*)[3]>(
|
corner_normals = me_eval->corner_normals();
|
||||||
CustomData_get_layer(&me_eval->loop_data, CD_NORMAL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const blender::Span<blender::float3> vert_normals = me->vert_normals();
|
const blender::Span<blender::float3> vert_normals = me->vert_normals();
|
||||||
|
@ -524,10 +521,10 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
|
||||||
triangles[i].tspace[2] = &tspace[lt->tri[2]];
|
triangles[i].tspace[2] = &tspace[lt->tri[2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loop_normals) {
|
if (!corner_normals.is_empty()) {
|
||||||
triangles[i].loop_normal[0] = loop_normals[lt->tri[0]];
|
triangles[i].loop_normal[0] = corner_normals[lt->tri[0]];
|
||||||
triangles[i].loop_normal[1] = loop_normals[lt->tri[1]];
|
triangles[i].loop_normal[1] = corner_normals[lt->tri[1]];
|
||||||
triangles[i].loop_normal[2] = loop_normals[lt->tri[2]];
|
triangles[i].loop_normal[2] = corner_normals[lt->tri[2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calculate_normal) {
|
if (calculate_normal) {
|
||||||
|
|
|
@ -519,6 +519,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
||||||
|
|
||||||
if (require_tangent) {
|
if (require_tangent) {
|
||||||
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
|
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
|
||||||
|
const blender::Span<blender::float3> corner_normals = temp_mesh->corner_normals();
|
||||||
BKE_mesh_calc_loop_tangent_ex(
|
BKE_mesh_calc_loop_tangent_ex(
|
||||||
reinterpret_cast<const float(*)[3]>(positions.data()),
|
reinterpret_cast<const float(*)[3]>(positions.data()),
|
||||||
faces,
|
faces,
|
||||||
|
@ -534,7 +535,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
||||||
0,
|
0,
|
||||||
reinterpret_cast<const float(*)[3]>(vert_normals.data()),
|
reinterpret_cast<const float(*)[3]>(vert_normals.data()),
|
||||||
reinterpret_cast<const float(*)[3]>(face_normals.data()),
|
reinterpret_cast<const float(*)[3]>(face_normals.data()),
|
||||||
(const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
|
reinterpret_cast<const float(*)[3]>(corner_normals.data()),
|
||||||
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* May be nullptr. */
|
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* May be nullptr. */
|
||||||
/* result */
|
/* result */
|
||||||
&dm->loopData,
|
&dm->loopData,
|
||||||
|
|
Loading…
Reference in New Issue