前言:什么是GLTF?
原文解释是:GLTF是一种被广泛使用的文件格式,用来储存3D模型和3D场景。在xr-frame里你可以非常轻松地引入任意GLTF模型,并将其渲染出来。想要更详细的讲解:glTF -传输格式;
优势(摘自GLTF介绍 | 微信开放文档 (qq.com)):
使用GLTF打包后的GLB文件,可将一整个场景的所有要素包揽进去。轻松管理你的3D资源。
来自全世界的优秀创作者,在不同社区中分享作品。配合xr-frame的渲染能力,简直是随取随用。
1.GLTF模型需要先通过Loader加载进小程序中,才可以渲染。
2.GLTF组件
GLTF组件
可以渲染一个已经加载完成的GLTFModel
资源。
使用xr-gltf
标签可以为标签自动创建GLTF组件
:
3.标签属性
属性名 | 组件.属性 | 备注 |
---|---|---|
model | GLTF.model | 使用的GLTFModel资源,对应xr-asset-load 标签中的asset-id属性 |
cast-shadow | GLTF.castShadow | GLTF模型是否投射阴影 |
receive-shadow | GLTF.receiveShadow | GLTF模型是否接受阴影 |
4.事件:
事件名 | 描述 | 事件回调参数 | 备注 |
---|---|---|---|
gltf-loaded | GLTF组件将GLTFModel渲染完毕后触发。 | { target: Element } | - |
5.修改 :
GLTF组件提供了一系列接口来让用户操作xr-frame为GLTF模型生成的内部子树,开发者也可以用这些接口来动态修改glTF模型的颜色、纹理等材质属性。
接口名 | 描述 | 备注 |
---|---|---|
getInternalNodeByName | 根据GLTFNode节点的name 字段来获取xr-frame对应的Element |
|
get meshes | 获取生成的所有Mesh组件 |
|
getPrimitivesByNodeName | 根据GLTFNode节点的name 字段来获取其下的所有Mesh组件 |
2.28.1版本加入;详见API文档 |
getPrimitivesByMeshName | 根据GLTFMesh节点的name 字段来获取所有相关的Mesh组件 |
2.28.1版本加入;详见API文档 |
用法:修改GLTF贴图
// gltf信息
{
...
"nodes": [{
"mesh": 0,
"name": "Banana"
}],
...
}
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内的所有动画片段:
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)加载动画资源
3)绑定动画
4)控制动画
如果你只想播放GLTF模型里的某一个动画片段,或者想切换播放的动画片段,可以使用TS脚本来控制。
例如以下代码在GLTF模型渲染完毕后播放名为idle
的动画:
// xml
// 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文件内的一个同时拥有POSITION
和NORMAL
属性的target节点
,在xr-frame
中算作2个target
(不影响渲染效果)。
8.注意事项(gltf模型限制)
GLTF模型
需要满足以下条件才能正常渲染:
UV
不超过2个;JOINTS
不超过1个;WEIGHTS
不超过1个;sparse accessor
;accessor
的normalized
属性不为true
;morph targets
数量小于等于8个;morph
的属性为POSITION
,NORMAL
或TANGENT
;图元类型
不为LINE_LOOP
或TRIANGLE_FAN
;经测试,只有少数模型会超出限制,大多数模型都可以正常渲染。并且随着项目迭代,未来将会解除或者放宽一些条件。
9.典型案例(多动画显示demo来源于微信开放文档)
1)wxml部分
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动画