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
This commit is contained in:
Kévin Dietrich 2022-01-20 12:20:30 +01:00
parent 9b4c017031
commit 4425e0cd64
45 changed files with 639 additions and 101 deletions

View File

@ -1071,7 +1071,15 @@ static void create_subd_mesh(Scene *scene,
for (BL::MeshEdge &e : b_mesh.edges) {
if (e.crease() != 0.0f) {
mesh->add_crease(e.vertices()[0], e.vertices()[1], e.crease());
mesh->add_edge_crease(e.vertices()[0], e.vertices()[1], e.crease());
}
}
for (BL::MeshVertexCreaseLayer &c : b_mesh.vertex_creases) {
for (int i = 0; i < c.data.length(); ++i) {
if (c.data[i].value() != 0.0f) {
mesh->add_vertex_crease(i, c.data[i].value());
}
}
}

View File

@ -1178,6 +1178,12 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame
cached_data.subd_creases_weight.copy_to_socket(
frame_time, mesh, mesh->get_subd_creases_weight_socket());
cached_data.subd_vertex_crease_indices.copy_to_socket(
frame_time, mesh, mesh->get_subd_vert_creases_socket());
cached_data.subd_vertex_crease_weights.copy_to_socket(
frame_time, mesh, mesh->get_subd_vert_creases_weight_socket());
mesh->set_num_subd_faces(mesh->get_subd_shader().size());
/* Update attributes. */

View File

@ -320,6 +320,8 @@ struct CachedData {
DataStore<int> num_ngons;
DataStore<array<int>> subd_creases_edge;
DataStore<array<float>> subd_creases_weight;
DataStore<array<int>> subd_vertex_crease_indices;
DataStore<array<float>> subd_vertex_crease_weights;
/* hair data */
DataStore<array<float3>> curve_keys;

View File

@ -478,7 +478,9 @@ static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &dat
cached_data.uv_loops.add_data(uv_loops, time);
}
static void add_subd_creases(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
static void add_subd_edge_creases(CachedData &cached_data,
const SubDSchemaData &data,
chrono_t time)
{
if (!(data.crease_indices.valid() && data.crease_indices.valid() &&
data.crease_sharpnesses.valid())) {
@ -517,6 +519,37 @@ static void add_subd_creases(CachedData &cached_data, const SubDSchemaData &data
}
}
static void add_subd_vertex_creases(CachedData &cached_data,
const SubDSchemaData &data,
chrono_t time)
{
if (!(data.corner_indices.valid() && data.crease_sharpnesses.valid())) {
return;
}
const ISampleSelector iss = ISampleSelector(time);
const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss);
const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss);
if (!(creases_indices && creases_sharpnesses) ||
creases_indices->size() != creases_sharpnesses->size()) {
return;
}
array<float> sharpnesses;
sharpnesses.reserve(creases_indices->size());
array<int> indices;
indices.reserve(creases_indices->size());
for (size_t i = 0; i < creases_indices->size(); i++) {
indices.push_back_reserved((*creases_indices)[i]);
sharpnesses.push_back_reserved((*creases_sharpnesses)[i]);
}
cached_data.subd_vertex_crease_indices.add_data(indices, time);
cached_data.subd_vertex_crease_weights.add_data(sharpnesses, time);
}
static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
{
const ISampleSelector iss = ISampleSelector(time);
@ -525,7 +558,8 @@ static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &da
if (data.topology_variance != kHomogenousTopology || cached_data.shader.size() == 0) {
add_subd_polygons(cached_data, data, time);
add_subd_creases(cached_data, data, time);
add_subd_edge_creases(cached_data, data, time);
add_subd_vertex_creases(cached_data, data, time);
}
}

View File

@ -76,9 +76,10 @@ struct SubDSchemaData {
vector<FaceSetShaderIndexPair> shader_face_sets;
// Those are unsupported for now.
Alembic::AbcGeom::IInt32ArrayProperty corner_indices;
Alembic::AbcGeom::IFloatArrayProperty corner_sharpnesses;
// Those are unsupported for now.
Alembic::AbcGeom::IInt32Property face_varying_interpolate_boundary;
Alembic::AbcGeom::IInt32Property face_varying_propagate_corners;
Alembic::AbcGeom::IInt32Property interpolate_boundary;

View File

@ -141,6 +141,9 @@ NODE_DEFINE(Mesh)
subdivision_type_enum.insert("catmull_clark", SUBDIVISION_CATMULL_CLARK);
SOCKET_ENUM(subdivision_type, "Subdivision Type", subdivision_type_enum, SUBDIVISION_NONE);
SOCKET_INT_ARRAY(subd_vert_creases, "Subdivision Vertex Crease", array<int>());
SOCKET_FLOAT_ARRAY(
subd_vert_creases_weight, "Subdivision Vertex Crease Weights", array<float>());
SOCKET_INT_ARRAY(subd_creases_edge, "Subdivision Crease Edges", array<int>());
SOCKET_FLOAT_ARRAY(subd_creases_weight, "Subdivision Crease Weights", array<float>());
SOCKET_INT_ARRAY(subd_face_corners, "Subdivision Face Corners", array<int>());
@ -408,7 +411,7 @@ Mesh::SubdFace Mesh::get_subd_face(size_t index) const
return s;
}
void Mesh::add_crease(int v0, int v1, float weight)
void Mesh::add_edge_crease(int v0, int v1, float weight)
{
subd_creases_edge.push_back_slow(v0);
subd_creases_edge.push_back_slow(v1);
@ -419,6 +422,17 @@ void Mesh::add_crease(int v0, int v1, float weight)
tag_subd_creases_weight_modified();
}
void Mesh::add_vertex_crease(int v, float weight)
{
assert(v < verts.size());
subd_vert_creases.push_back_slow(v);
subd_vert_creases_weight.push_back_slow(weight);
tag_subd_vert_creases_modified();
tag_subd_vert_creases_weight_modified();
}
void Mesh::copy_center_to_motion_step(const int motion_step)
{
Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);

View File

@ -160,6 +160,9 @@ class Mesh : public Geometry {
NODE_SOCKET_API_ARRAY(array<int>, subd_creases_edge)
NODE_SOCKET_API_ARRAY(array<float>, subd_creases_weight)
NODE_SOCKET_API_ARRAY(array<int>, subd_vert_creases)
NODE_SOCKET_API_ARRAY(array<float>, subd_vert_creases_weight)
/* Subdivisions parameters */
NODE_SOCKET_API(float, subd_dicing_rate)
NODE_SOCKET_API(int, subd_max_level)
@ -210,7 +213,8 @@ class Mesh : public Geometry {
void add_vertex_slow(float3 P);
void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_);
void add_crease(int v0, int v1, float weight);
void add_edge_crease(int v0, int v1, float weight);
void add_vertex_crease(int v, float weight);
void copy_center_to_motion_step(const int motion_step);

View File

@ -82,24 +82,54 @@ template<>
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner &refiner,
ccl::Mesh const &mesh)
{
/* Historical maximum crease weight used at Pixar, influencing the maximum in OpenSubDiv. */
static constexpr float CREASE_SCALE = 10.0f;
size_t num_creases = mesh.get_subd_creases_weight().size();
size_t num_vertex_creases = mesh.get_subd_vert_creases().size();
/* The last loop is over the vertices, so early exit to avoid iterating them needlessly. */
if (num_creases == 0 && num_vertex_creases == 0) {
return true;
}
for (int i = 0; i < num_creases; i++) {
ccl::Mesh::SubdEdgeCrease crease = mesh.get_subd_crease(i);
Index edge = findBaseEdge(refiner, crease.v[0], crease.v[1]);
if (edge != INDEX_INVALID) {
setBaseEdgeSharpness(refiner, edge, crease.crease * 10.0f);
setBaseEdgeSharpness(refiner, edge, crease.crease * CREASE_SCALE);
}
}
std::map<int, float> vertex_creases;
for (size_t i = 0; i < num_vertex_creases; ++i) {
const int vertex_idx = mesh.get_subd_vert_creases()[i];
const float weight = mesh.get_subd_vert_creases_weight()[i];
vertex_creases[vertex_idx] = weight * CREASE_SCALE;
}
for (int i = 0; i < mesh.get_verts().size(); i++) {
float sharpness = 0.0f;
std::map<int, float>::const_iterator iter = vertex_creases.find(i);
if (iter != vertex_creases.end()) {
sharpness = iter->second;
}
ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
if (vert_edges.size() == 2) {
float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
const float sharpness0 = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
const float sharpness1 = refiner.getLevel(0).getEdgeSharpness(vert_edges[1]);
sharpness += ccl::min(sharpness0, sharpness1);
sharpness = ccl::min(sharpness, CREASE_SCALE);
}
if (sharpness != 0.0f) {
setBaseVertexSharpness(refiner, i, sharpness);
}
}

View File

@ -557,6 +557,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
col.enabled = obj is not None and obj.mode != 'EDIT'
col.prop(me, "use_customdata_vertex_bevel", text="Vertex Bevel Weight")
col.prop(me, "use_customdata_edge_bevel", text="Edge Bevel Weight")
col.prop(me, "use_customdata_vertex_crease", text="Vertex Crease")
col.prop(me, "use_customdata_edge_crease", text="Edge Crease")

View File

@ -4026,6 +4026,10 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.separator()
layout.operator("transform.vert_crease")
layout.separator()
layout.operator("mesh.blend_from_shape")
layout.operator("mesh.shape_propagate_to_all", text="Propagate to Shapes")

View File

@ -306,8 +306,8 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v);
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease);
BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease);
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease);
BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease);
#ifdef __cplusplus
}

View File

@ -1692,7 +1692,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 29: CD_BWEIGHT */
{sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
{sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, layerInterp_bweight},
/* NOTE: we do not interpolate crease data as it should be either inherited for subdivided
* edges, or for vertex creases, only present on the original vertex. */
{sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, nullptr},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
"OrigSpaceLoop",
@ -1938,7 +1940,7 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
};
const CustomData_MeshMasks CD_MASK_MESH = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
/* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ 0,
/* pmask */
@ -1950,7 +1952,7 @@ const CustomData_MeshMasks CD_MASK_MESH = {
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
/* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
/* emask */ (CD_MASK_PROP_ALL),
/* fmask */ 0,
/* pmask */ (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
@ -1961,7 +1963,7 @@ const CustomData_MeshMasks CD_MASK_EDITMESH = {
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
CD_MASK_PROP_COLOR),
CD_MASK_PROP_COLOR | CD_MASK_CREASE),
/* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
/* pmask */
@ -1974,7 +1976,7 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
const CustomData_MeshMasks CD_MASK_BMESH = {
/* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL |
CD_MASK_PROP_COLOR),
CD_MASK_PROP_COLOR | CD_MASK_CREASE),
/* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ 0,
/* pmask */
@ -2001,7 +2003,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX |
CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
/* emask */
(CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
@ -4409,7 +4411,12 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
/* 0 structnum is used in writing code to tag layer types that should not be written. */
else if (typeInfo->structnum == 0 &&
/* XXX Not sure why those three are exception, maybe that should be fixed? */
!ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP, CD_MTEXPOLY, CD_SCULPT_FACE_SETS)) {
!ELEM(layer->type,
CD_PAINT_MASK,
CD_FACEMAP,
CD_MTEXPOLY,
CD_SCULPT_FACE_SETS,
CD_CREASE)) {
keeplayer = false;
CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written");
}
@ -5080,6 +5087,10 @@ void CustomData_blend_write(BlendWriter *writer,
const bool *layer_data = static_cast<const bool *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_CREASE) {
const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else {
const char *structname;
int structnum;

View File

@ -106,6 +106,9 @@ typedef struct MultiresReshapeContext {
/* Indexed by base face index, returns first ptex face index corresponding
* to that base face. */
int *face_ptex_offset;
/* Vertex crease custom data layer, null if none is present. */
const float *cd_vertex_crease;
} MultiresReshapeContext;
/**

View File

@ -75,6 +75,7 @@ typedef struct Vertex {
int num_grid_coords;
GridCoord *grid_coords;
float sharpness;
bool is_infinite_sharp;
} Vertex;
@ -489,19 +490,33 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co
return (1 << reshape_context->reshape.level) + 1;
}
static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context)
{
return !ELEM(reshape_smooth_context->smoothing_type,
MULTIRES_SUBDIVIDE_LINEAR,
MULTIRES_SUBDIVIDE_SIMPLE);
}
/* Get crease which will be used for communication to OpenSubdiv topology.
* Note that simple subdivision treats all base edges as infinitely sharp. */
static char get_effective_edge_crease_char(
const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context,
const MEdge *base_edge)
{
if (ELEM(reshape_smooth_context->smoothing_type,
MULTIRES_SUBDIVIDE_LINEAR,
MULTIRES_SUBDIVIDE_SIMPLE)) {
if (!is_crease_supported(reshape_smooth_context)) {
return 255;
}
return base_edge->crease;
}
static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
const float crease)
{
if (!is_crease_supported(reshape_smooth_context)) {
return 1.0f;
}
return crease;
}
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
const MultiresReshapeContext *reshape_context,
const eMultiresSubdivideModeType mode)
@ -596,6 +611,7 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
const GridCoord *grid_coord,
const int coarse_vertex_index,
const int subdiv_vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
@ -608,11 +624,32 @@ static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
sizeof(Vertex) * (vertex->num_grid_coords + 1));
vertex->grid_coords[vertex->num_grid_coords] = *grid_coord;
++vertex->num_grid_coords;
if (coarse_vertex_index == -1) {
return;
}
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
const float *cd_vertex_crease = reshape_context->cd_vertex_crease;
if (cd_vertex_crease == NULL) {
return;
}
float crease = cd_vertex_crease[coarse_vertex_index];
if (crease == 0.0f) {
return;
}
crease = get_effective_crease_float(reshape_smooth_context, crease);
vertex->sharpness = BKE_subdiv_crease_to_sharpness_f(crease);
}
/* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.c */
static void foreach_vertex(const SubdivForeachContext *foreach_context,
const PTexCoord *ptex_coord,
const int coarse_vertex_index,
const int subdiv_vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
@ -632,12 +669,13 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
GridCoord corner_grid_coord = grid_coord;
corner_grid_coord.grid_index = start_grid_index + current_corner;
foreach_single_vertex(foreach_context, &corner_grid_coord, subdiv_vertex_index);
foreach_single_vertex(
foreach_context, &corner_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
return;
}
foreach_single_vertex(foreach_context, &grid_coord, subdiv_vertex_index);
foreach_single_vertex(foreach_context, &grid_coord, coarse_vertex_index, subdiv_vertex_index);
if (grid_coord.u == 0.0f) {
GridCoord prev_grid_coord;
@ -645,7 +683,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
prev_grid_coord.u = grid_coord.v;
prev_grid_coord.v = 0.0f;
foreach_single_vertex(foreach_context, &prev_grid_coord, subdiv_vertex_index);
foreach_single_vertex(
foreach_context, &prev_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
if (grid_coord.v == 0.0f) {
@ -654,7 +693,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
next_grid_coord.u = 0.0f;
next_grid_coord.v = grid_coord.u;
foreach_single_vertex(foreach_context, &next_grid_coord, subdiv_vertex_index);
foreach_single_vertex(
foreach_context, &next_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
}
@ -672,7 +712,7 @@ static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_cont
.u = ptex_face_u,
.v = ptex_face_v,
};
foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
}
static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context,
@ -680,7 +720,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea
const int ptex_face_index,
const float ptex_face_u,
const float ptex_face_v,
const int UNUSED(coarse_vertex_index),
const int coarse_vertex_index,
const int UNUSED(coarse_face_index),
const int UNUSED(coarse_face_corner),
const int subdiv_vertex_index)
@ -690,7 +730,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea
.u = ptex_face_u,
.v = ptex_face_v,
};
foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index);
}
static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context,
@ -708,7 +748,7 @@ static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach
.u = ptex_face_u,
.v = ptex_face_v,
};
foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
}
static void foreach_loop(const struct SubdivForeachContext *foreach_context,
@ -778,7 +818,7 @@ static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
edge->v1 = subdiv_v1;
edge->v2 = subdiv_v2;
edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
edge->sharpness = BKE_subdiv_crease_to_sharpness_char(crease);
}
static void foreach_edge(const struct SubdivForeachContext *foreach_context,
@ -809,7 +849,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
/* Edges without crease are to be ignored as well. */
const Mesh *base_mesh = reshape_context->base_mesh;
const MEdge *base_edge = &base_mesh->medge[coarse_edge_index];
const char crease = get_effective_edge_crease_char(reshape_smooth_context, base_edge);
const char crease = get_effective_crease_char(reshape_smooth_context, base_edge);
if (crease == 0) {
return;
}
@ -835,8 +875,7 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) {
BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e);
const char crease = get_effective_edge_crease_char(reshape_smooth_context,
&base_edge[loop->e]);
const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]);
if (crease != 0) {
++num_used_edges;
}
@ -979,6 +1018,15 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int
return edge->sharpness;
}
static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
return vertex->sharpness;
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
@ -1015,7 +1063,7 @@ static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_co
converter->getNumVertexFaces = NULL;
converter->getVertexFaces = NULL;
converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
converter->getVertexSharpness = NULL;
converter->getVertexSharpness = get_vertex_sharpness;
converter->getNumUVLayers = NULL;
converter->precalcUVLayer = NULL;

View File

@ -211,6 +211,8 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
reshape_context->top.level = mmd->totlvl;
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
reshape_context->cd_vertex_crease = CustomData_get_layer(&base_mesh->vdata, CD_CREASE);
context_init_commoon(reshape_context);
return context_verify_or_free(reshape_context);

View File

@ -40,6 +40,8 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
#include "bmesh_class.h"
/* Enable work-around for non-working CPU evaluator when using bilinear scheme.
* This forces Catmark scheme with all edges marked as infinitely sharp. */
#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
@ -47,6 +49,8 @@
typedef struct ConverterStorage {
SubdivSettings settings;
const Mesh *mesh;
/* CustomData layer for vertex sharpnesses. */
const float *cd_vertex_crease;
/* Indexed by loop index, value denotes index of face-varying vertex
* which corresponds to the UV coordinate.
*/
@ -168,7 +172,7 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif
}
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
const MEdge *medge = storage->mesh->medge;
return BKE_subdiv_edge_crease_to_sharpness_char(medge[edge_index].crease);
return BKE_subdiv_crease_to_sharpness_char(medge[edge_index].crease);
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
@ -184,14 +188,14 @@ static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, vertex_index);
}
static float get_vertex_sharpness(const OpenSubdiv_Converter *converter,
int UNUSED(manifold_vertex_index))
static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
{
ConverterStorage *storage = converter->user_data;
if (!storage->settings.use_creases) {
if (!storage->settings.use_creases || storage->cd_vertex_crease == NULL) {
return 0.0f;
}
return 0.0f;
const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
return BKE_subdiv_crease_to_sharpness_f(storage->cd_vertex_crease[vertex_index]);
}
static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
@ -393,6 +397,7 @@ static void init_user_data(OpenSubdiv_Converter *converter,
ConverterStorage *user_data = MEM_mallocN(sizeof(ConverterStorage), __func__);
user_data->settings = *settings;
user_data->mesh = mesh;
user_data->cd_vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
user_data->loop_uv_indices = NULL;
initialize_manifold_indices(user_data);
converter->user_data = user_data;

View File

@ -103,13 +103,13 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
}
}
BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease)
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease)
{
return edge_crease * edge_crease * 10.0f;
}
BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease)
BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease)
{
const float edge_crease_f = edge_crease / 255.0f;
return BKE_subdiv_edge_crease_to_sharpness_f(edge_crease_f);
return BKE_subdiv_crease_to_sharpness_f(edge_crease_f);
}

View File

@ -122,6 +122,17 @@ void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
}
}
if (cd_flag & ME_CDFLAG_VERT_CREASE) {
if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->vdata, CD_CREASE);
}
}
else {
if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
BM_data_layer_free(bm, &bm->vdata, CD_CREASE);
}
}
if (cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT);
@ -151,6 +162,9 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
}
if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
cd_flag |= ME_CDFLAG_VERT_CREASE;
}
if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
}

View File

@ -323,7 +323,9 @@ GPUShader *OVERLAY_shader_edit_mesh_vert(void)
datatoc_edit_mesh_common_lib_glsl,
datatoc_edit_mesh_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
.frag = (const char *[]){datatoc_common_globals_lib_glsl,
datatoc_gpu_shader_point_varying_color_frag_glsl,
NULL},
.defs = (const char *[]){sh_cfg->def, "#define VERT\n", NULL},
});
}

View File

@ -36,7 +36,7 @@ vec4 EDIT_MESH_edge_vertex_color(int vertex_flag)
return color;
}
vec4 EDIT_MESH_vertex_color(int vertex_flag)
vec4 EDIT_MESH_vertex_color(int vertex_flag, float vertex_crease)
{
if ((vertex_flag & VERT_ACTIVE) != 0) {
return vec4(colorEditMeshActive.xyz, 1.0);
@ -45,6 +45,10 @@ vec4 EDIT_MESH_vertex_color(int vertex_flag)
return colorVertexSelect;
}
else {
/* Full crease color if not selected nor active. */
if (vertex_crease > 0.0) {
return mix(colorVertex, colorEdgeCrease, vertex_crease);
}
return colorVertex;
}
}

View File

@ -13,6 +13,9 @@ in vec4 norAndFlag;
#endif
out vec4 finalColor;
#ifdef VERT
out float vertexCrease;
#endif
#ifdef EDGE
out vec4 finalColorOuter;
#endif
@ -44,8 +47,9 @@ void main()
ivec4 m_data = data & dataMask;
#if defined(VERT)
finalColor = EDIT_MESH_vertex_color(m_data.y);
gl_PointSize = sizeVertex * 2.0;
vertexCrease = float(m_data.z >> 4) / 15.0;
finalColor = EDIT_MESH_vertex_color(m_data.y, vertexCrease);
gl_PointSize = sizeVertex * ((vertexCrease > 0.0) ? 3.0 : 2.0);
/* Make selected and active vertex always on top. */
if ((data.x & VERT_SELECTED) != 0) {
gl_Position.z -= 5e-7 * abs(gl_Position.w);
@ -65,9 +69,9 @@ void main()
selectOverride = (m_data.y & EDGE_SELECTED);
# endif
float crease = float(m_data.z) / 255.0;
float edge_crease = float(m_data.z & 0xF) / 15.0;
float bweight = float(m_data.w) / 255.0;
finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight);
finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, edge_crease, bweight);
if (finalColorOuter.a > 0.0) {
gl_Position.z -= 5e-7 * abs(gl_Position.w);

View File

@ -487,7 +487,8 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
mr->eed_act = BM_mesh_active_edge_get(mr->bm);
mr->eve_act = BM_mesh_active_vert_get(mr->bm);
mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
mr->vert_crease_ofs = CustomData_get_offset(&mr->bm->vdata, CD_CREASE);
mr->edge_crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
#ifdef WITH_FREESTYLE
mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);

View File

@ -1693,7 +1693,8 @@ void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
mr->eed_act = BM_mesh_active_edge_get(bm);
mr->efa_act = BM_mesh_active_face_get(bm, false, true);
mr->eve_act = BM_mesh_active_vert_get(bm);
mr->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE);
mr->edge_crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE);
mr->vert_crease_ofs = CustomData_get_offset(&bm->vdata, CD_CREASE);
mr->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
#ifdef WITH_FREESTYLE
mr->freestyle_edge_ofs = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);

View File

@ -84,7 +84,8 @@ typedef struct MeshRenderData {
const float (*bm_poly_centers)[3];
int *v_origindex, *e_origindex, *p_origindex;
int crease_ofs;
int edge_crease_ofs;
int vert_crease_ofs;
int bweight_ofs;
int freestyle_edge_ofs;
int freestyle_face_ofs;
@ -308,6 +309,8 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
typedef struct EditLoopData {
uchar v_flag;
uchar e_flag;
/* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4
* bits, while the vertex crease is stored in the upper 4 bits. */
uchar crease;
uchar bweight;
} EditLoopData;

View File

@ -72,11 +72,11 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr,
}
}
/* Use a byte for value range */
if (mr->crease_ofs != -1) {
float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
/* Use half a byte for value range */
if (mr->edge_crease_ofs != -1) {
float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->edge_crease_ofs);
if (crease > 0) {
eattr->crease = (uchar)(crease * 255.0f);
eattr->crease = (uchar)ceil(crease * 15.0f);
}
}
/* Use a byte for value range */
@ -107,6 +107,13 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr,
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
eattr->e_flag |= VFLAG_VERT_SELECTED;
}
/* Use half a byte for value range */
if (mr->vert_crease_ofs != -1) {
float crease = BM_ELEM_CD_GET_FLOAT(eve, mr->vert_crease_ofs);
if (crease > 0) {
eattr->crease |= (uchar)ceil(crease * 15.0f) << 4;
}
}
}
static GPUVertFormat *get_edit_data_format()

View File

@ -54,7 +54,8 @@ typedef enum {
TFM_TILT,
TFM_TRACKBALL,
TFM_PUSHPULL,
TFM_CREASE,
TFM_EDGE_CREASE,
TFM_VERT_CREASE,
TFM_MIRROR,
TFM_BONESIZE,
TFM_BONE_ENVELOPE,

View File

@ -87,7 +87,7 @@ typedef struct {
} TransformMedian_Generic;
typedef struct {
float location[3], bv_weight, be_weight, skin[2], crease;
float location[3], bv_weight, v_crease, be_weight, skin[2], e_crease;
} TransformMedian_Mesh;
typedef struct {
@ -319,6 +319,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMIter iter;
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
const int cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
@ -335,6 +336,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
}
if (cd_vert_crease_offset != -1) {
median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset);
}
if (has_skinradius) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */
@ -352,7 +357,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (cd_edge_crease_offset != -1) {
median->crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
}
totedgedata++;
@ -489,11 +494,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (has_meshdata) {
TransformMedian_Mesh *median = &median_basis.mesh;
if (totedgedata) {
median->crease /= (float)totedgedata;
median->e_crease /= (float)totedgedata;
median->be_weight /= (float)totedgedata;
}
if (tot) {
median->bv_weight /= (float)tot;
median->v_crease /= (float)tot;
if (has_skinradius) {
median->skin[0] /= (float)tot;
median->skin[1] /= (float)tot;
@ -683,6 +689,23 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
TIP_("Vertex weight used by Bevel modifier"));
UI_but_number_step_size_set(but, 1);
UI_but_number_precision_set(but, 2);
/* customdata layer added on demand */
but = uiDefButF(block,
UI_BTYPE_NUM,
B_TRANSFORM_PANEL_MEDIAN,
tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"),
0,
yi -= buth + but_margin,
butw,
buth,
&ve_median->v_crease,
0.0,
1.0,
0,
0,
TIP_("Weight used by the Subdivision Surface modifier"));
UI_but_number_step_size_set(but, 1);
UI_but_number_precision_set(but, 2);
}
if (has_skinradius) {
UI_block_align_begin(block);
@ -761,7 +784,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
yi -= buth + but_margin,
butw,
buth,
&ve_median->crease,
&ve_median->e_crease,
0.0,
1.0,
0,
@ -958,8 +981,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f);
if ((ob->type == OB_MESH) &&
(apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.skin[0] ||
median_basis.mesh.skin[1] || median_basis.mesh.be_weight || median_basis.mesh.crease)) {
(apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease ||
median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight ||
median_basis.mesh.e_crease)) {
const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
@ -969,18 +993,21 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMEdge *eed;
int cd_vert_bweight_offset = -1;
int cd_vert_crease_offset = -1;
int cd_vert_skin_offset = -1;
int cd_edge_bweight_offset = -1;
int cd_edge_crease_offset = -1;
float scale_bv_weight = 1.0f;
float scale_v_crease = 1.0f;
float scale_skin[2] = {1.0f, 1.0f};
float scale_be_weight = 1.0f;
float scale_crease = 1.0f;
float scale_e_crease = 1.0f;
/* Vertices */
if (apply_vcos || median->bv_weight || median->skin[0] || median->skin[1]) {
if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] ||
median->skin[1]) {
if (median->bv_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
@ -989,6 +1016,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight);
}
if (median->v_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
BLI_assert(cd_vert_crease_offset != -1);
scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease);
}
for (int i = 0; i < 2; i++) {
if (median->skin[i]) {
cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
@ -1011,6 +1046,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight);
}
if (cd_vert_crease_offset != -1) {
float *crease = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset);
apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease);
}
if (cd_vert_skin_offset != -1) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
@ -1033,7 +1073,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* Edges */
if (median->be_weight || median->crease) {
if (median->be_weight || median->e_crease) {
if (median->be_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
@ -1042,12 +1082,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight);
}
if (median->crease) {
if (median->e_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
BLI_assert(cd_edge_crease_offset != -1);
scale_crease = compute_scale_factor(ve_median->crease, median->crease);
scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease);
}
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
@ -1057,9 +1097,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight);
}
if (median->crease != 0.0f) {
if (median->e_crease != 0.0f) {
float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
apply_scale_factor_clamp(crease, tot, ve_median->crease, scale_crease);
apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease);
}
}
}

View File

@ -1465,7 +1465,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
if (t->mode == TFM_BWEIGHT) {
if (t->mode == TFM_BWEIGHT || t->mode == TFM_VERT_CREASE) {
td->val = bweight;
td->ival = *bweight;
}
@ -1606,10 +1606,15 @@ void createTransEditVerts(TransInfo *t)
}
int cd_vert_bweight_offset = -1;
int cd_vert_crease_offset = -1;
if (t->mode == TFM_BWEIGHT) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
else if (t->mode == TFM_VERT_CREASE) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE);
cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
}
TransData *tob = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
@ -1645,6 +1650,8 @@ void createTransEditVerts(TransInfo *t)
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
(cd_vert_crease_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) :
NULL;
/* Do not use the island center in case we are using islands

View File

@ -86,8 +86,8 @@ void createTransEdge(TransInfo *t)
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
}
else { /* if (t->mode == TFM_CREASE) { */
BLI_assert(t->mode == TFM_CREASE);
else { /* if (t->mode == TFM_EDGE_CREASE) { */
BLI_assert(t->mode == TFM_EDGE_CREASE);
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
}

View File

@ -260,7 +260,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Crease needs edge flag */
if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
if (ELEM(t->mode, TFM_EDGE_CREASE, TFM_BWEIGHT)) {
t->options |= CTX_EDGE_DATA;
}

View File

@ -1135,8 +1135,11 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
case TFM_PUSHPULL:
initPushPull(t);
break;
case TFM_CREASE:
initCrease(t);
case TFM_EDGE_CREASE:
initEgdeCrease(t);
break;
case TFM_VERT_CREASE:
initVertCrease(t);
break;
case TFM_BONESIZE:
initBoneSize(t);

View File

@ -106,7 +106,8 @@ void initCurveShrinkFatten(TransInfo *t);
void initBevelWeight(TransInfo *t);
/* transform_mode_edge_crease.c */
void initCrease(TransInfo *t);
void initEgdeCrease(TransInfo *t);
void initVertCrease(TransInfo *t);
/* transform_mode_edge_rotate_normal.c */
void initNormalRotation(TransInfo *t);

View File

@ -157,9 +157,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
void initCrease(TransInfo *t)
static void initCrease_ex(TransInfo *t, int mode)
{
t->mode = TFM_CREASE;
t->mode = mode;
t->transform = applyCrease;
initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
@ -176,4 +176,13 @@ void initCrease(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
void initEgdeCrease(TransInfo *t)
{
initCrease_ex(t, TFM_EDGE_CREASE);
}
void initVertCrease(TransInfo *t)
{
initCrease_ex(t, TFM_VERT_CREASE);
}
/** \} */

View File

@ -78,6 +78,7 @@ static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize";
static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
static const char OP_VERT_CREASE[] = "TRANSFORM_OT_vert_crease";
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
@ -98,6 +99,7 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
@ -118,7 +120,8 @@ static TransformModeItem transform_modes[] = {
{OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize},
{OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide},
{OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide},
{OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
{OP_EDGE_CREASE, TFM_EDGE_CREASE, TRANSFORM_OT_edge_crease},
{OP_VERT_CREASE, TFM_VERT_CREASE, TRANSFORM_OT_vert_crease},
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
{OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
@ -139,7 +142,8 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = {
{TFM_TILT, "TILT", 0, "Tilt", ""},
{TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""},
{TFM_PUSHPULL, "PUSHPULL", 0, "Push/Pull", ""},
{TFM_CREASE, "CREASE", 0, "Crease", ""},
{TFM_EDGE_CREASE, "CREASE", 0, "Crease", ""},
{TFM_VERT_CREASE, "VERTEX_CREASE", 0, "Vertex Crease", ""},
{TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
{TFM_BONESIZE, "BONE_SIZE", 0, "Bone Size", ""},
{TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""},
@ -1196,6 +1200,29 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
Transform_Properties(ot, P_SNAP);
}
static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Vertex Crease";
ot->description = "Change the crease of vertices";
ot->idname = OP_VERT_CREASE;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* api callbacks */
ot->invoke = transform_invoke;
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
ot->poll = ED_operator_editmesh;
ot->poll_property = transform_poll_property;
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
WM_operatortype_props_advanced_begin(ot);
Transform_Properties(ot, P_SNAP);
}
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
{
/* identifiers */

View File

@ -3,6 +3,10 @@ in vec4 finalColor;
out vec4 fragColor;
#endif
#if defined(VERT)
in float vertexCrease;
#endif
void main()
{
vec2 centered = gl_PointCoord - vec2(0.5);
@ -14,5 +18,14 @@ void main()
discard;
}
#if defined(VERT)
fragColor = finalColor;
float midStroke = 0.5 * rad_squared;
if (vertexCrease > 0.0 && dist_squared > midStroke) {
fragColor.rgb = mix(finalColor.rgb, colorEdgeCrease.rgb, vertexCrease);
}
#else
fragColor = finalColor;
#endif
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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) {

View File

@ -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,

View File

@ -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,

View File

@ -139,6 +139,10 @@ typedef enum CustomDataType {
CD_SHAPE_KEYINDEX = 27,
CD_SHAPEKEY = 28,
CD_BWEIGHT = 29,
/* Usage of CD_CREASE depends on where on the Mesh the layer is added:
* - for vertex creasing, this is persistent data accross all modes and is stored in the file,
* - for egde creasing, it is runtime data which is only used in edit-mode before being copied to
* MEdge when exiting edit-mode. */
CD_CREASE = 30,
CD_ORIGSPACE_MLOOP = 31,
CD_PREVIEW_MLOOPCOL = 32,

View File

@ -428,6 +428,7 @@ enum {
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
ME_CDFLAG_EDGE_CREASE = 1 << 2,
ME_CDFLAG_VERT_CREASE = 1 << 3,
};
/** #Mesh.remesh_mode */

View File

@ -984,6 +984,30 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* End skin vertices */
/* Vertex creases */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_crease, vdata, CD_CREASE)
static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type);
static char *rna_MeshVertexCreaseLayer_path(PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_creases", CD_CREASE);
}
static void rna_MeshVertexCreaseLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
rna_iterator_array_begin(iter, layer->data, sizeof(float), me->totvert, 0, NULL);
}
static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return me->totvert;
}
/* End vertex creases */
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
@ -1675,6 +1699,7 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
(void)rna_Mesh_face_map_active_index_set;
(void)rna_Mesh_face_map_active_index_get;
(void)rna_Mesh_face_map_active_set;
(void)rna_Mesh_vertex_crease_index_range;
/* end unused function block */
}
@ -2907,6 +2932,40 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_vertex_creases(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshVertexCreaseLayer", NULL);
RNA_def_struct_ui_text(srna, "Mesh Vertex Crease Layer", "Per-vertex crease");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshVertexCreaseLayer_path");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertexCrease");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_collection_funcs(prop,
"rna_MeshVertexCreaseLayer_data_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshVertexCreaseLayer_data_length",
NULL,
NULL,
NULL);
/* VertexCrease struct */
srna = RNA_def_struct(brna, "MeshVertexCrease", NULL);
RNA_def_struct_sdna(srna, "MFloatProperty");
RNA_def_struct_ui_text(srna, "Float Property", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f");
RNA_def_property_ui_text(prop, "Value", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
{
StructRNA *srna;
@ -3322,6 +3381,24 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_skin_vertices(brna, prop);
/* End skin vertices */
/* Vertex Crease */
prop = RNA_def_property(srna, "vertex_creases", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertexCreaseLayer");
RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
RNA_def_property_collection_funcs(prop,
"rna_Mesh_vertex_creases_begin",
NULL,
NULL,
NULL,
"rna_Mesh_vertex_creases_length",
NULL,
NULL,
NULL);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Vertex Creases", "Sharpness of the vertices");
rna_def_vertex_creases(brna);
/* End vertex crease */
/* Paint mask */
prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
@ -3519,6 +3596,10 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_BWEIGHT);
RNA_def_property_ui_text(prop, "Store Edge Bevel Weight", "");
prop = RNA_def_property(srna, "use_customdata_vertex_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_CREASE);
RNA_def_property_ui_text(prop, "Store Vertex Crease", "");
prop = RNA_def_property(srna, "use_customdata_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_CREASE);
RNA_def_property_ui_text(prop, "Store Edge Crease", "");

View File

@ -1741,7 +1741,7 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_UseCrease);
RNA_def_property_ui_text(
prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
prop, "Use Creases", "Use mesh crease information to sharpen edges or corners");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
@ -1956,7 +1956,7 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_UseCrease);
RNA_def_property_ui_text(
prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
prop, "Use Creases", "Use mesh crease information to sharpen edges or corners");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);

View File

@ -85,6 +85,9 @@ static void requiredDataMask(Object *UNUSED(ob),
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
}
if (smd->flags & eSubsurfModifierFlag_UseCrease) {
r_cddata_masks->vmask |= CD_MASK_CREASE;
}
}
static bool dependsOnNormals(ModifierData *md)