Sculpt: Data oriented refactor for cloth filter force calculation
Part of #118145.
This commit is contained in:
@@ -515,6 +515,46 @@ int vert_face_set_get(const SculptSession &ss, PBVHVertRef vertex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool vert_has_face_set(const GroupedSpan<int> vert_to_face_map,
|
||||
const int *face_sets,
|
||||
const int vert,
|
||||
const int face_set)
|
||||
{
|
||||
if (!face_sets) {
|
||||
return face_set == SCULPT_FACE_SET_NONE;
|
||||
}
|
||||
const Span<int> faces = vert_to_face_map[vert];
|
||||
return std::any_of(
|
||||
faces.begin(), faces.end(), [&](const int face) { return face_sets[face] == face_set; });
|
||||
}
|
||||
|
||||
bool vert_has_face_set(const SubdivCCG &subdiv_ccg,
|
||||
const int *face_sets,
|
||||
const int grid,
|
||||
const int face_set)
|
||||
{
|
||||
if (!face_sets) {
|
||||
return face_set == SCULPT_FACE_SET_NONE;
|
||||
}
|
||||
const int face = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid);
|
||||
return face_sets[face] == face_set;
|
||||
}
|
||||
|
||||
bool vert_has_face_set(const int face_set_offset, const BMVert &vert, const int face_set)
|
||||
{
|
||||
if (face_set_offset == -1) {
|
||||
return false;
|
||||
}
|
||||
BMIter iter;
|
||||
BMFace *face;
|
||||
BM_ITER_ELEM (face, &iter, &const_cast<BMVert &>(vert), BM_FACES_OF_VERT) {
|
||||
if (BM_ELEM_CD_GET_INT(face, face_set_offset) == face_set) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vert_has_face_set(const SculptSession &ss, PBVHVertRef vertex, int face_set)
|
||||
{
|
||||
switch (ss.pbvh->type()) {
|
||||
|
||||
@@ -769,7 +769,9 @@ static void calc_constraint_factors(const Object &object,
|
||||
tls.factors.resize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(mesh, verts, factors);
|
||||
auto_mask::calc_vert_factors(object, *automasking, *nodes[i], verts, factors);
|
||||
if (automasking) {
|
||||
auto_mask::calc_vert_factors(object, *automasking, *nodes[i], verts, factors);
|
||||
}
|
||||
if (ss.cache) {
|
||||
const MutableSpan positions = gather_data_mesh(init_positions, verts, tls.positions);
|
||||
calc_brush_simulation_falloff(
|
||||
@@ -791,7 +793,9 @@ static void calc_constraint_factors(const Object &object,
|
||||
tls.factors.resize(grid_verts_num);
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
|
||||
auto_mask::calc_grids_factors(object, *automasking, *nodes[i], grids, factors);
|
||||
if (automasking) {
|
||||
auto_mask::calc_grids_factors(object, *automasking, *nodes[i], grids, factors);
|
||||
}
|
||||
if (ss.cache) {
|
||||
tls.positions.resize(grid_verts_num);
|
||||
const MutableSpan<float3> positions = tls.positions;
|
||||
@@ -813,7 +817,9 @@ static void calc_constraint_factors(const Object &object,
|
||||
tls.factors.resize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(bm, verts, factors);
|
||||
auto_mask::calc_vert_factors(object, *automasking, *nodes[i], verts, factors);
|
||||
if (automasking) {
|
||||
auto_mask::calc_vert_factors(object, *automasking, *nodes[i], verts, factors);
|
||||
}
|
||||
if (ss.cache) {
|
||||
tls.positions.resize(verts.size());
|
||||
const MutableSpan<float3> positions = tls.positions;
|
||||
@@ -1485,107 +1491,283 @@ static void cloth_filter_apply_forces_to_vertices(const int v_index,
|
||||
cloth_brush_apply_force_to_vertex(*filter_cache.cloth_sim, final_force, v_index);
|
||||
}
|
||||
|
||||
static void cloth_filter_apply_forces_task(Object &ob,
|
||||
const Sculpt &sd,
|
||||
const ClothFilterType filter_type,
|
||||
const float filter_strength,
|
||||
bke::pbvh::Node *node)
|
||||
BLI_NOINLINE static void apply_gravity_to_verts(const float3 &gravity,
|
||||
const Span<int> verts,
|
||||
const Span<float> factors,
|
||||
filter::Cache &filter_cache)
|
||||
{
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
|
||||
SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
|
||||
|
||||
const bool is_deformation_filter = cloth_filter_is_deformation_filter(filter_type);
|
||||
|
||||
float3 sculpt_gravity(0.0f);
|
||||
if (sd.gravity_object) {
|
||||
sculpt_gravity = sd.gravity_object->object_to_world().ptr()[2];
|
||||
}
|
||||
else {
|
||||
sculpt_gravity[2] = -1.0f;
|
||||
}
|
||||
sculpt_gravity *= sd.gravity_factor * filter_strength;
|
||||
auto_mask::NodeData automask_data = auto_mask::node_begin(
|
||||
ob, auto_mask::active_cache_get(ss), *node);
|
||||
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (*ss.pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
auto_mask::node_update(automask_data, vd);
|
||||
|
||||
float fade = vd.mask;
|
||||
fade *= auto_mask::factor_get(
|
||||
ss.filter_cache->automasking.get(), ss, vd.vertex, &automask_data);
|
||||
fade = 1.0f - fade;
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
float3 force(0.0f);
|
||||
float3 disp, temp;
|
||||
|
||||
if (ss.filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
|
||||
if (!face_set::vert_has_face_set(ss, vd.vertex, ss.filter_cache->active_face_set)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (filter_type) {
|
||||
case ClothFilterType::Gravity:
|
||||
if (ss.filter_cache->orientation == filter::FilterOrientation::View) {
|
||||
/* When using the view orientation apply gravity in the -Y axis, this way objects will
|
||||
* fall down instead of backwards. */
|
||||
force[1] = -filter_strength * fade;
|
||||
}
|
||||
else {
|
||||
force[2] = -filter_strength * fade;
|
||||
}
|
||||
force = filter::to_object_space(*ss.filter_cache, force);
|
||||
break;
|
||||
case ClothFilterType::Inflate: {
|
||||
float3 normal = SCULPT_vertex_normal_get(ss, vd.vertex);
|
||||
force = normal * fade * filter_strength;
|
||||
break;
|
||||
}
|
||||
case ClothFilterType::Expand:
|
||||
cloth_sim.length_constraint_tweak[vd.index] += fade * filter_strength * 0.01f;
|
||||
force = float3(0);
|
||||
break;
|
||||
case ClothFilterType::Pinch:
|
||||
force = math::normalize(ss.filter_cache->cloth_sim_pinch_point - float3(vd.co));
|
||||
force *= fade * filter_strength;
|
||||
break;
|
||||
case ClothFilterType::Scale: {
|
||||
float3x3 transform = math::from_scale<float3x3>(float3(1.0f + fade * filter_strength));
|
||||
temp = cloth_sim.init_pos[vd.index];
|
||||
temp = transform * temp;
|
||||
disp = temp - cloth_sim.init_pos[vd.index];
|
||||
force = float3(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_deformation_filter) {
|
||||
cloth_filter_apply_displacement_to_deform_co(vd.index, disp, *ss.filter_cache);
|
||||
if (filter_cache.orientation == filter::FilterOrientation::View) {
|
||||
/* When using the view orientation apply gravity in the -Y axis, this way objects will
|
||||
* fall down instead of backwards. */
|
||||
force[1] = -factors[i];
|
||||
}
|
||||
else {
|
||||
cloth_filter_apply_forces_to_vertices(vd.index, force, sculpt_gravity, *ss.filter_cache);
|
||||
force[2] = -factors[i];
|
||||
}
|
||||
force = filter::to_object_space(filter_cache, force);
|
||||
cloth_filter_apply_forces_to_vertices(vert, force, gravity, filter_cache);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void apply_inflate_to_verts(const float3 &gravity,
|
||||
const Span<int> verts,
|
||||
const Span<float> factors,
|
||||
const Span<float3> normals,
|
||||
filter::Cache &filter_cache)
|
||||
{
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
const float3 force = normals[i] * factors[i];
|
||||
cloth_filter_apply_forces_to_vertices(vert, force, gravity, filter_cache);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void apply_expand_to_verts(const float3 &gravity,
|
||||
const Span<int> verts,
|
||||
const Span<float> factors,
|
||||
filter::Cache &filter_cache)
|
||||
{
|
||||
MutableSpan<float> length_constraint_tweak = filter_cache.cloth_sim->length_constraint_tweak;
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
length_constraint_tweak[vert] += factors[i] * 0.01f;
|
||||
cloth_filter_apply_forces_to_vertices(vert, float3(0), gravity, filter_cache);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void apply_pinch_to_verts(const float3 &gravity,
|
||||
const Span<int> verts,
|
||||
const Span<float> factors,
|
||||
const Span<float3> positions,
|
||||
filter::Cache &filter_cache)
|
||||
{
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
float3 force = math::normalize(filter_cache.cloth_sim_pinch_point - positions[i]);
|
||||
force *= factors[i];
|
||||
cloth_filter_apply_forces_to_vertices(vert, force, gravity, filter_cache);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void apply_scale_to_verts(const Span<int> verts,
|
||||
const Span<float> factors,
|
||||
filter::Cache &filter_cache)
|
||||
{
|
||||
MutableSpan<float3> init_pos = filter_cache.cloth_sim->init_pos;
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
float3x3 transform = math::from_scale<float3x3>(float3(1.0f + factors[i]));
|
||||
float3 disp = transform * init_pos[vert] - init_pos[vert];
|
||||
cloth_filter_apply_displacement_to_deform_co(vert, disp, filter_cache);
|
||||
}
|
||||
}
|
||||
|
||||
struct FilterLocalData {
|
||||
Vector<float> factors;
|
||||
Vector<int> vert_indices;
|
||||
Vector<float3> positions;
|
||||
Vector<float3> normals;
|
||||
};
|
||||
|
||||
static void apply_filter_forces_mesh(const ClothFilterType filter_type,
|
||||
const float filter_strength,
|
||||
const float3 &gravity,
|
||||
const Span<float3> positions_eval,
|
||||
const Span<float3> vert_normals,
|
||||
const bke::pbvh::Node &node,
|
||||
Object &object,
|
||||
FilterLocalData &tls)
|
||||
{
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
|
||||
tls.factors.resize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(mesh, verts, factors);
|
||||
if (const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss)) {
|
||||
auto_mask::calc_vert_factors(object, *automasking, node, verts, factors);
|
||||
}
|
||||
|
||||
if (ss.filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
if (!face_set::vert_has_face_set(
|
||||
ss.vert_to_face_map, ss.face_sets, vert, ss.filter_cache->active_face_set))
|
||||
{
|
||||
factors[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
scale_factors(factors, filter_strength);
|
||||
|
||||
switch (filter_type) {
|
||||
case ClothFilterType::Gravity:
|
||||
apply_gravity_to_verts(gravity, verts, factors, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Inflate:
|
||||
apply_inflate_to_verts(gravity,
|
||||
verts,
|
||||
factors,
|
||||
gather_data_mesh(vert_normals, verts, tls.normals),
|
||||
*ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Expand:
|
||||
apply_expand_to_verts(gravity, verts, factors, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Pinch:
|
||||
apply_pinch_to_verts(gravity,
|
||||
verts,
|
||||
factors,
|
||||
gather_data_mesh(positions_eval, verts, tls.positions),
|
||||
*ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Scale:
|
||||
apply_scale_to_verts(verts, factors, *ss.filter_cache);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_filter_forces_grids(const ClothFilterType filter_type,
|
||||
const float filter_strength,
|
||||
const float3 &gravity,
|
||||
const bke::pbvh::Node &node,
|
||||
Object &object,
|
||||
FilterLocalData &tls)
|
||||
{
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
|
||||
const Span<int> grids = bke::pbvh::node_grid_indices(node);
|
||||
const int grid_verts_num = grids.size() * key.grid_area;
|
||||
|
||||
tls.factors.resize(grid_verts_num);
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
|
||||
if (const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss)) {
|
||||
auto_mask::calc_grids_factors(object, *automasking, node, grids, factors);
|
||||
}
|
||||
|
||||
if (ss.filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
|
||||
for (const int i : grids.index_range()) {
|
||||
if (!face_set::vert_has_face_set(
|
||||
subdiv_ccg, ss.face_sets, grids[i], ss.filter_cache->active_face_set))
|
||||
{
|
||||
factors.slice(i * key.grid_area, key.grid_area).fill(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scale_factors(factors, filter_strength);
|
||||
|
||||
const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
|
||||
|
||||
switch (filter_type) {
|
||||
case ClothFilterType::Gravity:
|
||||
apply_gravity_to_verts(gravity, verts, factors, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Inflate:
|
||||
tls.normals.resize(grid_verts_num);
|
||||
gather_grids_normals(subdiv_ccg, grids, tls.normals);
|
||||
apply_inflate_to_verts(gravity, verts, factors, tls.normals, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Expand:
|
||||
apply_expand_to_verts(gravity, verts, factors, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Pinch: {
|
||||
apply_pinch_to_verts(gravity,
|
||||
verts,
|
||||
factors,
|
||||
gather_grids_positions(subdiv_ccg, grids, tls.positions),
|
||||
*ss.filter_cache);
|
||||
break;
|
||||
}
|
||||
case ClothFilterType::Scale:
|
||||
apply_scale_to_verts(verts, factors, *ss.filter_cache);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_filter_forces_bmesh(const ClothFilterType filter_type,
|
||||
const float filter_strength,
|
||||
const float3 &gravity,
|
||||
bke::pbvh::Node &node,
|
||||
Object &object,
|
||||
FilterLocalData &tls)
|
||||
{
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const BMesh &bm = *ss.bm;
|
||||
|
||||
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(&node);
|
||||
|
||||
tls.factors.resize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(bm, verts, factors);
|
||||
if (const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss)) {
|
||||
auto_mask::calc_vert_factors(object, *automasking, node, verts, factors);
|
||||
}
|
||||
|
||||
if (ss.filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
|
||||
const int face_set_offset = CustomData_get_offset_named(
|
||||
&bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
int i = 0;
|
||||
for (const BMVert *vert : verts) {
|
||||
if (!face_set::vert_has_face_set(face_set_offset, *vert, ss.filter_cache->active_face_set)) {
|
||||
factors[i] = 0.0f;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
scale_factors(factors, filter_strength);
|
||||
|
||||
const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
|
||||
|
||||
switch (filter_type) {
|
||||
case ClothFilterType::Gravity:
|
||||
apply_gravity_to_verts(gravity, vert_indices, factors, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Inflate:
|
||||
tls.normals.resize(verts.size());
|
||||
gather_bmesh_normals(verts, tls.normals);
|
||||
apply_inflate_to_verts(gravity, vert_indices, factors, tls.normals, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Expand:
|
||||
apply_expand_to_verts(gravity, vert_indices, factors, *ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Pinch:
|
||||
apply_pinch_to_verts(gravity,
|
||||
vert_indices,
|
||||
factors,
|
||||
gather_bmesh_positions(verts, tls.positions),
|
||||
*ss.filter_cache);
|
||||
break;
|
||||
case ClothFilterType::Scale:
|
||||
apply_scale_to_verts(vert_indices, factors, *ss.filter_cache);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Object &ob = *CTX_data_active_object(C);
|
||||
Object &object = *CTX_data_active_object(C);
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
|
||||
int filter_type = RNA_enum_get(op->ptr, "type");
|
||||
const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
|
||||
float filter_strength = RNA_float_get(op->ptr, "strength");
|
||||
|
||||
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
|
||||
MEM_delete(ss.filter_cache);
|
||||
ss.filter_cache = nullptr;
|
||||
undo::push_end(ob);
|
||||
flush_update_done(C, ob, UpdateType::Position);
|
||||
undo::push_end(object);
|
||||
flush_update_done(C, object, UpdateType::Position);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1598,28 +1780,68 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
|
||||
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, &ob, false);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, &object, false);
|
||||
|
||||
brush_store_simulation_state(ss, *ss.filter_cache->cloth_sim);
|
||||
|
||||
const Span<bke::pbvh::Node *> nodes = ss.filter_cache->nodes;
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
cloth_filter_apply_forces_task(
|
||||
ob, sd, ClothFilterType(filter_type), filter_strength, nodes[i]);
|
||||
float3 gravity(0.0f);
|
||||
if (sd.gravity_object) {
|
||||
gravity = sd.gravity_object->object_to_world().ptr()[2];
|
||||
}
|
||||
else {
|
||||
gravity[2] = -1.0f;
|
||||
}
|
||||
gravity *= sd.gravity_factor * filter_strength;
|
||||
|
||||
threading::EnumerableThreadSpecific<FilterLocalData> all_tls;
|
||||
switch (ss.pbvh->type()) {
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
const bke::pbvh::Tree &pbvh = *ss.pbvh;
|
||||
const Span<float3> positions_eval = BKE_pbvh_get_vert_positions(pbvh);
|
||||
const Span<float3> vert_normals = BKE_pbvh_get_vert_normals(pbvh);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
FilterLocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
apply_filter_forces_mesh(filter_type,
|
||||
filter_strength,
|
||||
gravity,
|
||||
positions_eval,
|
||||
vert_normals,
|
||||
*nodes[i],
|
||||
object,
|
||||
tls);
|
||||
BKE_pbvh_node_mark_positions_update(nodes[i]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
case bke::pbvh::Type::Grids:
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
FilterLocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
apply_filter_forces_grids(filter_type, filter_strength, gravity, *nodes[i], object, tls);
|
||||
BKE_pbvh_node_mark_positions_update(nodes[i]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case bke::pbvh::Type::BMesh:
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
FilterLocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
apply_filter_forces_bmesh(filter_type, filter_strength, gravity, *nodes[i], object, tls);
|
||||
BKE_pbvh_node_mark_positions_update(nodes[i]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
/* Activate all nodes. */
|
||||
sim_activate_nodes(*ss.filter_cache->cloth_sim, nodes);
|
||||
|
||||
/* Update and write the simulation to the nodes. */
|
||||
do_simulation_step(sd, ob, *ss.filter_cache->cloth_sim, nodes);
|
||||
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
}
|
||||
do_simulation_step(sd, object, *ss.filter_cache->cloth_sim, nodes);
|
||||
|
||||
flush_update_step(C, UpdateType::Position);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
|
||||
@@ -967,6 +967,15 @@ int active_face_set_get(const SculptSession &ss);
|
||||
int vert_face_set_get(const SculptSession &ss, PBVHVertRef vertex);
|
||||
|
||||
bool vert_has_face_set(const SculptSession &ss, PBVHVertRef vertex, int face_set);
|
||||
bool vert_has_face_set(const GroupedSpan<int> vert_to_face_map,
|
||||
const int *face_sets,
|
||||
const int vert,
|
||||
const int face_set);
|
||||
bool vert_has_face_set(const SubdivCCG &subdiv_ccg,
|
||||
const int *face_sets,
|
||||
const int grid,
|
||||
const int face_set);
|
||||
bool vert_has_face_set(const int face_set_offset, const BMVert &vert, const int face_set);
|
||||
bool vert_has_unique_face_set(const SculptSession &ss, PBVHVertRef vertex);
|
||||
bool vert_has_unique_face_set(const GroupedSpan<int> vert_to_face_map,
|
||||
const int *face_sets,
|
||||
|
||||
Reference in New Issue
Block a user