微信小程序xr-frame实现动画

基础知识:

  • 动画系统

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动画

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值