数日前に出張に行ったとき、飛行機の頭上の監視パネルがテレビシリーズや広告の再生に加えて、時々航空機のナビゲーション用の監視システムに切り替わるのを見ました。システムが少し粗く感じたので、気まぐれに HT for Web を使用してアップグレード版の監視システムを作成しました。デモが非常に優れていたので、お互いに学び合うために共有したいと思います。
デモ
実装プロセス雲の中を歩くエフェクト
雲の中を飛行する飛行機の効果を実現するために、私が最初に直面した問題は、一般に遠近効果として知られる飛行機の飛行のレイヤー化でした。ここでは、雲のチャネルと雲の背景を異なる速度で使用しました。飛行遠近効果を作成します。
雲をテクスチャで表現しましたが、テクスチャだけでは空と飛行機が遮られてしまい、飛んでいる飛行機の見た目や雰囲気に大きく影響してしまうため、対応するグラフィック要素の透明・不透明をオンにして、雲の背景と雲のチャンネルに異なる透明度を設定すると、レイヤー感が増すだけでなく、目の前を雲が流れていくような錯覚も得られます。
クラウド チャネルは ht.Polyline タイプを使用し、チャネル スケーリングにより Y 軸の比率が拡大され、reverse.flip back コピーを設定すると、クラウド チャネル内にテクスチャが表示されます。航空機が雲海を通過している場合、雲の背景は ht.Node タイプを採用し、1 つの面のみが雲の背景として表示されるように設定されます。
全体的な雲の流れの効果は、オフセット オフセットを使用して実現され、対応するプリミティブまたは対応するプリミティブ サーフェスのテクスチャ オフセットを変更して、雲の中を移動する飛行機の効果を実現します。コードは次のとおりです。
var i = 1, p = 0;setInterval(() => { i -= 0.1; p += 0.005; Clouds.s('shape3d.uv.offset', [i, 0]); CloudBackground.s(' all.uv.offset', [p, 0]);}, 100);
リフティングバンプ効果
飛行機が雲の中を飛んでいるような効果は得られますが、飛行機が真っすぐに飛ぶだけだと、飛行機に乗った経験のある人は気流による乱気流に遭遇したことがあると思います。飛行機の飛行による乱気流を感じるのは、飛行機の飛行ルートが常に一定の高度にあるわけではないため、上昇したり下降したりするため、 ht-animation.js
HT アニメーション拡張プラグを使用しました。 -in で航空機の凹凸効果を実現します。コードは次のとおりです。
dm.enableAnimation(20);plane.setAnimation({ back1: { from: 0、to: 160、イージング: 'Cubic.easeInOut'、duration: 8000、next: up1、onUpdate: function (value) { value = parseInt(値); var p3 = this.p3(); }, //...同様の開始を省略します: [back1]});球面セクターの視野角制限
飛行エフェクトが完成した後、さらに難しい問題に遭遇しました。実際には飛行機は雲海の中を飛んでいるのに、それは水路の中を飛んでいるだけであり、背景は実際には単なる平らなテクスチャだったので、一定の遠近感に達する このレベルに達すると、不協和音や非現実感が強くなり、視野角を一定範囲内に調整するには視野角制限が必要になります。
一般に、視野角の制限により、g3d の目と中心が制限されます。詳しくは、hightopo 公式 Web サイトの 3D マニュアルを参照してください。ここでは説明しません。角度範囲を決定しました。中心の位置を固定するには、次のコードを使用します。
g3d.addPropertyChangeListener(e => { // 中心点を固定 if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = センター[2] }}
次に、目を特定の範囲に制限すれば完了です。ただし、最初は目を立方体空間に限定しましたが、g3d のデフォルトのインタラクションを考慮すると、インタラクション効果は理想的ではありませんでした。 , マウスをドラッグしてパンして視点を変えると、実際に目は中心を中心とした球面上を動きますので、球面である扇形のボールから目の限られた空間の一部を掘り出すことにしました。よくわからない人は、次の図を参照してください。
球面扇形の視野角制限には、中心基準軸、中心軸と外縁の間の角度、およびボールの制限半径の合計 3 つのパラメータが必要です。中心基準軸は、それに基づいて決定できます。最初の目と中心を結ぶ補助線が配置され、ボールの制限半径が最大制限と最小制限に分けられます。 コードは次のとおりです。
function limitEye(g3d, eye, center, options) { var limitMaxL = options.limitMaxL, limitMinL = options.limitMinL, limitA = options.limitA; g3d.addPropertyChangeListener(e => { // 中心点を固定 if (e.property = == 'センター') { e.newValue[0] = センター[0]; e.newValue[1] = センター[1]; e.newValue[2] = center[2]; } // 視野角を制限します if (e.property === 'eye') { var newEyeV = new ht.Math.Vector3(e.newValue), centerV = new ht.Math.Vector3(center)、refEyeV = 新しい ht.Math.Vector3(eye)、refVector = refEyeV.clone().sub(centerV)、 newVector = newEyeV.clone().sub(centerV); if (centerV. distanceTo(newEyeV) > limitMaxL) { e.newValue[0] = newVector.x; newVector.y; e.newValue[2] = newVector.z } if (centerV. distanceTo(newEyeV); limitMinL) { newVector.setLength(limitMinL); e.newValue[0] = newVector.y; e.newValue[2] = newVector.z; refVector) > limitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos(oldAngle)、vertVector、realVector、realEye; newEyeV = newVector.clone().add(centerV); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); vertVector.setLength(vertLength); realVector.clone().add(refEyeV).sub(centerV); .add(centerV); // 移動角度が 180 度を超えないようにし、視点を反転します。 if (oldAngle > Math.PI / 2) { realEye.negate(); } e.newValue[0] = realEye.y; } } )}航空機監視システム
もちろん、監視システムとしては、右下隅に小さなマップを追加し、航空機に焦点を当てる、飛行軌跡に焦点を当てる、地図に焦点を当てる、流れ効果を制御するという 3 つのモードを提供するのは当然です。このうち、航空機に焦点を当てると、航空機の動きに追従して航空機が常にミニマップの中心に位置するように FitData が実行されます。 コードは次のとおりです。
var fitFlowP = function (e) { if (e.property === 'position' && e.data === plan) { mapGV.fitData(plane, false) }};buttonP.s({ 'interactive': true, 'onClick': 関数 (イベント、データ、ビュー、ポイント、幅、高さ) {map.a('fitDataTag', 'plane2D'); mapDM.md(fitFlowP); }});buttonL.s({ 'interactive': true, 'onClick': function (event, data, view, point, width, height) {mapDM.umd(fitFlowP); マップ。 a('fitDataTag', 'flyLine'); mapGV.fitData(flyLine, false);// ...省略
航空機の対応する位置にマウスを移動して名前を付ける、ダブルクリックして航空機の対応する位置の情報パネルを表示し、視点をパネルに集中させる、航空機の任意の場所をクリックして元の情報パネルに切り替えるためのプロンプトを追加しました。航空機の飛行モードやその他の効果。
左側に監視パネルを追加すると、上記の対応する位置のダブルクリックが置き換えられ、ここのボタンにより、対応する位置の情報パネルが有効になり、対応する対話ロジックが追加されます。
button_JC.s({ 'interactive': true, 'onClick': function (event, data, view, point, width, height) {event.preventDefault(); let g3d = G.g3d, g3dDM = G.g3d.dm (); g3d.fireInteractorEvent({ 種類: 'doubleClickData'、データ: g3dDM.getDataByTag(data.getTag()) }) }});//...省略空のレンダリング効果
監視システムなので、24時間無差別に監視しなければならないのですが、これでは真夜中に青空を飛ぶことは不可能です。空が明るい状態から暗い状態へ、そして暗い状態から明るい状態へ変化する過程を、仮に06:00〜06:30と19:00〜19:30の2つの時間帯に設定しました。
空は、shape3d: 'sphere' 球形を使用してシーン全体を包み、その後、reverse.flip を使用してバックコピーし、染料をブレンドします。その後、空を希望の色にレンダリングできます。時間に応じて空の明暗を変えるには、染料の値を変更するだけです。
ただし、昼と夜では照明条件が異なるため、雲の反射光の強度も異なり、それが昼と夜の雲の違いにつながるため、雲の不透明度の透明度も調整する必要があります。チャネルと雲の背景テクスチャ。夜間はより透明になります。コードは次のとおりです。
if ((時 > 6 && 時 < 19) || (時 == 6 && 分 >= 30)) { timePane && timePane.a({ 'Morning.visible': false, 'day.visible': true, ' dusk.visible': false, 'night.visible': false, 'day.opacity': 1 }) skyBox.s({shape3d.blend: 'rgb(127, 200, 240)', })cloudBackground.s({ back.opacity: 0.7, }) Clouds.s({shape3d.opacity: 0.7, })} else if ((hour < 6 || 時間> 19) || (時間 == 19 && 分 >= 30)) {//...省略} else if (時間 == 6 && minutes < 15 ) {//...省略} else if (時間 == 6 && 分 >= 15 && 分 < 30) {//...省略} else if (時間 == 19 && 分 < 15) { //...省略} else if (時 == 19 && 分 >= 15 && 分 < 30) {//...省略}
ここでは、時間パネルの右上隅に時間ステータス アイコンのサポートも追加し、アイコンが切り替わったときのフェードインおよびフェードアウト効果を追加しました。同時に、クリックして切り替える機能も追加しました。時間パネルのステータス アイコンの次の時間ステータス アイコンの位置に移動します。
効果を示すために、時間 2 倍ボタンを追加しました。次の図は、時間流量が 500 倍になったときの変化を示しています。
要約するこのデモを通じて、人々が気づいていない細部がたくさんあること、そしてこのビッグデータの時代において、より多くの可能性が探求される価値があることを知りました。詳細を視覚化することで、HT for Web の可能性を最大限に活用できるだけでなく、プログラマーとしての全体的な資質も強化できます。