[ヴァニラJS]平昌オリンピックのドローンショーを作る


Demo: https://heekang2271.github.io/artwork/Olympic/
2月20日2022北京オリンピック閉幕.
オリンピックで選手たちがメダルを取って喜ぶ姿を見て、思う存分スープ(?)過去のオリンピックの試合に陶酔する😛
今回も前回のオリンピックのビデオを見ていて、平昌オリンピックの開会式を見ました.

平昌オリンピックドローン展



出典:东アジア科学-平昌天空中1218架无人机の秘密...インテルはどうしたの?
オリンピック開幕当時は軍隊では見ることができなかったが、開会式では空を刺繍した無人機が集まって五輪旗を作る場面が4年後の今見ても驚嘆させられる.
残念ながらこの場面を現場で見ることができず、その時の戦慄を間接的に感じたいので、ドローンショーを再現してみましょう!こんな欲望が生まれた
だから直接vscodeを開けました

解決すべき問題


解決すべき問題は大体二つある.
1.どのようにして五環旗を描く座標を獲得しますか?
2.分散した無人機がどうして五輪旗のように集まるのか.
これらの問題を解決すれば、再現したい無人機ショーの構造を見つけることができます.

どのようにして五環旗を描く座標を手に入れますか?


1つ目のアイデアは、円を形成できる座標グループを作って、5つの円を作って、レイアウトをよく計算すればいいのではないでしょうか.はい.しかしいずれにしても,この方法では円の座標を手動で取得しなければならないと思い,これは全く問題を解決したとは思えない.
完全に自動化された方法で座標を得るためにcanvasの方法で利用可能な方法があるかどうかを観察するとき、getImageData()という方法があります.以下に説明します.
キャンバス上で指定した長方形のImageDataオブジェクトにピクセルデータをコピーします.
ImageDataオブジェクトのすべてのピクセルには、次の4つの情報があります.(RGBA値)
キャンバスにピクセルデータを抽出する矩形領域を指定し、その領域のすべてのピクセルのrgba値を取得します.キャンバスに五環画像を挿入し、rgba値のある画素だけを抽出し、座標で問題を解決できると思います.

分散した無人機がどうして五輪のように集まることができようか。


これは分散した無人機であり,無人機を生成しながらx,y座標をランダムに付与すれば容易に実現できるようである.
しかし、問題は、分散した無人機ごとに五環旗に対応する座標をどのように与えるかだ.
どうしようか悩んだ瞬间に顺番を変えたい
分散した無人機を集める
集まった無人機を散らして、再び集まります
分散した無人機に五環機座標を付与するのが難しい場合は、五環機座標に従って無人機を作成し、その値を保存し、ランダムなx,y座標を作成して分散させる.
このように,各無人機に五環機の座標,2つのランダム座標を持たせると,インタラクションが発生するたびに出発座標と到達座標を変えるだけで集積と分散の効果が得られる.
大きな問題を解決する方向が見つかったので、本格的に実施しましょう.

インプリメンテーションプロセス


五輪旗の座標を取得



まず、cssのlinear-gradientプロパティを使用して背景色を設定し、夜空の色を表示します.
キャンバスのdrawImage()関数を使用して、五環旗画像をロードします.このとき,五環機の座標は現在のウィンドウのwidthと五環機のwidthを算出し,真ん中から来るようにする.
その後、上記のようにgetImageData()関数を用いて画素値をロードした.

すべての画素のrgba値のデータを以下の順序で取得できます.
これらの値を使用して、x、y座標、rgb色の値を持つピクセル配列を作成します.
const particles = [];

for (let h = 0; h < this.stageHeight; h += this.density) {
	for (let w = 0; w < this.stageWidth; w += this.density) {
        const idx = (h * this.stageWidth + w) * 4;

        const r = imageData.data[idx];
        const g = imageData.data[idx + 1];
        const b = imageData.data[idx + 2];

        if (r != 0) {
          const color = `#${this.decToHex(r)}${this.decToHex(g)}${this.decToHex(
            b
          )}`;

          particles.push({
			x: w,
            y: h,
            color,
          });
		}
	}
}
スクリーン幅、高さを変数とするデュアルfor文を用いて、これらのデータを4つの割り込み処理し、各画素のx、y座標、色値を得て記憶した.
for文の増減値としてdensityを加え、画素単位が非常にコンパクトであるため、無人機の大きさを考慮してdensityの間隔を与えて画素を抽出する.

無人機の作成


このように画素情報を抽出すると、clearRect()を用いて五環旗画像を削除し、画素情報を用いて黄色の円形無人機を撮影すると、以下のようになる.

私が想像していたドローンショーのイメージとあまり違わず、とても満足しています.😊
五環機の形状がよく撮れていることを確認したので,ランダムなx,y座標を生成し,ページロード時に無人機を五環機の形状で置くのではなく,無人機をその位置に置く.

こんなに自由奔放(?)分散した無人機が確認できます.

集約効果

requestAnimation()関数を使用してキャンバス上の画像を消去し、繰り返し描画します.
そのループで座標位置を変更し続けると、ポイント移動の効果が得られます.
漫画映画を作るとき、大量の絵をすばやくめくるような原理です.
フレームを設定した後、無人機が持つランダム座標、五環座標のx、y星距離を求め、設定したフレームに分割することで、フレームごとの移動距離を求めることができる.
フレームごとに移動するx距離=(ランダム座標.x-五環座標.x)/フレーム
フレームごとに移動するy距離=(ランダム座標.y-五環機座標.y)/フレーム
現在の座標を変数とし、ランダム座標を初期値とします.requestAnimation()関数が呼び出されるたびに、上記で計算した距離に現在の座標を加算すると、ランダム座標から五環機座標に到達することができる.
いつMOYに効果を与えるかを考えていると、ユーザーが直接やり取りしてくれるのが面白いと思います.そのため、マウスの左ボタンを強く押すと、五輪旗の形になります.
結果は以下の通りです.

集まってもなぜか異質感があるのでしょうか?
一定距離の均一な動きを続ける方式なので、現実の無人機とは違って気まずい感じがします.
したがって、フレームごとの移動距離に現在の座標を加算するときに加速度を乗算することにした.
そして、目的地まで移動した場合、半分以上移動した場合は摩擦力を乗じて、出発時に加速し、到着時に遅くなり、位置を探すような感じがします.
結果は次のとおりです.

今は自然になった😀
こうして平昌オリンピックを再現したドローンショーは、まだ少し時間が残っているし、何かしたいという欲求もあるので、ドローンの特性を生かせるものを作りたいと思います.
今はただ空に印刷された点にすぎない.
だからマウスポインタで無人機に触れると、無人機が押されて戻ってくる効果を実現したいと思っています.

ドローンの効果


無人機の効果には数学の知識が必要だ.

まずマウスポインタに半径を与え、マウスが移動するたびにドローンとの距離を計算します.計算された距離がマウスの半径以下であれば、衝突が発生したと考えられ、遅延の効果が生じます.
衝突が発生した場合、マウスは無人機に指向する必要があり、三角関数では接線の逆関数であるアーク接線が使用されます.
マウスのx,y座標と無人機のx,y座標をMath.atan2関数に入れて方向を求め,無人機の座標を変更してこの方向に移動させた.
その結果、無人機は押し合いの効果を果たした.

しばらくすると元の位置に戻る効果もあり、
風のような外部刺激(マウスポインタ)で、位置を変えて元の位置に戻る無人機の姿を実現した.

の最後の部分


今ではドローンは単純な色彩で塗りつぶされた円の形ですが、ライトアップされたような効果をあげたいと思います.
したがってキャンバス上のcreateRadialGradient()関数を用いてグラデーションを行い,ライトに似た効果を最大限に与え,無人機がランダム位置に着席したときに点滅効果を増加させた.
最後に、黄色だけの五輪旗よりも、本来の五輪旗の色をあげてみてはいかがでしょうか.
そこで,本稿の前の部分では,画像から座標を抽出する際に保存した色値を用いて,それを五環形状に集約し,色を変更する.
最終結果は以下の通りです.

以上、平昌オリンピックを再現したドローンショーです.
実はアイデアを思いつくと勝手にやってしまい、整理がうまくいかなくて公開するのはちょっと恥ずかしいのですが、コードが気になるかもしれないので、リンクを残して終わりましょう.😀
Demo: https://heekang2271.github.io/artwork/Olympic/
Code: https://github.com/heekang2271/artwork/tree/main/Olympic
※画面の大きさによっては、大きな画面でカットされる可能性があります!
※表示画素の割合によって速度が異なります!
ウィバーグは解決している.ご了承ください