0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

HT for Web (Hightopo) 使用心得(5)- 動(dòng)畫的實(shí)現(xiàn)

圖撲-數(shù)字孿生 ? 來源:圖撲-數(shù)字孿生 ? 作者:圖撲-數(shù)字孿生 ? 2023-11-29 11:04 ? 次閱讀

其實(shí),在 HT for Web 中,有多種手段可以用來實(shí)現(xiàn)動(dòng)畫。我們這里仍然用直升機(jī)為例,只是更換了場景。增加了巡游過程。

使用 HT 開發(fā)的一個(gè)簡單網(wǎng)頁直升機(jī)巡邏動(dòng)畫(Hightopo 使用心得(5))

這里主要用到的動(dòng)畫實(shí)現(xiàn)方式有三種:

setInterval

ht.Default.startAnim()

DataModel.addScheduleTask(task)

場景搭建

具體3D場景的相關(guān)概念請參考《Hightopo 使用心得(4)- 3D 場景 Graph3dView 與 Obj 模型》。

這里的主要工作分為:3D 場景配置以及模型加載。其中 3D 場景部分的設(shè)置代碼如下:

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();

為了給直升機(jī)搭建一個(gè)逼真的環(huán)境。這里我們增加了一個(gè)山體模型。另外,由于直升機(jī)機(jī)體與螺旋槳模型是分開的,因此需要分別加載并調(diào)整其位置讓二者合并成一個(gè)模型。

// 加載山體模型

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); // 讓山體在地面以上

// 分別加載直升機(jī)及螺旋槳模型

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);

// 由于默認(rèn)創(chuàng)建 Node 的時(shí)候,其錨點(diǎn)是在 [0.5, 0.5, 0.5],位置是在 [0, 0, 0]。導(dǎo)致模型并不在水平面以上。

let size3d = this.helicopterNode.getSize3d(); // 獲取直升機(jī)模型的 [長,寬,高]

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

this.helicopterNode.setPosition3d([0, height/2, 0]); // 將直升機(jī)放到地面上

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

this.propellerNode.setPosition3d([0, 215, -99.00152946490829]); // 將螺旋槳放到直升機(jī)上

this.propellerNode.setHost(this.helicopterNode); // 螺旋槳吸附到直升機(jī)上

this.helicopterNode.p3(0,2000,0); // 直升機(jī)

wKgZomVmqlGARY9wAAt-S89mkn8765.png

螺旋槳?jiǎng)赢?- setInterval

螺旋槳?jiǎng)赢嫳容^簡單,我們在《Hightopo 使用心得(4)- 3D 場景 Graph3dView 與 Obj 模型_CodingInProgress的博客-CSDN博客》中已經(jīng)提過。其本質(zhì)是通過不斷地修改螺旋槳節(jié)點(diǎn)在豎直方向(Y 軸)的角度。

/**

* 螺旋槳旋轉(zhuǎn)動(dòng)畫

*

*/

startPropellerAnim(node) {

setInterval(() => {

const r3 = node.getRotation3d();

node.setRotation3d([r3[0], r3[1] + 0.4, r3[2]]); // 繞 Y 軸旋轉(zhuǎn)

}, 20);

}

創(chuàng)建直升機(jī)巡游路徑

有了直升機(jī)及環(huán)境,我們需要讓直升機(jī)動(dòng)起來。例如在這里,我們計(jì)劃讓直升機(jī)圍繞山體巡邏。這里該如何實(shí)現(xiàn)呢?

在 HT for Web 官方手冊中,其提供了一種實(shí)現(xiàn)方式,我們這里稍微加以改造便可讓直升機(jī)圍繞山體巡邏。

wKgaomVmqlKAEoGrAAf-OHJWVgU936.gif

在代碼層面,我們創(chuàng)建了一條三維線段(Polyline)。該線段實(shí)現(xiàn)的是一個(gè)圓環(huán),懸浮在山體上面。有了這條路徑,直升機(jī)便可沿著該路徑前進(jìn)實(shí)現(xiàn)巡游動(dòng)畫。

polyline的形狀主要由points和segments這兩個(gè)屬性描述。二者都是數(shù)組。其中 points 可以理解成組成 polyline 所要用到的點(diǎn)集合,而 segments 數(shù)組主要用來定義如何使用前面的點(diǎn)來組成 polyline。

points 中的每一項(xiàng)為 {x,y,e} 格式,需要注意的是,這里代表高度的是 e(elevation),而不是 y。

segments 數(shù)組里面有5種值。分別為:

1: moveTo,占用1個(gè)點(diǎn)信息,代表一個(gè)新路徑的起點(diǎn)

2: lineTo,占用1個(gè)點(diǎn)信息,代表從上次最后點(diǎn)連接到該點(diǎn)

3: quadraticCurveTo,占用2個(gè)點(diǎn)信息,第一個(gè)點(diǎn)作為曲線控制點(diǎn),第二個(gè)點(diǎn)作為曲線結(jié)束點(diǎn)

4: bezierCurveTo,占用3個(gè)點(diǎn)信息,第一和第二個(gè)點(diǎn)作為曲線控制點(diǎn),第三個(gè)點(diǎn)作為曲線結(jié)束點(diǎn)

5: closePath,不占用點(diǎn)信息,代表本次路徑繪制結(jié)束,并閉合到路徑的起始點(diǎn)

/**

* 創(chuàng)建直升機(jī)巡游路徑

*

* @memberof Index3d

*/

createPath() {

this.g3d.setDashDisabled(false); // 顯示虛線

let height = 2000; // 線段離地高度

let dataModel = this.dataModel;

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

polyline.setThickness(5); // 線段粗細(xì)

polyline.s({

'shape3d.image': 'assets/flow.png', // 貼圖

"shape3d": "cylinder", // polyline類型,這里是圓柱。也可以是

'repeat.uv.length': 400, // 貼圖寬度

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

});

dataModel.add(polyline);

// 起始點(diǎn)

const points = [{

x: -15000,

y: 0,

e: height,

}];

const segments = [1];

// 二次曲線,占用兩個(gè)點(diǎn)。生成一條弧線。下同。

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)

}

直升機(jī)巡游動(dòng)畫 - ht.Default.startAnim

接下來,我們需要讓直升機(jī)沿著巡游路徑前進(jìn)。在實(shí)現(xiàn)的時(shí)候,我們使用了 ht.Default.startAnim() 方法。該方法我們在前幾篇文章中都用過,這里就不再詳細(xì)介紹。

wKgZomVmqlOAb6jnAArqNcgMBts517.png

ht.Default.startAnim() 會執(zhí)行 duration 毫秒,在執(zhí)行過程中,其會自動(dòng)計(jì)算所需要的幀數(shù)并在每一幀都調(diào)用一次action 方法。也就是說,如果我們想讓直升機(jī) 40 秒圍繞路徑飛行一圈,我們只需要將 duration 設(shè)置成40*1000 毫秒,并且在每一幀拿到當(dāng)前時(shí)刻 polyline 上的點(diǎn)的坐標(biāo)及方向。同時(shí),使用該坐標(biāo)與方向設(shè)置直升機(jī)位置及朝向就可以實(shí)現(xiàn)巡游動(dòng)畫。

這里面比較關(guān)鍵的一個(gè)方法是 g3d.getLineOffset(polyline, length * v) 。該方法會返回一個(gè)對象:{point: p.M…h(huán).Vector3, tangent: p.M…h(huán).Vector3}。其分別代表當(dāng)前時(shí)刻 polyline 上的點(diǎn)的坐標(biāo)及放向。根據(jù)這兩個(gè)值,我們可以進(jìn)一步配置直升機(jī)的位置和朝向。

/**

* 直升機(jī)沿著巡游路徑飛行

*

* @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, // 讓直升機(jī)高于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'); // 一個(gè)模型有6個(gè)面,這里需要確定機(jī)頭處于哪個(gè)面

// 視角盯住直升機(jī)

if (this._cameraType == 1) {

g3d.setCenter(px, py, pz);

} else if (this._cameraType == 2) { // Camera跟隨直升機(jī)運(yùn)動(dòng)

g3d.setEye(px - tx * 1800 + 1000, py - ty * 1800 + 1000, pz - tz * 1800); // 讓鏡頭高于直升機(jī)并在尾部進(jìn)行觀察

g3d.setCenter(px, py, pz);

}

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

},

finishFunc: () => {

ht.Default.startAnim(params);

}

};

ht.Default.startAnim(params);

}

管道流動(dòng)動(dòng)畫 - DataModel.addScheduleTask()

實(shí)現(xiàn)管道流動(dòng)的動(dòng)畫有多種方式,其本質(zhì)是定期改變管道的貼圖偏移。

wKgaomVmqlOADRQtAArdggdCPLE722.gif

這里我們采用DataModel#addScheduleTask(task)實(shí)現(xiàn)流動(dòng)動(dòng)畫。DataModel#addScheduleTask(task)實(shí)際上是添加了一個(gè)調(diào)度任務(wù)。由于該方法是在 DataModel 上執(zhí)行,因此在每次執(zhí)行的時(shí)候,DataModel 里面的每個(gè) Data 都會被調(diào)用。我們可以在 action 參數(shù)里面對 Data 進(jìn)行過濾。DataModel#addScheduleTask(task)方法的參數(shù)task為json對象,可指定如下屬性:

interval:間隔毫秒數(shù),默認(rèn)值為10

enabled:是否啟用開關(guān),默認(rèn)為true

beforeAction:調(diào)度開始之前的動(dòng)作函數(shù)

action:間隔動(dòng)作函數(shù),對DataModel上的每個(gè)data節(jié)點(diǎn)都會執(zhí)行一次action操作

afterAction:調(diào)度結(jié)束之后的調(diào)度函數(shù)

另外,可以用DataModel#removeScheduleTask(task)刪除調(diào)度任務(wù),其中task為以前添加過的調(diào)度任務(wù)對象。

/**

* 通過DataModel的addScheduleTask實(shí)現(xiàn)流動(dòng)效果

*

* @memberof Index3d

*/

addScheduleTasks() {

const task = {

interval: 50, // 間隔毫秒數(shù),默認(rèn)值為10

enabled: true, // 是否啟用開關(guān),默認(rèn)為true

beforeAction: () => {}, // 調(diào)度開始之前的動(dòng)作函數(shù)

afterAction: () => {}, // 調(diào)度結(jié)束之后的調(diào)度函數(shù)

action: (data) => { // 間隔動(dòng)作函數(shù),對DataModel上的每個(gè)data節(jié)點(diǎn)都會執(zhí)行一次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); // 刪除調(diào)度任務(wù)

}

這里我們只是舉例介紹一下DataModel#addScheduleTask(task)的用法。對于一個(gè) DataModel 中大部分 Data 都需要?jiǎng)赢嫷臅r(shí)候,可以考慮使用該方法。

在代碼執(zhí)行的時(shí)候,我們可以選擇把巡游路徑隱藏。這樣看起來直升機(jī)就是沿著一個(gè)圓形持續(xù)巡游。

hidePath() {

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

}

總結(jié)

本文介紹了如何通過代碼實(shí)現(xiàn)一個(gè)直升機(jī)繞山巡游的動(dòng)畫,包括創(chuàng)建路徑和實(shí)現(xiàn)直升機(jī)的飛行動(dòng)畫。另外,還介紹了如何通過DataModel#addScheduleTask(task)實(shí)現(xiàn)流動(dòng)效果的動(dòng)畫。讀完本文,你將了解到如何使用 HT for Web 實(shí)現(xiàn)各種動(dòng)畫效果。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)字孿生
    +關(guān)注

    關(guān)注

    4

    文章

    1225

    瀏覽量

    12112
收藏 人收藏

    評論

    相關(guān)推薦

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

    本章主要介紹了 HT for Web 中的一些基本概念,包括:基礎(chǔ)數(shù)據(jù) ht.Data、數(shù)據(jù)模型 ht.DataModel 和選擇模型 ht
    的頭像 發(fā)表于 09-11 10:45 ?942次閱讀
    <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)- 吸附與錨點(diǎn)

    船錨所在點(diǎn),只不過船的錨點(diǎn)在船外面,而 HT 節(jié)點(diǎn)的錨點(diǎn)通常在其中心。并且這里的錨鏈?zhǔn)莿傂缘牟荒軓澢?/div>
    的頭像 發(fā)表于 10-12 10:44 ?937次閱讀
    <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)- 吸附與錨點(diǎn)

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

    這里我們通過代碼建立一個(gè) 3D 場景并添加一個(gè) Obj 模型來介紹一下 HT for Web 在 3D 場景和模型加載方面的使用。
    的頭像 發(fā)表于 11-20 11:05 ?676次閱讀
    <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 模型

    濾波電容的使用心得

    圖說濾波電容的使用心得,非常詳細(xì),不信你還不懂~
    發(fā)表于 07-18 15:23

    關(guān)于Spartan6板子的使用心得

    給大家分享一下關(guān)于Spartan6板子的使用心得。
    發(fā)表于 04-30 07:03

    TFT LCD使用心得

    TFT LCD使用心得體會的原因是,最近一段時(shí)間工作上一直在使用TFT LCD,主要是3.5寸LCD,以SAMSUNG的LTV350QV及其一些臺灣的兼容產(chǎn)品為主。工作的內(nèi)容就是把這些屏在我們的產(chǎn)品上應(yīng)用起
    發(fā)表于 10-16 13:04 ?45次下載

    詳細(xì)談?wù)凾FT LCD 的使用心得

    深入談?wù)凾FT LCD 的使用心得最近一段時(shí)間工作上一直在使用TFT LCD,主要是3、5 寸LCD,以SAMSUNG 的LTV350QV 及其一些臺灣的兼容產(chǎn)品為主。工作的內(nèi)容就是把這些屏在我們的產(chǎn)品上
    發(fā)表于 03-18 17:49 ?3次下載

    ADXL345芯片使用心得

    ADXL345芯片使用心得,介紹使用傳感器過程的使用體會
    發(fā)表于 05-11 11:08 ?23次下載

    數(shù)字溫濕度傳感器DHT11使用心得

    一點(diǎn)溫濕度傳感器DHT11使用心得
    發(fā)表于 04-14 15:35 ?7次下載

    Django教程之Django的使用心得詳細(xì)資料免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是Django教程之Django的使用心得詳細(xì)資料免費(fèi)下載。
    發(fā)表于 10-17 18:03 ?11次下載
    Django教程之Django的使<b class='flag-5'>用心得</b>詳細(xì)資料免費(fèi)下載

    合泰單片機(jī)使用心得 (轉(zhuǎn))

    合泰單片機(jī)使用心得 合泰單片機(jī)是臺灣芯片,集成開發(fā)環(huán)境為HT-3000。大陸這邊的芯片代理商是盛群半導(dǎo)體有限公司,官網(wǎng)上的程序用例都是由匯編編寫的,當(dāng)然也對C語言很好的支持,是標(biāo)準(zhǔn)C的子集。在工作中
    發(fā)表于 12-02 20:36 ?12次下載
    合泰單片機(jī)使<b class='flag-5'>用心得</b> (轉(zhuǎn))

    智慧服裝工廠電子看板試用心得

    智慧服裝工廠電子看板試用心得實(shí)現(xiàn)了企業(yè)生產(chǎn)的進(jìn)度實(shí)時(shí)監(jiān)控、現(xiàn)場拉式生產(chǎn)、生產(chǎn)節(jié)拍平衡和異常情況的反饋功能。而接下來我們主要討論的是智慧服裝工廠電子看板試用心得在生產(chǎn)線與倉庫之間的物料配送體系,要談到這個(gè)物料配送問題,則要首先考慮
    的頭像 發(fā)表于 02-17 18:02 ?962次閱讀
    智慧服裝工廠電子看板試<b class='flag-5'>用心得</b>

    使用Raspberry Pi和Arduino實(shí)現(xiàn)Web控制的LED動(dòng)畫

    電子發(fā)燒友網(wǎng)站提供《使用Raspberry Pi和Arduino實(shí)現(xiàn)Web控制的LED動(dòng)畫.zip》資料免費(fèi)下載
    發(fā)表于 07-03 14:52 ?0次下載
    使用Raspberry Pi和Arduino<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>Web</b>控制的LED<b class='flag-5'>動(dòng)畫</b>

    HT for Web (Hightopo) 使用心得(2)- 2D 圖紙、節(jié)點(diǎn)、連線 與基本動(dòng)畫

    概括來說,用 HT for Web 做可視化主要分為兩部分,也就是 2D 和 3D。這兩部分需要單獨(dú)創(chuàng)建。在它們被創(chuàng)建完成后,我們再把它們集成到一起。 HT for Web 的 2D
    的頭像 發(fā)表于 09-21 10:52 ?808次閱讀
    <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 圖紙、節(jié)點(diǎn)、連線 與基本<b class='flag-5'>動(dòng)畫</b>

    HT for Web并力ARMxy工業(yè)計(jì)算機(jī)實(shí)現(xiàn)數(shù)字化轉(zhuǎn)型可視化解決方案

    ,用戶可以輕松設(shè)計(jì)出直觀的監(jiān)控場景,實(shí)現(xiàn)對工業(yè)過程的實(shí)時(shí)數(shù)據(jù)展示和交互控制。而ARMxy系列產(chǎn)品以其強(qiáng)大的數(shù)據(jù)處理能力和靈活的IO配置,精準(zhǔn)響應(yīng)生產(chǎn)需求,驅(qū)動(dòng)自動(dòng)化流程,助力企業(yè)實(shí)現(xiàn)數(shù)字化轉(zhuǎn)型。 一、HT for
    的頭像 發(fā)表于 08-28 16:17 ?258次閱讀
    <b class='flag-5'>HT</b> for <b class='flag-5'>Web</b>并力ARMxy工業(yè)計(jì)算機(jī)<b class='flag-5'>實(shí)現(xiàn)</b>數(shù)字化轉(zhuǎn)型可視化解決方案