1
$\begingroup$

I have an idea how to get a faster workflow when assigning weights in edit mode, and would like to know how hard this would be to make in python as an addon:

Before: I'm manually setting weights using this method:

  1. Select one or more vertices
  2. Select a vertex group
  3. Choose a weight, by entering 0.2 and pressing enter
  4. Click Assign

If I'm not happy with it, repeat 3-4 until I'm happy. This can be quite cumbersome and a lot of clicking and typing.

After: With my addon, it would be one less step, like this:

  1. Select one or more vertices
  2. Select a vertex group
  3. Click 20 - And 0.2 is assigned in one click

If I'm not happy with it, I just click another value. It would save a lot of time for me.

And as an extra bonus, if this is possible, there is also a Liveweight slider, that updates the vertex group as I drag the slider, and I see the result right away. Pretty much like the Vertex weights in the Properties panel, but this affects all selected vertices.

Would this be possible, and where would I start? I have never coded anything in python, but I've been coding for a long time, mostly PHP and Javascript, so I think I can figure out the basics, if I get some pointers.

Also, is it possible to put this inside the Vertex Group section, or does it need to be in a separate panel?

Here's a rough screenshot of my idea as a separate panel, sorry for a weird number of buttons

enter image description here

Here's the code I've made so far. I got it working when I had another similar script loaded, but when I use only this, I only get the Panel, not the buttons. Is there a class I missed or something?

Now I'd be happy for some tips on finding the active vertex group and assigning the vertex values to the selected vertices.

I tried to implement the code, but I'm not sure if I should tab in the for loop, and make it iterate through all vertices.

bl_info = {
    "name": "Quickly set weights of Vertex Groups",
    "author": "nicmar",
    "version": (1, 0),
    "blender": (2, 78, 0),
    "location": "Properties Editor > Object data > Vertex Groups",
    "description": "Quickly set Vertex Groups with assigned weight and live edit",
    "warning": "",
    "wiki_url": "",
    "category": "Mesh"}

import bpy
import time

from bpy.types import Panel

class QuickWeightPanel(bpy.types.Panel):
    bl_label = "Quick Vertex Weights"
    bl_space_type = "PROPERTIES";
    bl_region_type = "WINDOW";
    bl_context = "data"
    #bl_category = "Test"
       
    def draw(self,context):
        layout = self.layout

        row = layout.row(align=True)
        row.alignment = 'EXPAND'
        row.operator("my.button", text="0").number=0
        row.operator("my.button", text="10").number=0.1
        row.operator("my.button", text="25").number=0.25
        row.operator("my.button", text="40").number=0.4
        row.operator("my.button", text="50").number=0.5
        row.operator("my.button", text="60").number=0.6
        row.operator("my.button", text="75").number=0.75
        row.operator("my.button", text="90").number=0.9
        row.operator("my.button", text="100").number=1


class MyOp(bpy.types.Operator): #The operator class derived from Operator
    bl_idname="my.button" #Same as in row.operator
    bl_label="my.button blabla" #Needed

    number=bpy.props.FloatProperty() #The property used in row.operator

    def execute(self, context): #Is trigered by buttons


        # Toggle into edit mode
        obj=bpy.context.active_object
        
        # Toggle into object mode (Wrong? I need to be in edit mode to set weights?)
        #prevMode = obj.mode
        #bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

        # Get active vertex group index
        active_vertex_group_index = obj.vertex_groups.active_index

        # Should I use this?
        #g=obj.vertex_groups['group name']
        
        # Loop through and get all selected vertices i v (?)
        [v for v in obj.data.vertices if v.select] 
        # Get first?
        v = obj.data.vertices[0]
        # Get the data for the group accessed by the group index 
        vg=v.groups[active_vertex_group_index]
        # Set weight of active vertices in active weight group
        # vg.weight = 0.5
        # Print weight of current vertex
        print(vg.weight) 
        
        # Return to previous mode before operator 
        bpy.ops.object.mode_set(mode=prevMode, toggle=False)

        return {'FINISHED'}     


def register():
    bpy.utils.register_module(__name__)
    #bpy.types.Data.ignit_panel = bpy.props.PointerProperty(type=IgnitProperties)


def unregister():
    bpy.utils.unregister_module(__name__)
    #del bpy.types.Data.ignit_panel


if __name__ == "__main__":
    register()
$\endgroup$
5
  • $\begingroup$ I don't get the point of having this extra panel? so what if my value wasn't one of the 0,10,25...100 buttons? and how do you expect to set the Liveweight as it looks to me exactly like the weight in the vertexgroups panel? $\endgroup$
    – Tak
    Mar 16, 2017 at 23:21
  • $\begingroup$ When I for example set up a finger I want to use 50/50 for the mid joint, 75/25 for the next edge loop and so on. And commonly for rigging I dont't think I would need more fine values than these, but if I meed another I can just enter it. Also the live weight updates the values as I pull, opposed to Weight where I need to press Assign each time which is slower. $\endgroup$
    – Niclas
    Mar 17, 2017 at 5:53
  • $\begingroup$ Niclas, reading your question, the answer may be either a complete tutorial on how to code these functions or a "I do it for you" answer (and of course, this is matter of free time to do it). So yes, what you describe can be done. First of all, have a look at the documentation docs.blender.org/api/2.78b/info_tutorial_addon.html and please ask more specific questions if you meet some issues $\endgroup$
    – lemon
    Mar 17, 2017 at 8:59
  • $\begingroup$ Sorry, I added the code I have made so far. The specific questions at this point is 1) Why isn't the buttons showing up 2) How do I find the active vertex group and assigning the vertex values to the selected vertices. $\endgroup$
    – Niclas
    Mar 17, 2017 at 9:05
  • $\begingroup$ You need to declare properties on your operator. See for instance docs.blender.org/api/blender_python_api_current/…. Here the operator will correspond to "my.button" (bl_idname="my.button") and "number" is the declared property in the operator class $\endgroup$
    – lemon
    Mar 17, 2017 at 9:35

2 Answers 2

3
$\begingroup$

If that can save you some time. See the commented part below:

bl_info = {
    "name": "Quickly set weights of Vertex Groups",
    "author": "nicmar",
    "version": (1, 0),
    "blender": (2, 78, 0),
    "location": "Properties Editor > Object data > Vertex Groups",
    "description": "Quickly set Vertex Groups with assigned weight and live edit",
    "warning": "",
    "wiki_url": "",
    "category": "Mesh"}

import bpy
import time
from bpy.types import Panel

class QuickWeightPanel(bpy.types.Panel):
    bl_label = "Quick Vertex Weights"
    bl_space_type = "PROPERTIES";
    bl_region_type = "WINDOW";
    bl_context = "data"
    #bl_category = "Tomte"

    def draw(self,context):

        layout = self.layout

        row = layout.row(align=True)
        row.alignment = 'EXPAND'
        
        row.operator("my.button", text="0").number=0
        row.operator("my.button", text="10").number=0.1
        row.operator("my.button", text="25").number=0.25
        row.operator("my.button", text="40").number=0.4
        row.operator("my.button", text="50").number=0.5
        row.operator("my.button", text="60").number=0.6
        row.operator("my.button", text="75").number=0.75
        row.operator("my.button", text="90").number=0.9
        row.operator("my.button", text="100").number=1

class MyOp(bpy.types.Operator): #The operator class derived from Operator
    bl_idname="my.button" #Same as in row.operator
    bl_label="my.button blabla" #Needed
    
    number=bpy.props.FloatProperty() #The property used in row.operator

    def execute(self, context): #Is trigered by buttons
        print("Test", self.number) #With the associated value
        return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

To go further on the addon:

  • Active object and its type

obj=bpy.context.active_object

obj.type needs to be 'MESH'

  • Object groups

obj.vertex_groups contains the groups.

Use obj.vertex_groups.new(...) to create one or remove(...) to remove

g=obj.vertex_groups['group name']

g.index used in vertices (see below)

obj.vertex_groups.active_index is the currently selected group in the property panel

  • Object data

obj.data all object inner data

obj.data.vertices its vertices

[v for v in obj.data.vertices if v.select] selected vertices

v = obj.data.vertices[0]

v.groups contains the weights for each group v is involved in

vg=v.groups[groupIndex] the data for the group accessed by the group index

vg.weight is the weight

You'll probably need something like

prevMode = obj.mode

bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

#... your code here

bpy.ops.object.mode_set(mode=prevMode, toggle=False)

To retrieve safely the selected vertices and come back to the mode selected before script execution.

$\endgroup$
5
  • $\begingroup$ Thanks, that helped to get the script running. I will fiddle some more with actually implementing the actions to edit the mesh and weights. This question was maybe a bit to broad :) But I'm not sure if I should accept this as an answer or not as it only partly answers my issue. Don't want anyone making it all for me though since I want to learn too... $\endgroup$
    – Niclas
    Mar 17, 2017 at 11:05
  • $\begingroup$ @Niclas, never mind about upvoting or accepting. I will simply add some elements that could be useful $\endgroup$
    – lemon
    Mar 17, 2017 at 11:11
  • $\begingroup$ I tried it, and I at least got the index of the selected vertex group. I have a few problems, I updated my code above. I don't understand if there's a for loop going on, and how [v for v in obj.data.vertices if v.select] works. I tried to add comments to what I think it's doing. If you're able to check I'll be very happy. Thanks again! $\endgroup$
    – Niclas
    Mar 17, 2017 at 14:25
  • $\begingroup$ Brilliant, it worked. The code was very clear. I had to add one line, weightToAssign = self.number. It can probably be improved in many ways, but you have taught me the basics of python in a very effective way. Thanks again - Answer accepted :) $\endgroup$
    – Niclas
    Mar 18, 2017 at 14:21
  • 1
    $\begingroup$ This didn't work for me. Just keeps telling me the operator object has no attribute 'number'. Problem with the newer versions of Blender? $\endgroup$ Feb 3, 2022 at 7:32
0
$\begingroup$

In the newer versions of blender you need to use a colon symbol instead of equal symbol operator.

So the operator from the example above becomes:

class MyOp(bpy.types.Operator): 
bl_idname="my.button" 
bl_label="my.button blabla" 

number : bpy.props.FloatProperty() # Equal symbol is changed to colon

def execute(self, context): 
    print("Test", self.number) 
    return {'FINISHED'}

(This is an answer to the comment made by Gary, but I don't have enough reputation to comment)

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .