Blender 3.1 introduces Python 3.10 API which rules out PyTorch 1.8.1 dependencies
PierceLBrooks opened this issue · 7 comments
The version 3.1 release patch notes for Blender show the internal distribution of Python has been bumped up to 3.10:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.1/Python_API#Python_3.10
This causes problems for resolving dependencies upon installation through the pip package manager using the provided wheel module listing, which only offers support for the necessary CUDA versions up to Python 3.9:
https://download.pytorch.org/whl/torch_stable.html
Here is some terminal output from an installation attempt through the Blender UI to illustrate this:
Read prefs: C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\config\userpref.blend
Reloading external rigs...
Reloading external metarigs...
adding C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\scripts\addons\brignet\_additional_modules\Lib
adding C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\scripts\addons\brignet\_additional_modules\Lib\site-packages
C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\scripts\addons\brignet\_additional_modules\Lib\site-packages\win32 not a directory, skipping
C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\scripts\addons\brignet\_additional_modules\Lib\site-packages\win32\lib not a directory, skipping
C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\scripts\addons\brignet\_additional_modules\DLLs not a directory, skipping
C:\Users\Pierce\AppData\Roaming\Blender Foundation\Blender\3.2\scripts\addons\brignet\_additional_modules\Lib\site-packages\Pythonwin not a directory, skipping
installing torch
Looking in links: https://download.pytorch.org/whl/torch_stable.html
ERROR: Could not find a version that satisfies the requirement torch==1.8.1+cu102 (from versions: 1.11.0, 1.11.0+cpu, 1.11.0+cu113, 1.11.0+cu115, 1.12.0, 1.12.0+cpu, 1.12.0+cu113, 1.12.0+cu116, 1.12.1, 1.12.1+cpu, 1.12.1+cu113, 1.12.1+cu116)
ERROR: No matching distribution found for torch==1.8.1+cu102
I think the add-on should somehow break free from those dependencies, but as a quickfix I might add a torch version parameter in the preferences
At least in the case of support for CUDA 10.2, the only version of torch that offers a Python 3.10 wheel build is 1.12.0, and even then only for linux platforms:
https://pytorch-geometric.com/whl/torch-1.12.0+cu102.html
FYI I also tried being sly about it and editing the find link flag for the virtual environment's PIP package installation invokations ( https://github.com/pKrime/brignet/blob/v0.1-alpha/setup_utils/venv_utils.py#L260 ) to an edited local copy of the wheel build directory page that pointed to an appropriate local wheel build, which somehow still did not seem to work sadly.
I had some issues compiling sparse torch on Windows for python 3.10
Something in the C++ extension compiling is failing.
C:\Users\ernes\micromamba\envs\brignet\lib\site-packages\torch\include\pybind11\cast.h(624): error: too few arguments for template template parameter "Tuple"
detected during instantiation of class "pybind11::detail::tuple_caster<Tuple, Ts...> [with Tuple=std::pair, Ts=<T1, T2>]"
(721): here
C:\Users\ernes\micromamba\envs\brignet\lib\site-packages\torch\include\pybind11\cast.h(717): error: too few arguments for template template parameter "Tuple"
detected during instantiation of class "pybind11::detail::tuple_caster<Tuple, Ts...> [with Tuple=std::pair, Ts=<T1, T2>]"
(721): here
The rest of the dependencies seems to go through for brignet
This still remains an issue for Blender 4.0+ builds.
I've been using https://github.com/V-Sekai/blender-rignet as my fork with Blender 4 if this helps anyone.
If you can generate bone information in RigNet, you could run the following script from blender to create the model. Just set obj_path and skel_path for your files. Tested with blender 4.2.0.
import bpy
class ArmatureGenerator(object):
def __init__(self, info, mesh=None):
self._info = info
self._mesh = mesh
def generate(self, matrix=None):
basename = self._mesh.name if self._mesh else ""
arm_data = bpy.data.armatures.new(basename + "_armature")
arm_obj = bpy.data.objects.new('brignet_rig', arm_data)
bpy.context.collection.objects.link(arm_obj)
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
this_level = [self._info.root]
hier_level = 1
while this_level:
next_level = []
for p_node in this_level:
pos = p_node.pos
parent = p_node.parent.name if p_node.parent is not None else None
e_bone = arm_data.edit_bones.new(p_node.name)
if self._mesh and e_bone.name not in self._mesh.vertex_groups:
self._mesh.vertex_groups.new(name=e_bone.name)
e_bone.head.x, e_bone.head.z, e_bone.head.y = pos[0], pos[2], pos[1]
if parent:
e_bone.parent = arm_data.edit_bones[parent]
if e_bone.parent.tail == e_bone.head:
e_bone.use_connect = True
if len(p_node.children) == 1:
pos = p_node.children[0].pos
e_bone.tail.x, e_bone.tail.z, e_bone.tail.y = pos[0], pos[2], pos[1]
elif len(p_node.children) > 1:
x_offset = [abs(c_node.pos[0] - pos[0]) for c_node in p_node.children]
idx = x_offset.index(min(x_offset))
pos = p_node.children[idx].pos
e_bone.tail.x, e_bone.tail.z, e_bone.tail.y = pos[0], pos[2], pos[1]
elif e_bone.parent:
offset = e_bone.head - e_bone.parent.head
e_bone.tail = e_bone.head + offset / 2
else:
e_bone.tail.x, e_bone.tail.z, e_bone.tail.y = pos[0], pos[2], pos[1]
e_bone.tail.y += .1
for c_node in p_node.children:
next_level.append(c_node)
this_level = next_level
hier_level += 1
if matrix:
arm_data.transform(matrix)
bpy.ops.object.mode_set(mode='POSE')
if self._mesh:
for v_skin in self._info.joint_skin:
v_idx = int(v_skin.pop(0))
for i in range(0, len(v_skin), 2):
self._mesh.vertex_groups[v_skin[i]].add([v_idx], float(v_skin[i + 1]), 'REPLACE')
arm_obj.matrix_world = self._mesh.matrix_world
mod = self._mesh.modifiers.new('rignet', 'ARMATURE')
mod.object = arm_obj
return arm_obj
class Node(object):
def __init__(self, name, pos):
self.name = name
self.pos = pos
class TreeNode(Node):
def __init__(self, name, pos):
super(TreeNode, self).__init__(name, pos)
self.children = []
self.parent = None
class Info:
def __init__(self, filename):
self.joint_pos = {}
self.joint_skin = []
self.root = None
self.load(filename)
def load(self, filename):
with open(filename, 'r') as f_txt:
lines = f_txt.readlines()
for line in lines:
word = line.split()
if word[0] == 'joints':
self.joint_pos[word[1]] = [float(word[2]), float(word[3]), float(word[4])]
elif word[0] == 'root':
root_pos = self.joint_pos[word[1]]
self.root = TreeNode(word[1], (root_pos[0], root_pos[1], root_pos[2]))
elif word[0] == 'skin':
skin_item = word[1:]
self.joint_skin.append(skin_item)
self.loadHierarchy_recur(self.root, lines, self.joint_pos)
def loadHierarchy_recur(self, node, lines, joint_pos):
for li in lines:
if li.split()[0] == 'hier' and li.split()[1] == node.name:
pos = joint_pos[li.split()[2]]
ch_node = TreeNode(li.split()[2], tuple(pos))
node.children.append(ch_node)
ch_node.parent = node
self.loadHierarchy_recur(ch_node, lines, joint_pos)
obj_path = '..._ori.obj'
skel_path = '..._ori_rig.txt'
bpy.ops.wm.obj_import(filepath=obj_path)
mesh_obj = bpy.context.selected_objects[0]
skel_info = Info(filename=skel_path)
ArmatureGenerator(skel_info, mesh_obj).generate()