XR-FRAME Beta /开始
开始
xr-frame是一套小程序官方提供的XR/3D应用解决方案,基于混合方案实现,性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准。
在这一章中,我们将会带大家从头开始,用它构建一个 XR 小程序。
本文只是开始指南,更加详细的信息请见组件框架文档和API文档。
⚠️ xr-frame
目前仍然是是 Beta 版本,需要Nightly版本的工具,特定客户端(8.0.29以上)和基础库(2.28.1以上),更多限制请见限制和展望。
新建一个 XR 组件
首先创建项目,让我们选择小程序工程:
之后先在app.json
加上一行配置:"lazyCodeLoading": "requiredComponents"
。然后创建好组件文件夹,新建一个组件,然后修改组件的内容:
index.json:
{
"component": true,
"renderer": "xr-frame",
"usingComponents": {}
}
index.wxml:
<xr-scene>
<xr-camera clear-color="0.4 0.8 0.6 1" />
</xr-scene>
在index.json
中,我们指定了这个组件的渲染器是xr-frame
;在index.wxml
中,我们创建了一个场景xr-scene
,并在其下添加了一个相机xr-camera
。
在页面中使用这个组件
创建完组件后,便可以在页面中使用它,让我们进入pages/index
,修改它的json
、wxml
和ts
文件:
在json
中:
{
"usingComponents": {
"xr-start": "../../components/xr-start/index"
},
"disableScroll": true
}
在ts
脚本中:
Page({
data: {
width: 300,
height: 300,
renderWidth: 300,
renderHeight: 300,
},
onLoad() {
const info = wx.getSystemInfoSync();
const width = info.windowWidth;
const height = info.windowHeight;
const dpi = info.pixelRatio;
this.setData({
width, height,
renderWidth: width * dpi,
renderHeight: height * dpi
});
},
})
在wxml
中:
<view>
<xr-start
disable-scroll
id="main-frame"
width="{{renderWidth}}"
height="{{renderHeight}}"
style="width:{{width}}px;height:{{height}}px;"
/>
</view>
这里我们在脚本中设置了xr-frame
组件需要渲染的宽高,然后传入wxml
,并在其中使用了json
中引用的组件进行渲染,目前效果如下,可见整个画布被xr-camera
上设置的清屏颜色清屏了:
添加一个物体
接下来我们给场上添加一个物体,直接使用xr-mesh
以及内置的几何数据、材质,创建一个立方体:
<xr-scene>
<xr-mesh node-id="cube" geometry="cube" />
<xr-camera clear-color="0.4 0.8 0.6 1" position="0 1 4" target="cube" camera-orbit-control />
</xr-scene>
这里我们给物体指定了一个node-id
,作为节点的索引,之后修改xr-camera
的position
和target
,让其始终看向这个立方体,最后再给相机加上camera-orbit-control
属性,使得我们能对相机进行控制。
至此,一个立方体是渲染了出来,不过 ... 为什么是黑色的?
来点颜色和灯光
物体黑色是因为在我们没有给xr-mesh
指定材质时,用的是基于 PBR 效果的默认材质,需要光照,解决这个问题有两种方法,其一是不需要光照的物体,可以使用simple
材质,这里就引入了材质定义:
<xr-asset-material asset-id="simple" effect="simple" uniforms="u_baseColorFactor:0.8 0.4 0.4 1" />
<xr-mesh node-id="cube" geometry="cube" material="simple" />
效果如下:
虽然这可以解决一些问题,但大部分情况下我们还是需要灯光的,就让我们把材质改回去,然后加上一些灯光吧:
<xr-light type="ambient" color="1 1 1" intensity="1" />
<xr-light type="directional" rotation="40 70 0" color="1 1 1" intensity="3" cast-shadow />
<xr-mesh
node-id="cube" cast-shadow
geometry="cube" uniforms="u_baseColorFactor:0.8 0.4 0.4 1"
/>
<xr-mesh
position="0 -1 0" scale="4 1 4" receive-shadow
geometry="plane" uniforms="u_baseColorFactor:0.4 0.6 0.8 1"
/>
这里我们加入了一个环境光和一个主平行光,调整了亮度和方向,同时加上了一个新的物体,再通过各个组件的caster-shadow
和receive-shadow
开启了阴影,效果如下:
有点寡淡,加上图像
虽然有了灯光,但只有纯色还是有一些寡淡,接下来我们尝试加入纹理,让场景的色彩更加丰富一些,这里需要用到资源加载器xr-asset-load
和xr-assets
:
<xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
<xr-asset-load type="texture" asset-id="waifu" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/waifu.png" />
</xr-assets>
<xr-mesh
node-id="cube" cast-shadow
geometry="cube" uniforms="u_baseColorMap: waifu"
/>
注意到我们在xr-assets
上绑定了两个事件progress
和loaded
,这便于开发者监听资源加载进度,然后按需做一些操作,比如资源加载完成后和wx:if
协作再显示物体。默认情况下,我们采用渐进式策略,当资源加载完成后会自动应用到物体上:
methods: {
handleAssetsProgress: function ({detail}) {
console.log('assets progress', detail.value);
},
handleAssetsLoaded: function ({detail}) {
console.log('assets loaded', detail.value);
}
}
这次的修改效果如下:
当然,我们还可以用代码动态加载一张纹理,然后将其设置到物体上,这里以获取用户信息的头像为例:
data: {
avatarTextureId: 'white'
},
methods: {
handleReady: function ({detail}) {
this.scene = detail.value;
wx.getUserProfile({
desc: '获取头像',
success: (res) => {
this.scene.assets.loadAsset({
type: 'texture', assetId: 'avatar', src: res.userInfo.avatarUrl
}).then(() => this.setData({avatarTextureId: 'avatar'}));
}
})
}
}
注意这里的handleReady
,我们可以在xr-scene
上绑定bind:ready="handleReady"
触发。完成头像获取后,将数据设置为uniforms
的来源:
<xr-mesh
position="0 -1 0" scale="4 1 4" receive-shadow
geometry="plane" uniforms="u_baseColorMap: {{avatarTextureId}}"
/>
效果如下:
让场景更丰富,环境数据
物体有了纹理,那么背景能不能也有纹理呢?当然可以。我们提供了环境元素xr-env
来定义环境信息,配合以相机可以渲染天空盒,这里以框架内置的一个环境数据xr-frame-team-workspace-day
为例:
<xr-env env-data="xr-frame-team-workspace-day" />
<xr-mesh
node-id="cube" cast-shadow
geometry="cube" uniforms="u_baseColorMap: waifu,u_metallicRoughnessValues:1 0.1"
/>
<xr-camera
position="0 1 4" target="cube" background="skybox"
clear-color="0.4 0.8 0.6 1" camera-orbit-control
/>
这里我们将xr-camera
的backgournd
设置为了skybox
,同时调整了立方体的金属粗糙度,效果如下:
同时可以看到场景中的物体相机叠加了一层反射,就像是被环境影响了一样,这是因为环境数据里还包括一些 IBL 的信息,当然这个我们不在这里赘述了,有兴趣的可以详细阅读后面的章节。
天空盒除了图像,还支持视频,我们可以先加载一个视频纹理,然后覆盖掉环境信息中的sky-map
:
<xr-asset-load type="video-texture" asset-id="office" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/videos/office-skybox.mp4" options="autoPlay:true,loop:true" />
<xr-env env-data="xr-frame-team-workspace-day" sky-map="video-office" />