頭と尻尾はくれてやる!

iOSアプリなどの開発日記です


SCNPhysicsSliderJointで回転させてみる

SceneKitでオブジェクトのヒンジっぽい接続と言えば文字通りSCNPhysicsHingeJointを使ってた。
SCNPhysicsSliderJointってのもあるけどこれはスライドドアみたいなのを表現するのに使うのだと思っていたし。
ところがこのSCNPhysicsSliderJointはどうやらヒンジっぽいのも表現できることに気付いた。しかも目標速度を与えてジョイント部分で回転(移動も)させることができるらしい!
ってことで試してみた。

実装自体はSCNPhysicsHingeJointとさほど変わらない。
+ (instancetype)jointWithBodyA:(SCNPhysicsBody *)bodyA axisA:(SCNVector3)axisA anchorA:(SCNVector3)anchorA bodyB:(SCNPhysicsBody *)bodyB axisB:(SCNVector3)axisB anchorB:(SCNVector3)anchorB;
という生成メソッドはSCNPhysicsHingeJointと全く同じ。

今回は回転させたいので
{
    sliderJointL.motorTargetAngularVelocity = 1.0;
}
てな感じで指定する。ちなみに移動させたい場合はmotorMaximumForceというプロパティがある。

可動範囲は下のような感じで指定できる。
{
    sliderJointL.maximumAngularLimit = AngleLimitMax;
    sliderJointL.minimumAngularLimit = AngleLimitMin;
}


↑手動でmotorTargetAngularVelocityの値を変えてる様子。
可動範囲のはしっこでプルプルしてるのはご愛嬌、、、?

うまくいってるように見えるけど最初意図通り動かず相当悩んだ。
-(void)control1
{
    sliderJointL.motorTargetAngularVelocity = -TargetAngularVelocityABS;
    sliderJointR.motorTargetAngularVelocity = TargetAngularVelocityABS;
}
↑タップ時にこんな感じで値を指定するんだが、なぜか全く動かない。トルクが足りないわけでもなく、、、なぜか動かないのだ。
motorTargetAngularVelocityの値を途中で変更しても問題ないはずなんだけどなあ。

試行錯誤してようやくたどり着いたのが、、、
-(void)control1
{
    [scene.physicsWorld removeBehavior:sliderJointL];
    [scene.physicsWorld removeBehavior:sliderJointR];

    sliderJointL.motorTargetAngularVelocity = -TargetAngularVelocityABS;
    sliderJointR.motorTargetAngularVelocity = TargetAngularVelocityABS;

    [scene.physicsWorld addBehavior:sliderJointL];
    [scene.physicsWorld addBehavior:sliderJointR];
}
SCNPhysicsSliderJointオブジェクトを一度physicsWorldから取り除いてサイドaddしてやる、というなんだかよくわかんない処理をすればなぜか動いた。
あまり深く考えるのはよそう、だってSceneKitだもの(みつを)。


SceneKitで動ける次元を拘束する

3Dの物理エンジンを使いつつも「この動きは二次元でいい!」って時あるよね。



↑以前アップした動画なんだけど、この時の動きは実質xy平面(赤がx軸、y軸は平面に垂直な方向)の二次元なのでホントはそういう指定をしたかった。
3D物理エンジンのBulletにはそういう機能があったので探したけどSceneKitでは見つからなかったのであきらめていた。なので動画だと途中からy軸に対して無駄に回転というかずれてしまってる。

別件でリファレンス見てたらそれを設定できるプロパティが見つかった!
SCNPhysicsBodyクラスに
velocityFactor
angularVelocityFactor
ってのがある。

velocityFactorでオブジェクトの移動
angularVelocityFactorでオブジェクトの回転
をそれぞれ制限できる。
{
    node.physicsBody.velocityFactor = SCNVector3Make(1.0 , 1.0 , 0);
    node.physicsBody.angularVelocityFactor = SCNVector3Make(0.0 , 0.0 , 1.0);
}
↑先ほどのxy平面で扱うような場合はこんな感じで指定すればOK。



↑動き方が二次元に変わった!
ホントは画面を右へ行くはずなんだけどむしろ左にじわじわ行ってるやん、、、というのは置いといて、ともかくxy平面上で動くようになってる。


それにしても、、、なんで ‘(angular) velocity factor’って名前にしたんだろうな、、、?別に速度だけじゃないのに。


SCNPhysicsVehicleで二輪車と一輪車

SCNPhysicsVehicleでシャーシとホイールの位置関係
↑この続き。四輪車をやったので、SCNPhysicsVehicleで二輪車や一輪車ってできるのかな?と思い試してみた。



↑基本的に、二輪車や一輪車だとちゃんとバランスを取らないとこけるんだろう。二輪車のこけ方を見るとちゃんと曲がるときに車体にかかる遠心力とか計算してそうだし。
なぜ適当に作ったのが走ってるかというとシャーシの底が床に接触しててたまたまこけなかっただけかな、と。

確かめようとSCNPhysicsContactDelegateで地面に接触しているオブジェクトを調べたらシャーシしか検出できなかった(シャーシとホイールを接続するのでそういう扱いになるんだろう)ので断定はできないが。

シャーシが接地しないような位置関係でうまく強化学習使いバランスをとって二輪車を走らせる、とかできると面白いかも。

なお動画の途中でbounding boxを表示させてるけど下のオプション設定でOK。
{
    scnView.debugOptions = SCNDebugOptionShowBoundingBoxes;
}



Qloneでスキャン→Blender→SceneKitで使う

一瞬で3Dモデルを生成!!イスラエルのソフトウェア企業EyeCueが開発したスキャンアプリ「Qlone」がすごい!! – CG GEEKS
↑先日この記事を見て面白そう!と思ってたので試してみた。

Qlone, the all in one tool for 3D Scanning
↑本家サイト。
iPhoneにアプリをダウンロードし、QRコードみたいなのをプリンタで印刷(アプリにもサイトにも画像あり)。

Qloneのマットとスキャン対象

↑そこにおもちゃのゴミ収集車を置いてスキャンしてみた。画像は横に寝かせてるけど、最初は普通に置いた状態でスキャンした。二つのデータを統合(統合は数十秒かかってた)して完成したのが、、、



↑ふーむ、、、デバイスがiPhone 7 Plusなので古いのか、撮影が雑だったのか、、、?


次にobjファイルで出力してみる。

Qloneの支払い画面

↑objファイルでの出力は有料。1つなので120円を払った。AirDropでファイルをMacに送る。

Blenderにインポートしたオブジェクト

↑Blenderにobjファイルを読み込み、テクスチャも設定。
この状態で頂点数が212,769個。

頂点数を減らしたオブジェクト

↑remove doubleとmodifierのdecimateで5,266個にした。どこまで減らすかは開発者次第。
Blenderでこのデータをdaeファイルとして出力する。

SceneKitにインポートしたオブジェクト

↑そのdaeファイルをXcodeに持ってくる。



↑SceneKitのSCNPhysicsVehicleを使って走らせた。ただし読み込んだデータ全体がシャーシでタイヤは別途くっつけてる。厳密にやるならBlenderでタイヤと車体を切り分けてデータ化するなど対応が必要。


とりあえず、iPhoneでスキャンしてSceneKitで使うという一連の作業ができることは確認できた。SceneKitでもできるくらいだからUnityとかでもできるんだろう、知らんけど。
何年か前には何枚も写真を撮影してどこぞのサーバに送ったら数時間とかしてデータがやってくる、というサービスがあったけどそれを考えたらすごい進化だなあ。
今回は溶けたようなオブジェクトになってしまったけど、うまく使えばアプリ作成に使えるかもしれない。


SCNPhysicsVehicleでシャーシとホイールの位置関係

SCNNodeをつなぐSCNPhysicsHingeJointやSCNPhysicsSliderJointと同列に(つまりみんなSCNPhysicsBehaviorのサブクラス)SCNPhysicsVehicleなるものがあって何やら車の挙動をシミュレーションできそう、なのがあるなあと思ってたので今更だけどいじってみた。

screenshot of SceneKitVehicle

↑APPLEのサンプルコードにSceneKitVehicleというiOS用アプリがあるのですごく参考になる。

はまったのはシャーシとホイールのつなぎ方。
{
    wheel0.connectionPosition = SCNVector3Make(x,y,z);
}
SCNPhysicsHingeJointの場合と同じような位置関係で接続する(上のコードでx,y,zはシャーシのローカル座標)でいいんだけど、この場合それだけでシャーシとホイールの位置関係が決まるわけではない。
SCNPhysicsVehicleWheelオブジェクトに設定できるプロパティに
suspensionRestLength
suspensionStiffness
などがあって、車体とホイールの間にはスプリングとダンパを持つサスペンションがあるイメージ(頑張ったな!SceneKit!!)。
このふたつをいじった場合の動画がこちら↓



スプリングにかかる力の話なので当然車体の重さなんかも影響する。
このあたりのパラメータを下手に設定するとタイヤが車体から不自然に離れてしまったりする。最初は普通に走ってても、車がひっくりかえったりした時に同じようにタイヤが離れてしまったりする。

なお、APPLEのサンプルコードだとこのあたりのサスペンション周りのプロパティが登場してこないので最初はホント悩んだ。おそらくデフォで設定しなくていい重さや形状になってんのね。





Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.