抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Character Creator 插件开发

最近在CC 4/iClone 8开发Python插件,真的是小刀拉屁股,开了眼了,都不知道该从哪里开始吐槽,如果说maya脚本开发叫恶心,CC脚本开发就是阴间

  • 去年CC 4发布,改动了大量API,大部分API都变成Experimental API,之前(指五六年前)的样例代码大多失效,并不不再维护(不会改你可以不改)
  • 官方文档简陋无比,大部分函数和参数没有用法和解释,写满了# No example
  • 给官方发邮件(这是花了钱的)问Python相关的东西,官方只会复读“脚本还在开发,可能有功能不全,你可以尝试去论坛问”
  • 官方论文发言需要审核,我提了两个问题都被拒绝发布(我发邮件你让我去论坛,我去论坛你堵我嘴)
  • 脚本功能不全,有些功能可以读写,有些是只读(像maya你的每一步操作都是由命令实现的,甚至会在窗口将当前命令输出出来)

介绍

Character Creator是reallusion推出的一款商业捏脸软件,可以制作表情动作、动作捕捉等。使用成本比较高,大部分公司都不会使用,网上的信息远少于Maya、3DMax这类DCC。

cc

CC支持使用Python编写脚本、插件,可以通过顶部导航栏中Script--Load Python加载脚本,通过Script--Console Log 打开Log面板,不过这个Log面板远不如Maya的面板信息齐全。

iClone是该公司的另一款软件,用于制作动画,功能与CC十分接近,可以参考iClone的文档编写插件

环境配置

可以参考maya python脚本的环境配置,当时使用的是PyCharm,这里我们使用VS Code

  1. VS Code安装Python插件

vscode-python

  1. 选择Python解释器(按ctrl+shift+p打开命令界面)

python解释器

python解释器2

编写脚本

脚本本身不难写,主要是文档和论坛信息太少,某些API的使用可以参考iClone的文档,下面是我认为值得处理的东西

创建带有按钮的窗口

加载脚本后会出现一个对话框,对话框中有一个Label和一个按钮,当按按钮时可以输出”Hello World“

import RLPy
from shiboken2 import wrapInstance
from PySide2 import QtWidgets

def run():
print("Hello world")

# 类似于main函数,是脚本的入口,加载脚本时自动执行该函数
def run_script():
# 创建一个对话框
rl_dialog = RLPy.RUi.CreateRDialog()
# 设置对话框名称
rl_dialog.SetWindowTitle("Main Dialog")

pyside_dialog = wrapInstance(int(rl_dialog.GetWindow()), QtWidgets.QDialog)
# 设置对话框宽度
pyside_dialog.setFixedWidth(200)
sample_layout = pyside_dialog.layout()
# 一个Label
label_hello = QtWidgets.QLabel("Hello World")
# 一个Button
button_run = QtWidgets.QPushButton("run")
# Button绑定事件函数 run
button_run.clicked.connect(run)

sample_layout.addWidget(label_hello)
sample_layout.addWidget(button_run)

rl_dialog.Show()

cc_dialog

定时任务

定时任务十分重要,通过开启计时,就会定时执行Timeout()内到操作

# 计时器回调
class TimerCallback(RLPy.RPyTimerCallback):
def __init__(self):
RLPy.RPyTimerCallback.__init__(self)

def Timeout(self):
# 类似于Update
print("Timeout")

# timer,计时器应当放在全局
timer = RLPy.RPyTimer()
# 设置间隔为 1000 ms
timer.SetInterval(1000)
# 定时器设为可以重复触发
timer.SetSingleShot(False)
# 注册事件
timer_callback = TimerCallback()
timer.RegisterPyTimerCallback(timer_callback)

def apply():
# 开始计时
timer.Start()

def cancel():
# 暂停计时
timer.Stop()

def run_script():
# menu
rl_dialog = RLPy.RUi.CreateRDialog()
rl_dialog.SetWindowTitle("main_dialog")

pyside_dialog = wrapInstance(int(rl_dialog.GetWindow()), QtWidgets.QDialog)
pyside_dialog.setFixedWidth(200)
sample_layout = pyside_dialog.layout()

button_apply = QtWidgets.QPushButton("Apply")
button_apply.clicked.connect(apply)
button_cancel = QtWidgets.QPushButton("Cancel")
button_cancel.clicked.connect(cancel)

sample_layout.addWidget(button_apply)
sample_layout.addWidget(button_cancel)

rl_dialog.Show()

导出当前模型

官网甚至还在用iClone7的老东西误导你,太可恶了!

def export():
# 获取当前场景所有的人物模型(一般只有一个)
all_avatars = RLPy.RScene.GetAvatars(RLPy.EAvatarType_All)
avatar_name = None
for _iter_avatar in all_avatars:
avatar_name = _iter_avatar.GetName()
avatar = RLPy.RScene.FindObject(RLPy.EObjectType_Avatar, avatar_name)
# 导出选项
export_option = RLPy.EExportFbxOptions__None
export_option2 = RLPy.EExportFbxOptions2__None
export_option3 = RLPy.EExportFbxOptions3__None
export_option = export_option | RLPy.EExportFbxOptions_AutoSkinRigidMesh
export_option2 = export_option2 | RLPy.EExportFbxOptions2_ResetBoneScale
original_size = RLPy.EExportTextureSize_Original
default_format = RLPy.EExportTextureFormat_Default

setting = RLPy.RExportFbxSetting()
setting.SetOption(export_option)
setting.SetOption2(export_option2)
setting.SetOption3(export_option3)
setting.SetTextureSize(original_size)
setting.SetTextureFormat(default_format)
setting.EnableExportMotion(True) # 开启动画导出,启动后默认导出当前Pose
setting.SetExportMotionFps(RLRy.RFps(60)) # 设置导出动画的帧率,会影响动画数据的精度

# 导出文件
result = RLPy.RFileIO.ExportFbxFile(avatar, f"D://Art/man/{file_name}.fbx", setting)

if(result):
print("Success export fbx")
else:
print("Export error")

评论