Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to use blender-oriented rigs #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 76 additions & 44 deletions plywood-cube/puppetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import math
import bpy.props
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
from mathutils import Vector, Matrix
import llbase.llsd
import socket
import errno
Expand All @@ -16,6 +16,7 @@

PLYWOOD_CUBE_PUMP = uuid.UUID('acc4ce6d-f50d-417e-b7c6-cc5d6a6b850b')


class PuppetrySession:
def __init__(self):
self.props = None
Expand Down Expand Up @@ -46,23 +47,23 @@ def send(self, pump, data):
if not self.pump:
return
data = llbase.llsd.format_notation({"pump": pump, "data": data})
data = str(len(data)).encode()+b":"+data
data = str(len(data)).encode() + b":" + data
print(data)
return self.sock.sendall(data)

def handleData(self, data):
data = llbase.llsd.parse_notation(data)
if not self.pump:
self.pump = data
#Disconnect any existing pumps
# Disconnect any existing pumps
self.send(self.pump["data"]["command"], {
"op": "stoplisten",
"reqid": -1,
"source": "puppetry.controller",
"listener": PLYWOOD_CUBE_PUMP
})

#Connect the pump
# Connect the pump
self.send(self.pump["data"]["command"], {
"op": "listen",
"reqid": -1,
Expand Down Expand Up @@ -93,15 +94,17 @@ def animate(self):
return 1

arm = bpy.data.objects[self.props.Target]
orient = self.props.ArmatureOrientationMatrix
orientI = orient.inverted()

updates = {}
shouldUpdate = False
for bn in arm.data.bones.keys():
if bn not in self.props.Transmit:
continue

if not (self.props.Transmit[bn].position \
or self.props.Transmit[bn].rotation):
if not (self.props.Transmit[bn].position
or self.props.Transmit[bn].rotation):
continue

db = arm.data.bones[bn]
Expand All @@ -110,6 +113,7 @@ def animate(self):
mat = pb.matrix_channel
if pb.parent:
mat = pb.parent.matrix_channel.inverted() @ mat
mat = orientI @ mat @ orient

r = mat.to_3x3().to_quaternion()

Expand Down Expand Up @@ -145,7 +149,7 @@ def animate(self):
shouldUpdate = True
elif self.last[bn][check] != updates[bn][check]:
shouldUpdate = True

for check in self.last[bn].keys():
if check not in updates[bn]:
shouldUpdate = True
Expand All @@ -158,7 +162,7 @@ def animate(self):
"command": "set",
"reply": None,
"data": {
#Could also use "joint_state" instead of "j"
# Could also use "joint_state" instead of "j"
"j": updates
}
})
Expand Down Expand Up @@ -207,19 +211,22 @@ def close(self):
self.shouldClose = True
self.disconnect()

#==============================================================================

# ==============================================================================
# Blender Operator class
#==============================================================================
#Custom types
# ==============================================================================
# Custom types
class PuppetryTransmitList(bpy.types.PropertyGroup):
position: bpy.props.IntProperty(name="A")
rotation: bpy.props.IntProperty(name="B")
group: bpy.props.StringProperty()


class StringArrayProperty(bpy.types.PropertyGroup):
name: bpy.props.StringProperty()

#Connect submenu

# Connect submenu
class VIEW3D_OT_puppetry_connect(bpy.types.Operator):
bl_idname = "puppetry.connect"
bl_label = 'Connect to puppetry server'
Expand All @@ -240,13 +247,14 @@ def execute(self, context):
def add_items_from_collection_callback(self, context):
return [(v.name, v.name, '') for v in bpy.context.scene.puppetry.TransmitGroups]


class PuppetryProperties(bpy.types.PropertyGroup):
Host: bpy.props.StringProperty(
name="Host",
default="127.0.0.1",
maxlen=1024,
)

Port: bpy.props.IntProperty(
name="Port",
default=5000,
Expand All @@ -255,20 +263,35 @@ class PuppetryProperties(bpy.types.PropertyGroup):
)

Armatures: bpy.props.CollectionProperty(type=StringArrayProperty)
ArmatureOrientation: bpy.props.EnumProperty(name="Orientation", items=(
("SL", "SL (+X forward)", "Bone orientations are exported to SL without transformation", 0),
("Blender", "Blender (-Y forward)", "Rotate bone orientations 90 degrees left before export", 1),
))

Target: bpy.props.StringProperty(name = "Target")
Target: bpy.props.StringProperty(name="Target")

Transmit: bpy.props.CollectionProperty(type=PuppetryTransmitList)
Transmit_index: bpy.props.IntProperty()
TransmitGroups: bpy.props.CollectionProperty(type=StringArrayProperty)
TransmitGroupEnum: bpy.props.EnumProperty(items=add_items_from_collection_callback)

UpdateTime: bpy.props.FloatProperty(
name = "Update rate",
default = 0.1,
min = 0.05,
max = 5
name="Update rate",
default=0.1,
min=0.05,
max=5
)

@property
def ArmatureOrientationMatrix(self):
if self.ArmatureOrientation == "Blender":
return Matrix(((0, 1, 0, 0),
(-1, 0, 0, 0),
(0, 0, 1, 0),
(0, 0, 0, 1)))
else:
return Matrix()


class VIEW3D_PT_puppetry_connect(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
Expand All @@ -283,24 +306,26 @@ def draw(self, context):
props = scene.puppetry

Session.setProps(props)

layout.prop(props, "Host")
layout.prop(props, "Port")
layout.separator()
if Session.connected:
layout.operator('puppetry.connect', text = 'Disconnect')
layout.operator('puppetry.connect', text='Disconnect')
else:
layout.operator('puppetry.connect', text = 'Connect')
layout.operator('puppetry.connect', text='Connect')


#Armature submenu
# Armature submenu
@bpy.app.handlers.persistent
def findArmatures(self):
findArmaturesReal()


def findArmaturesReal():
context = bpy.context
props = bpy.context.scene.puppetry

props.Armatures.clear()

for o in bpy.data.objects:
Expand All @@ -311,13 +336,14 @@ def findArmaturesReal():
if len(props.Armatures) == 1 and props.Target == "":
props.Target = props.Armatures[0].name


class VIEW3D_OT_puppetry_skeleton_action(bpy.types.Operator):
bl_idname = 'puppetry.skeletonedit'
bl_label = ''

action: bpy.props.IntProperty(
name = 'action',
default = -1
name='action',
default=-1
)

def execute(self, context):
Expand All @@ -332,10 +358,11 @@ def execute(self, context):
"reply": None
})
else:
#Reset skeleton?
# Reset skeleton?
pass
return {'FINISHED'}


class VIEW3D_PT_puppetry_armature(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
Expand All @@ -348,39 +375,41 @@ def draw(self, context):
props = scene.puppetry

layout.prop_search(props, "Target", props, "Armatures", text="", icon="ARMATURE_DATA")
layout.prop(props, "ArmatureOrientation")

layout.separator()
layout.prop(props, "UpdateTime")
row = layout.row()
"""
row = layout.row(align=True)
btn = row.operator("puppetry.skeletonedit", text="Sync Skeleton")
btn.action = 0

btn = row.operator("puppetry.skeletonedit", text="Reset Skeleton")
btn.action = 1
"""


#Transmit submenu

# Transmit submenu
class VIEW3D_OT_puppetry_transmit_toggle(bpy.types.Operator):
bl_idname = 'puppetry.transmittoggle'
bl_label = ''

target: bpy.props.StringProperty(
name = 'target'
name='target'
)

property: bpy.props.StringProperty(
name = 'property'
name='property'
)

group: bpy.props.StringProperty(
name = 'group'
name='group'
)

value: bpy.props.IntProperty(
name = 'value',
default = -1
name='value',
default=-1
)

def match(self, prop):
Expand All @@ -405,6 +434,7 @@ def execute(self, context):
setattr(p, self.property, bool(self.value))
return {'FINISHED'}


class VIEW3D_UL_puppetry_transmit(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
Expand All @@ -414,19 +444,20 @@ def draw_item(self, context, layout, data, item, icon, active_data, active_propn
split2 = layout.row()
split2.alignment = "RIGHT"

btn = split2.operator("puppetry.transmittoggle", icon="OBJECT_ORIGIN" if item.position else "DOT", emboss = False)
btn = split2.operator("puppetry.transmittoggle", icon="OBJECT_ORIGIN" if item.position else "DOT",
emboss=False)
btn.target = item.name
btn.property = "position"
btn = split2.operator("puppetry.transmittoggle", icon="ORIENTATION_GIMBAL" if item.rotation else "DOT", emboss = False)
btn = split2.operator("puppetry.transmittoggle", icon="ORIENTATION_GIMBAL" if item.rotation else "DOT",
emboss=False)
btn.target = item.name
btn.property = "rotation"


def draw_filter(self, context, layout):
scene = context.scene
props = scene.puppetry
row = layout.row()
row.prop(props, "TransmitGroupEnum", text = "")
row.prop(props, "TransmitGroupEnum", text="")

def filter_items(self, context, data, propname):
filtered = []
Expand All @@ -439,6 +470,7 @@ def filter_items(self, context, data, propname):
filtered.append(~self.bitflag_filter_item)
return filtered, ordered


class VIEW3D_PT_puppetry_transmit(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
Expand All @@ -449,7 +481,7 @@ def draw(self, context):
layout = self.layout
scene = context.scene
props = scene.puppetry

row = layout.row()
row.template_list(
"VIEW3D_UL_puppetry_transmit", "custom_def_list",
Expand All @@ -475,7 +507,6 @@ def draw(self, context):

btn = row.operator("puppetry.transmittoggle", text="Selected")


row = layout.row()
row.label(text="Disable:", icon="OBJECT_ORIGIN")

Expand All @@ -493,7 +524,6 @@ def draw(self, context):

btn = row.operator("puppetry.transmittoggle", text="Selected")


row = layout.row()
row.label(text="Enable:", icon="ORIENTATION_GIMBAL")

Expand Down Expand Up @@ -527,6 +557,7 @@ def draw(self, context):

btn = row.operator("puppetry.transmittoggle", text="Selected")


def populateBoneList():
transmit = bpy.context.scene.puppetry.Transmit
groups = bpy.context.scene.puppetry.TransmitGroups
Expand All @@ -544,7 +575,8 @@ def populateBoneList():
b.name = bone["name"]
b.group = bone["group"]

#Registration

# Registration

module_classes = (
VIEW3D_OT_puppetry_transmit_toggle,
Expand All @@ -559,10 +591,11 @@ def populateBoneList():
VIEW3D_PT_puppetry_transmit
)


def register():
for cls in module_classes:
bpy.utils.register_class(cls)

bpy.types.Scene.puppetry = bpy.props.PointerProperty(type=PuppetryProperties)

Global["Session"] = PuppetrySession()
Expand All @@ -582,4 +615,3 @@ def unregister():

Session.close()
del Global["Session"]