« えぇ… | トップページ | C4D Python R12 テスト:SendModelingCommand()編集可能にする »

C4D Python R12 テスト:ポリゴンオブジェクトと線分の交点…GeRayCollider()をグダグダと…

ポリゴンオブジェクトのポリゴンと線分の交点…
XPressoのノードだと、「光線の衝突」だろうね。

Geraycollider_01

c4d Pythonでは、utilsモジュールのGeRayColliderを使うんだね。

いつも通り、具体的な事はしませんけどね。

utils.GeRayColliderクラスは、始めて使ってみるので…

とりあえず…
ポリゴンオブジェクトとRayに見立てたスプラインオブジェクトを使ってテストしてみる。

Geraycollider_02

こんな具合だ…
あ…立方体プリミティブのままだった…

「編集可能にする」でポリゴンオブジェクトにしておきます。

Geraycollider_03

スプラインとオブジェクトの2個選択したのを、BaseDocument.GetSelection()で…
スプラインの先頭から2個のポイントを使うとして…

オブジェクトの選択が、スプライン/ポリゴン…なのかポリゴン/スプラインなのか…?

Python
import c4d
from c4d import utils


def main():
    sel_obj = doc.GetSelection()
    if len(sel_obj) != 2:return #選択が2個以外終了

    #スプラインをrayに、交点の判定するオブジェクトをobjに
    if isinstance(sel_obj[0], c4d.SplineObject):
        if isinstance(sel_obj[1], c4d.PolygonObject):
            obj = sel_obj[1]
            ray = sel_obj[0]
        else:return
    elif isinstance(sel_obj[1], c4d.SplineObject):
        if isinstance(sel_obj[0], c4d.PolygonObject):
            obj = sel_obj[0]
            ray = sel_obj[1]
        else:return
    else:return
    if ray.GetPointCount() != 2:return #スプラインのポイントが2個以外終了
    if obj.GetPolygonCount() == 0:return #ポリゴンが1枚も無ければ終了

    print 'ok'


if __name__=='__main__':
    main()
    c4d.EventAdd()

ヌルオブジェクトにユーザデータでリンク2個付けてやった方が楽じゃないか?

ま、どうせ、テストだし…
記事のタイトルも、「グダグダと…」だし…
このままで…

と思いながらも…

Geraycollider_04

ヌルオブジェクトにユーザデータのリンク2個付けてみた…
選択しておくのは、もちろんヌルオブジェクト。

Python
import c4d
from c4d import utils


def main():
    try:
        ray = op[c4d.ID_USERDATA, 1]
        if not isinstance(ray, c4d.SplineObject):return
        obj = op[c4d.ID_USERDATA, 2]
        if not isinstance(obj, c4d.PolygonObject):return
    except:return

    if ray.GetPointCount() != 2:return #スプラインのポイントが2個以外終了
    if obj.GetPolygonCount() == 0:return #ポリゴンが1枚も無ければ終了

    print 'ok'


if __name__=='__main__':
    main()
    c4d.EventAdd()

Pythonの例外を使ってみた…
簡単に言うと、「やってみてダメだったらなんとかする…」
具体的なことは検索してください。

選択オブジェクトからユーザデータを取得してダメだったら終了する…

グダグダしすぎた…
とっととGeRayColliderへ…

GeRayColliderクラスを使うときは初期化するんだね…

GeRayCollider.Init(goal[, force=False])

goalにポリゴンオブジェクトを指定…
forceは… 面倒だ、省略可能なので後回し…「Dirtyがどうの…」と書いてあるからオブジェクトをGeRayCollider()に渡した後にオブジェクトの形状を変更してしまった時の何かか?

線分のrayの設定は…

GeRayCollider.Intersect(ray_p, ray_dir, length[, only_test=False])

ray_pに線分のスタート座標
tay_dirに線分の方向
lengthには長さ
only_testは、省略可能なので無視…光線の衝突ノードの「テストのみ」なんだろうね…

スタート座標と方向は、ポリゴンオブジェクトのローカル座標で設定するのか…

交点の取得は…
交点は1個とは限らないよね…2個かもしれないし3個かもしれないし、それ以上かも…

交点の数の取得

GeRayCollider.GetIntersectionCount()

交点の取得

GeRayCollider.GetIntersection(number)

スタート位置より最も近い交点

GeRayCollider.GetNearestIntersection()

一番近い交点を取得するだけなら、交点の数を取得する必要はないなぁ

まぁ、こんなもんか… 少ないね…

じゃぁ早速、GeRayColliderで交点を取得してみよう。
そうかぁ、スプラインオブジェクトのポイント座標を立方体のローカル座標へ変換しないといけないのね…
面倒だなぁ…立方体とスプラインの軸を同じ設定にしておけば、座標変換なんてしなくても良いではないか…

スプラインのポイントをグローバル座標へ変換してから、更に立方体のローカル座標へ変換と…

Python
import c4d
from c4d import utils


#オブジェクトのポイントをグローバル座標へ変換
def GetGlobalPoint(obj):
    if not isinstance(obj, c4d.PointObject):return

    mg = obj.GetMg()
    pnt = obj.GetAllPoints()
    pnt_cnt = obj.GetPointCount()

    for id in xrange(pnt_cnt):
        pnt[id] = mg.__mul__(pnt[id])

    return pnt


#グローバル座標リストをオブジェクトのローカル座標へ変換
def GetLocalPoint(pnt, obj):
    if not isinstance(obj, c4d.BaseObject):return
    if type(pnt) != list:return

    mg = obj.GetMg()
    inv_mg = mg.__invert__()

    for id in xrange(len(pnt)):
        pnt[id] = inv_mg.__mul__(pnt[id])

    return pnt
   


def main():
    try:
        ray = op[c4d.ID_USERDATA, 1]
        if not isinstance(ray, c4d.SplineObject):return
        obj = op[c4d.ID_USERDATA, 2]
        if not isinstance(obj, c4d.PolygonObject):return
    except:return

    if ray.GetPointCount() != 2:return #スプラインのポイントが2個以外終了
    if obj.GetPolygonCount() == 0:return #ポリゴンが1枚も無ければ終了

    #スプラインオブジェクトのポイントをローカル座標からグローバル座標へ
    pnt = GetGlobalPoint(ray)

    #グローバル座標からポリゴンオブジェクトのローカル座標へ
    pnt = GetLocalPoint(pnt, obj)

    #GeRayColliderの線分の開始位置と方向、長さを求める
    start_pos = pnt[0]
    direct = pnt[1] - pnt[0]
    length = direct.GetLength()

    #GeRayColliderの設定
    rc = utils.GeRayCollider()
    rc.Init(obj)
    rc.Intersect(start_pos, direct, length)

    #交点の数を表示
    is_cnt = rc.GetIntersectionCount()
    print is_cnt

    #交点の表示
    for id in xrange(is_cnt):
        print rc.GetIntersection(id)

    print 'ok'



if __name__=='__main__':
    main()
    c4d.EventAdd()
2
{'tri_face_id': 1, 'distance': 0.29190841816349922, 's_normal': Vector(0, 0, -40000), 'backface': False, 'hitpos': Vector(-65.583, 34.234, -100), 'f_normal': Vector(0, 0, -40000), 'face_id': 0, 'barrycoords': Vector(0.329, 0.499, 0.172)}
{'tri_face_id': -2, 'distance': 0.70525196396342427, 's_normal': Vector(40000, 0, 0), 'backface': True, 'hitpos': Vector(100, -31.412, -16.719), 'f_normal': Vector(40000, 0, 0), 'face_id': 1, 'barrycoords': Vector(0.343, 0.073, 0.584)}
ok

ごめん、適当に書いちゃった…

確かに交点は2個
でも本当に交点を取得できているのか…?

ごちゃごちゃしてわかり辛いな…

  • 'tri_face_id':  よく分からんが… ポリゴンを2つの三角形abc/cdaに分け、交点がabcに含まれる場合、ポリゴン番号+1、cdaの場合は、-(ポリゴン番号+1)…よく分からん
  • 'distance':  線分の開始位置と交点との距離
  • 's_normal':  交点位置のフォン法線で、正規化されていない。
  • 'backface':  線分の開始位置からみた交わっているポリゴンが裏なのか?
  • 'hitpos':  交点だと…ローカル座標だと…
  • 'f_normal':  交わっているポリゴンの法線で、正規化されていない。
  • 'face_id':  交わっているポリゴン番号…
  • 'barrycoords':  uvd座標系らしいが…dとは、何だ!? wじゃないのか?wだったとしても… 分からん…

こんな具合だと思う… 正解なのか不正解なのかは、分からん…
アバウトだけど…

じゃあ、本当に交点を求められているのか、交点に球体プリミティブを配置させてみよう。

Python
import c4d
from c4d import utils


#オブジェクトのポイントをグローバル座標へ変換
def GetGlobalPoint(obj):
    if not isinstance(obj, c4d.PointObject):return

    mg = obj.GetMg()
    pnt = obj.GetAllPoints()
    pnt_cnt = obj.GetPointCount()

    for id in xrange(pnt_cnt):
        pnt[id] = mg.__mul__(pnt[id])

    return pnt


#グローバル座標リストをオブジェクトのローカル座標へ変換
def GetLocalPoint(pnt, obj):
    if not isinstance(obj, c4d.BaseObject):return
    if type(pnt) != list:return

    mg = obj.GetMg()
    inv_mg = mg.__invert__()

    for id in xrange(len(pnt)):
        pnt[id] = inv_mg.__mul__(pnt[id])

    return pnt



def main():
    try:
        ray = op[c4d.ID_USERDATA, 1]
        if not isinstance(ray, c4d.SplineObject):return
        obj = op[c4d.ID_USERDATA, 2]
        if not isinstance(obj, c4d.PolygonObject):return
    except:return

    if ray.GetPointCount() != 2:return #スプラインのポイントが2個以外終了
    if obj.GetPolygonCount() == 0:return #ポリゴンが1枚も無ければ終了

    #スプラインオブジェクトのポイントをローカル座標からグローバル座標へ
    pnt = GetGlobalPoint(ray)

    #グローバル座標からポリゴンオブジェクトのローカル座標へ
    pnt = GetLocalPoint(pnt, obj)

    #GeRayColliderの線分の開始位置と方向、長さを求める
    start_pos = pnt[0]
    direct = pnt[1] - pnt[0]
    length = direct.GetLength()

    #GeRayColliderの設定
    rc = utils.GeRayCollider()
    rc.Init(obj)
    rc.Intersect(start_pos, direct, length)

    #交点の数を表示
    is_cnt = rc.GetIntersectionCount()
    print is_cnt

    #交点の表示
    for id in xrange(is_cnt):
        print id, rc.GetIntersection(id)

        #球体を交点に配置する
        Intersection_obj = c4d.BaseObject(c4d.Osphere)
        Intersection_obj.MakeTag(c4d.Tphong)
        Intersection_obj[c4d.PRIM_SPHERE_RAD] = obj.GetRad().GetLength() * 0.05
        Intersection_obj[c4d.ID_BASEOBJECT_USECOLOR] = c4d.ID_BASEOBJECT_USECOLOR_ALWAYS
        Intersection_obj[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1.0, 0.0, 0.0)
        Intersection_obj.SetAbsPos(rc.GetIntersection(id)['hitpos'])
        Intersection_obj.InsertUnder(obj)


    #最後に線分の開始位置に最も近い交点を取得するメソッドを試してみる
    print 'Nearest', rc.GetNearestIntersection()


    print 'ok'



if __name__=='__main__':
    main()
    c4d.EventAdd()
2
0 {'tri_face_id': 1, 'distance': 0.29190841816349922, 's_normal': Vector(0, 0, -40000), 'backface': False, 'hitpos': Vector(-65.583, 34.234, -100), 'f_normal': Vector(0, 0, -40000), 'face_id': 0, 'barrycoords': Vector(0.329, 0.499, 0.172)}
1 {'tri_face_id': -2, 'distance': 0.70525196396342427, 's_normal': Vector(40000, 0, 0), 'backface': True, 'hitpos': Vector(100, -31.412, -16.719), 'f_normal': Vector(40000, 0, 0), 'face_id': 1, 'barrycoords': Vector(0.343, 0.073, 0.584)}
Nearest {'tri_face_id': 1, 'distance': 0.29190841816349922, 's_normal': Vector(0, 0, -40000), 'backface': False, 'hitpos': Vector(-65.583, 34.234, -100), 'f_normal': Vector(0, 0, -40000), 'face_id': 0, 'barrycoords': Vector(0.329, 0.499, 0.172)}
ok

Geraycollider_05

問題なく、球体は交点に配置されているようだ。
線分の開始位置からの最も近い交点も取得できているようだ。
id : 0とNearestが同じだ…

オブジェクトの属性「基本」の「色を指定」は…

なし ID_BASEOBJECT_USECOLOR_OFF
自動 ID_BASEOBJECT_USECOLOR_AUTOMATIC
オン ID_BASEOBJECT_USECOLOR_ALWAYS
レイヤ ID_BASEOBJECT_USECOLOR_LAYER

Geraycollider_06

ま、今回はこんな所で…

GeRayCollider… 何に使おうか…?

|

« えぇ… | トップページ | C4D Python R12 テスト:SendModelingCommand()編集可能にする »

コメント

コメントを書く



(ウェブ上には掲載しません)




« えぇ… | トップページ | C4D Python R12 テスト:SendModelingCommand()編集可能にする »