- 基础知识:
1.轮廓
- 如果想要与场景中的物体进行互动,比如说点击、拖拽物体,那么这个物体得先拥有一个轮廓才行。
- 轮廓是一个组件。与某个物体互动,实际上是在与这个物体的轮廓进行互动,轮廓让这个物体在物理世界中拥有了一个分身。
名称 | 标签属性名 | 组件数据 | 备注 |
球状轮廓 | sphere-shape | center, radius, autoFit | |
胶囊体轮廓 | capsule-shape | center, radius, height, autoFit | |
长方体轮廓 | cube-shape | center, size, autoFit | |
网格模型轮廓 | mesh-shape | - | 自动适配元素下的Mesh和GLTF模型 |
2.创建轮廓
- 创建轮廓非常简单,只要为xml标签添加上xxx-shape的属性即可。
例如:一个球体创建了一个球状轮廓:
<xr-mesh node-id="mesh-sphere" geometry="sphere" sphere-shape></xr-mesh>
注:任意一个场景标签都可以创建轮廓
3.轮廓交互
事件名 | 描述 | 事件的回调函数 | 备注 |
touch-shape | 点击轮廓时触发 | IShapeTouchEvent | 如果有多个物体叠在一起,会点中最上层的。 |
drag-shape | 点击轮廓后,手指不松开的情况下进行拖拽时触发 | IShapeDragEvent | 只有在先触发touch-shape之后才会触发这个事件,target和touch-shape保持一致 |
untouch-shape | 点击轮廓后,手指松开时触发 | IShapeTouchEvent | 只有在先触发touch-shape之后才会触发这个事件。 |
整体代码以及效果:(来源于微信开放文档demo)
- wxml部分
<xr-scene id="xr-scene" bind:tick="handleTick" bind:ready="handleReady">
<xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
<xr-asset-load type="texture" asset-id="earth-texture" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/2k_earth_daymap.jpeg" />
<xr-asset-load type="texture" asset-id="moon-texture" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/2k_moon.jpeg" />
<xr-asset-load type="texture" asset-id="sky" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/dark-cosmos.jpg" />
<xr-asset-material asset-id="standard-mat" effect="standard" />
<xr-asset-material asset-id="earth-mat" effect="standard" uniforms="u_baseColorMap: earth-texture" render-queue="501"/>
<xr-asset-material asset-id="earth-silhouette" effect="simple" uniforms="u_baseColorFactor: 1.0 0.5 0 1.0" states="depthTestWrite: false" render-queue="500"/>
<xr-asset-material asset-id="moon-mat" effect="standard" uniforms="u_baseColorMap: moon-texture" render-queue="503"/>
<xr-asset-material asset-id="moon-silhouette" effect="simple" uniforms="u_baseColorFactor: 0.476 0.82 0.957 1.0" states="depthTestWrite: false" render-queue="502"/>
</xr-assets>
<xr-env sky-map="sky" is-sky2d/>
<xr-node>
<xr-mesh node-id="mesh-earth" position="0 0 0" scale="8 8 8" geometry="sphere" material="earth-mat" bind:touch-shape="handleTouchEarth" bind:untouch-shape="handleUntouchEarth" bind:drag-shape="handleEarthRotation" sphere-shape receive-shadow cast-shadow></xr-mesh>
<xr-mesh node-id="earth-silhouette" scale="8.15 8.15 8.15" geometry="sphere" material="earth-silhouette" visible="{{touchingEarth}}"></xr-mesh>
<xr-mesh node-id="mesh-moon" position="10 0 0" scale="1.5 1.5 1.5" rotation="0 90 0" geometry="sphere" material="moon-mat" bind:drag-shape="handleDragMoon" bind:touch-shape="handleTouchMoon" bind:untouch-shape="handleUntouchMoon" sphere-shape="radius: 1.5" receive-shadow cast-shadow>
<xr-mesh node-id="moon-silhouette" scale="1.1 1.1 1.1" geometry="sphere" material="moon-silhouette" visible="{{touchingMoon}}"></xr-mesh>
</xr-mesh>
<xr-camera
id="camera" node-id="camera" position="0 20 -35" clear-color="0 0 0 1"
target="mesh-earth"
background="skybox"
></xr-camera>
</xr-node>
<xr-node node-id="lights">
<xr-light type="ambient" color="1 1 1" intensity="0.1" />
<xr-light id="directional-light" type="directional" rotation="0 60 0" color="1 1 1" intensity="5" shadow-distance="40" cast-shadow shadow-bias="0.004"/>
</xr-node>
</xr-scene>
- js部分
Component({
properties: {
a: Number,
},
data: {
loaded: false,
touchingMoon: false,
touchingEarth: false,
θ: Math.PI,
r: 10,
ω: 5e-4,
outerRing: 20,
innerRing: 10
},
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});
},
handleTouchEarth: function() {
this.setData({
touchingEarth: true
});
},
handleUntouchEarth: function() {
this.setData({
touchingEarth: false
});
},
handleEarthRotation: function({detail}) {
const { target, deltaX } = detail.value;
target._components.transform.rotation.y += deltaX / 100;
},
handleDragMoon: function({detail}) {
const { dir, target, camera } = detail.value;
const cameraPos = camera.el._components.transform.worldPosition;
const k = -cameraPos.y / dir[1];
const x = cameraPos.x + k * dir[0];
const z = cameraPos.z + k * dir[2];
const len = Math.sqrt(x * x + z * z);
if (len > this.data.innerRing) {
const transform = target._components.transform;
const scale = len > this.data.outerRing ? this.data.outerRing / len : 1.0;
transform.position.x = x * scale;
transform.position.z = z * scale;
}
},
handleTouchMoon: function() {
this.setData({touchingMoon: true});
},
handleUntouchMoon: function() {
const moon = this.scene.getNodeById("mesh-moon");
const transform = moon.el._components.transform;
const x = transform.position.x;
const z = transform.position.z;
const len = Math.sqrt(x * x + z * z);
this.setData({
r: len,
θ: x < 0 ? Math.atan(z / x) + Math.PI : Math.atan(z / x),
ω: Math.sqrt(2.5e-4 / (len * len * len))
});
this.setData({touchingMoon: false});
},
handleTick: function({detail}) {
if (this.data.touchingMoon || !this.scene) return;
const deltaTime = detail.value;
const moon = this.scene.getNodeById("mesh-moon");
const transform = moon.el._components.transform;
const x = Math.cos(this.data.θ) * this.data.r;
const z = Math.sin(this.data.θ) * this.data.r;
transform.position.x = x;
transform.position.z = z;
transform.rotation.y -= this.data.ω * deltaTime;
this.setData({
θ: this.data.θ + this.data.ω * deltaTime
});
}
}
})
- 效果展示: