-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge Vertex Groups tool, and update documentation
- Loading branch information
Showing
17 changed files
with
257 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Clean and Combine | ||
In Object mode, select the objects you want to clean and merge, and make the object you want to merge them into Active. Then, go to `Object > Cleanup > Clean and Combine`. Choose the corresponding settings you like. The resulting objects will have modifiers applied or discarded, be joined together, have geometry cleaned using the given settings, and finally have all transforms applied. This operator is great for multi-part characters, or just generally cleaning up messy files before exporting. | ||
|
||
Please note that all modifiers are applied or discarded. **THERE WILL BE DATA LOSS**, but **Armatures and bone weights are preserved**. Though the operator can be undone, it is strongly recommended to have a backup of your model, and only use this tool when you are certain that you want to, or are exporting a model. | ||
|
||
 | ||
 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Curl Bones | ||
In Pose mode, select the bones you want to edit, then go to `Pose > Curl Bones`. Then input the angle you want to offset the bones' rotation by. | ||
Note that currently this only applies to bones with a Euler rotation mode. | ||
|
||
 | ||
 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Mark Bone Side | ||
While editing an Armature, go to `Armature > Names > Mark Side`. This works similar to `Auto-Name Left/Right`, but allows you to set bones to one side or another regardless of actual position when not using the "automatic" setting. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Merge Vertex Groups | ||
## Accessing | ||
From Object mode, select the objects you want to edit, and go to `Object > Apply > Merge Vertex Groups`. | ||
The operation should apply to all possible objects it can, which is useful for multi-mesh character rigs. | ||
|
||
Or, if you're in Weight Paint Mode, simply go to `Weights > Merge Vertex Groups`. | ||
This will allow real-time view of the operation if you make changes after applying it. | ||
You can only do one object at a time with this method. | ||
|
||
## Utilization | ||
You should get a menu like this: | ||
|
||
 | ||
|
||
From here, fill out the names of the desired vertex groups you want to work with. | ||
If you want to use a constant, select 'Use Constant' and choose where in the formula you want it to be used. | ||
Then set the constant value. The constant value can be any float value--it is not clamped to 0 or 1. | ||
|
||
Finally, select your operation. If you want to see what the formula looks like for each one, simply hover your mouse over the option. | ||
|
||
 | ||
|
||
## Example | ||
 | ||
|
||
 | ||
|
||
 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Set Bone Rotation Mode | ||
In Pose mode, select the bones you want to edit, then go to `Pose > Set Rotation Mode`. Choose the rotation mode you want, and all selected pose bones will be set to the new rotation mode. Note that if the bones already have a keyframed rotation, these keyframes will not be converted to the new rotation mode, and you may run into issues with rotation channels clashing. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Surface Bone Placer | ||
While editing an Armature, go to `Add > Place Surface Bones`. If you would like the bones you place to fall under a parent, make the parent bone active before running this tool. | ||
|
||
Once the modal has started, left-click on 3D surfaces to place bones on them. The bone head will fall slightly inside the mesh, and the bone tail will face outward based off the surface normal. Bones should automatically inherit armature and parent bone transforms (essentially they are placed using global space). If there's an issue, let me know. | ||
|
||
When you are finished placing bones, hit `Escape` to exit the modal. When using the placed bones, I recommend using Automatic Weights over Envelope weights for initial weighting of your mesh. | ||
|
||
An example of what it does (made center bone active, then used tool to place bones on surface of mesh): | ||
|
||
 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import bpy | ||
from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty | ||
from bpy.types import Object, Operator, Mesh, VertexGroup | ||
from ..utility import * | ||
|
||
class BoneJuice_MergeVertexGroups(Operator): | ||
"""Combine two vertex groups on selected meshes using a given operation.""" | ||
bl_idname = "object.bj_merge_vert_groups" | ||
bl_label = "Merge Vertex Groups" | ||
bl_description = "Combine two vertex groups on selected meshes using a given operation." | ||
bl_options = {'REGISTER', 'UNDO'} | ||
|
||
## MAPPING | ||
def button(self, context): | ||
self.layout.operator( | ||
BoneJuice_MergeVertexGroups.bl_idname, | ||
text="Merge Vertex Groups", | ||
icon='NONE') | ||
|
||
def manual_map(): | ||
url_manual_prefix = "https://docs.blender.org/manual/en/latest/" | ||
url_manual_mapping = ( | ||
("bpy.ops.object.bj_merge_vert_groups", "scene_layout/object/types.html"), | ||
) | ||
return url_manual_prefix, url_manual_mapping | ||
|
||
## PROPERTIES | ||
groupAName: StringProperty( | ||
name = "Group A", | ||
description = "The name of the first vertex group to be used in the operation.", | ||
default = "Group", | ||
) | ||
groupBName: StringProperty( | ||
name = "Group B", | ||
description = "The name of the second vertex group to be used in the operation.", | ||
default = "Group.001", | ||
) | ||
groupCName: StringProperty( | ||
name = "Output Group", | ||
description = "The name of the vertex group to be outputted to. Will create one if not currently present.", | ||
default = "merged_group", | ||
) | ||
groupOperation: EnumProperty( | ||
name = 'Operation', | ||
description = 'What operation to use for the formula.', | ||
items = [ | ||
('add', 'Add', 'A + B = C'), | ||
('subtract', 'Subtract', 'A - B = C'), | ||
('multiply', 'Multiply', 'A * B = C'), | ||
('divide', 'Divide', 'A / B = C'), | ||
('modulus', 'Modulus', 'A % B = C'), | ||
('pow', 'Power', 'A ^ B = C'), | ||
('min', 'Minimum', 'min(A, B) = C'), | ||
('max', 'Maximum', 'max(A, B) = C'), | ||
], | ||
default = 'add', | ||
) | ||
useConstant: EnumProperty( | ||
name = 'Use Constant', | ||
description = 'Utilizes the provided constant in place of the given group.', | ||
items = [ | ||
('no', 'No', 'Does not use the constant value.'), | ||
('b', 'For B', 'Use constant in place of vertex group B'), | ||
('a', 'For A', 'Use constant in place of vertex group A'), | ||
], | ||
default = 'no', | ||
) | ||
operationConstant: FloatProperty( | ||
name = 'Constant', | ||
description = 'Numberic value to use in place of B, if Use Constant is checked.', | ||
default = 0 | ||
) | ||
|
||
|
||
## functions | ||
def runOperation(self, a: float, b: float) -> float: | ||
if self.groupOperation == 'subtract': | ||
return a - b | ||
elif self.groupOperation == 'multiply': | ||
return a * b | ||
elif self.groupOperation == 'divide': | ||
if (b == 0): # Approach infinity | ||
if (a == 0): # Unless we're also zero | ||
return 0 | ||
return 1 | ||
return a / b | ||
elif self.groupOperation == 'modulus': | ||
return a % b | ||
elif self.groupOperation == 'pow': | ||
return pow(a, b) | ||
elif self.groupOperation == 'min': | ||
return min(a, b) | ||
elif self.groupOperation == 'max': | ||
return max(a, b) | ||
|
||
return a + b | ||
def getVertexGroup(self, obj: bpy.types.Object, grpName: str) -> VertexGroup: | ||
return obj.vertex_groups.get(grpName) | ||
|
||
## INVOKE DIALOGUE | ||
def invoke(self, context: bpy.types.Context, event): | ||
return context.window_manager.invoke_props_dialog(self) | ||
|
||
## ACTUAL EXECUTION | ||
def execute(self, context: bpy.types.Context): | ||
primary = get_active() # Fetch primary object | ||
objects = bpy.context.selected_objects # Fetch selected objects | ||
|
||
# Iterate through all objects so we can work on the meshes | ||
for obj in objects: | ||
set_active(obj) # Set current object as active | ||
if type(get_active().data) is Mesh: | ||
|
||
# First, get vertex groups and make sure everything is in order! | ||
groupA: VertexGroup = None | ||
groupB: VertexGroup = None | ||
groupC: VertexGroup = self.getVertexGroup(obj, self.groupCName) | ||
|
||
# If we're not using a constant for group a, fetch it | ||
if self.useConstant != 'a': | ||
groupA = self.getVertexGroup(obj, self.groupAName) | ||
if not groupA: | ||
self.report({'WARNING'}, "Could not find vertex group '" + self.groupAName + "' on mesh '" + obj.name + "' Skipping.") | ||
break | ||
if self.useConstant != 'b': | ||
groupB = self.getVertexGroup(obj, self.groupBName) | ||
if not groupB: | ||
self.report({'WARNING'}, "Could not find vertex group '" + self.groupBName + "' on mesh '" + obj.name + "'. Skipping.") | ||
break | ||
|
||
if not groupC: | ||
groupC = bpy.context.active_object.vertex_groups.new(name=self.groupCName) | ||
|
||
# Then fetch total vertices | ||
numVerts = len(obj.data.vertices) | ||
vertIndices: List[int] = [] | ||
vertWeightsA: List[float] = [] | ||
vertWeightsB: List[float] = [] | ||
# Fill in indices and weights | ||
for i in range(0, numVerts): | ||
vertIndices.append(i) | ||
|
||
# Append A weights | ||
if groupA: | ||
try: # Attempt to append the weight of the given vertex if it exists in the group | ||
vertWeightsA.append(groupA.weight(i)) | ||
except: # If it isn't present, just append zero instead | ||
vertWeightsA.append(0) | ||
else: | ||
vertWeightsA.append(self.operationConstant) | ||
|
||
# Append B weights | ||
if groupB: | ||
try: # Attempt to append the weight of the given vertex if it exists in the group | ||
vertWeightsB.append(groupB.weight(i)) | ||
except: # If it isn't present, just append zero instead | ||
vertWeightsB.append(0) | ||
else: | ||
vertWeightsB.append(self.operationConstant) | ||
|
||
# Finally, perform operation and add vertices with weights > 0 to the array | ||
for i in range(0, numVerts): | ||
result: float = clampf(self.runOperation(vertWeightsA[i], vertWeightsB[i]), 0, 1) | ||
if (result > 0): | ||
groupC.add([i], result, 'REPLACE') | ||
else: | ||
groupC.remove([i]) | ||
|
||
self.report({'INFO'}, "Completed operation for mesh object '" + obj.name + "'.") | ||
|
||
set_active(primary) # Re-select primary object | ||
|
||
return {'FINISHED'} |
Oops, something went wrong.