Babylongjs-村庄动画

我们村现在不是很热闹,所以让我们添加一些动画。我们仍处于学习 Babylon.js 的早期阶段,离添加 Simms 系列还差得很远。您将要介绍的父级和子级是无声类型和一种将网格链接在一起的方式,以便对父网格的更改也应用于其子网格。我们将为一个非常简单的汽车制作动画,其车轮是父车身的子级。与真正的汽车不同的是,它是车身带动车轮。有一种方式可以让我们的网格父母和孩子表现得像一个真正的家庭,孩子们可以独立于父母行事。干得好,因为我们不希望汽车随车轮旋转。

父母和孩子

我们将添加一辆穿过村庄的非常简单的汽车。

无论多么简单的汽车需要车轮,我们都必须将车身和车轮结合起来。

使用合并网格将它们组合起来会导致车轮无法旋转。相反,我们将汽车的车身设置为每个车轮的父级。

在构建我们的简单汽车之前,让我们采取一种方法来设置父级以及这意味着什么。

messhChild.parent = meshParent

 在父级上使用任何位置、缩放和旋转也将应用于子级。设置孩子的位置在父空间中完成,设置孩子的旋转和缩放发生在孩子的本地空间中。

造车

这辆车将是一辆非常简单的车。主体将使用extrudePolygon方法构建。这是另一种可以使用MeshBuilder构建的形状。形状的轮廓是在 XZ 平面上绘制的,点按逆时针顺序排列,拉伸在 Y 方向。多边形的原点是底平面上的零点。

汽车的轮廓由一组 vector3 点组成,它们形成水平基线、前部的四分之一圆,然后是水平基线。垂直背面由extrudePolygon方法形成,因为它会自动连接第一个和最后一个点。

//base
const outline = [
    new BABYLON.Vector3(-0.3, 0, -0.1),
    new BABYLON.Vector3(0.2, 0, -0.1),
]

//curved front
for (let i = 0; i < 20; i++) {
    outline.push(new BABYLON.Vector3(0.2 * Math.cos(i * Math.PI / 40), 0, 0.2 * Math.sin(i * Math.PI / 40) - 0.1));
}

//top
outline.push(new BABYLON.Vector3(0, 0, 0.1));
outline.push(new BABYLON.Vector3(-0.3, 0, 0.1));

这些和沿 Y 方向挤压的深度,给出了汽车的形状

const car = BABYLON.MeshBuilder.ExtrudePolygon("car", {shape: outline, depth: 0.2});

注意:extrudePolygonPolygonMeshBuilder都使用耳切切片算法。
Playground 已经定义了 earcut,但是如果您在自己的文件系统上遵循本教程,则需要通过cdnnpm下载 earcut 算法。
如果您使用的是 TypeScript,那么您可以将 Earcut 算法作为extudePolygon函数上的earcutInjection参数注入。

车轮

我们从一个圆柱体中形成右靠背位置的轮子,并将它作为一个孩子添加到汽车中。然后复印右前轮、左后轮和左前轮。这次使用clone而不是createInstance因为我们可以克隆一个克隆。当我们克隆一个轮子时,它的父节点成为克隆的父节点。

const wheelRB = BABYLON.MeshBuilder.CreateCylinder("wheelRB", {diameter: 0.125, height: 0.05})
wheelRB.parent = car;
wheelRB.position.z = -0.1;
wheelRB.position.x = -0.2;
wheelRB.position.y = 0.035;

const wheelRF = wheelRB.clone("wheelRF");
wheelRF.position.x = 0.1;

const wheelLB = wheelRB.clone("wheelLB");
wheelLB.position.y = -0.2 - 0.035;

const wheelLF = wheelRF.clone("wheelLF");
wheelLF.position.y = -0.2 - 0.035;

现在我们将使用一些纹理使汽车看起来更像汽车。

汽车材质

就像我们在盒子的不同面上使用不同的图像一样,挤出的多边形和圆柱体也有类似的东西。

对于车身,我们使用此图像

 这个是轮子用的

 

对于挤压多边形和圆柱面,0 是底部,面 2 是顶部,面 1 是连接底部和顶部的边。请记住,目前车身和车轮都是平躺的

车身的顶部和底部使用左上角(几乎)四分之一的图像。边缘部分穿过底部,环绕前面,穿过顶部和身体的后部使用图像的下半部分。

车身底部如您所料,由左下角坐标 (0, 0.5) 到右上角坐标 (0.38, 1) 给出;

车身顶部使用相同的图像,但需要翻转以适合汽车的另一侧。

边从 (0, 0) 到 (1, 0.5)

//底部
faceUV[0] = new BABYLON.Vector4(0, 0.5, 0.38, 1);
//顶部
faceUV[2] = new BABYLON.Vector4(0.38, 1, 0, 0.5);
//边缘
faceUV[1] = new BABYLON.Vector4(0, 0, 1, 0.5);

轮子由于其对称性而更加直接,它使用整个图像作为顶部和底部,并且只为边缘拾取黑色像素。

wheelUV[0] = new BABYLON.Vector4(0, 0, 1, 1);
wheelUV[1] = new BABYLON.Vector4(0, 0.5, 0, 0.5);
wheelUV[2] = new BABYLON.Vector4(0, 0, 1, 1);

把这些放在一起,然后把成品车直立起来就可以了。

 动画基础-车轮动画

我们将从一个轮子开始,让它绕着它的轴旋转。请记住,为了使汽车保持直立,我们将其绕 x 轴旋转,因此轴沿圆柱体的 y 轴。

我们需要创建一个新的动画对象

const animWheel = new BABYLON.Animation("wheelAnimation", "rotation.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

它具有参数

1.名称、

2.动画属性、

3.每秒动画帧数、

4.动画类型属性、

5.循环模式,

在这种情况下是重复动画,我们遵循关键帧数组,在其中我们设置属性值以按帧编号进行动画处理:

const wheelKeys = []; 

//At the animation key 0, the value of rotation.y is 0
wheelKeys.push({
    frame: 0,
    value: 0
});

//At the animation key 30, (after 1 sec since animation fps = 30) the value of rotation.y is 2PI for a complete rotation
wheelKeys.push({
    frame: 30,
    value: 2 * Math.PI
});

最后,我们将关键帧数组链接到动画,将动画链接到网格并开始它。

//set the keys
animWheel.setKeys(wheelKeys);

//Link this animation to the right back wheel
wheelRB.animations = [];
wheelRB.animations.push(animWheel);

//Begin animation - object to animate, first frame, last frame and loop if true
scene.beginAnimation(wheelRB, 0, 30, true);

由于所有轮子旋转相同,我们可以对所有轮子使用相同的动画。

scene.beginAnimation(wheelRF, 0, 30, true);
scene.beginAnimation(wheelLB, 0, 30, true);
scene.beginAnimation(wheelLF, 0, 30, true);

为了确保在以后的操场上新代码不会被大量以前的代码淹没,我们将把汽车保存为模型并将其作为项目导入和动画。

BABYLON.SceneLoader.ImportMeshAsync("", "url to model car", "car.babylon").then(() =>  {
    const wheelRB = scene.getMeshByName("wheelRB");
    const wheelRF = scene.getMeshByName("wheelRF");
    const wheelLB = scene.getMeshByName("wheelLB");
    const wheelLF = scene.getMeshByName("wheelLF");

    scene.beginAnimation(wheelRB, 0, 30, true);
    scene.beginAnimation(wheelRF, 0, 30, true);
    scene.beginAnimation(wheelLB, 0, 30, true);
    scene.beginAnimation(wheelLF, 0, 30, true);
});

我们现在可以为汽车本身设置动画并将其添加到村庄中。

为村庄中的汽车制作动画

与我们为车轮设置动画的方式类似,我们现在为汽车设置动画以使其直线行驶 5 秒,然后停止 2 秒。然后重复。

const animCar = new BABYLON.Animation("carAnimation", "position.x", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

const carKeys = []; 

carKeys.push({
    frame: 0,
    value: -4
});

carKeys.push({
    frame: 150,
    value: 4
});

carKeys.push({
    frame: 210,
    value: 4
});

animCar.setKeys(carKeys);

car.animations = [];
car.animations.push(animCar);

scene.beginAnimation(car, 0, 210, true);

在调整汽车的位置和路线后,它会经过我们有的村屋。

我们已经制造了汽车。现在让我们看一个可以与其内置动画一起导入的模型角色。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值