▶ 実 行
▶ 実行
クリア
跳ねるボール 3D(ThreeJS+AmmoJS)
by てぃふと@うぇいく
!「https://n3s.nadesi.com/plain/plugin_weykthree.js」を取り込む !「https://n3s.nadesi.com/plain/plugin_weykammo.js」を取り込む AMOベースURL=「https://weyk.sakura.ne.jp/storage/ammojs」 # 衝突判定の許容誤差(距離) 衝突マージンは0.001 # 1mm ボール総数は100 床厚は0.1 壁厚は0.1 部屋幅は20 部屋奥行は20 部屋高は6 床反発率は1.0 天井反発率は1.0 壁反発率は1.0 ボールサイズは[0.1, 0.15, 0.20] # 10cm, 15cm, 20cm ボール質量は[0.1, 0.2, 0.3] # 100g, 200g, 300g ボール反発率は1.0 重力は9.8 # 9.8m/s^2 ボール色を[0xff0000, 0xffff00, 0x0000ff]に定める。 WEBGLキャンバスはNULL レンダラは空 ココは空 カメラは空 物理ワールドはNULL 前回タイムスタンプは0 床はNULL 天井はNULL 床鋼体はNULL 天井鋼体はNULL # Ammo適用用 変動物リストは空配列 # レイキャスタ用 レイ対象リストは空配列 鋼体索引は{} ワールドマトリクスワークはNULL レイキャスタはNULL ライブラリ準備完了はオフ ユーザオプション選択完了はオフ 開始する ●準備同期化とは もし、ライブラリ準備完了でなければ、戻る もし、ユーザオプション選択完了でなければ、戻る 準備完了 ここまで ●ユーザオプション選択とは 回答は「重力(9.8m/s^2)を有効にしますか?」で二択 もし、回答ならば、 重力は9.8 違えば、 重力は0 ここまで ユーザオプション選択完了はオン 準備同期化 ここまで ●ライブラリ準備とは TJSライブラリ読み込み後には プラグイン準備 ここまで ここまで ●プラグイン準備とは ["controls/OrbitControls.js", "libs/ammo.wasm.js"]をTJSプラグイン読み込み後には AMMOライブラリ準備 ここまで ここまで ●AMMOライブラリ準備とは AMOライブラリ読込後には ライブラリ準備完了はオン 準備同期化 ここまで ここまで ●準備完了とは WEBGLキャンバス要素準備 描画準備 レイキャスタはTJSレイキャスタ作成 描画中キャンバスの「click」に「キャンバスクリック」をDOMイベント追加する 0でアニメート ここまで ●WEBGLキャンバス要素準備とは WEBGLキャンバスは"#three_cv"のDOM要素取得 もし、WEBGLキャンバスならば、 WEBGLキャンバスをWEBGLキャンバス["parentNode"]からDOM子要素削除 WEBGLキャンバスはNULL ここまで もし、WEBGLキャンバスでなければ、 Pは描画中キャンバス["parentNode"] WEBGLキャンバスは"CANVAS"のDOM要素作成 WEBGLキャンバス["id"]は"three_cv" WEBGLキャンバス["width"]は描画中キャンバス["width"] WEBGLキャンバス["height"]は描画中キャンバス["height"] WEBGLキャンバス["style"]["display"]は「none」 PにWEBGLキャンバスをDOM子要素追加 ここまで ここまで ●後始末とは 描画中キャンバスの「mousedown」から「キャンバスクリック」をDOMイベント削除する ここまで ●キャンバスクリックとは EVTはWINDOW["event"] 要素位置はEVT["target"]の"getBoundingClientRect"を[]でJSメソッド実行 XはEVT["clientX"]-要素位置["left"] YはEVT["clientY"]-要素位置["top"] [X,Y]を狙い撃ちする ここまで ●(XYを)狙撃とは NXはXY[0]/描画中キャンバス["width"]*2-1 NYはXY[1]/描画中キャンバス["height"]*(-2)+1 レイキャスタでカメラから[NX,NY]にTJSカメラ起点レイ 命中一覧はレイキャスタでレイ対象リストにTJSレイ命中一覧取得 もし、(命中一覧の配列要素数)>0ならば、 コレは命中一覧[0]["object"] 発見はコレ もし、発見≠NULLならば、 対象鋼体は鋼体索引[発見["id"]] 対象鋼体を[0,3,0]でAMO重心押す 対象鋼体をAMO活性化 ここまで ここまで ここまで # 基本単位に従いものを配置する。 # この世界では、長さはメートル、重さはキログラム、時間は秒で指定する。 # ただし、あまり細かい数値はうまく扱えない。 ●描画準備とは # 物理エンジンの空間(力学ワールド)を準備 # 物理ワールドは標準鋼体ワールド作成 # 表示するためのシーンを準備 # ココは、TJSシーン作成 ココに0x004400をTJS背景設定 # カメラを準備 # カメラは、[60,WEBGLキャンバス["width"]/WEBGLキャンバス["height"],0.05,30]のTJS透視投影カメラ作成 カメラを[0,1.5,-10]にTJS位置設定 カメラを[0,0,0]にTJS視点設定 カメラを"+Y"にTJSカメラ上方設定 ココにカメラをTJS登場 カメラのTJS投影マトリクス更新 # 部屋を床と天井と壁で囲う # # 床兼天井の見た目 床材は{"幅":部屋幅,"高":床厚,"奥行":部屋奥行,バッファ:オン}のTJS箱作成 床素材は{color: 0xffff00}のTJS拡散反射材質作成 # 床兼天井の力学形状を作成 形状は[部屋幅÷2,床厚÷2,部屋奥行÷2]でAMO箱形状作成 形状に衝突マージンをAMOマージン設定 # 床の3Dモデルを配置 床は床材と床素材のTJSメッシュ作成 床を[0, 0, 0]にTJS位置設定 床にオンをTJS影受設定 床をココにTJS登場 # 床の物理エンジン空間の実体 床鋼体は床から形状の0でMESH付鋼体作成 床鋼体に床反発率でAMO反発係数設定 物理ワールドに床鋼体をAMO鋼体追加 # 天井の3Dモデルを配置 天井は床材と床素材のTJSメッシュ作成 天井を[0, 部屋高, 0]にTJS位置設定 天井にオンをTJS影受設定 天井をココにTJS登場 # 天井の物理エンジン空間の実体 天井鋼体は天井から形状の0でMESH付鋼体作成 天井鋼体に天井反発率でAMO反発係数設定 物理ワールドに天井鋼体をAMO鋼体追加 # 壁の見た目 壁材は{"幅":部屋幅,"高":部屋高,"奥行":壁厚,バッファ:オン}のTJS箱作成 壁素材は{color: 0xffffff}のTJS拡散反射材質作成 # 壁の力学形状を作成 形状は[部屋幅÷2,部屋高÷2,壁厚÷2]でAMO箱形状作成 形状に衝突マージンをAMOマージン設定 壁手前は壁材と壁素材のTJSメッシュ作成 壁手前を[0, 部屋高÷2, 部屋奥行÷2*(-1)]にTJS位置設定 壁手前にオンをTJS影受設定 壁手前をココにTJS登場 壁鋼体は壁手前から形状の0でMESH付鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 壁奥は壁材と壁素材のTJSメッシュ作成 壁奥を[0, 部屋高÷2, 部屋奥行÷2]にTJS位置設定 壁奥にオンをTJS影受設定 壁奥をココにTJS登場 壁鋼体は壁奥から形状の0でMESH付鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 壁左側は壁材と壁素材のTJSメッシュ作成 壁左側を[部屋幅÷2*(-1), 部屋高÷2, 0]にTJS位置設定 壁左側["rotation"]["y"]は(PI/2) 壁左側にオンをTJS影受設定 壁左側をココにTJS登場 壁鋼体は壁左側から形状の0でMESH付鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 壁右側は壁材と壁素材のTJSメッシュ作成 壁右側を[部屋幅÷2, 部屋高÷2, 0]にTJS位置設定 壁右側["rotation"]["y"]は(-PI/2) 壁右側にオンをTJS影受設定 壁右側をココにTJS登場 壁鋼体は壁右側から形状の0でMESH付鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 # ボールを指定の個数生成する # ボール形は空配列 ボール素材は空配列 ボール形[0]は{半径:ボールサイズ[0], 横分割数:8, 縦分割数:8, バッファ:オン}のTJS球体作成 ボール形[1]は{半径:ボールサイズ[1], 横分割数:10, 縦分割数:10, バッファ:オン}のTJS球体作成 ボール形[2]は{半径:ボールサイズ[2], 横分割数:16, 縦分割数:16, バッファ:オン}のTJS球体作成 ボール素材[0]は{ color: ボール色[0] }のTJS拡散反射材質作成 ボール素材[1]は{ color: ボール色[1] }のTJS拡散反射材質作成 ボール素材[2]は{ color: ボール色[2] }のTJS拡散反射材質作成 形状は空配列 形状[0]はボールサイズ[0]のAMO球形状作成 形状[1]はボールサイズ[1]のAMO球形状作成 形状[2]はボールサイズ[2]のAMO球形状作成 形状[0]に衝突マージンをAMOマージン設定 形状[1]に衝突マージンをAMOマージン設定 形状[2]に衝突マージンをAMOマージン設定 (ボール総数)回繰り返す Nは回数-1 # ボールの3Dモデル # 空間中の適当な位置に置く Iは3の乱数 Jは3の乱数 ボールはボール形[I]とボール素材[J]のTJSメッシュ作成 Xは((部屋幅*0.8)の乱数)+部屋幅*0.1-部屋幅÷2 Yは((部屋高*0.8)の乱数)+部屋高*0.1 Zは((部屋奥行*0.8)の乱数)+部屋奥行*0.1-部屋奥行÷2 ボールを[X,Y,Z]にTJS位置設定 ボールにオンをTJS影投設定 ココにボールをTJS登場 # レイキャスタでのレイ判定対象の一覧を準備する レイ対象リストにボールを配列追加 # ボールの物理エンジン空間の実体 # 適当な移動速度を設定する ボール鋼体はボールから形状[I]のボール質量[I]でMESH付鋼体作成 X速度は((50の乱数)/25+1.0)*((2の乱数)*2-1) Y速度は((50の乱数)/25+1.0)*((2の乱数)*2-1) Z速度は((50の乱数)/25+1.0)*((2の乱数)*2-1) ボール鋼体に[X速度, Y速度, Z速度]をAMO移動速度設定 ボール鋼体にボール反発率でAMO反発係数設定 物理ワールドにボール鋼体をAMO鋼体追加 # ボールは動くので一覧に入れて管理する 変動物リストに{表示体:ボール, 鋼体:ボール鋼体}を配列追加する 鋼体索引[ボール["id"]]はボール鋼体 ここまで # 光源を準備 # # 全体をぼやっと照らす環境光源を生成 光は0x202020のTJS環境光源作成 ココに光をTJS登場 # 1点から射程内を照らすポイント光源を生成 ランタンは[0xffffff, 2, 30, 1]のTJS点光源作成 ランタンを[5,5,-5]にTJS位置設定 ランタンにオンをTJS影投設定 ココにランタンをTJS登場 ランタンの["シャドー"]に[1024,1024]をTJSマップサイズ設定 ランタンの["シャドー","カメラ"]に0.001をTJSカメラ最近距離設定 ランタンの["シャドー","カメラ"]に50をTJSカメラ最遠距離設定 # ThreeJSの表示準備 # レンダラは'three_cv'にTJS描画準備 レンダラに[WEBGLキャンバス["width"],WEBGLキャンバス["height"]]をTJSサイズ設定 レンダラに0x000000をTJSクリア色設定 レンダラをTJS影処理有効 # ThreeJSのオービットコントロールを作成して適用 # # DOMには採取的に表示に使うキャンバスを指定する コントローラはカメラに描画中キャンバスのTJS衛星軌道コントローラ作成 ここまで # アニメーションのループを構成する # 呼び出しごとの時間差の算出もここで行う ●(タイムスタンプで)アニメートとは もし、前回タイムスタンプが0でなければ、 経過秒は(タイムスタンプ-前回タイムスタンプ)÷1000 経過秒でワンフレーム ここまで 前回タイムスタンプはタイムスタンプ 画面更新時実行には(タイムスタンプ) タイムスタンプでアニメート ここまで ここまで # アニメーションの1フレーム分を処理する ●(経過秒で)ワンフレームとは # 力学ワールドの時間を経過時間分進める 物理ワールドを経過秒で10までAMO時間経過 # 力学ワールド上の鋼体の位置・姿勢を3Dモデル空間のモデルに反映する 変動物リストを反復する 表示体は対象["表示体"] 鋼体は対象["鋼体"] 鋼体を表示体に物体姿勢反映 ここまで レンダラにココをカメラでTJS描画 WEBGLキャンバスを[0,0]へ画像描画 ここまで ●開始とは ライブラリ準備 ユーザオプション選択 ここまで # ThreeJS - Ammo 利用簡易支援 # ThreeJSのexamples/js/physics/AmmoPhysics.jsを参考に作成 # よくある組み合わせで力学ワールドを生成する ●標準鋼体ワールド作成とは CONFはAMOデフォルト衝突判定法作成 DISPはCONFのAMO衝突判定ディスパッチャ作成 BPHASEはAMODbvt作成 SOLVERはAMO物理ソルバー作成 ワールドは[DISP,BPHASE,SOLVER,CONF]でAMO離散力学ワールド作成 ワールドに[0,(-重力),0]でAMO重力設定 ワールドマトリクスワークはAMO変形マトリクス作成 ワールドで戻る ここまで # AmmoJSの鋼体の位置・姿勢をThreeJSのMESHに反映する ●(BODYをMESHに)物体姿勢反映とは 姿勢状態はBODYのAMO状態管理器取得 姿勢状態からワールドマトリクスワークにAMOワールド変換行列取得 位置はワールドマトリクスワークからAMO原点取得 回転はワールドマトリクスワークからAMO回転取得 MESHを位置にTJS位置設定 MESHを回転にTJS四元数設定 ここまで # ThreeJSのMESHを情報を元にAmmoJSの鋼体を作成する ●(MESHからSHAPEのMASSで)MESH付鋼体作成とは 位置はMESHからTJS位置取得 回転はMESHからTJS四元数取得 マトリクスはAMO変形マトリクス作成 マトリクスをAMO単位行列設定 マトリクスに(位置からAMOVec3)をAMO原点設定 マトリクスに(回転からAMO四元数)をAMO回転設定 BODYはマトリクスからSHAPEのMASSでMESH無鋼体作成 BODYで戻る ここまで # 変換マトリクスから鋼体を作成する ●(マトリクスからSHAPEのMASSで)MESH無鋼体作成とは もし、MASSでなければ、 MASSは0 ここまで 状態管理器はマトリクスからAMOデフォルト状態管理器作成 慣性は[0,0,0]からAMOVec3 SHAPEにMASSと慣性でAMO局所慣性計算 構成情報は[MASS, 状態管理器, SHAPE, 慣性]からAMO鋼体構成情報作成 BODYは構成情報からAMO鋼体作成 BODYで戻る ここまで # 型付配列のヘルパー命令 ●(ARGの)UI8配列とは 『(function (a) {return new Uint8Array(a)})』を[ARG]でJS関数実行で戻る ここまで ●(ARGの)F32配列とは 『(function (a) {return new Float32Array(a)})』を[ARG]でJS関数実行で戻る ここまで