import os
import sys
from typing import Dict
import numpy as np
from scipy.spatial.transform import Rotation as R
from SmplObject import SmplObjects
from pyfbx import *
try:
from fbx import *
from FbxCommon import *
except ImportError:
print("Error: module FbxCommon failed to import.\n")
print(
"Copy the files located in the compatible sub-folder lib/python<version> into your python interpreter site-packages folder."
)
import platform
if platform.system() == "Windows" or platform.system() == "Microsoft":
print(
"For example: copy ..\\..\\lib\\Python37_x64\\* C:\\Python37\\Lib\\site-packages"
)
elif platform.system() == "Linux":
print(
"For example: cp ../../lib/Python37_x64/* /usr/local/lib/python3.7/site-packages"
)
elif platform.system() == "Darwin":
print(
"For example: cp ../../lib/Python37_x64/* /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages"
)
class FbxReadWrite(object):
def __init__(self, fbx_source_path):
# Prepare the FBX SDK.
lSdkManager, lScene = InitializeSdkObjects()
self.lSdkManager = lSdkManager
self.lScene = lScene
# Load the scene.
# The example can take a FBX file as an argument.
lResult = LoadScene(self.lSdkManager, self.lScene, fbx_source_path)
if not lResult:
raise Exception("An error occured while loading the scene :(")
def _write_curve(self, lCurve: FbxAnimCurve , data: np.ndarray):
"""
data: np.ndarray of (N, )
"""
lKeyIndex = 0
lTime = FbxTime()
lTime.SetGlobalTimeMode(FbxTime.eFrames30) # Set to fps=60
data = np.squeeze(data)
lCurve.KeyModifyBegin()
for i in range(data.shape[0]):
lTime.SetFrame(i, FbxTime.eFrames30)
lKeyIndex = lCurve.KeyAdd(lTime)[0]
lCurve.KeySetValue(lKeyIndex, data[i])
lCurve.KeySetInterpolation(lKeyIndex, FbxAnimCurveDef.eInterpolationCubic)
lCurve.KeyModifyEnd()
def addAnimation(self, pkl_filename: str, smpl_params: Dict, verbose: bool = False):
lScene = self.lScene
# 0. Set fps to 30
lGlobalSettings = lScene.GetGlobalSettings()
lGlobalSettings.SetTimeMode(FbxTime.eFrames30)
self.destroyAllAnimation()
lAnimStackName = pkl_filename
lAnimStack = FbxAnimStack.Create(lScene, lAnimStackName)
lAnimLayer = FbxAnimLayer.Create(lScene, "Base Layer")
lAnimStack.AddMember(lAnimLayer)
lRootNode = lScene.GetRootNode()
names = SmplObjects.joints
# rotate back to y-up for rendering in blender, three.js etc
rotation = R.from_quat(np.array([ -0.7071068, 0, 0, 0.7071068 ])) # -90 degrees about the x axis
# 1. Write smpl_poses
smpl_poses = smpl_params["smpl_poses"]
for idx, name in enumerate(names):
node = lRootNode.FindChild(name)
rotvec = smpl_poses[:, idx * 3 : idx * 3 + 3]
# if root, rotate
if name == "m_avg_Pelvis":
rotvec = (rotation * R.from_rotvec(rotvec)).as_rotvec()
euler = R.from_rotvec(rotvec).as_euler("xyz", degrees=True)
lCurve = node.LclRotation.GetCurve(lAnimLayer, "X", True)
if lCurve:
self._write_curve(lCurve, euler[:, 0])
else:
print("Failed to write {}, {}".format(name, "x"))
lCurve = node.LclRotation.GetCurve(lAnimLayer, "Y", True)
if lCurve:
self._write_curve(lCurve, euler[:, 1])
else:
print("Failed to write {}, {}".format(name, "y"))
lCurve = node.LclRotation.GetCurve(lAnimLayer, "Z", True)
if lCurve:
self._write_curve(lCurve, euler[:, 2])
else:
print("Failed to write {}, {}".format(name, "z"))
# 3. Write smpl_trans to f_avg_root
smpl_trans = rotation.apply(smpl_params["smpl_trans"])
name = "m_avg_Pelvis"
node = lRootNode.FindChild(name)
lCurve = node.LclTranslation.GetCurve(lAnimLayer, "X", True)
if lCurve:
self._write_curve(lCurve, smpl_trans[:, 0])
else:
print("Failed to write {}, {}".format(name, "x"))
lCurve = node.LclTranslation.GetCurve(lAnimLayer, "Y", True)
if lCurve:
self._write_curve(lCurve, smpl_trans[:, 1])
else:
print("Failed to write {}, {}".format(name, "y"))
lCurve = node.LclTranslation.GetCurve(lAnimLayer, "Z", True)
if lCurve:
self._write_curve(lCurve, smpl_trans[:, 2])
else:
print("Failed to write {}, {}".format(name, "z"))
def writeFbx(self, write_base: str, filename: str):
if os.path.isdir(write_base) == False:
os.makedirs(write_base, exist_ok=True)
write_path = os.path.join(write_base, filename.replace(".pkl", ""))
lResult = SaveScene(self.lSdkManager, self.lScene, write_path)
if lResult == False:
raise Exception("Failed to write to {}".format(write_path))
def destroy(self):
self.lSdkManager.Destroy()
def destroyAllAnimation(self):
lScene = self.lScene
animStackCount = lScene.GetSrcObjectCount(
FbxCriteria.ObjectType(FbxAnimStack.ClassId)
)
for i in range(animStackCount):
lAnimStack = lScene.GetSrcObject(
FbxCriteria.ObjectType(FbxAnimStack.ClassId), i
)
lScene.RemoveMember(lAnimStack)
smpl2fbx smpl pkl 转 fbx EDGE模型
需积分: 0 77 浏览量
更新于2024-06-06
1
收藏 4.82MB ZIP 举报
在3D建模领域,转换模型格式是一项常见的任务,以便在不同的软件或平台间兼容。本文将详细探讨“smpl2fbx”工具,它主要用于将SMPL模型转换为FBX格式,特别是处理包含EDGE信息的模型。SMPL(Skinned Multi-Person Linear)是一种广泛使用的、基于人体形状和姿势的三维人体模型。FBX(Filmbox)则是Autodesk公司开发的一种跨平台的3D模型交换格式,被许多3D软件如Maya、Unity、Unreal Engine等广泛支持。
标题提到的“smpl2fbx smpl pkl 转 fbx EDGE模型”,意味着这个工具不仅转换基本的SMPL模型,还处理了模型的边缘数据。在3D建模中,边缘信息通常指模型的轮廓线,对于渲染和动画至关重要,因为它定义了模型的几何形状和边界。
描述中的"python smpl2fbx_v2/Convert_smpl.py --input_dir 'inputpath' --output_dir 'outpath'"是命令行用法,展示了如何运行这个Python脚本来执行转换。`Convert_smpl.py`是实际执行转换的脚本,位于`smpl2fbx_v2`目录下。`--input_dir`参数用于指定包含SMPL模型(通常是以.pkl格式存储的)的输入目录,而`--output_dir`则定义了转换后FBX文件的输出位置。
SMPL模型通常由一系列参数控制,包括身体形状、关节旋转等,这些参数以pickle格式存储,这是一种Python特有的数据序列化格式。转换过程中,`Convert_smpl.py`会读取这些参数,并将其转化为FBX能够理解的格式。
转换过程可能涉及以下几个关键步骤:
1. **解析SMPL模型**:脚本需要读取.pkl文件,解码SMPL模型的形状参数和关节信息。
2. **构建3D网格**:基于解码的参数,脚本将重建SMPL模型的三角网格,包括边缘信息。
3. **应用皮肤权重**:SMPL模型使用骨骼权重来驱动网格变形,这一部分需要转换到FBX的骨骼绑定系统。
4. **保存FBX格式**:脚本将3D网格、骨骼结构和权重信息保存为FBX文件,同时保留原始的边缘信息。
在实际应用中,这种转换工具可以用于多个场景,例如,从研究环境(通常使用SMPL模型)转移到游戏开发或电影制作(更倾向于FBX格式)。此外,保留EDGE信息对3D渲染、光照计算和碰撞检测都有重要意义。
“smpl2fbx”工具提供了从SMPL到FBX的有效转换,特别关注了对模型边缘信息的处理,使得3D艺术家和开发者能够在不同的工作流程之间无缝切换。通过Python脚本进行自动化处理,大大提高了工作效率,简化了复杂3D模型格式之间的转换过程。
GO·GO·GO
- 粉丝: 134
- 资源: 5
最新资源
- 基于HX711&STM32的压力传感器详细文档+全部资料+高分项目.zip
- 基于Linux的kfifo移植到STM32详细文档+全部资料+高分项目.zip
- 基于OneNet的stm32环境监测系统详细文档+全部资料+高分项目.zip
- 基于IMU和STM32的独轮自平衡机器人详细文档+全部资料+高分项目.zip
- 基于STLinkV21的STM32编程器和flash烧写器详细文档+全部资料+高分项目.zip
- 基于openmv+stm32的二维云台追踪系统详细文档+全部资料+高分项目.zip
- mmexport1735006369325.png
- mmexport1735006372544.png
- 基于STM32 HAL库的FOC封装详细文档+全部资料+高分项目.zip
- 基于stm32,cubemx,hal库的简易任务轮询,任务调度系统详细文档+全部资料+高分项目.zip
- 用python实现贪吃蛇
- wifi软件计算机基础 第二套(1).7z
- 美国国家健康与营养调查(NHANES).zip
- 基于stm32+fpgaecon位置模块详细文档+全部资料+高分项目.zip
- IT服务器,路由器等命令行式设备维护-命令行批量操作工具-免费分享
- 基于STM32、ESP8266、EMQX和Android的智能家居系统详细文档+全部资料+高分项目.zip