Babylon.js 深入

目录

1、第一章 动画

1. 设计动画

设计剪辑

反转动画 

2. 动画方法描述 

创建动画

设置关键帧

开始动画

可动画化

3. 排序动画

​编辑 (1)设计:对于相机

(2)对于门

(3)对于灯光

4. 卡通片

5. 分组动画:AnimationGroup

(1)组成一个动画组:addTargetedAnimation

(2)规范化动画组:normalize

(3)动画组的速率比:speedRatio

(4)从现有动画创建动画组

(5)在动画结束时:onAnimationEndObservable

 (6)在动画组循环时:onAnimationLoopObservable、onAnimationGroupLoopObservable

6. 合并动画

(1)如何合并动画

(2)连续动画:beginDirectAnimation

7. 动画角色

(1)用键盘控制动画角色的移动:animationGroups、ActionManager

8. 高级动画方法

(1)动画和promise

(2)控制动画

(3)辅助函数:CreateAndStartAnimation

(4)动画混合:enableBlending

(5)动画权重:beginWeightedAnimation

(6)完整的将动画混合在一起的示例:

(7)叠加动画混合:MakeAnimationAdditive

(8)覆盖属性:animationPropertiesOverride

(9)缓冲函数

(10)将事件附加到动画:addEvent

(11)确保同步

9. 使用渲染循环的动画:registerBeforeRender

10. 烘焙纹理动画

(1)烘焙顶点动画

(2)烘焙顶点纹理动画

(3)VAT的实例

(4)精简实例的VAT

(5)序列化和加载VAT

2、第二章 声音

1. 如何播放声音和音乐

2. 创建环境声音或音乐

3. 处理准备播放回调函数

4. 在鼠标单击或按键时发出声音

5. 一些基本属性

6. 播放声音精灵

7. 同时播放多个声音并同步

8. 从 ArrayBuffer 加载声音

9. 从 Assets Manager 加载声音

10. 创建空间3D声音

11. 将声音附加到网格:attachToMesh()

12. 将位置设置为音频侦听器:audioListenerPositionProvider

13. 创建空间定向 3D 声音

14. 创建自己的自定义衰减函数

15. 处理从 .babylon 文件加载的声音

16. 使用音轨:BABYLON.SoundTrack

17. 使用分析器:BABYLON.Analyser()

3、第三章 行为

1. 行为

2. 相机行为

(1)弹跳行为:BABYLON.BouncingBehavior

(2)自动旋转行为:BABYLON.AutoRotationBehavior 

(3) 框架行为:BABYLON.FramingBehavior

3. 网格行为

(1)指针拖动行为:PointerDragBehavior

(2)六自由度拖动行为:SixDofDragBehavior

(3)多指针缩放行为:MultiPointerScaleBehavior

(4)附加到框行为(应用栏):AttachToBoxBehavior

(5)跟随行为:FollowBehavior

(6)表面磁性行为:SurfaceMagnetismBehavior

(7)手约束行为:HandConstraintBehavior

2022.12.19

1、遇到的问题


1、第一章 动画

1. 设计动画

  • 设计剪辑

沿 x 方向滑动项目的动画变为:

const frameRate = 10;
const xSlide = new BABYLON.Animation("xSlide", "position.x", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

关键帧位于 01 和 2 秒。要找到 t 秒后的帧号,将时间乘以帧速率,即 t x frameRate
在这种情况下,关键帧的帧号为 01 x frameRate 和 2 x frameRate

关键帧被设置为具有帧(编号)和值属性的 JavaScript 对象数组,并添加到动画中:

const keyFrames = [];
keyFrames.push({
    frame: 0,
    value: 2,
});
keyFrames.push({
    frame: frameRate,
    value: -2,
});
keyFrames.push({
    frame: 2 * frameRate,
    value: 2,
});
xSlide.setKeys(keyFrames);

动画现在已完成制作,可以应用到盒子上:

box.animations.push(xSlide);

动画开始,参数二、三是关键帧列表中的起始帧和结束帧:

scene.beginAnimation(box, 0, 2 * frameRate, true);
  • 反转动画 

// 正向动画
scene.beginAnimation(box, startFrame, endFrame, false);

// 反向动画
scene.beginAnimation(box, endFrame, startFrame, false);

2. 动画方法描述 

  • 创建动画

const myAnim = new BABYLON.Animation(name, property, frames per second, property type, loop mode)

name:string,动画名称;

property:string,将应用动画的对象的属性。例如:position 是 Vector3 属性或 position.x 是浮点数属性;

frames per second:number,每秒动画帧数(与每秒的场景渲染帧数无关);

property type:属性参数的属性类型;

loop mode:循环模式。

  • 设置关键帧

keyFrames是一个对象数组。每个对象都有两个属性:

(1)frame:帧号

(2)value:用于被更改的属性

一旦构建,它就会被添加到动画中:

myAnim.setKeys(keyFrames);
  • 开始动画

为了运行动画,它被推送到网格的动画数组属性上:

mesh.animations.push(myAnim)

 开始动画:第四个参数为true表示循环动画

scene.beginAnimation(target, from, to, [loop]);

target:object,要动画化的 Babylon.js 对象;

from:number,开始动画的帧;

to:number,结束动画的帧。

使用以下方法将多个动画应用于目标:

scene.beginDirectAnimation(target, animations, from, to, loop)

  • 可动画化

两种启动动画的方法都返回一个 Animatable 对象 

const myAnimatable = myscene.beginAnimation(target, from, to, true)

 支持以下方法:pause()、restart()、stop()、reset()

3. 排序动画

组合多个剪辑以形成动画的一种直接方法是为每个动画剪辑指定开始时间。

图片地址 (1)设计:对于相机

移动相机会改变相机的位置(vector3)。相机环顾四周是围绕 y 轴(float)的旋转。

由于动画只能更改一个属性,因此相机需要两个动画。

相机的关键点的值将是它在 0、 3、 5 和 8 秒处的帧中的位置以及它在 0、 9 和 14 秒处的帧中的旋转。 

// 让相机向前移动
var movein = new BABYLON.Animation(
    "movein",
    "position",
    frameRate,
    BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
);
var movein_keys = [];
movein_keys.push({
    frame: 0,
    value: new BABYLON.Vector3(0, 5, -30)
});
movein_keys.push({
    frame: 3 * frameRate,
    value: new BABYLON.Vector3(0, 2, -10)
});
movein_keys.push({
    frame: 5 * frameRate,
    value: new BABYLON.Vector3(0, 2, -10)
});
movein_keys.push({
    frame: 8 * frameRate,
    value: new BABYLON.Vector3(-2, 2, 3)
});
movein.setKeys(movein_keys);
// 让相机扫一圈
var rotate = new BABYLON.Animation(
    "rotate",
    "rotation.y",
    frameRate,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
);
var rotate_keys = [];
rotate_keys.push({
    frame: 0,
    value: 0
});
rotate_keys.push({
    frame: 9 * frameRate,
    value: 0
});
rotate_keys.push({
    frame: 14 * frameRate,
    value: Math.PI
});
rotate.setKeys(rotate_keys);

(2)对于门

门以 y 轴为轴围绕铰链进行旋转。打开和关闭门的旋转将分别需要 2 秒。

关键点是 0、 3、 5、 13 和 15 秒。

关键点的值将是它在关键点处的帧中围绕 y 轴的旋转。

// 用于打开和关闭门
var sweep = new BABYLON.Animation(
    "sweep",
    "rotation.y",
    frameRate,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
);
var sweep_keys = [];
sweep_keys.push({
    frame: 0,
    value: 0
});
sweep_keys.push({
    frame: 3 * frameRate,
    value: 0
});
sweep_keys.push({
    frame: 5 * frameRate,
    value: Math.PI / 3
});
sweep_keys.push({
    frame: 13 * frameRate,
    value: Math.PI / 3
});
sweep_keys.push({
    frame: 15 * frameRate,
    value: 0
});
sweep.setKeys(sweep_keys);

(3)对于灯光

灯的关键点是保持关闭到 7 秒,在 10 秒达到全强度,直到 14 秒熄灭。

// 让光线变亮变暗
var lightDimmer = new BABYLON.Animation(
    "dimmer",
    "intensity",
    frameRate,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
);
var light_keys = [];
light_keys.push({
    frame: 0,
    value: 0
});
light_keys.push({
    frame: 7 * frameRate,
    value: 0
});
light_keys.push({
    frame: 10 * frameRate,
    value: 1
});
light_keys.push({
    frame: 14 * frameRate,
    value: 1
});
light_keys.push({
    frame: 15 * frameRate,
    value: 0
});
lightDimmer.setKeys(light_keys);

4. 卡通片

同时运行所有剪辑: 

scene.beginDirectAnimation(camera, [movein, rotate], 0, 25 * frameRate, false);
scene.beginDirectAnimation(hinge, [sweep], 0, 25 * frameRate, false);
scene.beginDirectAnimation(
    spotLights[0],
    [lightDimmer],
    0,
    25 * frameRate,
    false
);
scene.beginDirectAnimation(
    spotLights[1],
    [lightDimmer.clone()],
    0,
    25 * frameRate,
    false
);

5. 分组动画:AnimationGroup

AnimationGroup 允许您将动画和网格链接在一起并作为一个动画组播放、暂停和停止它们。

(1)组成一个动画组:addTargetedAnimation

使用 addTargetedAnimation 方法将动画与网格链接起来

var animationGroup1 = new BABYLON.AnimationGroup("Group1");
var animationGroup2 = new BABYLON.AnimationGroup("Group2");

animationGroup1.addTargetedAnimation(animation1, mesh1);
animationGroup1.addTargetedAnimation(animation3, mesh1);
animationGroup1.addTargetedAnimation(animation2, mesh2);
animationGroup2.addTargetedAnimation(animation2, mesh3);
animationGroup2.addTargetedAnimation(animation1, mesh4);
animationGroup2.addTargetedAnimation(animation2, mesh4);
animationGroup2.addTargetedAnimation(animation3, mesh4);

 由于动画可能是使用不同的时间线创建的,因此必须使用 normalize 规范这些动画。

(2)规范化动画组:normalize

可以使用 normalize 方法使所有动画的帧数相同。

animationGroup2.normalize(0, 100);

一般来说,规范化的参数是数字 beginFrame 和 endFrame

beginFrame:开始帧编号,必须小于或等于所有动画的最小开始帧

endFrame:结束帧编号,必须大于或等于所有动画的最大结束帧

            // 创建缩放动画
            var animation1 = new BABYLON.Animation("tutoAnimation", "scaling.z", 30, BABYLON.Animation
                .ANIMATIONTYPE_FLOAT,
                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
            // 动画帧数组
            var keys = [];
            // 在动画帧数组下标 0 处,缩放的值为 1
            keys.push({
                frame: 0,
                value: 1
            });
            // 在动画帧数组下标 20 处,缩放的值为 0.2
            keys.push({
                frame: 20,
                value: 0.2
            });
            // 在动画帧数组下标 100 处,缩放的值为 1
            keys.push({
                frame: 100,
                value: 1
            });
            // 向动画对象添加帧
            animation1.setKeys(keys);
            // 创建具有不同时间轴的第二个旋转动画
            var animation2 = new BABYLON.Animation("tutoAnimation", "rotation.y", 30, BABYLON.Animation
                .ANIMATIONTYPE_FLOAT,
                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
            // 动画帧数组
            keys = [];
            keys.push({
                frame: 0,
                value: 0
            });
            keys.push({
                frame: 40,
                value: Math.PI
            });
            keys.push({
                frame: 80,
                value: 0
            });
            // 向动画对象添加帧
            animation2.setKeys(keys);
            // 创建动画组
            var animationGroup = new BABYLON.AnimationGroup("my group");
            //只有box1在动
            animationGroup.addTargetedAnimation(animation1, box1);
            animationGroup.addTargetedAnimation(animation2, box1);

            //两个box都在动
            animationGroup.addTargetedAnimation(animation1, box1);
            animationGroup.addTargetedAnimation(animation2, box2);
            //两个box同频
            animationGroup.addTargetedAnimation(animation1, box1);
            animationGroup.addTargetedAnimation(animation2, box1);
            animationGroup.addTargetedAnimation(animation2, box2);
            // 确保将动画标准化为相同的时间线
            animationGroup.normalize(0, 100);

(3)动画组的速率比:speedRatio

可以设置组中所有动画的 speedRatio 来加快或减慢动画播放

animationGroup1.speedRatio = 0.25;
animationGroup2.speedRatio = 3;

(4)从现有动画创建动画组

通过枚举动画表中包含的动画来从动画表中创建新的 AnimationGroup

var animationGroup = new BABYLON.AnimationGroup("my-animation-group");
for (anim of idleAnim.getAnimations()) {
    animationGroup.addTargetedAnimation(anim.animation, anim.target);
}

(5)在动画结束时:onAnimationEndObservable

onAnimationEndObservable 可以用来在动画组结束时触发一个函数:

animationGroup1.onAnimationEndObservable.add(function () {
    mesh2.material = redMaterial;
});

 (6)在动画组循环时:onAnimationLoopObservable、onAnimationGroupLoopObservable

onAnimationLoopObservable 可用于在动画组循环时触发一个函数:

animationGroup1.onAnimationLoopObservable.add(function (targetAnimation) {
    console.log(targetAnimation.animation.name);
});

 onAnimationGroupLoopObservable 可用于在动画组的所有动画循环播放时触发一个函数:

animationGroup1.onAnimationGroupLoopObservable.add(function (group) {
    console.log("Group looped!");
});

6. 合并动画

(1)如何合并动画

  • 动画并行

只需设置多个动画并添加到 Babylon.js 对象的动画数组中即可实现多个动画并行执行。

1. 滑动和旋转并行

// 位置动画
var xSlide = new BABYLON.Animation("xSlide", "position.x", frameRate, BABYLON.Animation
    .ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
var keyFramesP = [];
keyFramesP.push({
    frame: 0,
    value: 2
});
keyFramesP.push({
    frame: frameRate,
    value: -2
});
keyFramesP.push({
    frame: 2 * frameRate,
    value: 2
});
xSlide.setKeys(keyFramesP);
// 旋转动画
var yRot = new BABYLON.Animation("yRot", "rotation.y", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
var keyFramesR = [];
keyFramesR.push({
    frame: 0,
    value: 0
});
keyFramesR.push({
    frame: frameRate,
    value: Math.PI
});
keyFramesR.push({
    frame: 2 * frameRate,
    value: 2 * Math.PI
});
yRot.setKeys(keyFramesR);
scene.beginDirectAnimation(box, [xSlide, yRot], 0, 2 * frameRate, true);

2. 滑动和更快速旋转并行

将旋转值更改为更大的数字会增加旋转速率

3. 滑动和变化速率的旋转并行

(2)连续动画:beginDirectAnimation

为了让一个动画跟随另一个动画,需要向 beginDirectAnimation 函数添加另一个参数。

beginDirectAnimation 及其参数

scene.beginDirectAnimation(target, animations, start frame, end frame, loop, speed, on animation end)

target:object,动画目标

animations:array,应用于目标的所有动画

start frame:number,开始动画的帧

end frame:number,结束动画的帧

loop:boolean,可选,true表示循环动画

speed:number,可选,默认1匹配动画帧率,数字越大,动画越快,数字越小,动画越慢

on animation end:function,可选,动画结束时调用的函数,要求 loop 为 false

旋转然后滑动的动画: 

scene.beginDirectAnimation(
    box,
    [yRot],
    0,
    2 * frameRate,
    false,
    1,
    nextAnimation
);

var nextAnimation = function () {
    scene.beginDirectAnimation(box, [xSlide], 0, 2 * frameRate, true);
};

 盒子进入滑动循环后,旋转继续进行:

var nextAnimation = function () {
    scene.beginDirectAnimation(box, [yRot, xSlide], 0, 2 * frameRate, true);
};

7. 动画角色

(1)用键盘控制动画角色的移动:animationGroups、ActionManager

导入模型并播放动画

确保添加 animationGroups 参数,因为它用于获取和播放动画。

BABYLON.SceneLoader.ImportMesh("", "https://assets.babylonjs.com/meshes/", "HVGirl.glb", scene, function (newMeshes, particleSystems, skeletons, animationGroups) {
    var hero = newMeshes[0];
    // 缩小模型
    hero.scaling.scaleInPlace(0.1);
    // 将相机锁定在角色上
    camera1.target = hero;
    // 获取 Samba 动画组
    const sambaAnim = scene.getAnimationGroupByName("Samba");
    // 播放 Samba 动画
    sambaAnim.start(true, 1.0, sambaAnim.from, sambaAnim.to, false);
});

默认情况下,加载带有动画组的模型时,会播放 animationGroups[0] ,停止动画

animationGroups[0].stop();

通过键盘控制动画 

Action Manager 可用于捕获键盘上按下的键

var inputMap = {};
scene.actionManager = new BABYLON.ActionManager(scene);
scene.actionManager.regist
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要给引入的模型加上手写动画,需要使用Babylon.js中的动画系统。首先,需要创建一个动画对象,并指定要动画的属性和变化值。然后,需要创建一个动画帧,并指定要改变的时间和值。最后,将动画帧添加到动画对象中,并将动画对象附加到模型上。 以下是一个简单的示例代码,演示如何使用Babylon.js添加手写动画: ```javascript // 导入模型 BABYLON.SceneLoader.ImportMesh("", "models/", "myModel.babylon", scene, function (newMeshes) { var mesh = newMeshes[0]; // 创建动画对象 var animationBox = new BABYLON.Animation("myAnimation", "rotation.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); // 创建动画帧 var keys = []; keys.push({ frame: 0, value: 0 }); keys.push({ frame: 20, value: Math.PI / 2 }); keys.push({ frame: 40, value: Math.PI }); animationBox.setKeys(keys); // 将动画对象添加到模型上 mesh.animations.push(animationBox); // 开始动画 scene.beginAnimation(mesh, 0, 100, true); }); ``` 在上面的代码中,我们创建了一个名为“myAnimation”的动画对象,指定了要改变的属性为“rotation.y”,变化值为浮点数。然后,我们创建了三个动画帧,分别在0、20和40帧时改变旋转角度。最后,将动画对象添加到模型的动画数组中,并使用场景的beginAnimation方法启动动画。 请注意,这只是一个简单的示例,您可以根据需要修改动画对象和动画帧的属性和值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值