网站建设费走什么费用,重庆网约车哪个平台最好,长沙岳麓区网站开发,电商网站开发制作目录
文件拖拽导入
smpl导入导出
好像可以导入动画
smpl_blender_addon导入一帧
保存pose
导入导出完整代码 文件拖拽导入
https://github.com/mika-f/blender-drag-and-drop
支持格式#xff1a;
*.abc*.bvh*.dae*.fbx*.glb*.gltf*.obj*.ply*.stl*.svg*.usd*.usda*.…目录
文件拖拽导入
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_planebl_label Snap To Ground Planebl_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(modeOBJECT)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, keylambda item: item.z)).zobject_eval.to_mesh_clear() # Remove temporary mesh# Translate armature edit bonescontext.view_layer.objects.active armaturebpy.ops.object.mode_set(modeEDIT)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(modeOBJECT)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_posebl_label Write Pose1bl_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_file1234.npznp.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_ANGLEaxis_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_genderbl_label Addbl_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(filenameobject_name, directorystr(objects_path))# Select imported meshobject_name context.selected_objects[0].namebpy.ops.object.select_all(actionDESELECT)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_texturebl_label Setbl_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(typeShaderNodeTexImage)if texture UV_GRID:if texture not in bpy.data.images:bpy.ops.image.new(nametexture, generated_typeUV_GRID)image bpy.data.images[texture]else:if texture not in bpy.data.images:bpy.ops.image.new(nametexture, generated_typeCOLOR_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_shapesbl_label Random Shapesbl_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 MESHexcept: return Falsedef execute(self, context):obj bpy.context.objectbpy.ops.object.mode_set(modeOBJECT)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_shapesbl_label Resetbl_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 MESHexcept: return Falsedef execute(self, context):obj bpy.context.objectbpy.ops.object.mode_set(modeOBJECT)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_planebl_label Snap To Ground Planebl_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(modeOBJECT)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, keylambda item: item.z)).zobject_eval.to_mesh_clear() # Remove temporary mesh# Translate armature edit bonescontext.view_layer.objects.active armaturebpy.ops.object.mode_set(modeEDIT)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(modeOBJECT)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_locationsbl_label Update Joint Locationsbl_description (Update joint locations after shape/expression changes)bl_options {REGISTER, UNDO}j_regressor_male Nonej_regressor_female Noneclassmethoddef 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(modeOBJECT)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_ANGLEaxis_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_ANGLEbone.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), dtypenp.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(modeEDIT)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(modeOBJECT)bpy.context.view_layer.objects.active obj# Restore posefor pose_bone in armature.pose.bones:pose_bone.rotation_mode AXIS_ANGLEpose_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_poseshapesbl_label Set Pose Shapesbl_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_poseshapesbl_label Resetbl_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_referenceNone, frame1): # I wish framebpy.data.scenes[0].frame_current worked here, but it doesntrod Vector((rodrigues[0], rodrigues[1], rodrigues[2]))angle_rad rod.lengthaxis rod.normalized()pbone armature.pose.bones[bone_name]pbone.rotation_mode QUATERNIONquat 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_pathrotation_quaternion, frameframe)if bone_name pelvis:pbone.keyframe_insert(location, frameframe)return
class SMPLLoadPose(bpy.types.Operator):bl_idname object.smpl_load_posebl_label Load Posebl_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_number5obj 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 rC:\Program Files\Blender Foundation\Blender 4.0\1234.npznpz_data np.load(npz_path, allow_pickleTrue)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, framebpy.data.scenes[0].frame_current)return {FINISHED}
class SMPLWritePose(bpy.types.Operator):bl_idname object.smpl_write_posebl_label Write Pose1bl_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_file1234.npznp.savez_compressed(npz_file, joints_3d{data: np.array([pose])})return {FINISHED}class SMPLResetPose(bpy.types.Operator):bl_idname object.smpl_reset_posebl_label Reset Posebl_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_ANGLEbone.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_fbxbl_label Export Unity FBXbl_description (Export skinned mesh to Unity in FBX format)bl_options {REGISTER, UNDO}# ExportHelper mixin class uses thisfilename_ext .fbxclassmethoddef 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(actionDESELECT)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(allFalse)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_mixTrue)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(allFalse)# 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(modeOBJECT)bpy.ops.object.select_all(actionDESELECT)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 femaleelse:gender maletarget_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-meshskinned_mesh.name target_mesh_nameif target_armature_name in bpy.data.objects:bpy.data.objects[target_armature_name].name SMPL-temp-armaturearmature.name target_armature_namebpy.ops.export_scene.fbx(filepathself.filepath, use_selectionTrue, apply_scale_optionsFBX_SCALE_ALL, add_leaf_bonesFalse)print(Exported: self.filepath)# Remove temporary copies of armature and skinned meshbpy.ops.object.select_all(actionDESELECT)skinned_mesh.select_set(True)armature.select_set(True)bpy.ops.object.delete()bpy.ops.object.select_all(actionDESELECT)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 Modelbl_category SMPLbl_space_type VIEW_3Dbl_region_type UIdef draw(self, context):layout self.layoutcol layout.column(alignTrue)row col.row(alignTrue)col.prop(context.window_manager.smpl_tool, smpl_gender)col.operator(scene.smpl_add_gender, textAdd)col.separator()col.label(textTexture:)row col.row(alignTrue)split row.split(factor0.75, alignTrue)split.prop(context.window_manager.smpl_tool, smpl_texture)split.operator(scene.smpl_set_texture, textSet)class SMPL_PT_Shape(bpy.types.Panel):bl_label Shapebl_category SMPLbl_space_type VIEW_3Dbl_region_type UIdef draw(self, context):layout self.layoutcol layout.column(alignTrue)row col.row(alignTrue)split row.split(factor0.75, alignTrue)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 Posebl_category SMPLbl_space_type VIEW_3Dbl_region_type UIdef draw(self, context):layout self.layoutcol layout.column(alignTrue)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 Exportbl_category SMPLbl_space_type VIEW_3Dbl_region_type UIdef draw(self, context):layout self.layoutcol layout.column(alignTrue)col.label(textShape 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, textExport OBJ [m], iconEXPORT)
# export_button.global_scale 1.0
# export_button.use_selection True
# col.separator()row col.row(alignTrue)row.operator(ed.undo, iconLOOP_BACK)row.operator(ed.redo, iconLOOP_FORWARDS)col.separator()(year, month, day) bl_info[version]col.label(textVersion: %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(typePG_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()