录制画布

在基础库版本v3.1.1之后,分享系统提供了如下方式来录制:

// 录制配置,以下是默认值
// 这里建议根据实际情况,等比缩放`width`和`height`,防止丢帧
const options: XrFrame.IShareRecordOptions = {
  fps: 30,
  width: scene.width,
  height: scene.height,
  videoBitsPerSecond: 1000
};

// 启动录制
await scene.share.recordStart(options);

// 暂停录制
await scene.share.recordPause(options);

// 唤醒录制
await scene.share.recordResume(options);

// 停止录制,并保存到临时文件
const tempFilePath = await scene.share.recordFinishToTempFile(options);

// 停止录制,直接保存到相册
await scene.share.recordFinishToAlbum(options);

// 可以获取录制状态,来做用户提示
if (scene.share.recordState === xrFrameSystem.EShareRecordState.Recording) {
  ......
}

截取画布

分享系统提供了三种方式来截图:

// 判断当前客户端是否支持分享系统
const supported = scene.share.supported;

// 截取配置,可选`type`为`jpg`或`png`,在为`jpg`时,可配置`0~1`的`quality`
// 以下是默认值
const options: XrFrame.IShareCaptureOptions = {
  type: 'jpg',
  quality: 0.8
};

// 在鸿蒙上有BUG,已弃用,请使用下方异步接口!
const base64 = scene.share.captureToDataURL(options);
// 基础库`3.0.2`以上新增的异步接口,获取原始的`base64`字符串
const base64 = await scene.share.captureToDataURLAsync(options);

// 在鸿蒙上有BUG,已弃用,请使用异步接口!
const buffer = scene.share.captureToArrayBuffer(options);
// 基础库`3.0.2`以上新增的异步接口,直接获取转换后的`ArrayBuffer`
const buffer = await scene.share.captureToArrayBufferAsync(options);

// 获取本地路径的分享图片
// 第一个方法来处理本地路径,结束后释放文件
// 此回调在`2.27.3`基础库以及之前时是异步,之后兼容同步和异步
// 在基础库`3.0.2`之后,为异步接口
await scene.share.captureToLocalPath(options, fp => {});

// 直接唤起分享图片给好友
// 在基础库`3.0.2`之后,为异步接口
await scene.share.captureToFriends(options);

唤起分享给好友的结果如下:

其他属性和动画

基于不同渲染模式的渲染

RenderMode不进行设置的前提下,无论相机如何转动,所有粒子永远正对着屏幕。

这里通过render-mode字段进行控制,示例如下:

<xr-particle id="colorGradient" position="2 0 -2" render-mode="off" capacity="20" emit-rate="5" life-time="3" emitter-type="BoxShape"></xr-particle>

渲染模式字段相关变量介绍

名称 备注
off 是否启用公告板渲染
default 默认公告板渲染模式,粒子始终正对屏幕
y Y轴渲染模式,粒子Y轴将锁定,其它轴的显示正对屏幕
stretched 拉伸渲染模式,将附带一些旋转,使粒子朝向其运动方向
mesh 粒子将以指定网格渲染,与粒子系统中的mesh字段搭配

可以通过代码调用禁用公告板渲染,粒子将保持它自己的位置,面片的显示不会随着相机旋转而进行调整:

  particleComponent.useBillBoard = false

要设定公告板模式,首先要启用useBillBoard,并对billboardMode进行设置,这里以”BILLBOARDMODE_Y”为例:

  particleComponent.useBillBoard = true
  particleComponent.billboardMode = BillBoardMode.BILLBOARDMODE_Y || 1

支持色彩取样构建

粒子系统目前支持基于alpha值,在色彩梯度渐变图上进行采样,从而更改粒子的颜色。要启用此功能,首先将useRampGradients置为true。

通过如下示例,构建自定义色彩取样表:

  particleComponent.useRampGradient = true;
  particleComponent.addRampGradient(0.0, Vector3.createFromNumber(1, 1, 1));
  particleComponent.addRampGradient(0.2, Vector3.createFromNumber(0.8, 0.8, 0.05));
  particleComponent.addRampGradient(0.4, Vector3.createFromNumber(0.86, 0.5, 0.05));
  particleComponent.addRampGradient(0.6, Vector3.createFromNumber(0.75, 0.18, 0.07));
  particleComponent.addRampGradient(0.8, Vector3.createFromNumber(0.45, 0.08, 0.06));
  particleComponent.addRampGradient(1, Vector3.createFromNumber(0.05, 0.05, 0.05));

最终粒子将根据自身alpha值,在取样表中采取对应的色彩。

通过如下示例,也可以在生命周期的不同阶段,指定alpha值的变化范围,影响对色彩渐变图的采样。

例如:0.2秒时,因为此时的采样范围为[0.1, 0.8],粒子alpha值小于等于0.1时视为0,当大于等于0.8时视为1,在区间内值映射为(alpha-0.1)/0.8。

  particleComponent.addColorRemapGradient(0, 0, 0.1);
  particleComponent.addColorRemapGradient(0.2, 0.1, 0.8);
  particleComponent.addColorRemapGradient(0.3, 0.2, 0.85);
名称 类型 备注 默认值
useRampGradients boolean 是否启用色彩梯度取样 false

相关方法

addRampGradient

名称 类型 备注
gradient number 在指定位置设置对应色彩,该值与(1-粒子alpha值)对应,取值范围[0~1]
color Vector3 色彩RGB值

addColorRemapGradient

名称 类型 备注
time number 指定粒子生命周期的阶段
min number alpha值左区间
max number alpha值右区间

粒子属性的动态变化

粒子在运动过程中,可以定制对其大小、颜色、速度的动态变化。

本粒子系统同时内置有关粒子大小的控制方法addSizeGradient,用法如下:

  particleComponent.addSizeGradient(0,1);
  particleComponent.addSizeGradient(0.5,0.8);
  particleComponent.addSizeGradient(0.75,0.3,0.5);
  particleComponent.addSizeGradient(1,0);

调用addColorGradient支持带有alpha通道的颜色过渡:

    particleComponent.addColorGradient(0, Vector4.createFromNumber(1,1,1,0));
    particleComponent.addColorGradient(0.3, Vector4.createFromNumber(0.3,1,1,0.5),Vector4.createFromNumber(0.2,0,0.6,0.5),);
    particleComponent.addColorGradient(1, Vector4.createFromNumber(0,1,1,1));

调用addAlphaGradient可以专门调整透明度的过渡:

    particleComponent.addAlphaGradient(0,0);
    particleComponent.addAlphaGradient(0.3,0.3, 0.5);
    particleComponent.addAlphaGradient(1,1);

调用addSpeedScaleGradient动态改变粒子运动过程中的速度大小:

    particleComponent.addSpeedScaleGradient(0,0);
    particleComponent.addSpeedScaleGradient(0.3,0.5, 1);
    particleComponent.addSpeedScaleGradient(1,2);

相关方法

addSizeGradient

参数 类型 描述
gradient number 指定所处粒子生命周期的阶段
sizeScale number 指定粒子大小的左区间
sizeScale2 number 指定粒子大小的右区间[可选]

其中gradient统一取值范围为[0,1]间,表示相对粒子生命周期的占比,如0.1,即指定粒子在0.1 * lifeTime的时刻;sizeScalesizeScale2值的大小为相对于粒子系统属性中scale配置的值,如sizeScale为2,则粒子体积大小为size * 2。

addColorGradient

参数 类型 描述
gradient number 指定所处粒子生命周期的阶段
color Vector4 指定粒子颜色的左区间
color2 Vector4 指定粒子颜色的右区间[可选]

addAlphaGradient

参数 类型 描述
gradient number 指定所处粒子生命周期的阶段
alpha number 指定粒子颜色透明度的左区间
alpha2 number 指定粒子颜色透明度的右区间[可选]

addSpeedScaleGradient

参数 类型 描述
gradient number 指定所处粒子生命周期的阶段
speed number 指定粒子速度的左区间
speed2 number 指定粒子速度的右区间[可选]

gradient number 指定所处粒子生命周期的阶段 speedScale number 指定粒子速度的左区间 speedScale2 number 指定粒子速度的右区间[可选]

speedScalespeedScale2值的大小为相对于粒子系统属性中speed配置的值,如speedScale为2,则粒子速度大小为speed * s2

动画粒子

首先我们需要创建一个图集资源,如实例所示,命名此资源名为”particle-atlas”:

    <xr-asset-load type="atlas" asset-id="particle-atlas" src="/path/to/atlas.json" />
    <xr-particle capacity="100" size="2" emit-rate="12" life-time="4" angle="0 360" atlas="particle-atlas" atlas-frames="frame-name" atlas-speed="4" atlas-random="true" atlas-loop="true"></xr-particle>

粒子将从图集依次序取出对应纹理样式进行渲染

  • atlas-random:决定默认的纹理从第一张开始或者是随机
  • atlas-frames:指定图集中特定的纹理名字参与渲染
  • atlas-speed:将控制纹理的变化速度
  • atlas-loop:决定当轮转到图集最后一张纹理时,是否回到第一张纹理开始渲染

子发射器

目前系统支持构建子发射器,可以通过构建子发射器实现类似的烟花绽放的粒子效果。 示例如下,为子发射器构建参数的过程与粒子系统的构建基本一致,可以参考粒子系统的相关参数介绍。

 <xr-asset-load type="texture" asset-id="particlePoint" src="xxx" /> <!-- xxx为纹理的url -->
   var myData ={}
    myData = {
      "capacity": 10,
      "emitRate": 5,
      "size":[0.1],
      "startColor":[1,1,0,1],
      "endColor":[1,1,0,1],
      "emitterType":"SphereShape",
      "emitterProps": [["radius","0.1"]],
      "stopDuration":3,
      "lifeTime":[3],
      "texture":"particlePoint", // xxx为纹理的url
      "speed":[0.5],
    }
    const particleSystemElement = xrScene.getElementById("xxxx"); // xxx为粒子系统的id命名
    tempSystem = particleSystemElement.getComponent(xrFrameSystem.Particle)
    var subEmitter = this.createSubEmitter(myData)
    subEmitter.state = 0
    //可以规定多个子发射器的阵列
    particleComponent.subEmitters = [subEmitter]

myData的配置所示,调用createSubEmitter创建一个子发射器,具体参数类型参考粒子系统的相关参数介绍:

相关属性

SubEmitterState

参数 类型 描述 默认值
ATTACH number 指定发射器为附加类型 0
END number 指定发射器为粒子结束时生成 1

SubEmitterState.ATTACH
当一个粒子产生时,从子发射器阵列中随机选择一种并附加到新粒子上,用于在新粒子上创建拖尾粒子效果。

SubEmitterState.END
当粒子灭亡时,从子发射器阵列中随机选择一种进行克隆并渲染,用于在新粒子上创建收尾特效。

粒子发射器

构建粒子发射器

粒子系统目前内置了不同形态的发射器类型,通过对相关参数的调整,满足开发者所需要的粒子效果。

目前支持以下发射器类型:

  • PointShape 点状发射器
  • SphereShape 球形发射器
  • BoxShape 箱形发射器
  • ConeShape 锥形发射器
  • CircleShape 圆形发射器

通过emitter-type指定发射器类型。emitter-props可以配置发射器参数,示例如下:

<xr-particle capacity="20" emit-rate="10" life-time="1.5 2" speed="0.4 0.8" size="0.3 0.5"
emitter-type="SphereShape" emitter-props="radius:1,randomizeDirection:0"></xr-particle>

不同发射器可以指定的相关参数如下:

BoxShapeEmitter 箱形发射器

参数名称 类型 备注 默认值
direction Vector3 粒子初始发射方向左区间 (0, 1.0, 0)
direction2 Vector3 粒子初始发射方向右区间 (0, 1.0, 0)
minEmitBox Vector3 粒子初始位置左区间 (-0.5, -0.5, -0.5)
maxEmitBox Vector3 粒子初始位置右区间 (0.5, 0.5, 0.5)

CircleShapeEmitter 圆形发射器

参数名称 类型 备注 默认值
radius number 粒子随机生成圆形区域的半径 1
radiusRange number 粒子在圆形区域内的覆盖范围 [0-1] 0
direction Vector3 粒子初始发射方向左区间 (0, 1.0, 0)
direction2 Vector3 粒子初始发射方向右区间 (0, 1.0, 0)
arc number 规定粒子生成的扇形区域角度大小 [0-360] 360

ConeShapeEmitter 锥形发射器

参数名称 类型 备注 默认值
radius number 粒子随机生成锥型区域的半径 3
radiusRange number 粒子在锥型区域内的覆盖范围 [0-1] 0
heightRange number 粒子在高度方向上的覆盖范围 [0-1] 1
arc number 规定粒子生成的扇形区域角度大小 [0-360] 360
randomizeDirection number 粒子发射方向的扰动程度 [0-1] 0

PointShapeEmitter 点状发射器

参数名称 类型 备注 默认值
direction Vector3 粒子初始发射方向左区间 (0, 1.0, 0)
direction2 Vector3 粒子初始发射方向右区间 (0, 1.0, 0)

SphereShapeEmitter 球形发射器

参数名称 类型 备注 默认值
radius number 粒子随机生成球型区域的半径 3
radiusRange number 粒子在球型区域内的覆盖范围 [0-1] 0
arc number 规定粒子生成的扇形区域角度大小 [0-360] 360
randomizeDirection number 粒子发射方向的扰动程度 [0-1] 0

控制粒子系统运作

通过调用stop函数, 可以对当前粒子效果进行暂停。

 particleComponent.stop()

通过调用start函数, 播放粒子效果。

 particleComponent.start() // 可以设置参数,如: particleComponent.start(2), 延时二秒启动

通过代码构建发射器

系统支持通过代码动态创建发射器,这种生成方式可以对发射器的具体参数进行设置, 这里以点型态发射器为例。

首先需要获得元素的实例,详情见element元素, 并获取对应的组件,详情见component组件

 particleComponent.createPointEmitter(direction1, direction2) 

通过自定义粒子发射过程构建一副画作

粒子运作的轨迹由粒子发射器规定的粒子运动矢量direction大小与粒子初始位置position决定,这一运作过程均由粒子系统进行模拟运算。

为了实现特殊的粒子效果,每个发射器中支持定义粒子运作接口processInstance, 这里以粒子复现一副图片效果为例。

    // 记录图片数据的二元数组content, 取值范围[0~1]
    var content = ..

    //设置箱型发射器的发射方向,与粒子初始位置范围
    particleComponent.createBoxEmitter(direction1, direction2, minEmitBox, maxEmitBox);

    //实现发射器的自定义粒子运作接口, 声明参数instance代表每个粒子实例,deltaTime为根据渲染更新的时间,均由系统自动传入
    particleComponent.particleEmitter.processInstance = (instance, deltaTime) => {
      var contentTemp = content
      var cellNumY = contentTemp.length
      var cellNumX = contentTemp[0].length
      // 影响画作的大小与粒子疏密程度的因子
      var step = 0.02
      // 实际渲染出的画作高度
      var height = Math.floor(step * content.length)
      // 实际渲染出的画作宽度
      var width =  Math.floor(step * cellNumX)
      if(instance.position.x - instance.particleSystem.emitterPosition.x> width){
        instance.age = instance.lifeTime;
            return;
        }
        instance.age = 0;
        const posX = Math.floor((instance.position.x -  instance.particleSystem.emitterPosition.x)/ step);
        const posY = Math.floor(instance.position.y/ step);
        const speed = contentTemp[cellNumY-1-posY][posX] * 0.97;
        instance.position.x += ( 1 - speed * 0.97 ) * 0.03 + Math.random() * 0.007;
        instance.color.w = speed * 0.3;
    };

这里介绍有关每个粒子实例的相关属性,用户可以在processInstance接口中设计它们的运作规律

粒子实例相关属性

名称 类型 备注
angle number 粒子的偏移角度
color Vector4 粒子颜色
direction Vector3 粒子的运动方向
particleSystem Particle 粒子所归属的粒子系统
position Vector3 粒子所处位置
size number 粒子大小

粒子系统

粒子属性与生命周期过程中的变化效果由系统ParticleSystem管理,其一个版本代理到元素XRParticleSystem,对应在xml中的标签是xr-particle

微信小程序wxml中创建

首先声明资源节点,导入纹理,用于描绘粒子的基本形态

<xr-asset-load type="texture" asset-id="particle-texture" src="path/to/texture.xxx" />

接下来在xml中通过xr-particle标签声明粒子节点,同时设置粒子系统的基本属性,例如

<xr-particle material="particle-mat" capacity="20" emit-rate="5" life-time="3" emitter-type="BoxShape" textre="particle-texture"></xr-particle>

粒子系统基本属性

影响粒子系统生命周期、初始色彩、初始体积等效果的相关属性介绍如下

名称 类型 备注 默认值 用例
angle number[] 粒子的起始角度,”最小值 最大值(可选)” [0, 0] angle=”0 0″
angular-speed number[] 每秒钟粒子旋转的角度(单位:角度) [0, 0] angular-speed=”0 0″
atlas Atlas 描绘粒子形态的纹理图集 atlas=”particle-atlas”
atlas-frames string[] 指定纹理图集中的特定帧,以帧名的形式 atlas-frames=”snow star”
atlas-loop boolean 决定纹理图集播放到最后一帧时是否循环 true atlas-loop=”false”
atlas-random boolean 粒子的初始形态是否从纹理集中随机选择 false atlas-random=”true”
atlas-speed number 粒子纹理的变化速度 1 atlas-speed=”2″
burst-count number 粒子一次性喷射的粒子数量,大于-1生效 -1 burst-count=”5″
capacity number 容许同时存在的最多粒子数量 1 capacity=”5″
delay number 延时启动粒子的秒数 0 delay=”3″
emit-rate number 每秒钟允许生成的最多粒子数量 10 emit-rate=”5″
emitter-type string 粒子发射器的类型 “PointShape” emitter-type=”SphereShape”
emitter-props map 粒子发射器的属性,搭配发射器类型使用 “” emitter-props=”radius:1.5″
emitter-position number[] 粒子发射器的位置 (0, 0, 0) emitter-position=”2 0 0″
end-color number[] 粒子生命周期结束时的颜色 [1, 1, 0, 1] end-color=”1 1 0 1″
gravity number 粒子在y轴上每秒的运动距离 0 gravity=”9.8″
life-time number[] 粒子的生命周期时长区间,”最小值 最大值(可选)” [1, 1] lifeTime=”1 3″
render-mode string 粒子的渲染模式,详见billboard模式介绍 “default” render-mode=”stretched”
size number[] 粒子的大小,”最小值 最大值(可选)” [0.3, 0.3] size=”1″
speed number[] 粒子的速度大小,”最小值 最大值(可选)” [1, 1] speed=”1 1″
start-color number[] 粒子初始颜色左区间 [1, 0, 0, 1] start-color=”1 0 0 1″
start-color2 number[] 粒子初始颜色右区间 start-color2=”1 1 0 1″
stop-duration number 粒子存在的总时长(单位:秒),0表示永远存在 0 stop-duration=”3″
texture string 描绘粒子形态的基本纹理 texture=”particle-texture”
mesh string 以特定网格形态渲染粒子 mesh=”cube”
use-noise boolean 是否对粒子运动轨迹启用噪声 false use-noise=”true”
noise-texture string 采样的噪声纹理名(可选),内置柏林噪声 noise-texture=”noiseTexture”
noise-strength number[] 不同轴向上施加噪声干涉运动的力度(可选) [1, 1, 1] noise-strength=”2 1 1″

注意:这里的属性类型指粒子系统内部对应的数据结构,在xml格式中按照用例的字符串形式输入即可,对应字符串转换规律如data-values中所示。

轮廓间交互

⚠️ 轮廓间交互功能目前尚在Beta阶段,并且需要2.32.1及之后的基础库才能使用。

碰撞与重叠

碰撞和重叠是不同的概念:

  • 碰撞是指:两个轮廓发生物理学碰撞,并因此而改变位置与速度,产生碰撞事件;
  • 重叠是指:两个轮廓在位置上发生了重叠,并产生重叠事件,发生物理学碰撞。

需要轮廓才能发生交互

碰撞重叠是在两个轮廓之间发生的行为,所以在添加交互属性之前,请先确保为物体创建了轮廓。

轮廓交互组件

通过为标签添加shape-interact属性来设置轮廓间交互:

<xr-mesh ... mesh-shape shape-interact>

设置shape-interact属性后会自动为对应元素创建ShapeInteract组件。

组件属性

属性值 描述 值类型 备注
disabled 是否禁用交互 boolean disable=true的话,效果和不存在shape-interact属性时一致
collide 是否发生碰撞 boolean collide=true的话,发生碰撞,否则发生重叠,默认false
bounciness 弹性系数 number 0≤bounciness≤1,仅当collide=true时生效
staticFriction 静摩擦系数 number 0≤staticFriction≤1,仅当collide=true时生效
dynamicFriction 动摩擦系数 number 0≤staticFriction≤1,仅当collide=true时生效

⚠️ 只有两个物体的collide都为true,他们之间才能发生碰撞!

交互事件

在两个轮廓之间发生交互时,会产生交互事件,可以在标签上绑定相关绑定事件回调:

<xr-mesh ... mesh-shape shape-interact bind:overlap-begin="handleOverlapBegin">

事件一共有以下6种:

事件名 描述 事件回调参数
collide-begin 发生碰撞 ICollideEvent
collide-persist 碰撞持续 ICollideEvent
collide-exit 碰撞结束 ICollideEvent
overlap-begin 发生重叠 IOverlapEvent
overlap-persist 重叠持续 IOverlapEvent
overlap-exit 重叠结束 IOverlapEvent

其中xxx-begin和xxx-exit会成对地出现,从相交的第二帧开始xxx-persist每帧都会生成一次。

刚体和全局物理

⚠️ 刚体物理功能目前尚在Beta阶段,并且需要2.32.1及之后的基础库才能使用。

全局物理

要让当前的场景成为一个物理世界,需要先在<xr-scene>下配置一个<xr-physics>标签:

<xr-scene>
    <xr-physics />
    ...(场景中的其他标签)
</xr-scene>

⚠️ <xr-physics>标签只能位于<xr-scene>下一级,不能放置在更深的层级中。

全局物理配置

可以通过修改在<xr-physics>上的属性来配置全局物理参数(目前仅开放了少数配置项):

属性名 描述 值类型 备注
disabled 是否禁用物理 boolean disable=true的话,效果和不存在<xr-physics>标签时一致。
gravity 全局重力 Vector3 默认重力(0, -9.8, 0)

刚体

在标签上添加rigidbody属性来使其成为一个刚体:

<xr-mesh ... rigidbody />

添加之后就能观察到物体受重力影响而下落了。

刚体配置

通过为rigidbody属性添加属性值来修改刚体配置:

<xr-mesh ... rigidbody="mass: 5.0" />
属性值 描述 值类型 备注
disabled 是否禁用刚体 boolean disable=true的话,效果和不存在rigidbody属性时一致。
mass 刚体质量 number mass > 0
useGravity 是否受重力影响 boolean
constraintsMask 限制刚体在某个轴上的移动 number 具体指参考 @TODO

刚体组件

标签上的rigidbody属性对应元素上的Rigidbody组件。
使用Rigidbody组件上的方法可以移动刚体或者修改刚体属性:

方法名 描述 备注
addForce / addTorque 对刚体施加力,产生加速度。 对刚体施加力,产生加速度。
sleep / wakeUp 强制刚体睡眠/唤醒 正常情况下睡眠状态是由物理引擎自动管理的,如果发现刚体异常静止,可以尝试手动wakeUp。

轮廓

如果想要与场景中的物体进行互动,比如说点击、拖拽物体,那么这个物体得先拥有一个轮廓才行。

轮廓是一个组件。与某个物体互动,实际上是在与这个物体的轮廓进行互动,轮廓让这个物体在物理世界中拥有了一个分身。

创建轮廓

创建轮廓非常简单,只要为xml标签添加上xxx-shape的属性即可。
例如以下代码为一个球体创建了一个球状轮廓:

<xr-mesh node-id="mesh-sphere" geometry="sphere" sphere-shape></xr-mesh>

实际上,不需要标签是xr-mesh,任意一个场景标签都可以创建轮廓:

<xr-node node-id="shape-node" sphere-shape></xr-node>

轮廓种类

名称 标签属性名 组件数据 备注
球状轮廓 sphere-shape center, radius, autoFit
胶囊体轮廓 capsule-shape center, radius, height, autoFit
长方体轮廓 cube-shape center, size, autoFit
网格模型轮廓 mesh-shape 自动适配元素下的Mesh和GLTF模型

除了网格模型轮廓之外,其他轮廓均拥有autoFit属性(实际上网格模型轮廓的autoFit常开,所以不能设置)。开启autoFit之后,轮廓会自动寻找当前元素下的Mesh组件GLTF组件,并使用自身形状去尽量贴合模型。

如果将GLTF组件和开启了autoFit轮廓组合使用,那么会为GLTF内部的每个Mesh都创建一个轮廓。 ⚠️ 使用MeshShape的时候,请确保模型顶点数量小于65535个。如果超过了数量限制,推荐使用CubeShape+autoFit来代替。

轮廓交互

可以通过为标签绑定事件的方式来与轮廓进行互动,如果尚未了解如何绑定事件,可以参考事件文档。

例如使用以下代码,可以为轮廓绑定一个log事件(需自行完成logFunction函数):

<xr-node node-id="shape-node" cube-shape bind:touch-shape="logFunction"></xr-node>
事件名 描述 事件回调参数 备注
touch-shape 点击轮廓时触发 IShapeTouchEvent 如果有多个物体叠在一起,会点中最上层的。
drag-shape 点击轮廓后,手指不松开的情况下进行拖拽时触发 IShapeDragEvent 只有在先触发touch-shape之后才会触发这个事件,target和touch-shape保持一致。
untouch-shape 点击轮廓后,手指松开时触发 IShapeTouchEvent 只有在先触发touch-shape之后才会触发这个事件。

无论有没有绑定事件,其实都会触发事件,只是没有事件回调函数就什么都没发生。

轮廓可视化

为标签加上shape-gizmo即可将标签上的轮廓用线框绘制出来:

<xr-node node-id="shape-node" cube-shape shape-gizmo></xr-node>

MeshShape不会显示轮廓,因为基本上和渲染出来的模型一致。

物理系统

xr-frame中的物理系统主要管理场景中的轮廓,以及触发轮廓点击事件。


  • 轮廓 – 为物体创建可交互的轮廓;
  • 刚体和全局物理Beta – 让物体成为刚体,可以受到力的影响而产生加速度;
  • 轮廓间交互Beta – 让物体可以与其他物体产生交互,包括碰撞以及重叠判断。

帧动画

帧动画是一种内置的动画实现,提供给开发者类似于 CSS 动画的能力,去控制一个元素下所有组件的数据。

我们提供了一种资源来定义帧动画,之后可以用对应的加载器加载,在组件中使用。

帧动画资源

首先我们要准备一个帧动画资源,它是被存储为json格式,大致如下:

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

可以看到其中有两个部分:keyframeanimation

keyframe中定义了帧动画具体的行为,本质上类似于css3中的keyframes,其中进度的范围是0~100,每个进度下是动画具体影响的键和值。其中键的规则是[组件].[属性].[属性2].[属性...],比如transform.postion.x,就是对应于使用了这个帧动画的元素下的transform组件的position属性的x属性变化。

当然我们不难看到,如果仅仅是按照这样的规则,一来是开发者必须要实现对应组件下每个属性的访问器,其次是对于一些常见的属性写起来会繁琐,再者对于材质动画会无从下手。为了解决这个问题,我做了一些实现上的优化:

  1. 如果整个属性路径最终是[组件].[属性]的形式,则不需要写访问器,会自动设置。
  2. positionrotationscale会被自动代理到transform组件下。
  3. material是一种特殊的定义,会被自动代理到mesh组件的材质的uniform下。

要注意,属性的值仅仅支持numbernumber-arraycolor类型的数据。 有了keyframe,再者就是animation了。animation中定义了真的暴露给animator的片段,其中第一级的每个键都是片段的名字,它对应的值就是其作为动画播放时的一些参数。keyframe定义这个片段对应于上面定义的哪个keyframeduration是以秒为单位的时长,loop是默认循环次数(-1为永远循环),delay是播放延迟,direction是播放方向,默认forwards,可选backwardsboth(在循环时交替前向反向),ease则是时间函数,决定动画的插值曲线。

支持的时间函数可见 API 文档:noneParamsEaseFuncs 和 useParamsEaseFuncs。

使用

有了资源我们便可以加载使用它,和其他资源一样,keyframe资源遵循标准加载流程:

<xr-asset-load type="keyframe" asset-id="anim" src="/assets/keyframes/test.json" />

然后便可以引用使用:

<xr-node anim-keyframe="anim" anim-autoplay="clip:parent">
  <xr-node position="0 -0.5 3" anim-keyframe="anim" anim-autoplay="clip:child">
  </xr-node>
</xr-node>

注意这里使用了anim-keyframe字段来指定animator组件要默认使用哪个keyframe动画。