Mesh: Replace auto smooth with node group #108014
|
@ -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(). *
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -449,15 +449,16 @@ static void add_orco_mesh(
|
||||||
|
|
||||||
static void mesh_calc_modifier_final_normals(const bool sculpt_dyntopo, Mesh *mesh_final)
|
static void mesh_calc_modifier_final_normals(const bool sculpt_dyntopo, Mesh *mesh_final)
|
||||||
{
|
{
|
||||||
const eAttrDomain domain = eAttrDomain(mesh_final->normals_domain());
|
using namespace blender::bke;
|
||||||
|
const MeshNormalDomain domain = mesh_final->normals_domain();
|
||||||
|
|
||||||
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
|
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
|
||||||
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
|
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
|
||||||
if (subsurf_runtime_data) {
|
if (subsurf_runtime_data) {
|
||||||
subsurf_runtime_data->calc_loop_normals = domain == ATTR_DOMAIN_CORNER;
|
subsurf_runtime_data->calc_loop_normals = domain == MeshNormalDomain::Corner;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain == ATTR_DOMAIN_CORNER) {
|
if (domain == MeshNormalDomain::Corner) {
|
||||||
/* Compute loop normals (NOTE: will compute face and vert normals as well, if needed!). In case
|
/* 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. */
|
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
|
||||||
if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
|
if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
|
||||||
|
@ -467,10 +468,10 @@ static void mesh_calc_modifier_final_normals(const bool sculpt_dyntopo, Mesh *me
|
||||||
else {
|
else {
|
||||||
if (sculpt_dyntopo == false) {
|
if (sculpt_dyntopo == false) {
|
||||||
HooglyBoogly marked this conversation as resolved
Outdated
|
|||||||
/* Eager normal calculation can potentially be faster than deferring to drawing code. */
|
/* Eager normal calculation can potentially be faster than deferring to drawing code. */
|
||||||
if (domain == ATTR_DOMAIN_FACE) {
|
if (domain == MeshNormalDomain::Face) {
|
||||||
mesh_final->face_normals();
|
mesh_final->face_normals();
|
||||||
}
|
}
|
||||||
HooglyBoogly marked this conversation as resolved
Outdated
Campbell Barton
commented
Shouldn't this be Shouldn't this be `ATTR_DOMAIN_VERT` ?
|
|||||||
else if (domain == ATTR_DOMAIN_POINT) {
|
else if (domain == MeshNormalDomain::Point) {
|
||||||
mesh_final->vert_normals();
|
mesh_final->vert_normals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,16 +299,16 @@ static void normals_calc_faces_and_verts(const Span<float3> positions,
|
||||||
/** \name Mesh Normal Calculation
|
/** \name Mesh Normal Calculation
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
int Mesh::normals_domain() const
|
blender::bke::MeshNormalDomain Mesh::normals_domain() const
|
||||||
{
|
{
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
using namespace blender::bke;
|
using namespace blender::bke;
|
||||||
if (this->faces_num == 0) {
|
if (this->faces_num == 0) {
|
||||||
return ATTR_DOMAIN_POINT;
|
return MeshNormalDomain::Point;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CustomData_has_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL)) {
|
if (CustomData_has_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL)) {
|
||||||
return ATTR_DOMAIN_CORNER;
|
return MeshNormalDomain::Corner;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AttributeAccessor attributes = this->attributes();
|
const AttributeAccessor attributes = this->attributes();
|
||||||
|
@ -317,22 +317,22 @@ int Mesh::normals_domain() const
|
||||||
|
|
||||||
const array_utils::BooleanMix face_mix = array_utils::booleans_mix_calc(sharp_faces);
|
const array_utils::BooleanMix face_mix = array_utils::booleans_mix_calc(sharp_faces);
|
||||||
if (face_mix == array_utils::BooleanMix::AllTrue) {
|
if (face_mix == array_utils::BooleanMix::AllTrue) {
|
||||||
return ATTR_DOMAIN_FACE;
|
return MeshNormalDomain::Face;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VArray<bool> sharp_edges = *attributes.lookup_or_default<bool>(
|
const VArray<bool> sharp_edges = *attributes.lookup_or_default<bool>(
|
||||||
"sharp_edge", ATTR_DOMAIN_EDGE, false);
|
"sharp_edge", ATTR_DOMAIN_EDGE, false);
|
||||||
const array_utils::BooleanMix edge_mix = array_utils::booleans_mix_calc(sharp_edges);
|
const array_utils::BooleanMix edge_mix = array_utils::booleans_mix_calc(sharp_edges);
|
||||||
if (edge_mix == array_utils::BooleanMix::AllTrue) {
|
if (edge_mix == array_utils::BooleanMix::AllTrue) {
|
||||||
return ATTR_DOMAIN_FACE;
|
return MeshNormalDomain::Face;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edge_mix == array_utils::BooleanMix::AllFalse &&
|
if (edge_mix == array_utils::BooleanMix::AllFalse &&
|
||||||
face_mix == array_utils::BooleanMix::AllFalse) {
|
face_mix == array_utils::BooleanMix::AllFalse) {
|
||||||
return ATTR_DOMAIN_POINT;
|
return MeshNormalDomain::Point;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ATTR_DOMAIN_CORNER;
|
return MeshNormalDomain::Corner;
|
||||||
}
|
}
|
||||||
|
|
||||||
blender::Span<blender::float3> Mesh::vert_normals() const
|
blender::Span<blender::float3> Mesh::vert_normals() const
|
||||||
|
@ -387,15 +387,16 @@ blender::Span<blender::float3> Mesh::face_normals() const
|
||||||
blender::Span<blender::float3> Mesh::corner_normals() const
|
blender::Span<blender::float3> Mesh::corner_normals() const
|
||||||
{
|
{
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
|
using namespace blender::bke;
|
||||||
this->runtime->corner_normals_cache.ensure([&](Vector<float3> &r_data) {
|
this->runtime->corner_normals_cache.ensure([&](Vector<float3> &r_data) {
|
||||||
|
r_data.reinitialize(this->totloop);
|
||||||
const OffsetIndices faces = this->faces();
|
const OffsetIndices faces = this->faces();
|
||||||
r_data.reinitialize(faces.total_size());
|
|
||||||
switch (this->normals_domain()) {
|
switch (this->normals_domain()) {
|
||||||
case ATTR_DOMAIN_POINT: {
|
case MeshNormalDomain::Point: {
|
||||||
array_utils::gather(this->vert_normals(), this->corner_verts(), r_data.as_mutable_span());
|
array_utils::gather(this->vert_normals(), this->corner_verts(), r_data.as_mutable_span());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_FACE: {
|
case MeshNormalDomain::Face: {
|
||||||
const Span<float3> face_normals = this->face_normals();
|
const Span<float3> face_normals = this->face_normals();
|
||||||
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
||||||
for (const int i : range) {
|
for (const int i : range) {
|
||||||
|
@ -404,14 +405,14 @@ blender::Span<blender::float3> Mesh::corner_normals() const
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_CORNER: {
|
case MeshNormalDomain::Corner: {
|
||||||
const bool *sharp_edges = static_cast<const bool *>(
|
const bool *sharp_edges = static_cast<const bool *>(
|
||||||
CustomData_get_layer_named(&this->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
CustomData_get_layer_named(&this->edge_data, CD_PROP_BOOL, "sharp_edge"));
|
||||||
const bool *sharp_faces = static_cast<const bool *>(
|
const bool *sharp_faces = static_cast<const bool *>(
|
||||||
CustomData_get_layer_named(&this->face_data, CD_PROP_BOOL, "sharp_face"));
|
CustomData_get_layer_named(&this->face_data, CD_PROP_BOOL, "sharp_face"));
|
||||||
const short2 *custom_normals = static_cast<const short2 *>(
|
const short2 *custom_normals = static_cast<const short2 *>(
|
||||||
CustomData_get_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL));
|
CustomData_get_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL));
|
||||||
bke::mesh::normals_calc_loop(this->vert_positions(),
|
mesh::normals_calc_loop(this->vert_positions(),
|
||||||
this->edges(),
|
this->edges(),
|
||||||
this->faces(),
|
this->faces(),
|
||||||
this->corner_verts(),
|
this->corner_verts(),
|
||||||
|
@ -426,8 +427,6 @@ blender::Span<blender::float3> Mesh::corner_normals() const
|
||||||
r_data);
|
r_data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this->runtime->corner_normals_cache.data();
|
return this->runtime->corner_normals_cache.data();
|
||||||
|
|
|
@ -142,7 +142,7 @@ 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->normals_domain() == ATTR_DOMAIN_CORNER) {
|
if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
data->clnors = reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data());
|
data->clnors = reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ 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 &&
|
return smd->flags & eSubsurfModifierFlag_UseCustomNormals &&
|
||||||
mesh->normals_domain() == ATTR_DOMAIN_CORNER;
|
mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_subdivision_evaluation_possible_on_gpu()
|
static bool is_subdivision_evaluation_possible_on_gpu()
|
||||||
|
|
|
@ -413,8 +413,9 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_
|
||||||
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) &&
|
if (((data_flag & MR_DATA_LOOP_NOR) && ELEM(mr.me->normals_domain(),
|
||||||
ELEM(mr.me->normals_domain(), ATTR_DOMAIN_CORNER, ATTR_DOMAIN_FACE)) ||
|
blender::bke::MeshNormalDomain::Corner,
|
||||||
|
blender::bke::MeshNormalDomain::Face)) ||
|
||||||
(data_flag & MR_DATA_TAN_LOOP_NOR))
|
(data_flag & MR_DATA_TAN_LOOP_NOR))
|
||||||
{
|
{
|
||||||
HooglyBoogly marked this conversation as resolved
Outdated
Jacques Lucke
commented
It seems like you could potentially use It seems like you could potentially use `VArray::ForDerivedSpan` here.
|
|||||||
mr.loop_normals = mr.me->corner_normals();
|
mr.loop_normals = mr.me->corner_normals();
|
||||||
|
|
|
@ -2152,7 +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->normals_domain() == ATTR_DOMAIN_CORNER;
|
mesh_eval->normals_domain() ==
|
||||||
|
blender::bke::MeshNormalDomain::Corner;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -712,7 +712,7 @@ 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->normals_domain() == ATTR_DOMAIN_CORNER) {
|
if (me->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
ED_mesh_split_faces(me);
|
ED_mesh_split_faces(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -526,12 +526,12 @@ static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals)
|
||||||
normals.clear();
|
normals.clear();
|
||||||
|
|
||||||
switch (mesh->normals_domain()) {
|
switch (mesh->normals_domain()) {
|
||||||
case ATTR_DOMAIN_POINT: {
|
case blender::bke::MeshNormalDomain::Point: {
|
||||||
/* If all faces are smooth shaded, and there are no custom normals, we don't need to
|
/* If all faces are smooth shaded, and there are no custom normals, we don't need to
|
||||||
* export normals at all. This is also done by other software, see #71246. */
|
* export normals at all. This is also done by other software, see #71246. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_FACE: {
|
case blender::bke::MeshNormalDomain::Face: {
|
||||||
normals.resize(mesh->totloop);
|
normals.resize(mesh->totloop);
|
||||||
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
|
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
|
||||||
|
|
||||||
|
@ -546,7 +546,7 @@ static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals)
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_CORNER: {
|
case blender::bke::MeshNormalDomain::Corner: {
|
||||||
normals.resize(mesh->totloop);
|
normals.resize(mesh->totloop);
|
||||||
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
|
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
|
||||||
|
|
||||||
|
@ -563,8 +563,6 @@ static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals)
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -626,7 +626,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
|
||||||
"sharp_face", ATTR_DOMAIN_FACE, false);
|
"sharp_face", ATTR_DOMAIN_FACE, false);
|
||||||
|
|
||||||
blender::Span<blender::float3> corner_normals;
|
blender::Span<blender::float3> corner_normals;
|
||||||
if (me->normals_domain() == ATTR_DOMAIN_CORNER) {
|
if (me->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
corner_normals = me->corner_normals();
|
corner_normals = me->corner_normals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ void MeshData::write_submeshes(const Mesh *mesh)
|
||||||
const Span<MLoopTri> looptris = mesh->looptris();
|
const Span<MLoopTri> looptris = mesh->looptris();
|
||||||
|
|
||||||
Span<float3> corner_normals;
|
Span<float3> corner_normals;
|
||||||
if (mesh->normals_domain() == ATTR_DOMAIN_CORNER) {
|
if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
corner_normals = mesh->corner_normals();
|
corner_normals = mesh->corner_normals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -653,11 +653,11 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
|
||||||
MutableSpan dst_normals(reinterpret_cast<float3 *>(loop_normals.data()), loop_normals.size());
|
MutableSpan dst_normals(reinterpret_cast<float3 *>(loop_normals.data()), loop_normals.size());
|
||||||
|
|
||||||
switch (mesh->normals_domain()) {
|
switch (mesh->normals_domain()) {
|
||||||
case ATTR_DOMAIN_POINT: {
|
case bke::MeshNormalDomain::Point: {
|
||||||
array_utils::gather(mesh->vert_normals(), mesh->corner_verts(), dst_normals);
|
array_utils::gather(mesh->vert_normals(), mesh->corner_verts(), dst_normals);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_FACE: {
|
case bke::MeshNormalDomain::Face: {
|
||||||
const OffsetIndices faces = mesh->faces();
|
const OffsetIndices faces = mesh->faces();
|
||||||
const Span<float3> face_normals = mesh->face_normals();
|
const Span<float3> face_normals = mesh->face_normals();
|
||||||
for (const int i : faces.index_range()) {
|
for (const int i : faces.index_range()) {
|
||||||
|
@ -665,12 +665,10 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_CORNER: {
|
case bke::MeshNormalDomain::Corner: {
|
||||||
array_utils::copy(mesh->corner_normals(), dst_normals);
|
array_utils::copy(mesh->corner_normals(), dst_normals);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(), true);
|
pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(), true);
|
||||||
|
|
|
@ -368,7 +368,7 @@ void OBJMesh::store_normal_coords_and_indices()
|
||||||
loop_to_normal_index_.fill(-1);
|
loop_to_normal_index_.fill(-1);
|
||||||
|
|
||||||
Span<float3> corner_normals;
|
Span<float3> corner_normals;
|
||||||
if (export_mesh_->normals_domain() == ATTR_DOMAIN_CORNER) {
|
if (export_mesh_->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||||
corner_normals = export_mesh_->corner_normals();
|
corner_normals = export_mesh_->corner_normals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -366,7 +367,7 @@ typedef struct Mesh {
|
||||||
* face corner normals, since there is a 2-4x performance cost increase for each more complex
|
* face corner normals, since there is a 2-4x performance cost increase for each more complex
|
||||||
* domain.
|
* domain.
|
||||||
*/
|
*/
|
||||||
HooglyBoogly marked this conversation as resolved
Outdated
Jacques Lucke
commented
I wonder if we could call this I wonder if we could call this `normals_domain`. I found "all info" more confusing than useful at first.
|
|||||||
int normals_domain() const;
|
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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -1619,7 +1620,7 @@ int rna_Mesh_loops_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
|
||||||
|
|
||||||
static int rna_Mesh_normals_domain_get(PointerRNA *ptr)
|
static int rna_Mesh_normals_domain_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
return rna_mesh(ptr)->normals_domain();
|
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)
|
||||||
|
@ -2999,11 +3000,18 @@ 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);
|
prop = RNA_def_property(srna, "normals_domain", PROP_ENUM, PROP_NONE);
|
||||||
RNA_def_property_enum_items(prop, rna_enum_attribute_domain_only_mesh_no_edge_items);
|
RNA_def_property_enum_items(prop, normal_domain_items);
|
||||||
RNA_def_property_ui_text(
|
RNA_def_property_ui_text(
|
||||||
prop,
|
prop,
|
||||||
"Normal Domain All Info",
|
"Normal Domain",
|
||||||
"The attribute domain that gives enough information to represent the mesh's normals");
|
"The attribute domain that gives enough information to represent the mesh's normals");
|
||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_enum_funcs(prop, "rna_Mesh_normals_domain_get", NULL, NULL);
|
RNA_def_property_enum_funcs(prop, "rna_Mesh_normals_domain_get", NULL, NULL);
|
||||||
|
|
|
@ -216,7 +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->normals_domain() == ATTR_DOMAIN_CORNER;
|
mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner;
|
||||||
/* 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. */
|
||||||
|
|
|
@ -337,7 +337,7 @@ static void compute_normal_outputs(const Mesh &mesh,
|
||||||
MutableSpan<float3> r_normals)
|
MutableSpan<float3> r_normals)
|
||||||
{
|
{
|
||||||
switch (mesh.normals_domain()) {
|
switch (mesh.normals_domain()) {
|
||||||
case ATTR_DOMAIN_POINT: {
|
case bke::MeshNormalDomain::Point: {
|
||||||
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();
|
||||||
const Span<float3> vert_normals = mesh.vert_normals();
|
const Span<float3> vert_normals = mesh.vert_normals();
|
||||||
|
@ -347,7 +347,7 @@ static void compute_normal_outputs(const Mesh &mesh,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_FACE: {
|
case bke::MeshNormalDomain::Face: {
|
||||||
const Span<int> looptri_faces = mesh.looptri_faces();
|
const Span<int> looptri_faces = mesh.looptri_faces();
|
||||||
VArray<float3> face_normals = VArray<float3>::ForSpan(mesh.face_normals());
|
VArray<float3> face_normals = VArray<float3>::ForSpan(mesh.face_normals());
|
||||||
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
||||||
|
@ -356,7 +356,7 @@ static void compute_normal_outputs(const Mesh &mesh,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_CORNER: {
|
case bke::MeshNormalDomain::Corner: {
|
||||||
const Span<MLoopTri> looptris = mesh.looptris();
|
const Span<MLoopTri> looptris = mesh.looptris();
|
||||||
const Span<float3> corner_normals = mesh.corner_normals();
|
const Span<float3> corner_normals = mesh.corner_normals();
|
||||||
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
|
||||||
|
@ -365,8 +365,6 @@ static void compute_normal_outputs(const Mesh &mesh,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
missing word after
the