Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKévin Dietrich <kevin.dietrich@mailoo.org>2022-01-20 14:20:30 +0300
committerKévin Dietrich <kevin.dietrich@mailoo.org>2022-01-20 14:21:34 +0300
commit4425e0cd64ff23b77c553041858a150665a32ba3 (patch)
tree45c76d67d99499377dc719679c22e87effc86d8f /source/blender/io
parent9b4c017031f94237d75320349e933462772d773e (diff)
Subdivision: add support for vertex creasing
This adds vertex creasing support for OpenSubDiv for modeling, rendering, Alembic and USD I/O. For modeling, vertex creasing follows the edge creasing implementation with an operator accessible through the Vertex menu in Edit Mode, and some parameter in the properties panel. The option in the Subsurf and Multires to use edge creasing also affects vertex creasing. The vertex crease data is stored as a CustomData layer, unlike edge creases which for now are stored in `MEdge`, but will in the future also be moved to a `CustomData` layer. See comments for details on the difference in behavior for the `CD_CREASE` layer between egdes and vertices. For Cycles this adds sockets on the Mesh node to hold data about which vertices are creased (one socket for the indices, one for the weigths). Viewport rendering of vertex creasing reuses the same color scheme as for edges and creased vertices are drawn bigger than uncreased vertices. For Alembic and USD, vertex crease support follows the edge crease implementation, they are always read, but only exported if a `Subsurf` modifier is present on the Mesh. Reviewed By: brecht, fclem, sergey, sybren, campbellbarton Differential Revision: https://developer.blender.org/D10145
Diffstat (limited to 'source/blender/io')
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc62
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc30
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc34
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h1
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc46
5 files changed, 156 insertions, 17 deletions
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index 7275d0addf0..6ab4b06fba6 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -76,10 +76,13 @@ static void get_topology(struct Mesh *mesh,
std::vector<int32_t> &poly_verts,
std::vector<int32_t> &loop_counts,
bool &r_has_flat_shaded_poly);
-static void get_creases(struct Mesh *mesh,
- std::vector<int32_t> &indices,
- std::vector<int32_t> &lengths,
- std::vector<float> &sharpnesses);
+static void get_edge_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses);
+static void get_vert_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<float> &sharpnesses);
static void get_loop_normals(struct Mesh *mesh,
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly);
@@ -283,15 +286,16 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh)
{
- std::vector<float> crease_sharpness;
+ std::vector<float> edge_crease_sharpness, vert_crease_sharpness;
std::vector<Imath::V3f> points;
std::vector<int32_t> poly_verts, loop_counts;
- std::vector<int32_t> crease_indices, crease_lengths;
+ std::vector<int32_t> edge_crease_indices, edge_crease_lengths, vert_crease_indices;
bool has_flat_poly = false;
get_vertices(mesh, points);
get_topology(mesh, poly_verts, loop_counts, has_flat_poly);
- get_creases(mesh, crease_indices, crease_lengths, 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);
if (!frame_has_been_written_ && args_.export_params->face_sets) {
write_face_sets(context.object, mesh, abc_subdiv_schema_);
@@ -322,10 +326,15 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *me
write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config);
}
- if (!crease_indices.empty()) {
- subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices));
- subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths));
- subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness));
+ if (!edge_crease_indices.empty()) {
+ subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices));
+ subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths));
+ subdiv_sample.setCreaseSharpnesses(FloatArraySample(edge_crease_sharpness));
+ }
+
+ if (!vert_crease_indices.empty()) {
+ subdiv_sample.setCornerIndices(Int32ArraySample(vert_crease_indices));
+ subdiv_sample.setCornerSharpnesses(FloatArraySample(vert_crease_sharpness));
}
update_bounding_box(context.object);
@@ -477,10 +486,10 @@ static void get_topology(struct Mesh *mesh,
}
}
-static void get_creases(struct Mesh *mesh,
- std::vector<int32_t> &indices,
- std::vector<int32_t> &lengths,
- std::vector<float> &sharpnesses)
+static void get_edge_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses)
{
const float factor = 1.0f / 255.0f;
@@ -503,6 +512,29 @@ static void get_creases(struct Mesh *mesh,
lengths.resize(sharpnesses.size(), 2);
}
+static void get_vert_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<float> &sharpnesses)
+{
+ indices.clear();
+ sharpnesses.clear();
+
+ const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->vdata, CD_CREASE));
+
+ if (!creases) {
+ return;
+ }
+
+ for (int i = 0, v = mesh->totvert; i < v; i++) {
+ const float sharpness = creases[i];
+
+ if (sharpness != 0.0f) {
+ indices.push_back(i);
+ sharpnesses.push_back(sharpness);
+ }
+ }
+}
+
static void get_loop_normals(struct Mesh *mesh,
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly)
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 3c1ac8ceeaf..bd40eb35123 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -45,6 +45,7 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
+using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::IV3fArrayProperty;
using Alembic::Abc::P3fArraySamplePtr;
@@ -910,6 +911,32 @@ static void read_subd_sample(const std::string &iobject_full_name,
}
}
+static void read_vertex_creases(Mesh *mesh,
+ const Int32ArraySamplePtr &indices,
+ const FloatArraySamplePtr &sharpnesses)
+{
+ if (!(indices && sharpnesses && indices->size() == sharpnesses->size() &&
+ indices->size() != 0)) {
+ return;
+ }
+
+ float *vertex_crease_data = (float *)CustomData_add_layer(
+ &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert);
+ const int totvert = mesh->totvert;
+
+ for (int i = 0, v = indices->size(); i < v; ++i) {
+ const int idx = (*indices)[i];
+
+ if (idx >= totvert) {
+ continue;
+ }
+
+ vertex_crease_data[idx] = (*sharpnesses)[i];
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_VERT_CREASE;
+}
+
/* ************************************************************************** */
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
@@ -973,6 +1000,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
return;
}
+ /* Read egde creases. */
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
@@ -1003,6 +1031,8 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
}
+ read_vertex_creases(mesh, sample.getCornerIndices(), sample.getCornerSharpnesses());
+
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
}
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 53dbaac99fd..95b73c85da6 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -522,6 +522,38 @@ void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
}
}
+void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime)
+{
+ pxr::VtIntArray corner_indices;
+ if (!mesh_prim_.GetCornerIndicesAttr().Get(&corner_indices, motionSampleTime)) {
+ return;
+ }
+
+ pxr::VtIntArray corner_sharpnesses;
+ if (!mesh_prim_.GetCornerSharpnessesAttr().Get(&corner_sharpnesses, motionSampleTime)) {
+ return;
+ }
+
+ /* It is fine to have fewer indices than vertices, but never the other way other. */
+ if (corner_indices.size() > mesh->totvert) {
+ std::cerr << "WARNING: too many vertex crease for mesh " << prim_path_ << std::endl;
+ return;
+ }
+
+ if (corner_indices.size() != corner_sharpnesses.size()) {
+ std::cerr << "WARNING: vertex crease indices and sharpnesses count mismatch for mesh "
+ << prim_path_ << std::endl;
+ return;
+ }
+
+ float *creases = static_cast<float *>(
+ CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert));
+
+ for (size_t i = 0; i < corner_indices.size(); i++) {
+ creases[corner_indices[i]] = corner_sharpnesses[i];
+ }
+}
+
void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
{
if (!mesh) {
@@ -640,6 +672,8 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
mvert.co[1] = positions_[i][1];
mvert.co[2] = positions_[i][2];
}
+
+ read_vertex_creases(mesh, motionSampleTime);
}
if (new_mesh || (settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index 9ed73ba5a28..c5869fcbd32 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -86,6 +86,7 @@ class USDMeshReader : public USDGeomReader {
void read_mpolys(Mesh *mesh);
void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false);
void read_colors(Mesh *mesh, double motionSampleTime);
+ void read_vertex_creases(Mesh *mesh, double motionSampleTime);
void read_mesh_sample(ImportSettings *settings,
Mesh *mesh,
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index b21dd8ac1fd..b061a2ff795 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -110,6 +110,12 @@ struct USDMeshData {
* single sharpness or a value per-edge, USD will encode either a single sharpness per crease on
* a mesh, or sharpness's for all edges making up the creases on a mesh. */
pxr::VtFloatArray crease_sharpnesses;
+
+ /* The lengths of this array specifies the number of sharp corners (or vertex crease) on the
+ * surface. Each value is the index of a vertex in the mesh's vertex list. */
+ pxr::VtIntArray corner_indices;
+ /* The per-vertex sharpnesses. The lengths of this array must match that of `corner_indices`. */
+ pxr::VtFloatArray corner_sharpnesses;
};
void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
@@ -214,6 +220,23 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
attr_crease_sharpness, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
}
+ if (!usd_mesh_data.corner_indices.empty() &&
+ usd_mesh_data.corner_indices.size() == usd_mesh_data.corner_sharpnesses.size()) {
+ pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr(
+ pxr::VtValue(), true);
+
+ if (!attr_corner_indices.HasValue()) {
+ attr_corner_indices.Set(usd_mesh_data.corner_indices, defaultTime);
+ attr_corner_sharpnesses.Set(usd_mesh_data.corner_sharpnesses, defaultTime);
+ }
+
+ usd_value_writer_.SetAttribute(
+ attr_corner_indices, pxr::VtValue(usd_mesh_data.corner_indices), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_corner_sharpnesses, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
+ }
+
if (usd_export_context_.export_params.export_uvmaps) {
write_uv_maps(mesh, usd_mesh);
}
@@ -268,7 +291,7 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
}
}
-static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
const float factor = 1.0f / 255.0f;
@@ -293,11 +316,30 @@ static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
}
}
+static void get_vert_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->vdata, CD_CREASE));
+
+ if (!creases) {
+ return;
+ }
+
+ for (int i = 0, v = mesh->totvert; i < v; i++) {
+ const float sharpness = creases[i];
+
+ if (sharpness != 0.0f) {
+ usd_mesh_data.corner_indices.push_back(i);
+ usd_mesh_data.corner_sharpnesses.push_back(sharpness);
+ }
+ }
+}
+
void USDGenericMeshWriter::get_geometry_data(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
get_vertices(mesh, usd_mesh_data);
get_loops_polys(mesh, usd_mesh_data);
- get_creases(mesh, usd_mesh_data);
+ get_edge_creases(mesh, usd_mesh_data);
+ get_vert_creases(mesh, usd_mesh_data);
}
void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,