2018年7月5日木曜日

pyode ボール 直方体以外のバウンドのおかしなところ



ボール 直方体以外のバウンドのおかしなところ

self.v_box = box( pos=pos,  width=w, height=h, length=l)
とvisualのboxを設定しても、物理シュミレーションをupdateすると

    def update(self):
        pos = self.geom.getPosition()
        mat = self.geom.getRotation()
        self.v_box.pos = pos

        self.v_box.axis = mat[0], mat[3], mat[6]
        self.v_box.up = mat[1], mat[4], mat[7]



        self.v_box.axis = mat[0], mat[3], mat[6]
        self.v_box.up = mat[1], mat[4], mat[7]

を拾ってきて、寸法がおかしくなり、その方向も90度おかしい。
何か物理シュミレーション用に変更されているみたいだ。

物理シュミレーションするなら(バウンドなど)ボール 直方体以外は
してはおかしなシュミレーションになる。
つまり、物体の大きさ、方向が変わってしまう。
しかし、その表現された物体としてはまあまあのシュミレーションがされる。

物体の大きさ、方向を保つなら上の2行をupdateから削除し
posだけupdateしたらよい。つまりpyodeのジョイント、モータなどをつかうだけなら
このほうがいい。 

以下画像は左が下の2行を削除したもの。 vpython的にはboxは正確に表現されている。  
 
上が2行を残したもの。 vpythonの寸法、方向はおかしいが pyodeの落下シュミレーション
を実現している。

boxが全然ちがうものになっている。






K:\MyBackups\goolgedrive\myprg_main\python_my_prg\vpython\zahyou_kakunin_cylinder.py

# coding: UTF-8

#https://www10.atwiki.jp/bambooflow/pages/242.html
#スライダーでスプリングダンパーモデル
#上サイトを参考に、pyode + vpython でやってみる
#上ボールが固定されていて、下ボールがスライダージョイントで
#接続されている
#キーのmで下ボールが下がり、バネの動作で何回か上下に振動す
#る。
#元サイトのように連続で振動しなかった。
#重力0で実行、重力をかけるとさらに振動しなくなる


import ode
from visual import *
boxList  = []
ballList = []

class Field:
    """
    scene = display(forward=visual.norm((-2.0,-1.0,-1.0)))
    ベクトル:forward はカメラが見ている方向と同じ向きを指します。
    (すなわち、scene.mouse.camera で与えられる現在のカメラ位置から scene.center へ向かう方向です
    <http://www.nasuinfo.or.jp/FreeSpace/kenji/sf/visualj/display.html>
    norm( vector )
    vector オブジェクトから長さ 1 の vector オブジェクトを生成して返します
    """
    scene = display(forward=norm((-0.05,-0.3,-1.0)),
            range=(7,7,7), autoscale=0
            )
   
    #物理世界を作成   
    world=ode.World()
    world.setGravity((0, -9.81, 0))
    #自由落下させたいなら worldのコメントアウトのほうを生かし
    # 最後の方の ball.body.addForce((0,-1000,0)) を殺す
    #world.setGravity((0, 0, 0))
    #地平面を作成?
    space=ode.Space()

    #座標確認用
    ball = sphere(pos=(5,0,0), radius=0.2, color=color.red)
    ball = sphere(pos=(0,5,0), radius=0.2, color=color.yellow)
    ball = sphere(pos=(0,0,5), radius=0.2, color=color.blue)
    ball = sphere(pos=(0,0,0), radius=0.2, color=color.white)

    #衝突関係
    jointgroup=ode.JointGroup()
    ode_floor=ode.GeomPlane(space,(0,1,0),0)
    #()なかの引数 上の例ではy軸方向に重力が発生
    #多分 spaceの最後の引数が y軸の座標を示す
    #ode_floor.setCategoryBits(5)
    #ode_floor.setCollideBits(5)
    ode_floor.viz=box(
        pos=(0,-0.03,0),
        width=10,length=10,height=0.06,color=(0.5,0.5,1.0))

    target_fps=30
    #target_fps=30だから1秒間に30回の処理をする
    dt=1.0/target_fps

    def near_callback(self,args,geom1,geom2):
        for c in ode.collide(geom1,geom2):
            #接触ジョイント (Contact joint) 
            #mu    摩擦係数 (摩擦方向1) mu2    摩擦係数 (摩擦方向2)
            #bounce    反発係数
            c.setBounce(0.8)
            c.setMu(50)
            c.setMu2(50)
            j=ode.ContactJoint(self.world,self.jointgroup,c)
            j.attach(geom1.getBody(),geom2.getBody())

    def tick(self):
        cyl.update()
        ball1.update()
        ball2.update()
        box.update()
        #print
        #time.sleep(0.23)
        self.space.collide((),self.near_callback)
        self.world.step(self.dt)
        # self.check_timeの間隔で世界を動かしていく
        self.jointgroup.empty()
        return True


class Cylinder:
    def __init__(self, field, r, h):
    #def __init__(self, field, pos, r, h):
        #res = Cylinder(field, radius=0.3, length=0.7)
        #このコードにはCylinderのインスタンスコードは上のものしかないので
        #**keysには radius lengthが格納される

        self.body = ode.Body(field.world)
        M = ode.Mass()
        M.setCylinder( 0.01, 3, r, h)
        self.body.setMass(M)
        # setCylinder (密度、方向、半径 長さ)
        #方向:1だからgeomはx方向に長い
        # http://www10.atwiki.jp/bambooflow/pages/226.html#id_8fb8a607


        #0000000000簡単のためCCylinderでなくcylinderにする
        self.geom = ode.GeomCCylinder(
            space=field.space, radius=r, length=h)
        #self.geom = ode.GeomCCylinder(
        #    space=field.space, radius=r, length=h)
        #CCylinder GeomCapsuleの別名

        #self.geom.setCategoryBits(5)
        #self.geom.setCollideBits(5)

        self.body.setPosition((0,5,0))
        self.geom.setBody(self.body)
        #self.geom.setPosition((0,5,0))

        #vpythonのcylinder 円柱の部分センターがposとなる
        #これのみだと、x方向へhの長さのcylinderとなる
        #以下コード間違い length → axis
        self.vcyl = cylinder( pos=(0,5,0), radius=r, length=h, color=color.red)
        #self.vcyl = cylinder( radius=r, axis=(h, 0, 0), color=color.red)
        #self.vcyl.rotate(angle=pi/2, axis=(0,0,1), origin=(0,5,0))

        #self.vcyl.pos = (0,5,0)
        print self.vcyl.pos


    def update(self):
        #pos = self.body.getPosition()
        pos = self.geom.getPosition()
        print pos
        #mat = self.body.getRotation()
        mat = self.geom.getRotation()
        self.vcyl.pos = pos

        #以下のコードを活かすと正しく h が表示されなく短くなる
        self.vcyl.axis = mat[0], mat[3], mat[6]

        self.vcyl.up = mat[1], mat[4], mat[7]
        #これも姿勢に関するもの あとで詳しく調べよう


class Ball:
    def __init__(
            self,field,
            m_density=0.01,
            m_radius=0.3,
            g_radius=0.3,
            v_radius=0.3,
            b_pos=vector(1,3,0),
            b_sp =vector(10,0,0),
            v_color=color.cyan
            ):
        self.body=ode.Body(field.world)
        M=ode.Mass()
        M.setSphere(m_density, m_radius)
        #(密度,半径)
        self.body.setMass(M)
        self.body.setPosition(b_pos)
        #self.body.addForce(b_sp)
        self.geom=ode.GeomSphere(
                space=field.space,
                radius=g_radius
                )
        #このradiusが実際のバウンドを決める
        #多分 sphereの座標が0で radiusが0.3だから
        #posが0.3ぐらいのバウンド点になる
        #self.geom.setCategoryBits(5)
        #self.geom.setCollideBits(5)
        #ボール同士の衝突を避ける
        #上は Boxのジオメトリを作成
        self.geom.setBody(self.body)
        # 剛体にジオメトリをセット
        self.vball=sphere(
            radius=v_radius,
            color=v_color
            )

    def update(self):
        pos=self.geom.getPosition()
        #boxのジオメトリの位置を得る
        self.vball.pos=pos
        #print pos,


class Box:
    def __init__(self, field, pos, w, h, l):
        #初期的設定では、Vehicleクラスのなかで以下行のようにしているので
        #self.body = Box(field, width=2.0, height=0.5, length=3.5)

        self.old_pos = []
        self.body = ode.Body(field.world)
        M = ode.Mass()
        M.setBox( 1, w, h, l)
        #引数 d:密度 w: h: l:
        self.body.setMass(M)
        self.body.setPosition(pos)

        #vpythonと引数l wの順序が入れ替わる
        self.geom = ode.GeomBox( space=field.space, lengths=(l, h, w))
        # lengthの引数 w h l
        self.geom.setBody(self.body)
        #self.geom.setPosition(pos)
        self.v_box = box( pos=pos,  width=w, height=h, length=l)
        #self.v_box.rotate(angle=pi/2.0, axis=(0,1,0))

   
    def update(self):
        pos = self.geom.getPosition()
        mat = self.geom.getRotation()
        self.v_box.pos = pos
        self.v_box.axis = mat[0], mat[3], mat[6]
        self.v_box.up = mat[1], mat[4], mat[7]


if __name__=='__main__':
    field = Field()
    #cyl = Cylinder(field, 0.3, 0.7, "red")

    #cyl = Cylinder(field,(0, 5, 0), 0.3, 5.0)
    #cyl = Cylinder(field,(0, 5, 0), 0.3, 5.0)
    cyl = Cylinder(field, 0.3, 5.0)

    #cyl.body.setPosition((0, 5, 0))

    ball1 = Ball(field, b_pos=(1,2,0))
    ball2 = Ball(field, b_pos=(1,1,0), v_color=color.red)

    box = Box(field, (-4, 5, 0), 2, 1, 4 )
    #box.v_box.rotate(angle=pi/20, axis=(0,0,1))

    while True:
        rate(100)
        time.sleep(0.05)

        field.tick()


   
   
   

0 件のコメント:

コメントを投稿

About

参加ユーザー

連絡フォーム

名前

メール *

メッセージ *

ページ

Featured Posts