微信小程序xr-frame实现交互(地月案例)

  • 基础知识:

1.轮廓

  • 如果想要与场景中的物体进行互动,比如说点击、拖拽物体,那么这个物体得先拥有一个轮廓才行。
  • 轮廓是一个组件。与某个物体互动,实际上是在与这个物体的轮廓进行互动,轮廓让这个物体在物理世界中拥有了一个分身。
名称标签属性名组件数据备注
球状轮廓sphere-shapecenter, radius, autoFit
胶囊体轮廓capsule-shapecenter, radius, height, autoFit
长方体轮廓cube-shapecenter, 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
        });
    }
  }
})
  • 效果展示: 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值