Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-02-16 13:57:57 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-03-14 14:39:16 +0300
commit36e8d00aec705b06008a0bc334fe266448b4f2c2 (patch)
tree02bf0290ec6423c611e3cd4ad49c69cb77acb67e /rigify/utils/widgets.py
parenteabb5cddf79e5fae3ca429242cf2c6f5a272920e (diff)
Rigify: add support for user-defined rig packages and related utilities.
As suggested by @icappielo, and after discussion with @meta-androcto, I start a public request to commit third-party contributions already accepted to https://github.com/eigen-value/rigify/tree/rigify_0.6_beta Specifically, this includes: * User-defined rig package (feature set) support by @pioverfour. This allows users to install pre-packaged rig sets via zip files, which become accessible together with built-in rigs, as discussed in T52758. https://github.com/eigen-value/rigify/pull/1 * Modularization of python script generation, allowing rigs to add their own utility functions and operators to the generated script. This is critical to make custom rig support really useful. https://github.com/eigen-value/rigify/pull/5 * The utils.py file is split into multiple modules with a backward compatibility proxy for old functions. * Automatic verification that different rigs don't try to create different rig settings with the same name to alleviate increased risk of namespace conflicts with custom rigs. https://github.com/eigen-value/rigify/pull/7 * New utility class that implements bone layer selection UI. https://github.com/eigen-value/rigify/pull/6 * New utilities to replace copy & pasted boilerplate code for creating custom properties, constraints and drivers. https://github.com/eigen-value/rigify/pull/11 Some other random changes by MAD have likely slipped through. These changes have already been extensively discussed and accepted into the branch by @luciorossi, so I see no reason not to commit them to the official repository to be tested during 2.8 beta. Reviewers: icappiello Differential Revision: https://developer.blender.org/D4364
Diffstat (limited to 'rigify/utils/widgets.py')
-rw-r--r--rigify/utils/widgets.py168
1 files changed, 168 insertions, 0 deletions
diff --git a/rigify/utils/widgets.py b/rigify/utils/widgets.py
new file mode 100644
index 00000000..184429a3
--- /dev/null
+++ b/rigify/utils/widgets.py
@@ -0,0 +1,168 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+import math
+
+from .errors import MetarigError
+
+WGT_PREFIX = "WGT-" # Prefix for widget objects
+
+#=============================================
+# Widget creation
+#=============================================
+
+
+def obj_to_bone(obj, rig, bone_name):
+ """ Places an object at the location/rotation/scale of the given bone.
+ """
+ if bpy.context.mode == 'EDIT_ARMATURE':
+ raise MetarigError("obj_to_bone(): does not work while in edit mode")
+
+ bone = rig.data.bones[bone_name]
+
+ mat = rig.matrix_world @ bone.matrix_local
+
+ obj.location = mat.to_translation()
+
+ obj.rotation_mode = 'XYZ'
+ obj.rotation_euler = mat.to_euler()
+
+ scl = mat.to_scale()
+ scl_avg = (scl[0] + scl[1] + scl[2]) / 3
+ obj.scale = (bone.length * scl_avg), (bone.length * scl_avg), (bone.length * scl_avg)
+
+
+def create_widget(rig, bone_name, bone_transform_name=None):
+ """ Creates an empty widget object for a bone, and returns the object.
+ """
+ if bone_transform_name is None:
+ bone_transform_name = bone_name
+
+ obj_name = WGT_PREFIX + rig.name + '_' + bone_name
+ scene = bpy.context.scene
+ collection = bpy.context.collection
+
+ # Check if it already exists in the scene
+ if obj_name in scene.objects:
+ # Move object to bone position, in case it changed
+ obj = scene.objects[obj_name]
+ obj_to_bone(obj, rig, bone_transform_name)
+
+ return None
+ else:
+ # Delete object if it exists in blend data but not scene data.
+ # This is necessary so we can then create the object without
+ # name conflicts.
+ if obj_name in bpy.data.objects:
+ bpy.data.objects[obj_name].user_clear()
+ bpy.data.objects.remove(bpy.data.objects[obj_name])
+
+ # Create mesh object
+ mesh = bpy.data.meshes.new(obj_name)
+ obj = bpy.data.objects.new(obj_name, mesh)
+ collection.objects.link(obj)
+
+ # Move object to bone position and set layers
+ obj_to_bone(obj, rig, bone_transform_name)
+ wgts_group_name = 'WGTS_' + rig.name
+ if wgts_group_name in bpy.data.objects.keys():
+ obj.parent = bpy.data.objects[wgts_group_name]
+
+ return obj
+
+
+def create_circle_polygon(number_verts, axis, radius=1.0, head_tail=0.0):
+ """ Creates a basic circle around of an axis selected.
+ number_verts: number of vertices of the poligon
+ axis: axis normal to the circle
+ radius: the radius of the circle
+ head_tail: where along the length of the bone the circle is (0.0=head, 1.0=tail)
+ """
+ verts = []
+ edges = []
+ angle = 2 * math.pi / number_verts
+ i = 0
+
+ assert(axis in 'XYZ')
+
+ while i < (number_verts):
+ a = math.cos(i * angle)
+ b = math.sin(i * angle)
+
+ if axis == 'X':
+ verts.append((head_tail, a * radius, b * radius))
+ elif axis == 'Y':
+ verts.append((a * radius, head_tail, b * radius))
+ elif axis == 'Z':
+ verts.append((a * radius, b * radius, head_tail))
+
+ if i < (number_verts - 1):
+ edges.append((i , i + 1))
+
+ i += 1
+
+ edges.append((0, number_verts - 1))
+
+ return verts, edges
+
+
+def write_widget(obj):
+ """ Write a mesh object as a python script for widget use.
+ """
+ script = ""
+ script += "def create_thing_widget(rig, bone_name, size=1.0, bone_transform_name=None):\n"
+ script += " obj = create_widget(rig, bone_name, bone_transform_name)\n"
+ script += " if obj != None:\n"
+
+ # Vertices
+ if len(obj.data.vertices) > 0:
+ script += " verts = ["
+ for v in obj.data.vertices:
+ script += "(" + str(v.co[0]) + "*size, " + str(v.co[1]) + "*size, " + str(v.co[2]) + "*size), "
+ script += "]\n"
+
+ # Edges
+ if len(obj.data.edges) > 0:
+ script += " edges = ["
+ for e in obj.data.edges:
+ script += "(" + str(e.vertices[0]) + ", " + str(e.vertices[1]) + "), "
+ script += "]\n"
+
+ # Faces
+ if len(obj.data.polygons) > 0:
+ script += " faces = ["
+ for f in obj.data.polygons:
+ script += "("
+ for v in f.vertices:
+ script += str(v) + ", "
+ script += "), "
+ script += "]\n"
+
+ # Build mesh
+ script += "\n mesh = obj.data\n"
+ script += " mesh.from_pydata(verts, edges, faces)\n"
+ script += " mesh.update()\n"
+ script += " mesh.update()\n"
+ script += " return obj\n"
+ script += " else:\n"
+ script += " return None\n"
+
+ return script