当前位置: 首页 > 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是一个完整的框架,提供了各种各样的功能,包括依赖注入、面向切面编程、数据访问、事务管…...

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

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

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...