当前位置: 首页 > news >正文

blender插件笔记

目录

文件拖拽导入

smpl导入导出

好像可以导入动画

smpl_blender_addon导入一帧

保存pose

导入导出完整代码


文件拖拽导入

https://github.com/mika-f/blender-drag-and-drop

支持格式:

  • *.abc
  • *.bvh
  • *.dae
  • *.fbx
  • *.glb
  • *.gltf
  • *.obj
  • *.ply
  • *.stl
  • *.svg
  • *.usd
  • *.usda
  • *.usdc
  • *.vrm (Required VRM Add-on for Blender)
  • *.x3d
  • *.wrl

smpl导入导出

好像可以导入动画

https://github.com/vltmedia/QuickMocap-BlenderAddon

smpl_blender_addon导入一帧

这个也是一次只能导入一帧,不能导入动画

https://github.com/Meshcapade/SMPL_blender_addon

这个可以写pose,就是把旋转角度保存下来

class SMPLSnapGroundPlane(bpy.types.Operator):bl_idname = "object.smpl_snap_ground_plane"bl_label = "Snap To Ground Plane"bl_description = ("Snaps mesh to the XY ground plane")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh or armature is active objectreturn ((context.object.type == 'MESH') or (context.object.type == 'ARMATURE'))except: return Falsedef execute(self, context):bpy.ops.object.mode_set(mode='OBJECT')obj = bpy.context.objectif obj.type == 'ARMATURE':armature = objobj = bpy.context.object.children[0]else:armature = obj.parent# Get vertices with applied skin modifier in object coordinatesdepsgraph = context.evaluated_depsgraph_get()object_eval = obj.evaluated_get(depsgraph)mesh_from_eval = object_eval.to_mesh()# Get vertices in world coordinatesmatrix_world = obj.matrix_worldvertices_world = [matrix_world @ vertex.co for vertex in mesh_from_eval.vertices]z_min = (min(vertices_world, key=lambda item: item.z)).zobject_eval.to_mesh_clear() # Remove temporary mesh# Translate armature edit bonescontext.view_layer.objects.active = armaturebpy.ops.object.mode_set(mode='EDIT')for edit_bone in armature.data.edit_bones:if edit_bone.name != "root":edit_bone.translate(Vector((0.0, 0.0, -z_min)))# Translate skinned mesh and apply translationbpy.ops.object.mode_set(mode='OBJECT')context.view_layer.objects.active = objobj.location = (0.0, 0.0, -z_min)bpy.ops.object.transform_apply(location = True)return {'FINISHED'}

保存pose

class SMPLWritePose(bpy.types.Operator):bl_idname = "object.smpl_write_pose"bl_label = "Write Pose1"bl_description = ("Writes SMPL pose thetas to console window")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh or armature is active objectreturn (context.object.type == 'MESH') or (context.object.type == 'ARMATURE')except: return Falsedef execute(self, context):obj = bpy.context.objectif obj.type == 'MESH':armature = obj.parentelse:armature = obj# Get armature pose in rodrigues representationpose = [0.0] * (len(SMPL_JOINT_NAMES) * 3)for index in range(len(SMPL_JOINT_NAMES)):joint_name = SMPL_JOINT_NAMES[index]joint_pose = rodrigues_from_pose(armature, joint_name)pose[index*3 + 0] = joint_pose[0]pose[index*3 + 1] = joint_pose[1]pose[index*3 + 2] = joint_pose[2]print("pose = " + str(pose))npz_file="1234.npz"np.savez_compressed(npz_file, joints_3d={"data": pose})return {'FINISHED'}

导入导出完整代码

这个可以导入导出,代码没有报错了,但是加载后没有显示出来,而且只能保存一帧,不能保存动画

# ##### 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 #####
import loggingbl_info = {"name": "SMPL for Blender","author": "Joachim Tesch, Max Planck Institute for Intelligent Systems","version": (2021, 6, 11),"blender": (2, 80, 0),"location": "Viewport > Right panel","description": "SMPL for Blender","wiki_url": "https://smpl.is.tue.mpg.de/","category": "SMPL"}import bpy
import bmesh
from bpy_extras.io_utils import ExportHelper # ExportHelper is a helper class, defines filename and invoke() function which calls the file selector.from mathutils import Vector, Quaternion
from math import radians
import numpy as np
import os
import picklefrom bpy.props import ( BoolProperty, EnumProperty, FloatProperty, PointerProperty )
from bpy.types import ( PropertyGroup )# SMPL globals
SMPL_JOINT_NAMES = {0:  'Pelvis',1:  'L_Hip',        4:  'L_Knee',            7:  'L_Ankle',           10: 'L_Foot',2:  'R_Hip',        5:  'R_Knee',            8:  'R_Ankle',           11: 'R_Foot',3:  'Spine1',       6:  'Spine2',            9:  'Spine3',            12: 'Neck',            15: 'Head',13: 'L_Collar',     16: 'L_Shoulder',       18: 'L_Elbow',            20: 'L_Wrist',         22: 'L_Hand',14: 'R_Collar',     17: 'R_Shoulder',       19: 'R_Elbow',            21: 'R_Wrist',         23: 'R_Hand',
}
smpl_joints = len(SMPL_JOINT_NAMES) 
# End SMPL globalsdef rodrigues_from_pose(armature, bone_name):# Ensure that rotation mode is AXIS_ANGLE so the we get a correct readout of current posearmature.pose.bones[bone_name].rotation_mode = 'AXIS_ANGLE'axis_angle = armature.pose.bones[bone_name].rotation_axis_angleangle = axis_angle[0]rodrigues = Vector((axis_angle[1], axis_angle[2], axis_angle[3]))rodrigues.normalize()rodrigues = rodrigues * anglereturn rodriguesdef update_corrective_poseshapes(self, context):if self.smpl_corrective_poseshapes:bpy.ops.object.smpl_set_poseshapes('EXEC_DEFAULT')else:bpy.ops.object.smpl_reset_poseshapes('EXEC_DEFAULT')# Property groups for UI
class PG_SMPLProperties(PropertyGroup):smpl_gender: EnumProperty(name = "Model",description = "SMPL model",items = [ ("female", "Female", ""), ("male", "Male", "") ])smpl_texture: EnumProperty(name = "",description = "SMPL model texture",items = [ ("NONE", "None", ""), ("UV_GRID", "UV Grid", ""), ("COLOR_GRID", "Color Grid", "") ])smpl_corrective_poseshapes: BoolProperty(name = "Corrective Pose Shapes",description = "Enable/disable corrective pose shapes of SMPL model",update = update_corrective_poseshapes)smpl_export_setting_shape_keys: EnumProperty(name = "",description = "Blend shape export settings",items = [ ("SHAPE_POSE", "All: Shape + Posecorrectives", "Export shape keys for body shape and pose correctives"), ("SHAPE", "Reduced: Shape space only", "Export only shape keys for body shape"), ("NONE", "None: Apply shape space", "Do not export any shape keys, shape keys for body shape will be baked into mesh") ],)class SMPLAddGender(bpy.types.Operator):bl_idname = "scene.smpl_add_gender"bl_label = "Add"bl_description = ("Add SMPL model of selected gender to scene")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if in Object Modeif (context.active_object is None) or (context.active_object.mode == 'OBJECT'):return Trueelse: return Falseexcept: return Falsedef execute(self, context):gender = context.window_manager.smpl_tool.smpl_genderprint("Adding gender: " + gender)path = os.path.dirname(os.path.realpath(__file__))objects_path = os.path.join(path, "data", "smpl-model-20200803.blend", "Object")object_name = "SMPL-mesh-" + genderbpy.ops.wm.append(filename=object_name, directory=str(objects_path))# Select imported meshobject_name = context.selected_objects[0].namebpy.ops.object.select_all(action='DESELECT')context.view_layer.objects.active = bpy.data.objects[object_name]bpy.data.objects[object_name].select_set(True)return {'FINISHED'}class SMPLSetTexture(bpy.types.Operator):bl_idname = "scene.smpl_set_texture"bl_label = "Set"bl_description = ("Set selected texture")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if in active object is meshif (context.object.type == 'MESH'):return Trueelse:return Falseexcept: return Falsedef execute(self, context):texture = context.window_manager.smpl_tool.smpl_textureprint("Setting texture: " + texture)obj = bpy.context.objectif (len(obj.data.materials) == 0) or (obj.data.materials[0] is None):self.report({'WARNING'}, "Selected mesh has no material: %s" % obj.name)return {'CANCELLED'}mat = obj.data.materials[0]links = mat.node_tree.linksnodes = mat.node_tree.nodes# Find texture nodenode_texture = Nonefor node in nodes:if node.type == 'TEX_IMAGE':node_texture = nodebreak# Find shader nodenode_shader = Nonefor node in nodes:if node.type.startswith('BSDF'):node_shader = nodebreakif texture == 'NONE':# Unlink texture nodeif node_texture is not None:for link in node_texture.outputs[0].links:links.remove(link)nodes.remove(node_texture)# 3D Viewport still shows previous texture when texture link is removed via script.# As a workaround we trigger desired viewport update by setting color value.node_shader.inputs[0].default_value = node_shader.inputs[0].default_valueelse:if node_texture is None:node_texture = nodes.new(type="ShaderNodeTexImage")if texture == 'UV_GRID':if texture not in bpy.data.images:bpy.ops.image.new(name=texture, generated_type='UV_GRID')image = bpy.data.images[texture]else:if texture not in bpy.data.images:bpy.ops.image.new(name=texture, generated_type='COLOR_GRID')image = bpy.data.images[texture]node_texture.image = image# Link texture node to shader node if not already linkedif len(node_texture.outputs[0].links) == 0:links.new(node_texture.outputs[0], node_shader.inputs[0])return {'FINISHED'}class SMPLRandomShapes(bpy.types.Operator):bl_idname = "object.smpl_random_shapes"bl_label = "Random Shapes"bl_description = ("Sets all shape blend shape keys to a random value")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh is active objectreturn context.object.type == 'MESH'except: return Falsedef execute(self, context):obj = bpy.context.objectbpy.ops.object.mode_set(mode='OBJECT')for key_block in obj.data.shape_keys.key_blocks:if key_block.name.startswith("Shape"):key_block.value = np.random.normal(0.0, 1.0)bpy.ops.object.smpl_update_joint_locations('EXEC_DEFAULT')return {'FINISHED'}class SMPLResetShapes(bpy.types.Operator):bl_idname = "object.smpl_reset_shapes"bl_label = "Reset"bl_description = ("Resets all blend shape keys for shape")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh is active objectreturn context.object.type == 'MESH'except: return Falsedef execute(self, context):obj = bpy.context.objectbpy.ops.object.mode_set(mode='OBJECT')for key_block in obj.data.shape_keys.key_blocks:if key_block.name.startswith("Shape"):key_block.value = 0.0bpy.ops.object.smpl_update_joint_locations('EXEC_DEFAULT')return {'FINISHED'}class SMPLSnapGroundPlane(bpy.types.Operator):bl_idname = "object.smpl_snap_ground_plane"bl_label = "Snap To Ground Plane"bl_description = ("Snaps mesh to the XY ground plane")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh or armature is active objectreturn ((context.object.type == 'MESH') or (context.object.type == 'ARMATURE'))except: return Falsedef execute(self, context):bpy.ops.object.mode_set(mode='OBJECT')obj = bpy.context.objectif obj.type == 'ARMATURE':armature = objobj = bpy.context.object.children[0]else:armature = obj.parent# Get vertices with applied skin modifier in object coordinatesdepsgraph = context.evaluated_depsgraph_get()object_eval = obj.evaluated_get(depsgraph)mesh_from_eval = object_eval.to_mesh()# Get vertices in world coordinatesmatrix_world = obj.matrix_worldvertices_world = [matrix_world @ vertex.co for vertex in mesh_from_eval.vertices]z_min = (min(vertices_world, key=lambda item: item.z)).zobject_eval.to_mesh_clear() # Remove temporary mesh# Translate armature edit bonescontext.view_layer.objects.active = armaturebpy.ops.object.mode_set(mode='EDIT')for edit_bone in armature.data.edit_bones:if edit_bone.name != "root":edit_bone.translate(Vector((0.0, 0.0, -z_min)))# Translate skinned mesh and apply translationbpy.ops.object.mode_set(mode='OBJECT')context.view_layer.objects.active = objobj.location = (0.0, 0.0, -z_min)bpy.ops.object.transform_apply(location = True)return {'FINISHED'}class SMPLUpdateJointLocations(bpy.types.Operator):bl_idname = "object.smpl_update_joint_locations"bl_label = "Update Joint Locations"bl_description = ("Update joint locations after shape/expression changes")bl_options = {'REGISTER', 'UNDO'}j_regressor_male = Nonej_regressor_female = None@classmethoddef poll(cls, context):try:# Enable button only if mesh is active objectreturn ((context.object.type == 'MESH') and (context.object.parent.type == 'ARMATURE'))except: return Falsedef execute(self, context):obj = bpy.context.objectbpy.ops.object.mode_set(mode='OBJECT')if self.j_regressor_female is None:path = os.path.dirname(os.path.realpath(__file__))regressor_path = os.path.join(path, "data", "smpl_joint_regressor_female.npz")with np.load(regressor_path) as data:self.j_regressor_female = data['joint_regressor']if self.j_regressor_male is None:path = os.path.dirname(os.path.realpath(__file__))regressor_path = os.path.join(path, "data", "smpl_joint_regressor_male.npz")with np.load(regressor_path) as data:self.j_regressor_male = data['joint_regressor']if "female" in obj.name:j_regressor = self.j_regressor_femaleelse:j_regressor = self.j_regressor_male# Store current bone rotationsarmature = obj.parentbone_rotations = {}for pose_bone in armature.pose.bones:pose_bone.rotation_mode = 'AXIS_ANGLE'axis_angle = pose_bone.rotation_axis_anglebone_rotations[pose_bone.name] = (axis_angle[0], axis_angle[1], axis_angle[2], axis_angle[3])# Set model in default posefor bone in armature.pose.bones:bpy.ops.object.smpl_reset_poseshapes('EXEC_DEFAULT')bone.rotation_mode = 'AXIS_ANGLE'bone.rotation_axis_angle = (0, 0, 1, 0)# Reset corrective poseshapes if usedif context.window_manager.smpl_tool.smpl_corrective_poseshapes:bpy.ops.object.smpl_reset_poseshapes('EXEC_DEFAULT')# Get vertices with applied skin modifierdepsgraph = context.evaluated_depsgraph_get()object_eval = obj.evaluated_get(depsgraph)mesh_from_eval = object_eval.to_mesh()# Get Blender vertices as numpy matrixvertices_np = np.zeros((len(mesh_from_eval.vertices)*3), dtype=np.float)mesh_from_eval.vertices.foreach_get("co", vertices_np)vertices_matrix = np.reshape(vertices_np, (len(mesh_from_eval.vertices), 3))object_eval.to_mesh_clear() # Remove temporary mesh# Note: Current joint regressor uses 6890 vertices as input which is slow numpy operationjoint_locations = j_regressor @ vertices_matrix# Set new bone joint locationsbpy.context.view_layer.objects.active = armaturebpy.ops.object.mode_set(mode='EDIT')for index in range(smpl_joints):bone = armature.data.edit_bones[SMPL_JOINT_NAMES[index]]bone.head = (0.0, 0.0, 0.0)bone.tail = (0.0, 0.0, 0.1)bone_start = Vector(joint_locations[index])bone.translate(bone_start)bpy.ops.object.mode_set(mode='OBJECT')bpy.context.view_layer.objects.active = obj# Restore posefor pose_bone in armature.pose.bones:pose_bone.rotation_mode = 'AXIS_ANGLE'pose_bone.rotation_axis_angle = bone_rotations[pose_bone.name]# Restore corrective poseshapes if usedif context.window_manager.smpl_tool.smpl_corrective_poseshapes:bpy.ops.object.smpl_set_poseshapes('EXEC_DEFAULT')return {'FINISHED'}class SMPLSetPoseshapes(bpy.types.Operator):bl_idname = "object.smpl_set_poseshapes"bl_label = "Set Pose Shapes"bl_description = ("Sets corrective poseshapes for current pose")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh is active object and parent is armaturereturn ( ((context.object.type == 'MESH') and (context.object.parent.type == 'ARMATURE')) or (context.object.type == 'ARMATURE'))except: return False# https://github.com/gulvarol/surreal/blob/master/datageneration/main_part1.py# Computes rotation matrix through Rodrigues formula as in cv2.Rodriguesdef rodrigues_to_mat(self, rotvec):theta = np.linalg.norm(rotvec)r = (rotvec/theta).reshape(3, 1) if theta > 0. else rotveccost = np.cos(theta)mat = np.asarray([[0, -r[2], r[1]],[r[2], 0, -r[0]],[-r[1], r[0], 0]])return(cost*np.eye(3) + (1-cost)*r.dot(r.T) + np.sin(theta)*mat)# https://github.com/gulvarol/surreal/blob/master/datageneration/main_part1.py# Calculate weights of pose corrective blend shapes# Input is pose of all 24 joints, output is weights for all joints except pelvis (23)def rodrigues_to_posecorrective_weight(self, pose):joints_posecorrective = smpl_jointsrod_rots = np.asarray(pose).reshape(joints_posecorrective, 3)mat_rots = [self.rodrigues_to_mat(rod_rot) for rod_rot in rod_rots]bshapes = np.concatenate([(mat_rot - np.eye(3)).ravel() for mat_rot in mat_rots[1:]])return(bshapes)def execute(self, context):obj = bpy.context.object# Get armature pose in rodrigues representationif obj.type == 'ARMATURE':armature = objobj = bpy.context.object.children[0]else:armature = obj.parentpose = [0.0] * (smpl_joints * 3)for index in range(smpl_joints):joint_name = SMPL_JOINT_NAMES[index]joint_pose = rodrigues_from_pose(armature, joint_name)pose[index*3 + 0] = joint_pose[0]pose[index*3 + 1] = joint_pose[1]pose[index*3 + 2] = joint_pose[2]# print("Current pose: " + str(pose))poseweights = self.rodrigues_to_posecorrective_weight(pose)# Set weights for pose corrective shape keysfor index, weight in enumerate(poseweights):obj.data.shape_keys.key_blocks["Pose%03d" % index].value = weight# Set checkbox without triggering update functioncontext.window_manager.smpl_tool["smpl_corrective_poseshapes"] = Truereturn {'FINISHED'}class SMPLResetPoseshapes(bpy.types.Operator):bl_idname = "object.smpl_reset_poseshapes"bl_label = "Reset"bl_description = ("Resets corrective poseshapes for current pose")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh is active object and parent is armaturereturn ( ((context.object.type == 'MESH') and (context.object.parent.type == 'ARMATURE')) or (context.object.type == 'ARMATURE'))except: return Falsedef execute(self, context):obj = bpy.context.objectif obj.type == 'ARMATURE':obj = bpy.context.object.children[0]for key_block in obj.data.shape_keys.key_blocks:if key_block.name.startswith("Pose"):key_block.value = 0.0return {'FINISHED'}def set_pose_from_rodrigues(armature, bone_name, rodrigues, rodrigues_reference=None, frame=1):  # I wish frame=bpy.data.scenes[0].frame_current worked here, but it doesn'trod = Vector((rodrigues[0], rodrigues[1], rodrigues[2]))angle_rad = rod.lengthaxis = rod.normalized()pbone = armature.pose.bones[bone_name]pbone.rotation_mode = 'QUATERNION'quat = Quaternion(axis, angle_rad)if rodrigues_reference is None:pbone.rotation_quaternion = quatelse:# SMPL-X is adding the reference rodrigues rotation to the# relaxed hand rodrigues rotation, so we have to do the same here.# This means that pose values for relaxed hand model cannot be# interpreted as rotations in the local joint coordinate system of the relaxed hand.# https://github.com/vchoutas/smplx/blob/f4206853a4746139f61bdcf58571f2cea0cbebad/smplx/body_models.py#L1190#   full_pose += self.pose_meanrod_reference = Vector((rodrigues_reference[0], rodrigues_reference[1], rodrigues_reference[2]))rod_result = rod + rod_referenceangle_rad_result = rod_result.lengthaxis_result = rod_result.normalized()quat_result = Quaternion(axis_result, angle_rad_result)pbone.rotation_quaternion = quat_resultpbone.keyframe_insert(data_path="rotation_quaternion", frame=frame)if bone_name == 'pelvis':pbone.keyframe_insert('location', frame=frame)return
class SMPLLoadPose(bpy.types.Operator):bl_idname = "object.smpl_load_pose"bl_label = "Load Pose"bl_description = ("Load SMPL pose thetas to console window")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh or armature is active objectreturn (context.object.type == 'MESH') or (context.object.type == 'ARMATURE')except: return Falsedef execute(self, context):self.frame_number=5obj = bpy.context.objectif obj.type == 'MESH':armature = obj.parentelse:armature = objobj = armature.children[0]context.view_layer.objects.active = obj  # mesh needs to be active object for recalculating joint locationsjoint_names = SMPL_JOINT_NAMESobj = bpy.context.objectnpz_path = r"C:\Program Files\Blender Foundation\Blender 4.0\1234.npz"npz_data = np.load(npz_path, allow_pickle=True)if 'joints_3d' not in npz_data:print('joints_3d not find')returndata = npz_data['joints_3d'].item()['data']body_pose = data.reshape(( 24, 3))logging.error("np.array(data):"+str(len(np.array(data))))# pose_index = max(0, min(self.frame_number, (len(np.array(data)))))  # clamp the frame they give you from 0 and the max number of frames in this poses array# body_pose = np.array(data[pose_index]).reshape(len(joint_names), 3)# pose the entire bodyfor index in range(len(joint_names)):pose_rodrigues = body_pose[index]bone_name = joint_names[index]set_pose_from_rodrigues(armature, bone_name, pose_rodrigues, frame=bpy.data.scenes[0].frame_current)return {'FINISHED'}
class SMPLWritePose(bpy.types.Operator):bl_idname = "object.smpl_write_pose"bl_label = "Write Pose1"bl_description = ("Writes SMPL pose thetas to console window")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh or armature is active objectreturn (context.object.type == 'MESH') or (context.object.type == 'ARMATURE')except: return Falsedef execute(self, context):obj = bpy.context.objectif obj.type == 'MESH':armature = obj.parentelse:armature = obj# Get armature pose in rodrigues representationpose = [0.0] * (len(SMPL_JOINT_NAMES) * 3)for index in range(len(SMPL_JOINT_NAMES)):joint_name = SMPL_JOINT_NAMES[index]joint_pose = rodrigues_from_pose(armature, joint_name)pose[index*3 + 0] = joint_pose[0]pose[index*3 + 1] = joint_pose[1]pose[index*3 + 2] = joint_pose[2]print("pose = " + str(pose))npz_file="1234.npz"np.savez_compressed(npz_file, joints_3d={"data": np.array([pose])})return {'FINISHED'}class SMPLResetPose(bpy.types.Operator):bl_idname = "object.smpl_reset_pose"bl_label = "Reset Pose"bl_description = ("Resets pose to default zero pose")bl_options = {'REGISTER', 'UNDO'}@classmethoddef poll(cls, context):try:# Enable button only if mesh is active objectreturn ( ((context.object.type == 'MESH') and (context.object.parent.type == 'ARMATURE')) or (context.object.type == 'ARMATURE'))except: return Falsedef execute(self, context):obj = bpy.context.objectif obj.type == 'MESH':armature = obj.parentelse:armature = objfor bone in armature.pose.bones:bone.rotation_mode = 'AXIS_ANGLE'bone.rotation_axis_angle = (0, 0, 1, 0)# Reset corrective pose shapesbpy.ops.object.smpl_reset_poseshapes('EXEC_DEFAULT')return {'FINISHED'}class SMPLExportUnityFBX(bpy.types.Operator, ExportHelper):bl_idname = "object.smpl_export_unity_fbx"bl_label = "Export Unity FBX"bl_description = ("Export skinned mesh to Unity in FBX format")bl_options = {'REGISTER', 'UNDO'}# ExportHelper mixin class uses thisfilename_ext = ".fbx"@classmethoddef poll(cls, context):try:# Enable button only if mesh is active objectreturn (context.object.type == 'MESH')except: return Falsedef execute(self, context):obj = bpy.context.objectexport_shape_keys = context.window_manager.smpl_tool.smpl_export_setting_shape_keysarmature_original = obj.parentskinned_mesh_original = obj# Operate on temporary copy of skinned mesh and armaturebpy.ops.object.select_all(action='DESELECT')skinned_mesh_original.select_set(True)armature_original.select_set(True)bpy.context.view_layer.objects.active = skinned_mesh_originalbpy.ops.object.duplicate()skinned_mesh = bpy.context.objectarmature = skinned_mesh.parent# Reset posebpy.ops.object.smpl_reset_pose('EXEC_DEFAULT')if export_shape_keys != 'SHAPE_POSE':# Remove pose corrective shape keysprint('Removing pose corrective shape keys')num_shape_keys = len(skinned_mesh.data.shape_keys.key_blocks.keys())current_shape_key_index = 0for index in range(0, num_shape_keys):bpy.context.object.active_shape_key_index = current_shape_key_indexif bpy.context.object.active_shape_key is not None:if bpy.context.object.active_shape_key.name.startswith('Pose'):bpy.ops.object.shape_key_remove(all=False)else:current_shape_key_index = current_shape_key_index + 1        if export_shape_keys == 'NONE':# Bake and remove shape keysprint("Baking shape and removing shape keys for shape")# Create shape mix for current shapebpy.ops.object.shape_key_add(from_mix=True)num_shape_keys = len(skinned_mesh.data.shape_keys.key_blocks.keys())# Remove all shape keys except newly added onebpy.context.object.active_shape_key_index = 0for count in range(0, num_shape_keys):bpy.ops.object.shape_key_remove(all=False)# Model (skeleton and skinned mesh) needs to have rotation of (90, 0, 0) when exporting so that it will have rotation (0, 0, 0) when imported into Unitybpy.ops.object.mode_set(mode='OBJECT')bpy.ops.object.select_all(action='DESELECT')skinned_mesh.select_set(True)skinned_mesh.rotation_euler = (radians(-90), 0, 0)bpy.context.view_layer.objects.active = skinned_meshbpy.ops.object.transform_apply(rotation = True)skinned_mesh.rotation_euler = (radians(90), 0, 0)skinned_mesh.select_set(False)armature.select_set(True)armature.rotation_euler = (radians(-90), 0, 0)bpy.context.view_layer.objects.active = armaturebpy.ops.object.transform_apply(rotation = True)armature.rotation_euler = (radians(90), 0, 0)# Select armature and skinned mesh for exportskinned_mesh.select_set(True)# Rename armature and skinned mesh to not contain Blender copy suffixif "female" in skinned_mesh.name:gender = "female"else:gender = "male"target_mesh_name = "SMPL-mesh-%s" % gendertarget_armature_name = "SMPL-%s" % genderif target_mesh_name in bpy.data.objects:bpy.data.objects[target_mesh_name].name = "SMPL-temp-mesh"skinned_mesh.name = target_mesh_nameif target_armature_name in bpy.data.objects:bpy.data.objects[target_armature_name].name = "SMPL-temp-armature"armature.name = target_armature_namebpy.ops.export_scene.fbx(filepath=self.filepath, use_selection=True, apply_scale_options="FBX_SCALE_ALL", add_leaf_bones=False)print("Exported: " + self.filepath)# Remove temporary copies of armature and skinned meshbpy.ops.object.select_all(action='DESELECT')skinned_mesh.select_set(True)armature.select_set(True)bpy.ops.object.delete()bpy.ops.object.select_all(action='DESELECT')skinned_mesh_original.select_set(True)bpy.context.view_layer.objects.active = skinned_mesh_originalif "SMPL-temp-mesh" in bpy.data.objects:bpy.data.objects["SMPL-temp-mesh"].name = target_mesh_nameif "SMPL-temp-armature" in bpy.data.objects:bpy.data.objects["SMPL-temp-armature"].name = target_armature_namereturn {'FINISHED'}class SMPL_PT_Model(bpy.types.Panel):bl_label = "SMPL Model"bl_category = "SMPL"bl_space_type = "VIEW_3D"bl_region_type = "UI"def draw(self, context):layout = self.layoutcol = layout.column(align=True)row = col.row(align=True)col.prop(context.window_manager.smpl_tool, "smpl_gender")col.operator("scene.smpl_add_gender", text="Add")col.separator()col.label(text="Texture:")row = col.row(align=True)split = row.split(factor=0.75, align=True)split.prop(context.window_manager.smpl_tool, "smpl_texture")split.operator("scene.smpl_set_texture", text="Set")class SMPL_PT_Shape(bpy.types.Panel):bl_label = "Shape"bl_category = "SMPL"bl_space_type = "VIEW_3D"bl_region_type = "UI"def draw(self, context):layout = self.layoutcol = layout.column(align=True)row = col.row(align=True)split = row.split(factor=0.75, align=True)split.operator("object.smpl_random_shapes")split.operator("object.smpl_reset_shapes")col.separator()col.operator("object.smpl_snap_ground_plane")col.separator()col.operator("object.smpl_update_joint_locations")class SMPL_PT_Pose(bpy.types.Panel):bl_label = "Pose"bl_category = "SMPL"bl_space_type = "VIEW_3D"bl_region_type = "UI"def draw(self, context):layout = self.layoutcol = layout.column(align=True)col.prop(context.window_manager.smpl_tool, "smpl_corrective_poseshapes")col.separator()col.operator("object.smpl_set_poseshapes")col.separator()col.operator("object.smpl_load_pose")col.separator()col.operator("object.smpl_write_pose")col.separator()class SMPL_PT_Export(bpy.types.Panel):bl_label = "Export"bl_category = "SMPL"bl_space_type = "VIEW_3D"bl_region_type = "UI"def draw(self, context):layout = self.layoutcol = layout.column(align=True)col.label(text="Shape Keys (Blend Shapes):")col.prop(context.window_manager.smpl_tool, "smpl_export_setting_shape_keys")col.separator()col.separator()col.operator("object.smpl_export_unity_fbx")col.separator()#        export_button = col.operator("export_scene.obj", text="Export OBJ [m]", icon='EXPORT')
#        export_button.global_scale = 1.0
#        export_button.use_selection = True
#        col.separator()row = col.row(align=True)row.operator("ed.undo", icon='LOOP_BACK')row.operator("ed.redo", icon='LOOP_FORWARDS')col.separator()(year, month, day) = bl_info["version"]col.label(text="Version: %s-%s-%s" % (year, month, day))classes = [PG_SMPLProperties,SMPLAddGender,SMPLSetTexture,SMPLRandomShapes,SMPLResetShapes,SMPLSnapGroundPlane,SMPLUpdateJointLocations,SMPLSetPoseshapes,SMPLResetPoseshapes,SMPLLoadPose,SMPLWritePose,SMPLResetPose,SMPLExportUnityFBX,SMPL_PT_Model,SMPL_PT_Shape,SMPL_PT_Pose,SMPL_PT_Export
]def register():from bpy.utils import register_classfor cls in classes:bpy.utils.register_class(cls)# Store properties under WindowManager (not Scene) so that they are not saved in .blend files and always show default values after loadingbpy.types.WindowManager.smpl_tool = PointerProperty(type=PG_SMPLProperties)def unregister():from bpy.utils import unregister_classfor cls in classes:bpy.utils.unregister_class(cls)del bpy.types.WindowManager.smpl_toolif __name__ == "__main__":register()

相关文章:

  • shell实现查询进程号并批量kill(脚本)
  • Git学习笔记之基础
  • 2015年认证杯SPSSPRO杯数学建模D题(第二阶段)城市公共自行车全过程文档及程序
  • [深度学习]yolov8+pyqt5搭建精美界面GUI设计源码实现五
  • 推荐多样性 - 华为OD统一考试(C卷)
  • PEReDi 完全隐私的央行数字货币方案
  • SiLM8260ADCS-DG带米勒钳位功能 双通道隔离驱动器 完美解决了干扰发热问题
  • index.js:235 uView提示:maxDate不能小于当前时间
  • 100个openharmony开源demo:1.日历
  • ReactNative项目构建分析与思考之RN组件化
  • Git的使用记录+坑的处理
  • VTK9.2.0+Qt5.14.0 绘制点云
  • STM32F103 CubeMX 使用USB生成键盘设备
  • 蓝桥杯刷题(十四)
  • 分布式系统面试全集通第一篇(dubbo+redis+zookeeper----分布式+CAP+BASE+分布式事务+分布式锁)
  • [数据结构]链表的实现在PHP中
  • css属性的继承、初识值、计算值、当前值、应用值
  • JAVA SE 6 GC调优笔记
  • JAVA_NIO系列——Channel和Buffer详解
  • JavaScript 一些 DOM 的知识点
  • java多线程
  • k8s 面向应用开发者的基础命令
  • laravel5.5 视图共享数据
  • MySQL主从复制读写分离及奇怪的问题
  • WePY 在小程序性能调优上做出的探究
  • 百度小程序遇到的问题
  • 从setTimeout-setInterval看JS线程
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 如何编写一个可升级的智能合约
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 深入浅出Node.js
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 消息队列系列二(IOT中消息队列的应用)
  • 延迟脚本的方式
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • raise 与 raise ... from 的区别
  • Spring第一个helloWorld
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 积累各种好的链接
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #Lua:Lua调用C++生成的DLL库
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (145)光线追踪距离场柔和阴影
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (分享)自己整理的一些简单awk实用语句
  • (九十四)函数和二维数组
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (五)Python 垃圾回收机制
  • (译)计算距离、方位和更多经纬度之间的点
  • (轉貼) UML中文FAQ (OO) (UML)
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现