基础知识:
-
动画系统
xr-frame
中所有的动画都是通过动画系统AnimationSystem
统一管理的,在每帧的同一个时机统一更新。动画系统自身没有什么逻辑,所有的逻辑都是在动画组件Animator
和动画实现Animation
中的。
-
动画实现
1.动画json数据(类似于CSS):
{
"keyframe": {
"cube": {
"0": {
"position": [-3, 0, 2]
},
"50": {
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
},
"100": {
"position": [3, 0, 2],
"rotation": [0, 3.14, 0],
"scale": [1.4, 1.4, 1.4]
}
},
"sphere": {
"0": {
"position": [-3, 0, 0],
"scale": [0.8, 0.8, 0.8]
},
"50": {
"position": [0, 0.2, 0],
"scale": [1, 1, 1]
},
"100": {
"position": [3, 0, 0],
"scale": [0.8, 0.8, 0.8]
}
},
"cylinder": {
"0": {
"position": [-3, 0, -2],
"rotation": [0, 0, 0]
},
"50": {
"rotation": [0, 0, -3.14]
},
"100": {
"position": [3, 0, -2],
"rotation": [0, 0, 3.14]
}
},
"plane": {
"0": {
"material.u_baseColorFactor": [0.48, 0.78, 0.64, 1]
},
"50": {
"material.u_baseColorFactor": [0.368, 0.937, 0.176, 1]
},
"100": {
"material.u_baseColorFactor": [0.176, 0.368, 0.937, 1]
}
},
"spotLight": {
"0": {
"position": [-4, 1, -4]
},
"25": {
"position": [-4.3, 0.5, -2]
},
"75": {
"position": [-3, 1.5, 2]
},
"100": {
"position": [-4, 1, 4]
}
}
},
"animation": {
"default": {
"keyframe": "cube",
"duration": 1,
"ease": "ease-in-out",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"sphere": {
"keyframe": "sphere",
"duration": 1,
"ease": "ease-out",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"cylinder": {
"keyframe": "cylinder",
"duration": 1,
"ease": "ease-in",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"plane": {
"keyframe": "plane",
"duration": 4,
"ease": "linear",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"spotLight": {
"keyframe": "spotLight",
"duration": 2,
"ease": "ease-in-out",
"loop": 400000,
"delay": 1,
"direction": "both"
}
}
}
- 属性的值为number、number-array和color类型的数据都可以进行动画,程序会自动计算关键帧之间每一帧每个属性的值应该是多少。
- 除了position、rotation、scale之外,像material.u_baseColorFactor这样的属性也可以,如下,可以改变物体的颜色。
"0": {
"material.u_baseColorFactor": [0.48, 0.78, 0.64, 1]
},
"100": {
"material.u_baseColorFactor": [0.176, 0.368, 0.937, 1]
}
2.引入动画(type="keyframe")
<xr-asset-load asset-id="basic-anim" type="keyframe" src="../basic-animation.json"/>
3.模型或者节点绑定动画
<xr-mesh
node-id="mesh-cube" position="-3 0 2" scale="1 1 1" rotation="0 0 0" geometry="cube" material="standard-mat" uniforms="u_baseColorFactor:0.298 0.764 0.85 1"
anim-keyframe="basic-anim" anim-clipmap="default:cube" anim-autoplay="clip:cube, speed:2"
cast-shadow
></xr-mesh>
注明:此案例用到的动画:(default:cube")
1. anim-keyframe:绑定动画的名字对应动画资源asset-id;
2. anim-clipmap:绑定动画数据中的名字;
3. anim-autoplay:
.第一种情况不加参数:模型自身的动画;
.第二种情况加参数:anim-autoplay对应json中的动画名,还可以指定速度;
整体代码效果(来源于:动画系统 | 微信开放文档)
- wxml部分:
<xr-scene id="xr-scene" bind:ready="handleReady">
<xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
<xr-asset-load asset-id="basic-anim" type="keyframe" src="/assets/animation/basic-animation.json"/>
<xr-asset-load type="texture" asset-id="waifu" src="/assets/waifu.png" />
<xr-asset-material asset-id="standard-mat" effect="standard" />
</xr-assets>
<xr-node>
<xr-node node-id="camera-target" position="0 0 0"></xr-node>
<xr-mesh
node-id="mesh-plane" position="0 -0.8 0" rotation="0 0 0" scale="10 1 8" geometry="plane" material="standard-mat" uniforms="u_baseColorFactor:0.48 0.78 0.64 1" states="cullOn: false"
anim-keyframe="basic-anim" anim-autoplay="clip:plane, speed:4"
receive-shadow
></xr-mesh>
<xr-mesh
node-id="mesh-cube" position="-3 0 2" scale="1 1 1" rotation="0 0 0" geometry="cube" material="standard-mat" uniforms="u_baseColorFactor:0.298 0.764 0.85 1"
anim-keyframe="basic-anim" anim-clipmap="default:cube" anim-autoplay="clip:cube, speed:2"
cast-shadow
></xr-mesh>
<xr-mesh
node-id="mesh-sphere" position="-3 0 0" scale="0.8 0.8 0.8" geometry="sphere" material="standard-mat" uniforms="u_baseColorFactor:0.937 0.176 0.368 1"
anim-keyframe="basic-anim" anim-autoplay="clip:sphere, speed:2"
cast-shadow
></xr-mesh>
<xr-mesh
node-id="mesh-cylinder" position="-3 0 -2" scale="1 0.6 1" geometry="cylinder" material="standard-mat" uniforms="u_baseColorFactor:1 0.776 0.364 1"
anim-keyframe="basic-anim" anim-autoplay="clip:cylinder, speed:2"
cast-shadow
></xr-mesh>
<xr-mesh node-id="mesh-light-cube" position="-5 1 0" scale="0.5 10 10" rotation="0 0 0" geometry="cube" material="standard-mat" uniforms="u_baseColorFactor:0.3 0.3 0.3 1, u_baseColorMap: waifu"></xr-mesh>
<xr-camera
id="camera" node-id="camera" position="5 3 0" clear-color="0.925 0.925 0.925 1"
target="camera-target"
camera-orbit-control=""
></xr-camera>
</xr-node>
<xr-node node-id="lights">
<xr-light type="ambient" color="1 1 1" intensity="1" />
<xr-light type="directional" rotation="30 230 0" color="1 1 1" intensity="3" cast-shadow/>
<xr-light
type="spot" position="-4 1 0" rotation="0 -90 0" color="0 1 0" range="20" intensity="100" inner-cone-angle="20" outer-cone-angle="60"
anim-keyframe="basic-anim" anim-autoplay="clip:spotLight, speed:2"
/>
</xr-node>
</xr-scene>
- js部分:
Component({
properties: {
a: Number,
},
data: {
loaded: false
},
lifetimes: {},
methods: {
handleReady({detail}) {
const xrScene = this.scene = detail.value;
console.log('xr-scene', xrScene);
},
handleAssetsProgress: function({detail}) {
console.log('assets progress', detail.value);
},
handleAssetsLoaded: function({detail}) {
console.log('assets loaded', detail.value);
this.setData({loaded: true});
},
handleRaf: function({detail}) {
console.log('raf', detail.value);
}
}
})
- 动画json部分:
{
"keyframe": {
"cube": {
"0": {
"position": [-3, 0, 2]
},
"50": {
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
},
"100": {
"position": [3, 0, 2],
"rotation": [0, 3.14, 0],
"scale": [1.4, 1.4, 1.4]
}
},
"sphere": {
"0": {
"position": [-3, 0, 0],
"scale": [0.8, 0.8, 0.8]
},
"50": {
"position": [0, 0.2, 0],
"scale": [1, 1, 1]
},
"100": {
"position": [3, 0, 0],
"scale": [0.8, 0.8, 0.8]
}
},
"cylinder": {
"0": {
"position": [-3, 0, -2],
"rotation": [0, 0, 0]
},
"50": {
"rotation": [0, 0, -3.14]
},
"100": {
"position": [3, 0, -2],
"rotation": [0, 0, 3.14]
}
},
"plane": {
"0": {
"material.u_baseColorFactor": [0.48, 0.78, 0.64, 1]
},
"50": {
"material.u_baseColorFactor": [0.368, 0.937, 0.176, 1]
},
"100": {
"material.u_baseColorFactor": [0.176, 0.368, 0.937, 1]
}
},
"spotLight": {
"0": {
"position": [-4, 1, -4]
},
"25": {
"position": [-4.3, 0.5, -2]
},
"75": {
"position": [-3, 1.5, 2]
},
"100": {
"position": [-4, 1, 4]
}
}
},
"animation": {
"default": {
"keyframe": "cube",
"duration": 1,
"ease": "ease-in-out",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"sphere": {
"keyframe": "sphere",
"duration": 1,
"ease": "ease-out",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"cylinder": {
"keyframe": "cylinder",
"duration": 1,
"ease": "ease-in",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"plane": {
"keyframe": "plane",
"duration": 4,
"ease": "linear",
"loop": 400000,
"delay": 1,
"direction": "both"
},
"spotLight": {
"keyframe": "spotLight",
"duration": 2,
"ease": "ease-in-out",
"loop": 400000,
"delay": 1,
"direction": "both"
}
}
}
- 效果展示:
xr-frame动画