▶ 実 行
▶ 実行
クリア
さいころ 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」 # 長さはメートル単位。質量はキログラム単位。 # 床を突き抜けるようなら、サイコロを大きくするか床を厚くする。 サイコロ個数は10 床辺長は20 # 5m四方(20m×20m×20cm) 床厚は0.2 # 20cm 床反発率は0.7 壁高は50 # 四方を囲む壁の高さ。50m。透明。 壁反発率は0.7 サイコロ辺長は0.5 # 50cm角(50cm×50cm×50cm) サイコロ質量は1 # 1Kg サイコロ反発率は0.9 重力は9.8 # 9.8m/s^2 #衝突時に跳ね返りはぶつかったもの同士での反発率の積で決まります。 #積が1.0を超える場合、ぶつかる勢いより跳ね返る勢いが強くなります(総エネルギーが増加する) # 衝突判定の許容誤差(距離) 衝突マージンは0.001 # 1mm WEBGLキャンバスはNULL レンダラは空 ココは空 カメラは空 物理ワールドはNULL 前回タイムスタンプは0 床はNULL 床鋼体はNULL # Ammo適用用 変動物リストは空配列 # レイキャスタ用 レイ対象リストは空配列 鋼体索引は{} ワールドマトリクスワークはNULL レイキャスタはNULL 開始する ●ライブラリ準備とは TJSライブラリ読み込み後には プラグイン準備 ここまで ここまで ●プラグイン準備とは ["controls/OrbitControls.js", "libs/ammo.wasm.js"]をTJSプラグイン読み込み後には AMMOライブラリ準備 ここまで ここまで ●AMMOライブラリ準備とは AMOライブラリ読込後には 準備完了 ここまで ここまで ●準備完了とは WEBGLキャンバス要素準備 描画準備 レイキャスタはTJSレイキャスタ作成 描画中キャンバスの「click」に「キャンバスクリック」をDOMイベント追加する 0でアニメート ここまで ●WEBGLキャンバス要素準備とは WEBGLキャンバスは"#three_cv"のDOM要素取得 もし、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 オンの間 もし、コレ["type"]="Group"ならば、 発見はコレ 抜ける ここまで コレはコレ["parent"] ここまで もし、発見≠NULLならば、 対象鋼体は鋼体索引[発見["id"]] X回転は((50の乱数)/25+2.5)*((2の乱数)*2-1) Y回転は((50の乱数)/25+2.5)*((2の乱数)*2-1) Z回転は((50の乱数)/25+2.5)*((2の乱数)*2-1) 対象鋼体に[X回転, Y回転, Z回転]をAMO回転速度設定 対象鋼体を[0,10,0]でAMO重心押す 対象鋼体をAMO活性化 ここまで ここまで ここまで # 基本単位に従いものを配置する。 # この世界では、長さはメートル、重さはキログラム、時間は秒で指定する。 # ただし、あまり細かい数値はうまく扱えない。 ●描画準備とは # 物理エンジンの空間(力学ワールド)を準備 # 物理ワールドは標準鋼体ワールド作成 # 表示するためのシーンを準備 # ココは、TJSシーン作成 ココに0x004400をTJS背景設定 # カメラを準備 # カメラは、[60,WEBGLキャンバス["width"]/WEBGLキャンバス["height"],0.05,20]のTJS透視投影カメラ作成 カメラを[2,3.5,-3]にTJS位置設定 カメラを[0,0,0]にTJS視点設定 カメラを"+Y"にTJSカメラ上方設定 ココにカメラをTJS登場 カメラのTJS投影マトリクス更新 # 床を生成する # # 床の見た目 床材は{"幅":床辺長,"高":床厚,"奥行":床辺長,バッファ:オン}のTJS箱作成 床素材は{color: 0xffff00}のTJS拡散反射材質作成 床は床材と床素材のTJSメッシュ作成 床にオンをTJS影受設定 床をココにTJS登場 # 床の物理エンジン空間の実体 形状は[床辺長÷2,床厚÷2,床辺長÷2]でAMO箱形状作成 形状に衝突マージンをAMOマージン設定 床鋼体は床から形状の0でMESH付鋼体作成 床鋼体に床反発率でAMO反発係数設定 物理ワールドに床鋼体をAMO鋼体追加 # 壁を物理エンジン空間に配置。表示はしない。 形状は[床辺長÷2,壁高÷2,床厚÷2]でAMO箱形状作成 形状に衝突マージンをAMOマージン設定 マトリクスはAMO変形マトリクス作成 マトリクスをAMO単位行列設定 マトリクスに[0, 壁高÷2, 床辺長÷2]をAMO原点設定 壁鋼体はマトリクスから形状の0でMESH無鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 マトリクスはAMO変形マトリクス作成 マトリクスをAMO単位行列設定 マトリクスに[0, 壁高÷2, (-床辺長÷2)]をAMO原点設定 壁鋼体はマトリクスから形状の0でMESH無鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 形状は[床厚÷2,壁高÷2,床辺長÷2]でAMO箱形状作成 形状に衝突マージンをAMOマージン設定 マトリクスはAMO変形マトリクス作成 マトリクスをAMO単位行列設定 マトリクスに[床辺長÷2, 壁高÷2, 0]をAMO原点設定 壁鋼体はマトリクスから形状の0でMESH無鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 マトリクスはAMO変形マトリクス作成 マトリクスをAMO単位行列設定 マトリクスに[(-床辺長÷2), 壁高÷2, 0]をAMO原点設定 壁鋼体はマトリクスから形状の0でMESH無鋼体作成 壁鋼体に壁反発率でAMO反発係数設定 物理ワールドに壁鋼体をAMO鋼体追加 # サイコロの各面の画像を非表示のキャンバスに準備 # サイコロ画像はサイコロ画像作成する。 サイコロテクスチャは{CANVAS:サイコロ画像}をTJSキャンバステクスチャ作成 # さいころを指定の個数生成する # 立方体部品はサイコロ辺長と(サイコロ辺長*0.1)のサイコロ構造作成 立方体平面部品は立方体部品[0] 立方体縁角部品は立方体部品[1] 立方体平面部品のTJS境界球計算 立方体平面素材は{ map:サイコロテクスチャ }のTJS拡散反射材質作成 もし、立方体縁角部品≠NULLならば、 立方体縁角部品のTJS境界球計算 立方体縁角素材は{ color: 0xffffffff }のTJS拡散反射材質作成 ここまで 形状は[サイコロ辺長÷2,サイコロ辺長÷2,サイコロ辺長÷2]でAMO箱形状作成 形状に衝突マージンをAMOマージン設定 (サイコロ個数)回繰り返す Nは回数-1 # さいころの見た目 立方はTJSグループ作成 立方体平面は立方体平面部品と立方体平面素材のTJSメッシュ作成 立方体平面にオンをTJS影受設定 立方体平面にオンをTJS影投設定 立方に立方体平面をTJS登場 レイ対象リストに立方体平面を配列追加 もし、立方体縁角部品≠NULLならば、 立方体縁角は立方体縁角部品と立方体縁角素材のTJSメッシュ作成 立方体縁角にオンをTJS影受設定 立方体縁角にオンをTJS影投設定 立方に立方体縁角をTJS登場 レイ対象リストに立方体縁角を配列追加 ここまで Xは0+((N%2)*2-1)*0.5 Yは3+((N/4)の整数部分)*1 Zは0+((((N%4)/2)の整数部分)*2-1)*0.5 立方を[X,Y,Z]にTJS位置設定 ココに立方をTJS登場 # レイキャスタでのレイ判定対象の一覧を準備する # さいころの物理エンジン空間の実体 立方体鋼体は立方から形状のサイコロ質量でMESH付鋼体作成 X回転は((50の乱数)/25+2.5)*((2の乱数)*2-1) Y回転は((50の乱数)/25+2.5)*((2の乱数)*2-1) Z回転は((50の乱数)/25+2.5)*((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衛星軌道コントローラ作成 ここまで # 辺長 角が丸くない状態での1辺の長さ # 角半径 1つの角の丸みの部分の半径 # 丸み角未実装のため、丸みを持たせると隙間が空きます。 ●(辺長と角半径の)サイコロ構造作成とは 結果は[NULL,NULL] # triangle_stripによる四角形をtrianglesに分解する際の参照順序 頂点順序は[0,1,2,2,1,3] # -1~+1に正規化した座標で平面部分の位置を求める 正点は((辺長÷2)-角半径)÷(辺長÷2) 負点は(-正点) # 256*128のサイズ上に64*64を3*2で配置されているのを想定 U0は0 U1は64*1/256 U2は64*2/256 U3は64*3/256 V0は0 V1は64*1/128 V2は64*2/128 # 起点[0,0,0]、縮退三角形抜きで1面4頂点で定義する # 前後左右上下の順 # 上記の頂点順に合わせてUVも定義する。 平面頂点リストは[ 負点, 正点, -1, U0, V0, 正点, 正点, -1, U1, V0, 負点, 負点, -1, U0, V1, 正点, 負点, -1, U1, V1, 正点, 正点, 1, U0, V1, 負点, 正点, 1, U1, V1, 正点, 負点, 1, U0, V2, 負点, 負点, 1, U1, V2, -1, 正点, 正点, U1, V0, -1, 正点, 負点, U2, V0, -1, 負点, 正点, U1, V1, -1, 負点, 負点, U2, V1, 1, 正点, 負点, U1, V1, 1, 正点, 正点, U2, V1, 1, 負点, 負点, U1, V2, 1, 負点, 正点, U2, V2, 負点, 1, 正点, U2, V0, 正点, 1, 正点, U3, V0, 負点, 1, 負点, U2, V1, 正点, 1, 負点, U3, V1, 負点, -1, 負点, U2, V1, 正点, -1, 負点, U3, V1, 負点, -1, 正点, U2, V2, 正点, -1, 正点, U3, V2 ] インデックスは空配列 6回繰り返す Iは(回数-1)*4 6回繰り返す JはI+(頂点順序[回数-1]) インデックスにJを配列追加 ここまで ここまで geoはTJS空構造作成 geoにインデックスをTJSインデックス設定 頂点配列は平面頂点リストのF32配列 bufは頂点配列から5でTJSインターリーブバッファ作成 bufに"有り"をTJS変更有無設定 attrはbufで0から3のTJSインターリーブ属性作成 geoの"position"にattrをTJS属性設定 attrはbufで3から2のTJSインターリーブ属性作成 geoの"uv"にattrをTJS属性設定 geoを[辺長÷2,辺長÷2,辺長÷2]にTJS拡大 geoのTJS法線計算 結果[0]はgeo # 縁の四角形の定義 # 手前の面の、上下左右 # 上の面の右左奥 # 右の面の下奥 # 左の面の下奥 # 奥の面の下 # 角の三角形の定義 # 手前の面の左上、右上、左下、右下 # 奥の面の左上、右上、左下、右下 # 常に手前も奥も手前から見た状態での左右(反転しない) 縁角頂点リストは[ 負点 1, 負点, 0, 1, 0, 正点 1, 負点, 0, 1, 0, 負点, 正点, -1, 0, 0, -1, 正点, 正点, -1, 0, 0, -1, 負点, 負点, -1, 0, 0, -1, 正点, 負点, -1, 0, 0, -1, 負点, -1, 負点, 0, -1, 0, 正点, -1, 負点, 0, -1, 0, 負点, 正点, -1, 0, 0, -1, 負点, 負点, -1, 0, 0, -1, -1, 正点, 負点, -1, 0, 0, -1, 負点, 負点, -1, 0, 0, 正点, 負点, -1, 0, 0, -1, 正点, 正点, -1, 0, 0, -1, 1, 負点, 負点, 1, 0, 0, 1, 正点, 負点, 1, 0, 0, 正点, 1, 負点, 0, 1, 0, 正点, 1, 正点, 0, 1, 0, 1, 正点, 負点, 1, 0, 0, 1, 正点, 正点, 1, 0, 0, 負点, 1, 正点, 0, 1, 0, 負点, 1, 負点, 0, 1, 0, -1, 正点, 正点, -1, 0, 0, -1, 正点, 負点, -1, 0, 0, 負点, 正点, 1, 0, 0, 1, 正点, 正点, 1, 0, 0, 1, 負点, 1, 正点, 0, 1, 0, 正点, 1, 正点, 0, 1, 0, 1, 負点, 負点, 1, 0, 0, 1, 負点, 正点, 1, 0, 0, 正点, -1, 負点, 0, -1, 0, 正点, -1, 正点, 0, -1, 0, 正点, 正点, 1, 0, 0, 1, 正点, 負点, 1, 0, 0, 1, 1, 正点, 正点, 1, 0, 0, 1, 負点, 正点, 1, 0, 0, -1, 負点, 正点, -1, 0, 0, -1, 負点, 負点, -1, 0, 0, 負点, -1, 正点, 0, -1, 0, 負点, -1, 負点, 0, -1, 0, 負点, 負点, 1, 0, 0, 1, 負点, 正点, 1, 0, 0, 1, -1, 負点, 正点, -1, 0, 0, -1, 正点, 正点, -1, 0, 0, 正点, 負点, 1, 0, 0, 1, 負点, 負点, 1, 0, 0, 1, 正点, -1, 正点, 0, -1, 0, 負点, -1, 正点, 0, -1, 0, 負点, 正点, -1, 0, 0, -1, -1, 正点, 負点, -1, 0, 0, 負点, 1, 負点, 0, 1, 0, 正点, 正点, -1, 0, 0, -1, 正点, 1, 負点, 0, 1, 0, 1, 正点, 負点, 1, 0, 0, 負点, 負点, -1, 0, 0, -1, 負点, -1, 負点, 0, -1, 0, -1, 負点, 負点, -1, 0, 0, 正点, 負点, -1, 0, 0, -1, 1, 負点, 負点, 1, 0, 0, 正点, -1, 負点, 0, -1, 0, 負点, 正点, 1, 0, 0, 1, 負点, 1, 正点, 0, 1, 0, -1, 正点, 正点, -1, 0, 0, 正点, 正点, 1, 0, 0, 1, 1, 正点, 正点, 1, 0, 0, 正点, 1, 正点, 0, 1, 0, 負点, 負点, 1, 0, 0, 1, -1, 負点, 正点, -1, 0, 0, 負点, -1, 正点, 0, -1, 0, 正点, 負点, 1, 0, 0, 1, 正点, -1, 正点, 0, -1, 0, 1, 負点, 正点, 1, 0, 0 ] インデックスは空配列 # 縁の部分(四角形)のインデックスを生成 12回繰り返す Iは(回数-1)*4 6回繰り返す JはI+(頂点順序[回数-1]) インデックスにJを配列追加 ここまで ここまで # 角の部分(三角形)のインデックスを生成 8回繰り返す Iは(回数-1)*3+4*12 3回繰り返す JはI+(回数-1) インデックスにJを配列追加 ここまで ここまで geoはTJS空構造作成 geoにインデックスをTJSインデックス設定 頂点配列は縁角頂点リストのF32配列 bufは頂点配列から6でTJSインターリーブバッファ作成 bufに"有り"をTJS変更有無設定 attrはbufで0から3のTJSインターリーブ属性作成 geoの"position"にattrをTJS属性設定 attrはbufで3から3のTJSインターリーブ属性作成 geoの"normal"にattrをTJS属性設定 geoを[辺長÷2,辺長÷2,辺長÷2]にTJS拡大 結果[1]はgeo 結果で戻る ここまで # アニメーションのループを構成する # 呼び出しごとの時間差の算出もここで行う ●(タイムスタンプで)アニメートとは もし、前回タイムスタンプが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関数実行で戻る ここまで # サイコロのテクスチャ用画像生成 # # サイコロ描画を使って、1-6の目を決まった位置に描く ●サイコロ画像作成とは 元キャンバスは描画中キャンバス CANVASは"CANVAS"のDOM要素作成 # テクスチャ用なので2のべき乗にする CANVAS["width"]は256 CANVAS["height"]は128 CANVASへ描画開始 [0,0]に64で1のサイコロ描画する [0,64]に64で6のサイコロ描画する [64,0]に64で2のサイコロ描画する [64,64]に64で5のサイコロ描画する [128,0]に64で3のサイコロ描画する [128,64]に64で4のサイコロ描画する 元キャンバスへ描画開始 CANVASで戻る ここまで # # 雪乃☆雫 作のイコロ3(canvasに角丸サイコロを描画)から。 # 目位置=[[4],[0,8],[0,4,8],[0,2,6,8],[0,2,4,6,8],[0,2,3,5,6,8]] ●(XYに辺長で数の)サイコロ描画とは X=XY[0]。Y=XY[1]。 r=8/60*辺長。r=0。 マス=辺長/4。目半径=辺長/10。 空に線色設定。白色に塗り色設定。3に線太さ設定。 もし、rが0ならば、 [X,Y,辺長,辺長]に四角描画。 違えば、 # [X,Y,辺長,辺長]に[r,r]の角丸四角描画。 ここまで もし、数が1ならば、目色は赤色。 違えば、目色は黒色。 目色に線色設定。目色に塗り色設定。1に線太さ設定。 (数)回 目x=1+目位置[数-1][回数-1]%3。 目y=1+目位置[数-1][回数-1]/3を整数変換。 [X+マス*目x,Y+マス*目y]に目半径の円描画。 ここまで。 ここまで。