HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2024
0916
youdai任意の3次元の頂点3つの三角形に対し、線分の当たり判定を得たい2解決


youdai

リンク

2024/9/16(Mon) 14:10:19|NO.102219

任意の3次元の頂点3つの三角形に対し、線分の当たり判定を得たいです。

3次元の衝突判定のアルゴリズムを調べているのですが、難しくてよく分かりませんでした。

3D衝突編
http://marupeke296.com/COL_main.html

この記事の中で特に重要だなと思ったのは、「線分と板ポリゴン」でした、

線分と板ポリゴン
http://marupeke296.com/COL_3D_No4_LineToPlanePolygon.html

この当たり判定の取得が可能になれば、大概の3次元の当たり判定が実装可能だなと思いました。

イメージは以下のような関数です。


#module #defcfunc get_hit array _a, array _b0, array _b1 ;何らかの処理 ;hitした場合は1を返す if hit == 1 : return 1 ;hitしていない場合は0を返す return 0 #global ddim a, 3*3 ;3つの頂点xyz ddim b0, 3 ;線分の開始位置xyz0 ddim b1, 3 ;線分の終了位置xyz1 mes "hit " + str( get_hit( a, b0, b1 ) ) stop

イメージとしてはhgimg4のgppraytestのようなものを想定しています。

衝突判定だけでなく、接触した位置まで取得できればさらに良いのですが、衝突判定だけでも構いません。

アドバイスよろしくお願い致します。



この記事に返信する


usagi

リンク

2024/9/16(Mon) 22:18:14|NO.102223

こんにちわ。
どの辺りが分かっていないの分からず、あてずっぽうになってしまい申し訳ないですが。
おそらく。。。ここが理解できてない可能性がある所に★コメントしました。
宜しかったらどうぞ。

1)面の法線と線分の開始、終了点の内積をとれば裏表は分かる。
 表表:貫通してない ×
 裏裏:貫通してない ×
 表裏:貫通している ○

2)面(板ポリゴン)の接触した点が含まれるかは法線が一致しているか見ればわかる。
面の法線が↑の時、各辺と接触した点の法線が、、、
↑↑↑:含まれる  ○
↑↑↓:含まれない ×
↑↓↑:含まれない ×
etc...

3)接触位置は2)を求める段階で既に分かってますのでそのまま使えば良いです。


; 基本的なベクトル演算 #module #deffunc vadd array res, array a, array b ; 加算 res = a.0 + b.0, a.1 + b.1, a.2 + b.2 : return #deffunc vsub array res, array a, array b ; 減算 res = a.0 - b.0, a.1 - b.1, a.2 - b.2 : return #deffunc vmul array res, array a, array b ; 乗算 res = a.0 * b.0, a.1 * b.1, a.2 * b.2 : return #deffunc vdiv array res, array a, array b ; 除算 res = a.0 / b.0, a.1 / b.1, a.2 / b.2 : return #deffunc vunit array res ; 単位ベクトル _d = sqrt(res.0*res.0 + res.1*res.1 + res.2*res.2)+0.00000000001 res = res.0/_d, res.1 / _d, res.2 / _d : return #defcfunc dot array a, array b ; 内積 return a.0 * b.0 + a.1 * b.1 + a.2 * b.2 #deffunc cross array res, array a, array b ; 外積 res = a.1*b.2-a.2*b.1, a.2*b.0-a.0*b.2, a.0*b.1-a.1*b.0 : return #deffunc normal array res, array f ; 面の法線 _a = f.3-f.0, f.4-f.1, f.5-f.2 : _b = f.6-f.0, f.7-f.1, f.8-f.2 : cross res, _a, _b : return #deffunc fmid array res, array f ; 面の中心 res = (f.0+f.3+f.6)/3,(f.1+f.4+f.7)/3,(f.2+f.5+f.8)/3 : return #global #include "d3m.hsp" ; 初期設定 ; --------------------------------------------------------------- screen 0, 800, 800 repeat 4, 1 : buffer cnt, 400,400 : loop : gsel 0 speed = 0.05 ; 線分 sp = 2.0, 2.0, 2.0 ; 開始 ep = 2.0, 2.0, -2.0 ; 終了 ; 面 f.0 = 0.0, 5.0, 0.; 点1 f.3 = 4.3, -2.5, 0.; 点2 f.6 = -4.3, -2.5, 0.; 点3 *MAIN ; 線分移動 keyT = 65,68,87,83,69,81 ;ADWSEQ repeat 3 getkey key,keyT(cnt*2) : if key { sp.cnt += speed : ep.cnt += speed } getkey key,keyT(cnt*2+1) : if key { sp.cnt -= speed : ep.cnt -= speed } loop ; 面回転 stick pad, 15 : if pad&15 { if pad&9 { rad = 0.01 } : if pad&6 { rad = -0.01 } if pad&5 { axis = 0,1,0 } : if pad&10 { axis = 1,0,0 } d3vrotate f.0,f.1,f.2, f.0,f.1,f.2, axis.0,axis.1,axis.2, rad d3vrotate f.3,f.4,f.5, f.3,f.4,f.5, axis.0,axis.1,axis.2, rad d3vrotate f.6,f.7,f.8, f.6,f.7,f.8, axis.0,axis.1,axis.2, rad } ; ★ここがお目当ての部分★ ; 分からない所はデバック表示し易い用、関数化してないので色々見てみて下さい ; --------------------------------------------------------------- hit = 0 ; ★1)ここから平面と線分の判定 normal nv, f ; 面の法線を求める vsub v1, sp, f : vsub v2, ep, f ; 面の適当な点から線分の開始、終了点までのベクトル d1 = dot(nv, v1) : d2 = dot(nv, v2) ; 面の法線と内積(面に対して表か裏かを求める) if d1*d2 <= 0.0 { ; d1,d2の符号が違えば貫通している hit = 1 ; ★2)ここから面(3角ポリコン)に含まれるか判定 ; 内分点 ★3)接触した位置がipに入る。 m = absf(d1) : n = absf(d2) : t = m + n repeat 3 : ip.cnt = (sp.cnt * n + ep.cnt * m) / t : loop repeat 3 ; 辺と接触点の外積が面の法線と一致したら含まれる。 on cnt goto *l0, *l1, *l2 *l0 e = f.3 - f.0, f.4 - f.1, f.5 - f.2 ; ベクトル:点1〜点2 p = ip.0 - f.0, ip.1 - f.1, ip.2 - f.2 ; ベクトル:点1〜接触点 goto *l_check *l1 e = f.6 - f.3, f.7 - f.4, f.8 - f.5 ; ベクトル:点2〜点3 p = ip.0 - f.3, ip.1 - f.4, ip.2 - f.5 ; ベクトル:点2〜接触点 goto *l_check *l2 e = f.0 - f.6, f.1 - f.7, f.2 - f.8 ; ベクトル:点3〜点1 p = ip.0 - f.6, ip.1 - f.7, ip.2 - f.8 ; ベクトル:点3〜接触点 *l_check cross n, e, p if dot(nv, n) < 0 : hit = 0 : break loop } ; --------------------------------------------------------------- ; 描画 gsel 1 : d3setcam 0, 20, 0, 0, 0, 0 : gosub *DRAW gsel 2 : d3setcam 20, 0, 0, 0, 0, 0 : gosub *DRAW gsel 3 : d3setcam 0, 0.0001, 20, 0, 0, 0 : gosub *DRAW t = 0.001*d3timer() gsel 4 : d3setcam cos(t)*20, sin(t)*20, 10, 0, 0, 0 : gosub *DRAW gsel 0 : repeat 4 : pos (cnt\2)*400, (cnt/2)*400 : celput cnt+1 : loop rgbcolor $888888 : line 0, 400, 800, 400 : line 400, 0, 400, 800 pos 4, 4 : rgbcolor $FFFFFF mes "線分の移動: X:[AD], Y:[WS], Z:[EQ]", 4 mes " 面の回転: カーソルキー", 4 redraw 1 : await 16 : redraw 0 goto *MAIN *DRAW d3setlocal 0,0,0, 1,0,0, 0,0,1, 0,1,0 ; 描画 rgbcolor $333333 : boxf ; 軸 rgbcolor $FF5555 : d3line 8,0,0,0,0,0 : d3mes "X", 8.4, 0, 0 rgbcolor $55FF55 : d3line 0,8,0,0,0,0 : d3mes "Y", 0, 8.4, 0 rgbcolor $5555FF : d3line 0,0,8,0,0,0 : d3mes "Z", 0, 0, 8.4 ; 面 if hit { col = $FF0000 } else { col = $FFFFFF } : rgbcolor col d3pos f.6, f.7, f.8 : d3lineto f.0, f.1, f.2 : d3lineto f.3, f.4, f.5 : d3lineto f.6, f.7, f.8 _x = f.0, f.3, f.6, f.6 : _y = f.1, f.4, f.7, f.7 : _z = f.2, f.5, f.8, f.8 gmode 3,,,64 : d3square _x, _y, _z ; 法線 unv = nv.0, nv.1, nv.2 : fmid mid, f : vunit unv : unv = unv.0*5, unv.1*5, unv.2*5 d3line mid.0, mid.1, mid.2, mid.0+unv.0, mid.1+unv.1, mid.2+unv.2 ; 線分 rgbcolor $00FFFF : d3line sp.0, sp.1, sp.2, ep.0, ep.1, ep.2 rgbcolor $FF55FF : d3circle sp.0, sp.1, sp.2, 0.1, 1 : d3mes strf("\nd1:%+.1f", d1), sp.0, sp.1, sp.2 rgbcolor $FFFF55 : d3circle ep.0, ep.1, ep.2, 0.1, 1 : d3mes strf("\nd2:%+.1f", d2), ep.0, ep.1, ep.2 rgbcolor $880088 : d3line f.0, f.1, f.2, f.0+v1.0, f.1+v1.1, f.2+v1.2 rgbcolor $888000 : d3line f.0, f.1, f.2, f.0+v2.0, f.1+v2.1, f.2+v2.2 if hit { rgbcolor $00FFFF : d3circle ip.0, ip.1, ip.2, 0.2, 1 } return



youdai

リンク

2024/9/18(Wed) 23:22:05|NO.102238

> usagi さん

アドバイスありがとうございます! 早速自作の3Dエンジンに組み込んで、当たり判定を実装することができました!

これほどコンパクトなスクリプトで複雑な3Dの当たり判定を取得できることに驚きました。
HSP3で実装したのに、実験用に作った3072ポリゴンのメッシュの判定でも60FPSを保つことができました。

あと最近やっと3DエンジンをOpenGLで自作できるようになりました。
これは昔からの夢だったので、以前の別のスレッドの件になりますがOpenGL関連のアドバイスを下さったusagiさんやTOMATOさんにはとても感謝しています。ありがとうございます。



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.102219への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

解決したら質問者本人がここをチェックしてください。

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

ONION software Copyright 1997-2023(c) All rights reserved.