46 defgroups.
add(dg->name);
53 for (; md; md = md->
next) {
71 if (defgroups.
contains(channel->name)) {
72 bone_deformed_vgroups.
add(channel->name);
77 return bone_deformed_vgroups;
85 const int vertex_groups_num,
86 const Span<bool> vertex_group_is_bone_deformed,
87 const FunctionRef<
bool(
int)> vertex_group_is_locked)
95 float sum_weights_total = 0.0f;
96 float sum_weights_locked = 0.0f;
97 float sum_weights_unlocked = 0.0f;
104 if (dw.
def_nr >= vertex_groups_num || !vertex_group_is_bone_deformed[dw.
def_nr] ||
110 sum_weights_total += dw.
weight;
112 if (vertex_group_is_locked(dw.
def_nr)) {
114 sum_weights_locked += dw.
weight;
118 sum_weights_unlocked += dw.
weight;
123 if (sum_weights_total == 1.0f) {
128 if (unlocked_num == 0) {
130 return (locked_num == 1);
139 if (dw.
def_nr < vertex_groups_num && vertex_group_is_bone_deformed[dw.
def_nr] &&
140 !vertex_group_is_locked(dw.
def_nr))
146 return (sum_weights_locked == 1.0f);
151 if (sum_weights_unlocked != 0.0f) {
152 const float normalize_factor = (1.0f - sum_weights_locked) / sum_weights_unlocked;
156 if (dw.
def_nr < vertex_groups_num && vertex_group_is_bone_deformed[dw.
def_nr] &&
157 dw.
weight > FLT_EPSILON && !vertex_group_is_locked(dw.
def_nr))
168 (1.0f - sum_weights_locked) / unlocked_num, 0.0f, 1.0f);
172 if (dw.
def_nr < vertex_groups_num && vertex_group_is_bone_deformed[dw.
def_nr] &&
173 dw.
weight > FLT_EPSILON && !vertex_group_is_locked(dw.
def_nr))
175 dw.
weight = weight_remainder;
183 const int active_vertex_group,
185 const Span<bool> vertex_group_is_bone_deformed)
189 const auto active_vertex_group_is_locked = [&](
const int vertex_group_index) {
190 return vertex_group_is_locked[vertex_group_index] || vertex_group_index == active_vertex_group;
193 vertex_group_is_locked.
size(),
194 vertex_group_is_bone_deformed,
195 active_vertex_group_is_locked);
202 const auto active_vertex_group_is_unlocked = [&](
const int vertex_group_index) {
203 return vertex_group_is_locked[vertex_group_index];
206 vertex_group_is_locked.
size(),
207 vertex_group_is_bone_deformed,
208 active_vertex_group_is_unlocked);
216 if (bone !=
nullptr) {
218 count += bone_callback(ob, bone) ? 1 : 0;
242 object, armature, [&](
Object &
object,
const Bone *bone) {
254 return added_vertex_groups > 0;
263 object, armature, [&](
Object &
object,
const Bone *bone) {
272 r_skinnable_bones.
append(bone);
278 if (added_vertex_groups <= 0) {
290 for (const int i : range) {
291 const Bone *bone = bones[i];
292 roots[i] = math::transform_point(transform, float3(bone->arm_head));
293 tips[i] = math::transform_point(transform, float3(bone->arm_tail));
305 name.copy_utf8_truncated(defgroup->
name);
319 const float4x4 armature_to_world = ob_armature.object_to_world();
325 armature,
object, skinnable_bones, deform_group_names))
348 for (
const int bone_i : skinnable_bones.
index_range()) {
349 const Bone *bone = skinnable_bones[bone_i];
350 const char *deform_group_name = deform_group_names[bone_i].c_str();
351 const float3 bone_root = roots[bone_i];
352 const float3 bone_tip = tips[bone_i];
358 for (
const int point_i :
curves.points_range()) {
365 if (weight != 0.0f) {
366 weights.
set(point_i, weight);
378 const float4x4 armature_to_world = ob_armature.object_to_world();
380 const float default_ratio = 0.1f;
381 const float default_decay = 0.8f;
386 armature,
object, skinnable_bones, deform_group_names))
398 const auto get_weight = [](
const float dist,
const float decay_rad,
const float diff_rad) {
399 return (dist < decay_rad) ? 1.0f :
415 for (
const int bone_i : skinnable_bones.
index_range()) {
416 const char *deform_group_name = deform_group_names[bone_i].c_str();
417 const float3 bone_root = roots[bone_i];
418 const float3 bone_tip = tips[bone_i];
421 const float decay_rad = radius_squared - (radius_squared * default_decay);
422 const float diff_rad = radius_squared - decay_rad;
428 for (
const int point_i :
curves.points_range()) {
429 const float3 position = positions[point_i];
431 const float weight = (dist_to_bone > radius_squared) ?
433 get_weight(dist_to_bone, decay_rad, diff_rad);
434 if (weight != 0.0f) {
435 weights.
set(point_i, weight);
457 if (object_defgroup_nr == -1) {
475 for (
const int i : range) {
482 if (drawing_defgroup_nr == -1) {
500 std::optional<ed::curves::FindClosestData> new_closest_elem =
510 if (new_closest_elem) {
511 new_closest.
elem = *new_closest_elem;
528 closest.drawing->strokes().deform_verts(),
closest.active_defgroup_index);
545 ot->name =
"Weight Paint Sample Weight";
546 ot->idname =
"GREASE_PENCIL_OT_weight_sample";
548 "Set the weight of the Draw tool to the weight of the vertex under the mouse cursor";
580 if (paint ==
nullptr) {
584 if (brush ==
nullptr) {
593 ot->name =
"Weight Paint Toggle Direction";
594 ot->idname =
"GREASE_PENCIL_OT_weight_toggle_direction";
595 ot->description =
"Toggle Add/Subtract for the weight paint draw tool";
613 if (active_index == -1) {
631 active_defgroup->
name);
632 if (drawing_vgroup_index == -1) {
637 curves.deform_verts_for_write(), drawing_vgroup_index);
638 if (weights.
size() == 0) {
643 const float invert_weight = 1.0f - weights[
i];
644 weights.
set(
i, invert_weight);
670 ot->name =
"Invert Weight";
671 ot->idname =
"GREASE_PENCIL_OT_weight_invert";
672 ot->description =
"Invert the weight of active vertex group";
687 if (object_defgroup_nr == -1) {
706 for (const int drawing : drawing_range) {
707 bke::CurvesGeometry &curves = drawings[drawing].drawing.strokes_for_write();
708 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
711 if (!attributes.contains(object_defgroup->name)) {
715 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(
716 object_defgroup->name);
717 geometry::smooth_curve_attribute(curves.curves_range(),
718 curves.points_by_curve(),
719 VArray<bool>::from_single(true, curves.points_num()),
739 ot->name =
"Smooth Vertex Group";
740 ot->idname =
"GREASE_PENCIL_OT_vertex_group_smooth";
741 ot->description =
"Smooth the weights of the active vertex group";
751 RNA_def_float(
ot->srna,
"factor", 0.5f, 0.0f, 1.0,
"Factor",
"", 0.0f, 1.0f);
752 RNA_def_int(
ot->srna,
"repeat", 1, 1, 10000,
"Iterations",
"", 1, 200);
760 if (object_defgroup_nr == -1) {
777 bool changed =
false;
778 for (
const int frame_i : drawings_per_frame.
index_range()) {
785 [&](
const IndexRange drawing_range,
const float &drawing_weight_init) {
786 float max_weight_in_drawing = drawing_weight_init;
787 for (const int drawing_i : drawing_range) {
788 const bke::CurvesGeometry &curves = drawings[drawing_i].drawing.strokes();
789 const bke::AttributeAccessor attributes = curves.attributes();
792 if (!attributes.contains(object_defgroup->name)) {
797 const VArray<float> weights = *curves.attributes().lookup_or_default<float>(
798 object_defgroup->name, bke::AttrDomain::Point, 0.0f);
799 const float max_weight_in_points = threading::parallel_reduce(
800 weights.index_range(),
802 max_weight_in_drawing,
803 [&](const IndexRange point_range, const float &init) {
804 float max_weight = init;
805 for (const int point_i : point_range) {
806 max_weight = math::max(max_weight, weights[point_i]);
810 [](const float a, const float b) { return math::max(a, b); });
811 max_weight_in_drawing = math::max(max_weight_in_drawing, max_weight_in_points);
813 return max_weight_in_drawing;
815 [](
const float a,
const float b) {
return math::max(a,
b); });
817 if (
ELEM(max_weight_in_frame, 0.0f, 1.0f)) {
825 for (const int drawing_i : drawing_range) {
826 bke::CurvesGeometry &curves = drawings[drawing_i].drawing.strokes_for_write();
827 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
830 if (!attributes.contains(object_defgroup->name)) {
834 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(
835 object_defgroup->name);
836 threading::parallel_for(
837 weights.span.index_range(), 1024, [&](const IndexRange point_range) {
838 for (const int point_i : point_range) {
839 weights.span[point_i] /= max_weight_in_frame;
858 ot->name =
"Normalize Vertex Group";
859 ot->idname =
"GREASE_PENCIL_OT_vertex_group_normalize";
860 ot->description =
"Normalize weights of the active vertex group";
883 object_locked_defgroups.
add(dg->name);
895 for (const int drawing_i : drawing_range) {
896 bke::CurvesGeometry &curves = drawings[drawing_i].drawing.strokes_for_write();
899 int active_vertex_group = -1;
900 if (object_defgroup && lock_active_group) {
901 active_vertex_group = BKE_defgroup_name_index(&curves.vertex_group_names,
902 object_defgroup->name);
906 Vector<bool> vertex_group_is_locked;
907 Vector<bool> vertex_group_is_included;
908 LISTBASE_FOREACH (bDeformGroup *, dg, &curves.vertex_group_names) {
909 vertex_group_is_locked.append(object_locked_defgroups.contains(dg->name));
911 vertex_group_is_included.append(true);
916 MutableSpan<MDeformVert> deform_verts = curves.deform_verts_for_write();
917 threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange point_range) {
918 for (const int point_i : point_range) {
919 normalize_vertex_weights(deform_verts[point_i],
921 vertex_group_is_locked,
922 vertex_group_is_included);
937 ot->name =
"Normalize All Vertex Groups";
938 ot->idname =
"GREASE_PENCIL_OT_vertex_group_normalize_all";
940 "Normalize the weights of all vertex groups, so that for each vertex, the sum of all "
955 "Keep the values of the active group while normalizing others");
float distfactor_to_bone(const blender::float3 &position, const blender::float3 &head, const blender::float3 &tail, float radius_head, float radius_tail, float falloff_distance)
void BKE_brush_weight_set(Paint *paint, 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)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
int BLI_listbase_count(const 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)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ GPWEIGHT_BRUSH_TYPE_DRAW
@ eModifierType_GreasePencilArmature
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
BPy_StructRNA * depsgraph
bool closest(btVector3 &v)
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
float4x4 to_world_space(const Object &object) const
void ED_operatortypes_grease_pencil_weight_paint()
void * MEM_callocN(size_t len, const char *str)
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval, const Object &ob_orig, const bke::greasepencil::Drawing &drawing_orig)
VMutableArray< float > varray_for_mutable_deform_verts(MutableSpan< MDeformVert > dverts, int defgroup_index)
VArray< float > varray_for_deform_verts(Span< MDeformVert > dverts, int defgroup_index)
std::optional< FindClosestData > closest_elem_find_screen_space(const ViewContext &vc, const OffsetIndices< int > points_by_curve, const Span< float3 > positions, const VArray< bool > &cyclic, const float4x4 &projection, const IndexMask &mask, const bke::AttrDomain domain, const int2 coord, const FindClosestData &initial_closest)
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 wmOperatorStatus grease_pencil_weight_invert_exec(bContext *C, wmOperator *op)
Set< std::string > get_bone_deformed_vertex_group_names(const Object &object)
static wmOperatorStatus 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)
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 wmOperatorStatus vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
static bool toggle_weight_tool_direction_poll(bContext *C)
static wmOperatorStatus vertex_group_normalize_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus toggle_weight_tool_direction_exec(bContext *C, wmOperator *)
static void GREASE_PENCIL_OT_weight_toggle_direction(wmOperatorType *ot)
static wmOperatorStatus weight_sample_invoke(bContext *C, wmOperator *, const wmEvent *event)
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)
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)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
void parallel_for_each(Range &&range, const Function &function)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
static void init(bNodeTree *, bNode *node)
static wmOperatorStatus 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
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
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 *))