Playcanvas是一款开源的3d引擎,底层格式是自家定义的json格式,其文档说明如下:
https://developer.playcanvas.com/en/user-manual/graphics/file-format/
但是在官网翻不到其动画文件的解析代码,这里根据其引擎源码的解析,对其源码文件格式解析如下记录
{
"animation":{
// 动画时长
"duration": 0.2,
"nodes":[
{
// key.t 动画对应的时间节点
// key.p 该时间节点对应的translations
// key.r 该时间节点对应的rotations
// key.s 该时间节点对应的scale
"keys":[
{"p":[0,0,0],"s":[1,1,1],"r":[0,0,0],"t":0}
],
//节点名称
"name": "RootNode",
// 一般为空,当keys为null时,取default作为keys的值
"default": {}
},
{
"keys":[
{"p":[0,0,0],"s":[1,1,1],"r":[0,0,0],"t":0},
{"p":[0.1,0,0],"s":[1,1,1],"r":[0,0,0],"t":0.1},
{"p":[0.1,0,0.1],"s":[1,1,1],"r":[0,0,0],"t":0.2}
],
"name": "Node1",
// 一般为空,当keys为null时,取default作为keys的值
"default": {}
}
]
}
}
实现playcanvas动画到gltf动画的转换(python代码示例)
animation_nodes = animation_data['nodes']
# 一般animation_nodes第一个节点为root,无需转换
animation_nodes.pop(0)
animations = []
channels = []
samplers = []
for animation_node in animation_nodes:
# 查找node name 对应 gltf node 的 index
node_index = self.search_node_index(animation_node['name'])
if node_index == -1:
continue
current_times = []
translations = []
rotations = []
scales = []
for key in animation_node['keys']:
current_times.append(key['t'])
translations.extend(key['p'])
rotations.extend(math_util.euler_to_quaternion(key['r']))
scales.extend(key['s'])
input_accessor = gltf_accessor_util.create_gltf_accessors(
current_times, AccessorComponentType.FLOAT, 'SCALAR', 0
)
output_t_accessor = gltf_accessor_util.create_gltf_accessors(
translations, AccessorComponentType.FLOAT, 'VEC3', 0
)
output_r_accessor = gltf_accessor_util.create_gltf_accessors(
rotations, AccessorComponentType.FLOAT, 'VEC4', 0
)
output_s_accessor = gltf_accessor_util.create_gltf_accessors(
scales, AccessorComponentType.FLOAT, 'VEC3', 0
)
# playcanvas每个node的p、r、s 对应 gltf三个sampler和channel
path_accessor_relatives = dict(
translation=output_t_accessor,
rotation=output_r_accessor,
scale=output_s_accessor,
)
for path, accessor in path_accessor_relatives.items():
samplers.append(
dict(
input=input_accessor,
interpolation='LINEAR', # 默认
output=accessor,
)
)
channels.append(
dict(
target=dict(node=node_index, path=path),
sampler=len(samplers) - 1,
)
)
if len(channels) > 0 and len(samplers) > 0:
animation_dict['channels'] = channels
animation_dict['samplers'] = samplers
# 当有多段动画(多个json)时,可以在最外层添加for循环,并添加到animations
animations.append(animation_dict)
if len(animations) > 0:
self.gltf_json['animations'] = animations