0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

HT for Web (Hightopo) 使用心得(5)- 动画的实现

图扑-数字孪生 来源:图扑-数字孪生 作者:图扑-数字孪生 2023-11-29 11:04 次阅读

其实,在 HT for Web 中,有多种手段可以用来实现动画。我们这里仍然用直升机为例,只是更换了场景。增加了巡游过程。

使用 HT 开发的一个简单网页直升机巡逻动画(Hightopo 使用心得(5))

这里主要用到的动画实现方式有三种:

setInterval

ht.Default.startAnim()

DataModel.addScheduleTask(task)

场景搭建

具体3D场景的相关概念请参考《Hightopo 使用心得(4)- 3D 场景 Graph3dView 与 Obj 模型》。

这里的主要工作分为:3D 场景配置以及模型加载。其中 3D 场景部分的设置代码如下:

this.g3d = new ht.graph3d.Graph3dView();

this.g3d.setGridVisible(true);

this.g3d.setGridSize(5000);

this.g3d.setGridGap(2000);

this.g3d.setNear(10)

this.g3d.setFar(10000000)

this.g3d.addToDOM();

this.dataModel = this.dm = this.g3d.dm();

为了给直升机搭建一个逼真的环境。这里我们增加了一个山体模型。另外,由于直升机机体与螺旋桨模型是分开的,因此需要分别加载并调整其位置让二者合并成一个模型。

// 加载山体模型

this.mountains = await this.createObj(MODELS.MOUNTAINS.name, MODELS.MOUNTAINS.obj, MODELS.MOUNTAINS.mtl);

this.mountains.s('3d.selectable',false);

this.mountains.s('shape3d.scaleable',true);

this.mountains.setScale3d([0.01, 0.1, 0.01]);

this.mountains.setElevation(1800); // 让山体在地面以上

// 分别加载直升机及螺旋桨模型

this.helicopterNode = await this.createObj(MODELS.HELICOPTER.name, MODELS.HELICOPTER.obj, MODELS.HELICOPTER.mtl);

this.propellerNode = await this.createObj(MODELS.PROPELLER.name, MODELS.PROPELLER.obj, MODELS.PROPELLER.mtl);

// 由于默认创建 Node 的时候,其锚点是在 [0.5, 0.5, 0.5],位置是在 [0, 0, 0]。导致模型并不在水平面以上。

let size3d = this.helicopterNode.getSize3d(); // 获取直升机模型的 [长,宽,高]

let height = size3d[1]; // 获取模型高度

this.helicopterNode.setPosition3d([0, height/2, 0]); // 将直升机放到地面上

this.propellerNode.setRotation3d([0.10506443461595279, 4.550746858974086, -0.007825951889059535]); // 让螺旋桨水平

this.propellerNode.setPosition3d([0, 215, -99.00152946490829]); // 将螺旋桨放到直升机上

this.propellerNode.setHost(this.helicopterNode); // 螺旋桨吸附到直升机上

this.helicopterNode.p3(0,2000,0); // 直升机

wKgZomVmqlGARY9wAAt-S89mkn8765.png

螺旋桨动画 - setInterval

螺旋桨动画比较简单,我们在《Hightopo 使用心得(4)- 3D 场景 Graph3dView 与 Obj 模型_CodingInProgress的博客-CSDN博客》中已经提过。其本质是通过不断地修改螺旋桨节点在竖直方向(Y 轴)的角度。

/**

* 螺旋桨旋转动画

*

*/

startPropellerAnim(node) {

setInterval(() => {

const r3 = node.getRotation3d();

node.setRotation3d([r3[0], r3[1] + 0.4, r3[2]]); // 绕 Y 轴旋转

}, 20);

}

创建直升机巡游路径

有了直升机及环境,我们需要让直升机动起来。例如在这里,我们计划让直升机围绕山体巡逻。这里该如何实现呢?

在 HT for Web 官方手册中,其提供了一种实现方式,我们这里稍微加以改造便可让直升机围绕山体巡逻。

wKgaomVmqlKAEoGrAAf-OHJWVgU936.gif

在代码层面,我们创建了一条三维线段(Polyline)。该线段实现的是一个圆环,悬浮在山体上面。有了这条路径,直升机便可沿着该路径前进实现巡游动画。

polyline的形状主要由points和segments这两个属性描述。二者都是数组。其中 points 可以理解成组成 polyline 所要用到的点集合,而 segments 数组主要用来定义如何使用前面的点来组成 polyline。

points 中的每一项为 {x,y,e} 格式,需要注意的是,这里代表高度的是 e(elevation),而不是 y。

segments 数组里面有5种值。分别为:

1: moveTo,占用1个点信息,代表一个新路径的起点

2: lineTo,占用1个点信息,代表从上次最后点连接到该点

3: quadraticCurveTo,占用2个点信息,第一个点作为曲线控制点,第二个点作为曲线结束点

4: bezierCurveTo,占用3个点信息,第一和第二个点作为曲线控制点,第三个点作为曲线结束点

5: closePath,不占用点信息,代表本次路径绘制结束,并闭合到路径的起始点

/**

* 创建直升机巡游路径

*

* @memberof Index3d

*/

createPath() {

this.g3d.setDashDisabled(false); // 显示虚线

let height = 2000; // 线段离地高度

let dataModel = this.dataModel;

let polyline = this.polyline = new ht.Polyline();

polyline.setThickness(5); // 线段粗细

polyline.s({

'shape3d.image': 'assets/flow.png', // 贴图

"shape3d": "cylinder", // polyline类型,这里是圆柱。也可以是

'repeat.uv.length': 400, // 贴图宽度

'shape3d.resolution': 1600, // 管线分辨率,分辨率越高越平滑

});

dataModel.add(polyline);

// 起始点

const points = [{

x: -15000,

y: 0,

e: height,

}];

const segments = [1];

// 二次曲线,占用两个点。生成一条弧线。下同。

points.push({

x: -15000,

y: -15000,

e: height

});

points.push({

x: 0,

y: -15000,

e: height

});

segments.push(3);

points.push({

x: 15000,

y: -15000,

e: height

});

points.push({

x: 15000,

y: 0,

e: height

});

segments.push(3);

points.push({

x: 15000,

y: 15000,

e: height

});

points.push({

x: 0,

y: 15000,

e: height

});

segments.push(3);

points.push({

x: -15000,

y: 15000,

e: height

});

points.push({

x: -15000,

y: 0,

e: height,

});

segments.push(3);

polyline.setPoints(points);

polyline.setSegments(segments);

polyline.setAnchorElevation(0)

}

直升机巡游动画 - ht.Default.startAnim

接下来,我们需要让直升机沿着巡游路径前进。在实现的时候,我们使用了 ht.Default.startAnim() 方法。该方法我们在前几篇文章中都用过,这里就不再详细介绍。

wKgZomVmqlOAb6jnAArqNcgMBts517.png

ht.Default.startAnim() 会执行 duration 毫秒,在执行过程中,其会自动计算所需要的帧数并在每一帧都调用一次action 方法。也就是说,如果我们想让直升机 40 秒围绕路径飞行一圈,我们只需要将 duration 设置成40*1000 毫秒,并且在每一帧拿到当前时刻 polyline 上的点的坐标及方向。同时,使用该坐标与方向设置直升机位置及朝向就可以实现巡游动画。

这里面比较关键的一个方法是 g3d.getLineOffset(polyline, length * v) 。该方法会返回一个对象:{point: p.M…h.Vector3, tangent: p.M…h.Vector3}。其分别代表当前时刻 polyline 上的点的坐标及放向。根据这两个值,我们可以进一步配置直升机的位置和朝向。

/**

* 直升机沿着巡游路径飞行

*

* @param {number} [duration=40 * 1000]

* @memberof Index3d

*/

startFly(duration = 40 * 1000) {

const {

g3d,

polyline

} = this;

/** 获取巡游路径总长度 */

let length = g3d.getLineLength(polyline);

const params = {

delay: 0,

duration,

easing: (t) => {

return t;

},

action: (v, t) => {

let offset = g3d.getLineOffset(polyline, length * v),

point = offset.point,

px = point.x,

py = point.y + 200, // 让直升机高于polyline

pz = point.z,

tangent = offset.tangent,

tx = tangent.x,

ty = tangent.y,

tz = tangent.z;

this.helicopterNode.p3(px, py, pz);

this.helicopterNode.lookAt([px + tx, py + ty, pz + tz], 'back'); // 一个模型有6个面,这里需要确定机头处于哪个面

// 视角盯住直升机

if (this._cameraType == 1) {

g3d.setCenter(px, py, pz);

} else if (this._cameraType == 2) { // Camera跟随直升机运动

g3d.setEye(px - tx * 1800 + 1000, py - ty * 1800 + 1000, pz - tz * 1800); // 让镜头高于直升机并在尾部进行观察

g3d.setCenter(px, py, pz);

}

this.helicopterNode.a('angle', v * Math.PI * 120);

},

finishFunc: () => {

ht.Default.startAnim(params);

}

};

ht.Default.startAnim(params);

}

管道流动动画 - DataModel.addScheduleTask()

实现管道流动的动画有多种方式,其本质是定期改变管道的贴图偏移。

wKgaomVmqlOADRQtAArdggdCPLE722.gif

这里我们采用DataModel#addScheduleTask(task)实现流动动画。DataModel#addScheduleTask(task)实际上是添加了一个调度任务。由于该方法是在 DataModel 上执行,因此在每次执行的时候,DataModel 里面的每个 Data 都会被调用。我们可以在 action 参数里面对 Data 进行过滤。DataModel#addScheduleTask(task)方法的参数task为json对象,可指定如下属性:

interval:间隔毫秒数,默认值为10

enabled:是否启用开关,默认为true

beforeAction:调度开始之前的动作函数

action:间隔动作函数,对DataModel上的每个data节点都会执行一次action操作

afterAction:调度结束之后的调度函数

另外,可以用DataModel#removeScheduleTask(task)删除调度任务,其中task为以前添加过的调度任务对象。

/**

* 通过DataModel的addScheduleTask实现流动效果

*

* @memberof Index3d

*/

addScheduleTasks() {

const task = {

interval: 50, // 间隔毫秒数,默认值为10

enabled: true, // 是否启用开关,默认为true

beforeAction: () => {}, // 调度开始之前的动作函数

afterAction: () => {}, // 调度结束之后的调度函数

action: (data) => { // 间隔动作函数,对DataModel上的每个data节点都会执行一次action操作

if (data.getClassName() == 'ht.Polyline') {

const offset = (data.s('shape3d.uv.offset') || [0,0]);

data.s('shape3d.uv.offset', [offset[0] + 0.1, offset[1]]);

}

}

};

this.dataModel.addScheduleTask(task);

// this.dataModel.removeScheduleTask(task); // 删除调度任务

}

这里我们只是举例介绍一下DataModel#addScheduleTask(task)的用法。对于一个 DataModel 中大部分 Data 都需要动画的时候,可以考虑使用该方法。

在代码执行的时候,我们可以选择把巡游路径隐藏。这样看起来直升机就是沿着一个圆形持续巡游。

hidePath() {

this.polyline.s('3d.visible', false);

}

总结

本文介绍了如何通过代码实现一个直升机绕山巡游的动画,包括创建路径和实现直升机的飞行动画。另外,还介绍了如何通过DataModel#addScheduleTask(task)实现流动效果的动画。读完本文,你将了解到如何使用 HT for Web 实现各种动画效果。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数字孪生
    +关注

    关注

    4

    文章

    991

    浏览量

    11800
收藏 人收藏

    评论

    相关推荐

    HT for Web (Hightopo) 使用心得(1)- 基本概念

    本章主要介绍了 HT for Web 中的一些基本概念,包括:基础数据 ht.Data、数据模型 ht.DataModel 和选择模型 ht
    的头像 发表于 09-11 10:45 504次阅读
    <b class='flag-5'>HT</b> for <b class='flag-5'>Web</b> (<b class='flag-5'>Hightopo</b>) 使<b class='flag-5'>用心得</b>(1)- 基本概念

    HT for Web (Hightopo) 使用心得(3)- 吸附与锚点

    吸附,顾名思义,是一个节点吸附到另一个节点上。就像船底的贝类一样,通过吸附到船身,在船移动的时候自己也会跟着移动;而锚点,则决定了哪个位置是该节点的坐标点位置。这里继续以船舶为例,锚点就是船舶抛锚后船锚所在点,只不过船的锚点在船外面,而 HT 节点的锚点通常在其中心。并且这里的锚链是刚性的不能弯曲。
    的头像 发表于 10-12 10:44 707次阅读
    <b class='flag-5'>HT</b> for <b class='flag-5'>Web</b> (<b class='flag-5'>Hightopo</b>) 使<b class='flag-5'>用心得</b>(3)- 吸附与锚点

    HT for Web (Hightopo) 使用心得(4)- 3D 场景 Graph3dView 与 Obj 模型

    这里我们通过代码建立一个 3D 场景并添加一个 Obj 模型来介绍一下 HT for Web 在 3D 场景和模型加载方面的使用。
    的头像 发表于 11-20 11:05 275次阅读
    <b class='flag-5'>HT</b> for <b class='flag-5'>Web</b> (<b class='flag-5'>Hightopo</b>) 使<b class='flag-5'>用心得</b>(4)- 3D 场景 Graph3dView 与 Obj 模型

    【MATLAB使用心得汇总——Tips6 】

    本帖最后由 maxfiner 于 2013-12-12 12:48 编辑 MATLAB使用心得汇总——Tips6 变量使用前要预先定义大小。对于大变量来说,至关重要。如下例,仅仅是长度
    发表于 12-12 12:47

    滤波电容的使用心得

    图说滤波电容的使用心得,非常详细,不信你还不懂~
    发表于 07-18 15:23

    关于Spartan6板子的使用心得

    给大家分享一下关于Spartan6板子的使用心得
    发表于 04-30 07:03

    TFT LCD使用心得

    TFT LCD使用心得体会的原因是,最近一段时间工作上一直在使用TFT LCD,主要是3.5寸LCD,以SAMSUNG的LTV350QV及其一些台湾的兼容产品为主。工作的内容就是把这些屏在我们的产品上应用起
    发表于 10-16 13:04 43次下载

    详细谈谈TFT LCD 的使用心得

    深入谈谈TFT LCD 的使用心得最近一段时间工作上一直在使用TFT LCD,主要是3、5 寸LCD,以SAMSUNG 的LTV350QV 及其一些台湾的兼容产品为主。工作的内容就是把这些屏在我们的产品上
    发表于 03-18 17:49 3次下载

    ADXL345芯片使用心得

    ADXL345芯片使用心得,介绍使用传感器过程的使用体会
    发表于 05-11 11:08 23次下载

    Django教程之Django的使用心得详细资料免费下载

    本文档的主要内容详细介绍的是Django教程之Django的使用心得详细资料免费下载。
    发表于 10-17 18:03 11次下载
    Django教程之Django的使<b class='flag-5'>用心得</b>详细资料免费下载

    合泰单片机使用心得 (转)

    合泰单片机使用心得 合泰单片机是台湾芯片,集成开发环境为HT-3000。大陆这边的芯片代理商是盛群半导体有限公司,官网上的程序用例都是由汇编编写的,当然也对C语言很好的支持,是标准C的子集。在工作中
    发表于 12-02 20:36 10次下载
    合泰单片机使<b class='flag-5'>用心得</b> (转)

    智慧服装工厂电子看板试用心得

    智慧服装工厂电子看板试用心得实现了企业生产的进度实时监控、现场拉式生产、生产节拍平衡和异常情况的反馈功能。而接下来我们主要讨论的是智慧服装工厂电子看板试用心得在生产线与仓库之间的物料配送体系,要谈到这个物料配送问题,则要首先考虑
    的头像 发表于 02-17 18:02 766次阅读
    智慧服装工厂电子看板试<b class='flag-5'>用心得</b>

    使用Raspberry Pi和Arduino实现Web控制的LED动画

    电子发烧友网站提供《使用Raspberry Pi和Arduino实现Web控制的LED动画.zip》资料免费下载
    发表于 07-03 14:52 0次下载
    使用Raspberry Pi和Arduino<b class='flag-5'>实现</b><b class='flag-5'>Web</b>控制的LED<b class='flag-5'>动画</b>

    HT for Web (Hightopo) 使用心得(2)- 2D 图纸、节点、连线 与基本动画

    概括来说,用 HT for Web 做可视化主要分为两部分,也就是 2D 和 3D。这两部分需要单独创建。在它们被创建完成后,我们再把它们集成到一起。 HT for Web 的 2D
    的头像 发表于 09-21 10:52 456次阅读
    <b class='flag-5'>HT</b> for <b class='flag-5'>Web</b> (<b class='flag-5'>Hightopo</b>) 使<b class='flag-5'>用心得</b>(2)- 2D 图纸、节点、连线 与基本<b class='flag-5'>动画</b>

    图扑 HT for Web 风格属性手册教程

    图扑软件明星产品 HT for Web 是一套纯国产化独立自主研发的 2D 和 3D 图形界面可视化引擎。HT for Web(以下简称 HT
    的头像 发表于 10-11 10:50 294次阅读
    图扑 <b class='flag-5'>HT</b> for <b class='flag-5'>Web</b> 风格属性手册教程