个人网站建设yxhuying,软件培训内容怎么写,公众号注册流程,seo是指什么岗位一#xff1a;应用场景
在工作中#xff0c;由于算法给到的动画文件是Unity的.anim格式动画文件#xff0c;这个格式不能直接在Web端用Three.js引擎运行。因此需要将.anim格式的动画文件转换为Three.js的AnimationClip动画对象。
二#xff1a;.ANIM格式与AnimationClip对…一应用场景
在工作中由于算法给到的动画文件是Unity的.anim格式动画文件这个格式不能直接在Web端用Three.js引擎运行。因此需要将.anim格式的动画文件转换为Three.js的AnimationClip动画对象。
二.ANIM格式与AnimationClip对象的差异
1. AnimationClip对象格式如下
// AnimationClip
{duration: Number // 持续时间name: String // 名称tracks: [ // 动画所有属性的关键帧轨道数组{name: String // 关键帧轨道标识符times: Float32Array // 时间数组values: Float32Array // 与时间数组中的时间点对应的相关值interpolation: Constant // 使用的插值类型},{...}] uuid: String // 实例的uuid
}2. Unity的.anim格式如下
它是用YAML写的这是一个专门用来写配置文件的语言。
注意坑点unity的.anim用的是yaml 1.1版本, yaml现在新版是1.2.x了。解析的时候注意版本是否兼容。我用js-yaml解析的时候发现它不兼容1.1旧版了Unity (Game Engine) Yaml parsing #100 降js-yaml版本后解决js-yaml: ^3.6.1,
.anim格式化后的内容如下
{AnimationClip: {m_ObjectHideFlags: 0,m_CorrespondingSourceObject: {fileID: 0},m_PrefabInstance: {fileID: 0},m_PrefabAsset: {fileID: 0},m_Name: Take 001,serializedVersion: 6,m_Legacy: 0,m_Compressed: 0,m_UseHighQualityCurve: 1,m_RotationCurves: [],m_CompressedRotationCurves: [],m_EulerCurves: [],m_PositionCurves: [],m_ScaleCurves: [],m_FloatCurves: [],m_PPtrCurves: [],m_SampleRate: 30,m_WrapMode: 0,m_Bounds: {},m_ClipBindingConstant: {},m_AnimationClipSettings: {},m_EditorCurves: [],m_EulerEditorCurves: [],m_HasGenericRootTransform: 0,m_HasMotionFloatCurves: 0,m_Events: []}
}三 anim格式转AnimationClip对象格式
1. 骨骼蒙皮动画
.anim文件的时间信息很可能不是按每帧给出的如果直接转换为AnimationClip格式没有进行插值运算算出每一帧的信息这样用three.js运行起来的实际效果会卡顿。
目前从网上找了个带动画的模型测了下效果 模型对象里的原始AnimationClip运行效果每秒30帧
Unity动画转Three.js动画: 模型原始的骨骼动画效将模型导入Unity后生成.anim动画文件。再通过脚本将这个.anim动画文件 转换为 AnimationClip对象 的运行效果如下没有进行插值缺帧导致有点卡顿 Unity动画转Three.js动画: 转换后卡顿的骨骼动画2. 顶点变形动画3d捏脸
blendshape动画的转换没有骨骼蒙皮动画转换缺帧的问题。它只需要有初始值和末值three.js会进行插值运算。
四关键代码
import * as THREE from three;
interface AnimationClip {name: string,duration: number,tracks: any[],uuid: string,
}const get_three_js_track_type: any {scale: vector,quaternion: quaternion,position: vector,
}const parse_unity_curve (curve: any, curve_type: string) {const type get_three_js_track_type[curve_type];const name curve.path.split(/).slice(-1) . curve_type;const values [];const times [];for (let cc of curve.curve.m_Curve) {times.push(cc.time)if (curve_type quaternion) {values.push(cc.value.x)values.push(-cc.value.y)values.push(-cc.value.z)values.push(cc.value.w)} else if (curve_type position) {values.push(-cc.value.x * 100)values.push(cc.value.y * 100)values.push(cc.value.z * 100)} else if (curve_type scale) {values.push(cc.value.x)values.push(cc.value.y)values.push(cc.value.z)}}// if (curve_type quaternion) {// return new THREE.AnimationClip(name, times, values);// }// if (curve_type position) {// return new THREE.VectorKeyframeTrack(name, times, values);// }return {type,name,times,values,}
}const getAnimateClip (obj: any, type: string, morphTargetDictionary?: any) {const data: any {name: ,duration: 0,tracks: [],uuid: 18A2138E-2ABF-4B83-AA15-C1D85BCE2F76,}data.name obj.AnimationClip.m_Name;data.duration obj.AnimationClip.m_AnimationClipSettings.m_StopTime - obj.AnimationClip.m_AnimationClipSettings.m_StartTime;if (obj.AnimationClip.m_ScaleCurves.length 0) {for(const curve of obj.AnimationClip.m_ScaleCurves) {data.tracks.push(parse_unity_curve(curve, scale));}}if (obj.AnimationClip.m_RotationCurves.length 0) {for (const curve of obj.AnimationClip.m_RotationCurves) {data.tracks.push(parse_unity_curve(curve, quaternion));}}if (obj.AnimationClip.m_PositionCurves.length 0) {for (const curve of obj.AnimationClip.m_PositionCurves) {data.tracks.push(parse_unity_curve(curve, position));}}if (obj.AnimationClip.m_FloatCurves.length 0) {for (const item of obj.AnimationClip.m_FloatCurves) {let name ;if (type fbx) {name item.path.split(/).slice(-1) .morphTargetInfluences[ morphTargetDictionary[item.attribute.replace(blendShape., )] ]} else if (type glb) {name item.path.split(/).slice(-1) .morphTargetInfluences[ morphTargetDictionary[item.attribute.split(.).slice(-1)[0]] ]}const values [];const times [];const firstCC item.curve.m_Curve[0];const lastCC item.curve.m_Curve.slice(-1)[0]times.push(firstCC.time);times.push(lastCC.time);values.push(/e-/.test(firstCC.value) ? 0 : (firstCC.value / 100))values.push(/e-/.test(lastCC.value) ? 0 : (lastCC.value / 100))const track new THREE.NumberKeyframeTrack(name, times, values);data.tracks.push(track)}}return data;
}export {getAnimateClip,
}