Ruby-FFIでODEを動かす実験2
ODE付属のdrawstuffもFFIで動かしてみました。
試した環境は、
linuxでのコンパイルの場合、drawstuffの動的ライブラリは通常は生成されないので、工夫が必要です。
require 'ffi' module DrawStuff extend FFI::Library ffi_lib '/usr/local/lib/libdrawstuff.so' # ffi_lib 'C:/opt/ode-1.12/lib/ReleaseDoubleDLL/drawstuff.dll' callback :start_callback, [], :void callback :step_callback, [:int], :void callback :command_callback, [:int], :void callback :stop_callback, [], :void class DsFunctions < FFI::Struct layout :version, :int, :start, :start_callback, :step, :step_callback, :command, :command_callback, :stop, :stop_callback, :path_to_textures, :string end attach_function :dsSimulationLoop, [:int, :pointer, :int, :int, :pointer], :void attach_function :dsPrint, [:string], :void attach_function :dsSetViewpoint, [:pointer, :pointer], :void attach_function :dsSetColor, [:float, :float, :float], :void attach_function :dsDrawSphereD, [:pointer, :pointer, :float], :void # attach_function :dsDrawSphere, [:pointer, :pointer, :float], :void end
$:.unshift File.dirname(__FILE__) require 'ode' require 'draw_stuff' @start = Proc.new do puts "start" # DrawStuff.dsSetViewpoint(xyz, hpr) end @step = Proc.new do |pause| break unless pause == 0 ODE.dSpaceCollide(@space, nil, @nearCallback) ODE.dWorldStep(@world, 0.01) ODE.dJointGroupEmpty(@contactgroup) DrawStuff.dsSetColor(1.0, 0.0, 0.0) pos = ODE.dBodyGetPosition(@sphere_body) rot = ODE.dBodyGetRotation(@sphere_body) DrawStuff.dsDrawSphereD( pos, rot, 1.0 ) pos_p = ODE.dBodyGetPosition(@sphere_body) pos = ODE::DVector3.new(pos_p) puts "pos x=#{pos[:x]}, y=#{pos[:y]}, z=#{pos[:z]}" end @command = Proc.new do |cmd| puts "command #{cmd}" end @stop = Proc.new do puts "stop" end ODE.dInitODE @world = ODE.dWorldCreate @space = ODE.dSimpleSpaceCreate(nil) @contactgroup = ODE.dJointGroupCreate(nil) ODE.dCreatePlane(@space, 0.0, 0.0, 1.0, 0) ODE.dWorldSetGravity(@world, 0.0, 0.0, -9.8) @sphere_body = ODE.dBodyCreate(@world) ODE.dBodySetPosition(@sphere_body, 0.0, 0.0, 10.0) @sphere_geom = ODE.dCreateSphere(@space, 1.0) ODE.dGeomSetBody(@sphere_geom, @sphere_body) @nearCallback = Proc.new do |data_p, g1, g2| b1 = ODE.dGeomGetBody( g1 ) b2 = ODE.dGeomGetBody( g2 ) # break if b1 and b2 and ODE.dAreConnectedExcluding(b1, b2, 4) # 誤り return if !b1.null? and !b2.null? and ODE.dAreConnectedExcluding(b1, b2, 4) == 1 contacts = [] 4.times do c = ODE::DContact.new c[:surface][:mode] = 0x004 | 0x010 c[:surface][:mu] = 10000.0 c[:surface][:bounce] = 0.1 c[:surface][:soft_cfm] = 0.01 contacts << c end numc = ODE.dCollide(g1, g2, 4, contacts[0][:geom], ODE::DContact.size) if numc > 0 numc.times do |i| c = ODE.dJointCreateContact(@world, @contactgroup, contacts[i]) ODE.dJointAttach(c, b1, b2) end end end # drawstuff @args = FFI::MemoryPointer.new(:pointer, 0) #[$0]+ARGV @width = 320 @height = 240 fn = DrawStuff::DsFunctions.new fn[:version] = 2 fn[:start] = @start fn[:step] = @step fn[:command] = @command fn[:stop] = @stop fn[:path_to_textures] = "./textures" #CRuby@linuxだとうまく読めない。。。 DrawStuff.dsSimulationLoop(@args.size, @args, @width, @height, fn)
動いてくれると、感動しますネ。
はまったこと
メモ
配列をCのfloat[]に変換するにはどうすればよいでしょうか。
dsSetViewpointで試して動いた方法をメモします。
xyz = [ 3.0, 5.0, 1.0].pack('f*') hpr = [-120.0, 0.0, 0.0].pack('f*') DrawStuff.dsSetViewpoint(xyz, hpr)