当前位置: 首页 > 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()

相关文章:

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*.…...

解释关系型数据库和非关系型数据库的区别

一、解释关系型数据库和非关系型数据库的区别 关系型数据库和非关系型数据库在多个方面存在显著的区别。 首先,从数据存储方式来看,关系型数据库采用表格形式,数据存储在数据表的行和列中,且数据表之间可以关联存储,…...

YAML-02-yml 配置文件 java 整合使用 yamlbeans + snakeyaml + jackson-dataformat-yaml

java 中处理 yml 的开源组件是什么? 在Java中处理YAML(YAML Aint Markup Language)格式的开源组件有很多,其中一些比较常用的包括: SnakeYAML: SnakeYAML 是一个Java库,用于解析和生成YAML格式…...

【综述+LLMs】国内团队大语言模型综述:A Survey of Large Language Models (截止2023.11.24)

Github主页: https://github.com/RUCAIBox/LLMSurvey 中文版v10:https://github.com/RUCAIBox/LLMSurvey/blob/main/assets/LLM_Survey_Chinese.pdf 英文版v13: https://arxiv.org/abs/2303.18223 解析:大语言模型LLM入门看完你就懂了(一&…...

开始喜欢上了runnergo,JMeter out了?

RunnerGo是一款基于Go语言、国产自研的测试平台。它支持高并发、分布式性能测试。和JMeter不一样的是,它采用了B/S架构,更灵活、更方便。而且,除了API测试和性能测试,RunnerGo还加上了UI测试和项目管理等实用功能,让测…...

LLM - 大语言模型的分布式训练 概述

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/136924304 大语言模型的分布式训练是一个复杂的过程,涉及到将大规模的计算任务分散到多个计算节点上。这样做的目的是为了处…...

Spring Cloud Alibaba 整合Seata分布式事务

目录 前言步骤引入相关maven依赖添加相关配置Client端配置注册中心Server端配置注册中心Seata-Server相关配置启动seata-server 使用方法Seata AT 模式整体机制 步骤初始化表结构标记注解GlobalTransactional 总结 前言 在数字化转型的浪潮下,企业业务系统的复杂度…...

unity 多屏幕操作

想了解基础操作请移步:(重点是大佬写的好,这里就不再赘述) Unity 基础 之 使用 Display 简单的实现 多屏幕显示的效果_unity display-CSDN博客 在panel上也可以通过获取 Canvas,来达到切换多屏幕的操作, …...

4、Jenkins持续集成-用户权限和凭证管理

文章目录 一、用户权限管理1、安装用户权限管理插件2、开启权限全局安全配置3、创建角色4、创建用户5、给用户分配角色6、创建项目测试权限二、凭证管理1、安装凭证管理插件2、安装Git插件和工具2.1 用户密码类型2.2 SSH密钥类型一、用户权限管理 利用Role-based Authorizatio…...

K8s-网络原理-中篇

引言 本文是《深入剖析 K8s》的学习笔记,相关图片和案例可从https://github.com/WeiXiao-Hyy/k8s_example中获取,欢迎 ⭐️! 上篇主要介绍了 Flannel 插件为例,讲解了 K8s 里容器网络和 CNI 插件的主要工作原理。还有一种“纯三层”的网络方…...

vue基础——java程序员版(vue路由)

1、引入路由 在控制台执行vue ui,在插件市场里可以找到vue-router并导入。 ​ 一般情况下,vue会自动在main,js中引入vue-router,如下: import Vue from vue import App from ./App.vue import ./plugins/element.js import rou…...

【vue3学习之路(一)】

文章目录 前言一、vue3项目创建1.1环境准备1.1.1 基于 vue-cli 创建(脚手架创建)1.1.2 基于 vite 创建(推荐) 二、熟悉流程总结 前言 参考视频:https://www.bilibili.com/video/BV1Za4y1r7KE?p10&spm_id_frompag…...

基于Spring Boot网络相册设计与实现

摘 要 网络相册设计与实现的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品,体验高科技时代带给人们的方便,同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓,iOS相比较起来&am…...

6 Spring-AOP

文章目录 1,AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念 2,AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知类配给容器…...

这回轮到鸿蒙禁用安卓了!!!

1月18日,鸿蒙生态千帆仪式上,华为正式宣布了HarmonyOS NEXT(下简称鸿蒙星河版或纯血鸿蒙)开发者预览已向开发者开放申请,纯血鸿蒙开始走向普及阶段。伴随着不再兼容安卓的纯血鸿蒙铺开,鸿蒙走进了运营属于自…...

Java问题详解

在Java中,问题可能涵盖多个领域,如基础知识、高级特性、设计模式、性能优化、并发编程等。下面,我将提供两个问题以及对它们的详细回答。请注意,2000字的要求可能过于庞大,我将尽量确保回答详细而不过于冗长。 问题1&…...

Go——指针和内存逃逸

区别于C/C中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。 要搞明白Go语言中的指针概念需要先知道3个概念:指针地址,指针类型和指针取值。 一. Go语言的指针 Go语言中的函数传参都是值拷贝,当我们想修改某个…...

PTA L2-032 彩虹瓶

彩虹瓶的制作过程(并不)是这样的:先把一大批空瓶铺放在装填场地上,然后按照一定的顺序将每种颜色的小球均匀撒到这批瓶子里。 假设彩虹瓶里要按顺序装 N 种颜色的小球(不妨将顺序就编号为 1 到 N)。现在工…...

Spring和Spring Boot之间的区别

Spring和Spring Boot之间的区别 不仅仅体现在操作简化、配置方式以及开发速度上,还有以下几个方面: 模块化和功能范围: Spring是一个完整的框架,提供了各种各样的功能,包括依赖注入、面向切面编程、数据访问、事务管…...

海外客户获取难?海外云手机助力电商引流!

海外电商面临的市场竞争激烈,如何在海外市场获客成为了摆在许多卖家面前的难题。而在这个问题的解决方案中,海外云手机崭露头角,成为助力电商引流的新利器。 在当前市场中,云手机主要用于游戏挂机,但其潜力在海外电商领…...

Continue 开源 AI 编程助手框架深度分析

Continue 开源 AI 编程助手框架深度分析 一、项目简介 Continue 是一个模块化、可配置、跨平台的开源 AI 编程助手框架,目标是让开发者能在本地或云端环境中,快速集成和使用自定义的 LLM 编程辅助工具。它通过支持 VS Code 与 JetBrains 等主流 IDE 插件…...

Prompt工程学习之思维树(TOT)

思维树 定义:思维树(Tree of Thoughts, ToT) 是一种先进的推理框架,它通过同时探索多条推理路径对思维链(Chain of Thought)** 进行了扩展。该技术将问题解决视为一个搜索过程 —— 模型生成不同的中间步骤…...

编程笔记---问题小计

编程笔记 qml ProgressBar 为什么valuemodel.progress / 100 在QML中,ProgressBar的value属性用于表示进度条的当前进度值,其范围通常为0到1(或0%到100%)。当使用model.progress / 100来设置value时,这样做的原因是为…...

Selenium自动化测试工具安装和使用(PyCharm)

一,了解驱动 手工测试我们很了解,假设我要测试百度首页是否正常,只需要鼠标点击打开浏览器,然后输入百度网址即可 但是对于程序来说,打开浏览器,需要用到对应的驱动,就好比你给电脑装了个外置…...

1 Studying《蓝牙核心规范5.3》

目录 [Vol 0][Part B 蓝牙规范要求] 3 定义 3.1 蓝牙产品类型 4 核心配置 4.1 基本速率核心配置 4.2 增强型数据速率核心配置 4.4 低功耗核心配置 4.5 基本速率和低功耗结合的核心配置 4.6 主机控制器接口核心配置 [Vol 1][Part A 架构]1 概述 1.1 BR/EDR操作概述 …...

如何实现本地mqtt服务器和云端服务器同步?

有时候,一个物联网项目,A客户想要本地使用,B客户想要线上使用,C客户想要本地部署,当有网环境时能线上使用。这个时候就需要本地MQTT服务和线上MQTT服务能相互自动转发。 后来经我一翻研究,其实Activemq支持…...

机器学习实战37-基于情感字典和机器学习的股市舆情分析可视化系统

文章目录 一、项目背景数字时代情感分析情况二、项目流程1.数据采集与预处理2.复合情感分析模型构建3.舆情分析可视化:三、机器学习算法原理1.支持向量机基础2.核函数与高维映射3.情感分类特征融合4.模型训练与优化四、实现代码五、系统特点与优势1.复合情感分析模型2.多维度可…...

503 Service Unavailable:服务器暂时无法处理请求,可能是超载或维护中如何处理?

处理 "503 Service Unavailable" 错误是服务器管理者面临的常见挑战之一。这种错误通常表示服务器暂时无法处理请求,可能是由于服务器超载、维护中或其他临时性问题导致的。在本文中,我将介绍如何处理 "503 Service Unavailable" 错…...

Grafana 地图本土化方案:使用高德地图API平替GeoMap地图指南

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 📢 大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(De…...

亚马逊AWS云服务器高效使用指南:最大限度降低成本的实战策略

对于初次接触云计算的企业或个人开发者而言,亚马逊云服务器(Amazon EC2)的配置与成本控制往往面临双重挑战:既要理解数百种实例规格的技术参数,又要避免因配置不当导致的资源浪费。本文将深入剖析AWS EC2的核心使用场景…...