前言:什么是GLTF?

原文解释是:GLTF是一种被广泛使用的文件格式,用来储存3D模型和3D场景。在xr-frame里你可以非常轻松地引入任意GLTF模型,并将其渲染出来。想要更详细的讲解:glTF -传输格式

优势(摘自GLTF介绍 | 微信开放文档 (qq.com)):

  •  单一文件,完整场景

使用GLTF打包后的GLB文件,可将一整个场景的所有要素包揽进去。轻松管理你的3D资源。

  •  成熟生态,海量资源

来自全世界的优秀创作者,在不同社区中分享作品。配合xr-frame的渲染能力,简直是随取随用。

1.GLTF模型需要先通过Loader加载进小程序中,才可以渲染。

<xr-asset-load type="gltf" asset-id="gltfModel" src="/assets/xxx.gltf" />

2.GLTF组件

GLTF组件可以渲染一个已经加载完成的GLTFModel资源。

使用xr-gltf标签可以为标签自动创建GLTF组件

<xr-gltf id="myGLTF" model="gltfModel"></xr-gltf>

 3.标签属性

 4.事件:

5.修改 :

GLTF组件提供了一系列接口来让用户操作xr-frame为GLTF模型生成的内部子树,开发者也可以用这些接口来动态修改glTF模型的颜色、纹理等材质属性

用法:修改GLTF贴图

// gltf信息
{
    ...
    "nodes": [{
      "mesh": 0,
      "name": "Banana"
    }],
    ...
}
<xr-gltf id="myGLTF" model="gltfModel" bind:gltf-loaded="handleGLTFLoaded"></xr-gltf>
function handleGLTFLoaded({ detail }) {
    const el = detail.value.target;
    //获取名字为nana的mesh
    const gltf = el.getComponent("gltf");
    const newMat = this.scene.assets.getAsset("texture", "...texture name...");
    for (const mesh of gltf.getPrimitivesByNodeName("Banana")) {
         //更改材质
        mesh.material.setTexture("u_baseColorMap", newMat);
    }
}

6.动画

如果GLTF模型有自带的动画,就会在当前元素下自动创建一个Animator组件,并将GLTF模型内的动画片段加入到这个Animator组件中。 

如果GLTF组件所在的元素本来已经拥有Animator组件,就不会新建,而是直接使用这个Animator组件。 在标签上添加anim-autoplay属性可以自动播放GLTF模型内的动画,会播放GLTF内的所有动画片段:

  •  自身就有动画直接加 anim-autoplay
<xr-gltf id="myGLTF" model="gltfModel" anim-autoplay></xr-gltf>
  • 使用animator实现动画

1) 设置动画json

{
  "keyframe": {
    "parent": {
      "0": {
        "rotation": [0, 0, 0]
      },
      "100": {
        "rotation": [0, 6.28, 0]
      }
    },
    "child": {
      "0": {
        "position.y": -0.5
      },
      "100": {
        "position.y": 1.5
      }
    }
  },
  "animation": {
    "parent": {
      "keyframe": "parent",
      "duration": 8,
      "ease": "linear",
      "loop": -1
    },
    "child": {
      "keyframe": "child",
      "duration": 4,
      "ease": "ease-in-out",
      "direction": "both",
      "loop": -1
    }
  }
}

2)加载动画资源

 <xr-asset-load asset-id="anim" type="keyframe" src="/assets/animation/miku-kawaii-animation.json"/>

3)绑定动画

  <xr-node anim-keyframe="anim" anim-autoplay="clip:parent">

4)控制动画

如果你只想播放GLTF模型里的某一个动画片段,或者想切换播放的动画片段,可以使用TS脚本来控制。

例如以下代码在GLTF模型渲染完毕后播放名为idle的动画:

// xml
<xr-gltf id="myGLTF" model="gltfModel" bind:gltf-loaded="handleGLTFLoaded"></xr-gltf>
// ts
function handleGLTFLoaded({ detail }) {
    const el = detail.value.target;
    const animator = el.getComponent("animator");
    animator.play("idle");
}

动画的名字idle,对应的是.gltf文件中animations数组节点的每一个元素的name属性(参考官方文档)。

7.Morph Target:(demo详见下篇文章)

1.什么是Morph Target?详见:静态网格体变形目标 | 虚幻引擎文档 (unrealengine.com)

xr-frame支持Morph Target动画,但是对target的数量有限制,同一个模型最多使用8个target

这里的target概念有别于.gltf文件内的target节点:.gltf文件内的一个同时拥有POSITIONNORMAL属性的target节点,在xr-frame中算作2个target(不影响渲染效果)。

8.注意事项(gltf模型限制)

GLTF模型需要满足以下条件才能正常渲染:

  • 纹理使用的顶点UV不超过2个;
  • 使用的顶点JOINTS不超过1个;
  • 使用的顶点WEIGHTS不超过1个;
  • 不使用sparse accessor
  • accessornormalized属性不为true
  • morph targets数量小于等于8个;
  • morph的属性为POSITION,NORMALTANGENT
  • 图元类型不为LINE_LOOPTRIANGLE_FAN;

经测试,只有少数模型会超出限制,大多数模型都可以正常渲染。并且随着项目迭代,未来将会解除或者放宽一些条件。

9.典型案例(多动画显示demo来源于微信开放文档

1)wxml部分

<xr-scene id="xr-scene" bind:ready="handleReady">
  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
    <xr-asset-load asset-id="anim" type="keyframe" src="/assets/animation/miku-kawaii-animation.json"/>
    <xr-asset-load type="gltf" asset-id="cloud-station" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/cloud-station/index.glb" />
    <xr-asset-load type="gltf" asset-id="miku-kawaii" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/shiteyanyo-hatsune-miku/index.glb" />
    <xr-asset-load type="gltf" asset-id="miku" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/miku.glb" />
  </xr-assets>
  <xr-node>
    <xr-node node-id="target" position="0 1 0" />
    <xr-gltf position="0 0 0" scale="1 1 1" model="cloud-station" anim-autoplay></xr-gltf>
    <xr-gltf position="1.8 -0.5 1.5" scale="0.12 0.12 0.12" rotation="0 180 0" model="miku" anim-autoplay></xr-gltf>
    <xr-node anim-keyframe="anim" anim-autoplay="clip:parent">
      <xr-node position="0 -0.5 3" rotation="0 90 0" anim-keyframe="anim" anim-autoplay="clip:child">
        <xr-gltf model="miku-kawaii" anim-keyframe="anim" anim-autoplay></xr-gltf>
      </xr-node>
    </xr-node>
    <xr-camera
      id="camera" node-id="camera" position="0 1 7" clear-color="0.925 0.925 0.925 1"
      target="target" background="default" 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="40 180 0" color="1 1 1" intensity="2" />
  </xr-node>
</xr-scene>

2)json动画部分

{
  "keyframe": {
    "parent": {
      "0": {
        "rotation": [0, 0, 0]
      },
      "100": {
        "rotation": [0, 6.28, 0]
      }
    },
    "child": {
      "0": {
        "position.y": -0.5
      },
      "100": {
        "position.y": 1.5
      }
    }
  },
  "animation": {
    "parent": {
      "keyframe": "parent",
      "duration": 8,
      "ease": "linear",
      "loop": -1
    },
    "child": {
      "keyframe": "child",
      "duration": 4,
      "ease": "ease-in-out",
      "direction": "both",
      "loop": -1
    }
  }
}

3)js部分

Component({
  properties: {
    a: Number,
  },
  data: {
    loaded: false
  },
  lifetimes: {
    attached() {
      console.log('data.a', this.data.a) // expected 123
    }
  },
  methods: {
    handleReady: function({detail}) {
      this.scene = detail.value;
      console.log('scene', detail.value);
    },
    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);
    }
  }
})

4)效果展示

xr-frame gltf动画

05-22 16:28