45 defgroups.
add(dg->name);
52 for (; md; md = md->
next) {
69 if (defgroups.
contains(channel->name)) {
70 bone_deformed_vgroups.
add(channel->name);
75 return bone_deformed_vgroups;
83 const int vertex_groups_num,
84 const Span<bool> vertex_group_is_bone_deformed,
85 const FunctionRef<
bool(
int)> vertex_group_is_locked)
93 float sum_weights_total = 0.0f;
94 float sum_weights_locked = 0.0f;
95 float sum_weights_unlocked = 0.0f;
102 if (dw.
def_nr >= vertex_groups_num || !vertex_group_is_bone_deformed[dw.
def_nr] ||
108 sum_weights_total += dw.
weight;
110 if (vertex_group_is_locked(dw.
def_nr)) {
112 sum_weights_locked += dw.
weight;
116 sum_weights_unlocked += dw.
weight;
121 if (sum_weights_total == 1.0f) {
126 if (unlocked_num == 0) {
128 return (locked_num == 1);
137 if (dw.
def_nr < vertex_groups_num && vertex_group_is_bone_deformed[dw.
def_nr] &&
138 !vertex_group_is_locked(dw.
def_nr))
144 return (sum_weights_locked == 1.0f);
149 if (sum_weights_unlocked != 0.0f) {
150 const float normalize_factor = (1.0f - sum_weights_locked) / sum_weights_unlocked;
154 if (dw.
def_nr < vertex_groups_num && vertex_group_is_bone_deformed[dw.
def_nr] &&
155 dw.
weight > FLT_EPSILON && !vertex_group_is_locked(dw.
def_nr))
166 (1.0f - sum_weights_locked) / unlocked_num, 0.0f, 1.0f);
170 if (dw.
def_nr < vertex_groups_num && vertex_group_is_bone_deformed[dw.
def_nr] &&
171 dw.
weight > FLT_EPSILON && !vertex_group_is_locked(dw.
def_nr))
173 dw.
weight = weight_remainder;
181 const int active_vertex_group,
183 const Span<bool> vertex_group_is_bone_deformed)
187 const auto active_vertex_group_is_locked = [&](
const int vertex_group_index) {
188 return vertex_group_is_locked[vertex_group_index] || vertex_group_index == active_vertex_group;
191 vertex_group_is_locked.
size(),
192 vertex_group_is_bone_deformed,
193 active_vertex_group_is_locked);
200 const auto active_vertex_group_is_unlocked = [&](
const int vertex_group_index) {
201 return vertex_group_is_locked[vertex_group_index];
204 vertex_group_is_locked.
size(),
205 vertex_group_is_bone_deformed,
206 active_vertex_group_is_unlocked);
214 if (bone !=
nullptr) {
216 count += bone_callback(ob, bone) ? 1 : 0;
240 object, armature, [&](
Object &
object,
const Bone *bone) {
243 if (!BKE_object_defgroup_find_name(&object, bone->name)) {
245 BKE_object_defgroup_add_name(&object, bone->name);
252 return added_vertex_groups > 0;
261 object, armature, [&](
Object &
object,
const Bone *bone) {
264 bDeformGroup *dg = BKE_object_defgroup_find_name(&object, bone->name);
267 dg = BKE_object_defgroup_add_name(&object, bone->name);
269 r_deform_group_names.
append(dg->name);
270 r_skinnable_bones.
append(bone);
276 if (added_vertex_groups <= 0) {
288 for (const int i : range) {
289 const Bone *bone = bones[i];
290 roots[i] = math::transform_point(transform, float3(bone->arm_head));
291 tips[i] = math::transform_point(transform, float3(bone->arm_tail));
302 bDeformGroup *defgroup = MEM_cnew<bDeformGroup>(__func__);
303 name.copy(defgroup->
name);
317 const float4x4 armature_to_world = ob_armature.object_to_world();
323 armature,
object, skinnable_bones, deform_group_names))
338 const float4x4 layer_to_world = layer.to_world_space(
object);
344 threading::parallel_for(positions.index_range(), 4096, [&](
const IndexRange range) {
345 for (const int i : range) {
346 positions[i] = math::transform_point(layer_to_world, src_positions[i]);
350 for (
const int bone_i : skinnable_bones.
index_range()) {
351 const Bone *bone = skinnable_bones[bone_i];
352 const char *deform_group_name = deform_group_names[bone_i].c_str();
353 const float3 bone_root = roots[bone_i];
354 const float3 bone_tip = tips[bone_i];
360 for (
const int point_i : curves.points_range()) {
367 if (weight != 0.0f) {
368 weights.
set(point_i, weight);
380 const float4x4 armature_to_world = ob_armature.object_to_world();
382 const float default_ratio = 0.1f;
383 const float default_decay = 0.8f;
388 armature,
object, skinnable_bones, deform_group_names))
400 const auto get_weight = [](
const float dist,
const float decay_rad,
const float diff_rad) {
401 return (dist < decay_rad) ? 1.0f :
409 const float4x4 layer_to_world = layer.to_world_space(
object);
415 threading::parallel_for(positions.index_range(), 4096, [&](
const IndexRange range) {
416 for (const int i : range) {
417 positions[i] = math::transform_point(layer_to_world, src_positions[i]);
421 for (
const int bone_i : skinnable_bones.
index_range()) {
422 const char *deform_group_name = deform_group_names[bone_i].c_str();
423 const float3 bone_root = roots[bone_i];
424 const float3 bone_tip = tips[bone_i];
427 const float decay_rad = radius_squared - (radius_squared * default_decay);
428 const float diff_rad = radius_squared - decay_rad;
434 for (
const int point_i : curves.points_range()) {
435 const float3 position = positions[point_i];
437 const float weight = (dist_to_bone > radius_squared) ?
439 get_weight(dist_to_bone, decay_rad, diff_rad);
440 if (weight != 0.0f) {
441 weights.
set(point_i, weight);
461 if (object_defgroup_nr == -1) {
479 for (
const int i :
range) {
486 if (drawing_defgroup_nr == -1) {
492 bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
497 if (points.is_empty()) {
500 const float4x4 layer_to_world = layer.to_world_space(*ob_eval);
504 std::optional<ed::curves::FindClosestData> new_closest_elem =
505 ed::curves::closest_elem_find_screen_space(vc,
506 curves.points_by_curve(),
507 deformation.positions,
511 bke::AttrDomain::Point,
514 if (new_closest_elem) {
515 new_closest.
elem = *new_closest_elem;
523 return (a.elem.distance <
b.elem.distance) ? a :
b;
526 if (!closest.drawing) {
531 const VArray<float> point_weights = bke::varray_for_deform_verts(
532 closest.drawing->strokes().deform_verts(), closest.active_defgroup_index);
533 const float new_weight =
math::clamp(point_weights[closest.elem.index], 0.0f, 1.0f);
549 ot->
name =
"Weight Paint Sample Weight";
550 ot->
idname =
"GREASE_PENCIL_OT_weight_sample";
552 "Set the weight of the Draw tool to the weight of the vertex under the mouse cursor";
584 if (paint ==
nullptr) {
588 if (brush ==
nullptr) {
597 ot->
name =
"Weight Paint Toggle Direction";
598 ot->
idname =
"GREASE_PENCIL_OT_weight_toggle_direction";
599 ot->
description =
"Toggle Add/Subtract for the weight paint draw tool";
617 if (active_index == -1) {
635 active_defgroup->
name);
636 if (drawing_vgroup_index == -1) {
641 curves.deform_verts_for_write(), drawing_vgroup_index);
642 if (weights.
size() == 0) {
647 const float invert_weight = 1.0f - weights[i];
648 weights.
set(i, invert_weight);
674 ot->
name =
"Invert Weight";
675 ot->
idname =
"GREASE_PENCIL_OT_weight_invert";
676 ot->
description =
"Invert the weight of active vertex group";
691 if (object_defgroup_nr == -1) {
710 for (const int drawing : drawing_range) {
711 bke::CurvesGeometry &curves = drawings[drawing].drawing.strokes_for_write();
712 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
715 if (!attributes.contains(object_defgroup->name)) {
719 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(
720 object_defgroup->name);
721 geometry::smooth_curve_attribute(curves.curves_range(),
722 curves.points_by_curve(),
723 VArray<bool>::ForSingle(true, curves.points_num()),
743 ot->
name =
"Smooth Vertex Group";
744 ot->
idname =
"GREASE_PENCIL_OT_vertex_group_smooth";
745 ot->
description =
"Smooth the weights of the active vertex group";
764 if (object_defgroup_nr == -1) {
781 bool changed =
false;
782 for (
const int frame_i : drawings_per_frame.
index_range()) {
785 const float max_weight_in_frame = threading::parallel_reduce(
789 [&](
const IndexRange drawing_range,
const float &drawing_weight_init) {
790 float max_weight_in_drawing = drawing_weight_init;
791 for (const int drawing_i : drawing_range) {
792 const bke::CurvesGeometry &curves = drawings[drawing_i].drawing.strokes();
793 const bke::AttributeAccessor attributes = curves.attributes();
796 if (!attributes.contains(object_defgroup->name)) {
801 const VArray<float> weights = *curves.attributes().lookup_or_default<float>(
802 object_defgroup->name, bke::AttrDomain::Point, 0.0f);
803 const float max_weight_in_points = threading::parallel_reduce(
804 weights.index_range(),
806 max_weight_in_drawing,
807 [&](const IndexRange point_range, const float &init) {
808 float max_weight = init;
809 for (const int point_i : point_range) {
810 max_weight = math::max(max_weight, weights[point_i]);
814 [](const float a, const float b) { return math::max(a, b); });
815 max_weight_in_drawing = math::max(max_weight_in_drawing, max_weight_in_points);
817 return max_weight_in_drawing;
819 [](
const float a,
const float b) {
return math::max(a,
b); });
821 if (
ELEM(max_weight_in_frame, 0.0f, 1.0f)) {
828 threading::parallel_for(drawings.index_range(), 1, [&](
const IndexRange drawing_range) {
829 for (const int drawing_i : drawing_range) {
830 bke::CurvesGeometry &curves = drawings[drawing_i].drawing.strokes_for_write();
831 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
834 if (!attributes.contains(object_defgroup->name)) {
838 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(
839 object_defgroup->name);
840 threading::parallel_for(
841 weights.span.index_range(), 1024, [&](const IndexRange point_range) {
842 for (const int point_i : point_range) {
843 weights.span[point_i] /= max_weight_in_frame;
862 ot->
name =
"Normalize Vertex Group";
863 ot->
idname =
"GREASE_PENCIL_OT_vertex_group_normalize";
864 ot->
description =
"Normalize weights of the active vertex group";
887 object_locked_defgroups.
add(dg->name);
899 for (const int drawing_i : drawing_range) {
900 bke::CurvesGeometry &curves = drawings[drawing_i].drawing.strokes_for_write();
903 int active_vertex_group = -1;
904 if (object_defgroup && lock_active_group) {
905 active_vertex_group = BKE_defgroup_name_index(&curves.vertex_group_names,
906 object_defgroup->name);
910 Vector<bool> vertex_group_is_locked;
911 Vector<bool> vertex_group_is_included;
912 LISTBASE_FOREACH (bDeformGroup *, dg, &curves.vertex_group_names) {
913 vertex_group_is_locked.append(object_locked_defgroups.contains(dg->name));
915 vertex_group_is_included.append(true);
920 MutableSpan<MDeformVert> deform_verts = curves.deform_verts_for_write();
921 threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange point_range) {
922 for (const int point_i : point_range) {
923 normalize_vertex_weights(deform_verts[point_i],
925 vertex_group_is_locked,
926 vertex_group_is_included);
941 ot->
name =
"Normalize All Vertex Groups";
942 ot->
idname =
"GREASE_PENCIL_OT_vertex_group_normalize_all";
944 "Normalize the weights of all vertex groups, so that for each vertex, the sum of all "
959 "Keep the values of the active group while normalizing others");
float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
void BKE_brush_weight_set(const Scene *scene, Brush *brush, float value)
void BKE_brush_tag_unsaved_changes(Brush *brush)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Low-level operations for grease pencil.
ModifierData * BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *data)
Paint * BKE_paint_get_active_from_context(const bContext *C)
Brush * BKE_paint_brush(Paint *paint)
void BKE_report(ReportList *reports, eReportType type, const char *message)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
float mat4_to_scale(const float mat[4][4])
void DEG_id_tag_update(ID *id, unsigned int flags)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ GPWEIGHT_BRUSH_TYPE_DRAW
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
blender::float4x4 ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, const blender::float4x4 &obmat)
@ OPTYPE_DEPENDS_ON_CURSOR
MutableSpan< T > as_mutable_span()
IndexRange index_range() const
bool contains(const Key &key) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
IndexRange index_range() const
void set(const int64_t index, T value)
void append(const T &value)
IndexRange index_range() const
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
void ED_operatortypes_grease_pencil_weight_paint()
static bool normalize_vertex_weights_try(MDeformVert &dvert, const int vertex_groups_num, const Span< bool > vertex_group_is_bone_deformed, const FunctionRef< bool(int)> vertex_group_is_locked)
static int toggle_weight_tool_direction(bContext *C, wmOperator *)
static int vertex_group_normalize_exec(bContext *C, wmOperator *op)
Set< std::string > get_bone_deformed_vertex_group_names(const Object &object)
static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
static int foreach_bone_in_armature(Object &ob, const bArmature &armature, const FunctionRef< bool(Object &, const Bone *)> bone_callback)
static void GREASE_PENCIL_OT_vertex_group_normalize(wmOperatorType *ot)
static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
void add_armature_automatic_weights(Scene &scene, Object &object, const Object &ob_armature)
IndexMask retrieve_visible_points(Object &object, const bke::greasepencil::Drawing &drawing, IndexMaskMemory &memory)
Vector< DrawingInfo > retrieve_visible_drawings(const Scene &scene, const GreasePencil &grease_pencil, const bool do_onion_skinning)
static bool toggle_weight_tool_direction_poll(bContext *C)
static void GREASE_PENCIL_OT_weight_sample(wmOperatorType *ot)
void normalize_vertex_weights(MDeformVert &dvert, const int active_vertex_group, const Span< bool > vertex_group_is_locked, const Span< bool > vertex_group_is_bone_deformed)
static void GREASE_PENCIL_OT_vertex_group_normalize_all(wmOperatorType *ot)
static void GREASE_PENCIL_OT_weight_invert(wmOperatorType *ot)
static void GREASE_PENCIL_OT_weight_toggle_direction(wmOperatorType *ot)
void add_armature_envelope_weights(Scene &scene, Object &object, const Object &ob_armature)
bool grease_pencil_weight_painting_poll(bContext *C)
bool add_armature_vertex_groups(Object &object, const Object &ob_armature)
static int grease_pencil_weight_invert_exec(bContext *C, wmOperator *op)
Vector< MutableDrawingInfo > retrieve_editable_drawings(const Scene &scene, GreasePencil &grease_pencil)
static int foreach_bone_in_armature_ex(Object &ob, const Bone *bone, const FunctionRef< bool(Object &, const Bone *)> bone_callback)
static bool get_skinnable_bones_and_deform_group_names(const bArmature &armature, Object &object, Vector< const Bone * > &r_skinnable_bones, Vector< std::string > &r_deform_group_names)
Array< Vector< MutableDrawingInfo > > retrieve_editable_drawings_grouped_per_frame(const Scene &scene, GreasePencil &grease_pencil)
static void get_root_and_tips_of_bones(Span< const Bone * > bones, const float4x4 &transform, MutableSpan< float3 > roots, MutableSpan< float3 > tips)
static bool grease_pencil_vertex_group_weight_poll(bContext *C)
static int lookup_or_add_deform_group_index(CurvesGeometry &curves, const StringRef name)
T clamp(const T &a, const T &min, const T &max)
T interpolate(const T &a, const T &b, const FactorT &t)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T max(const T &a, const T &b)
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
char gpencil_weight_brush_type
blender::ed::curves::FindClosestData elem
blender::bke::greasepencil::Drawing * drawing
ListBase vertex_group_names
struct ModifierData * next
struct ToolSettings * toolsettings
const c_style_mat & ptr() const
int active_defgroup_index
ed::curves::FindClosestData elem
const bke::greasepencil::Drawing * drawing
const bke::greasepencil::Drawing & drawing
bke::greasepencil::Drawing & drawing
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
struct ReportList * reports
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))