LoginSignup
4
4

More than 5 years have passed since last update.

iOSでCocos3dでNewtonで3D物理演算

Last updated at Posted at 2012-03-17

NewtonGameDynamicsってあんまり日本では使ってる人を見ませんね。
でも、僕は好きです。

Newtonをビルド

おもむろにNewtonの最新版をチェックアウト。

core_Library200/projects/mac/OS10_xcode3.2.5/newton.xcodeproj
を開く。

ターゲットの設定から、BaseSDKをiOSに設定。しかし、このままではビルドが通らない。

なぜかプロジェクトに追加されていないソースファイルがあったので、
core_Library200/source/physics/dgMeshEffect2.cpp
core_Library200/source/physics/dgMeshEffect3.cpp
core_Library200/source/physics/dgMeshEffectSolidTree.cpp
あたりを追加。

さらに、core_Library200/source/newton/Newton.hの中からNewtonSceneCollisionCreateProxy()が宣言されている行を探し、これをコメントアウトする。

自分の環境では、LLVM GCC4.2でビルドするとうまく動かなかった。LLVM 3.1でビルドした。

XcodeのSchemeを編集し、iPhone/iPad実機用と、iOS Simulator用に別々にビルドする。
終わったら、ターミナルでビルドディレクトリを開き、armv7とi386のユニバーサルバイナリを作成する。

lipo -create -output libnewton.a release-iphoneos/libnewton.a release-iossimulator/libnewton.a

Cocos3Dで使う

先ほどビルドしたバイナリを、Cocos3Dプロジェクトに追加する。
core_Library200/source/newton にパスを通す。

core_Library200/projects/mac/iPhoneTranslator/iNewton.h に、Objective-CのNewtonラッパが置いてある。
だがこいつは使えない子。
大人しくNewton.hをインクルードして、通常のCのライブラリとして呼ぶことにする。

CC3Worldを継承したクラスのメンバに、NewtonWorld* newtonを追加して、こんな感じの関数を書く。

MyWorld.m
@implementation MyWorld

- (void)initializeWorld {
    newton = NewtonCreate();
    NewtonSetSolverModel(newton, 1);
}

- (void)dealloc {
    NewtonDestroyAllBodies(newton);
    NewtonDestroy(newton);
    [super dealloc];
}

- (void)updateBeforeTransform:(CC3NodeUpdatingVisitor*)visitor {
    NewtonUpdate(newton, visitor.deltaTime);
}

@end

CC3Nodeを継承したクラスのメンバに、NewtonBody* bodyを追加して、こんな感じの関数を書く。

MyNode.m
static void NewtonGravityCallback(const NewtonBody* body, float timestep, int thredindex) {
    const float GRAVITY = -9.8f;
    float Ixx, Iyy, Izz, mass;

    NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
    float vector[] = {
        0.0f, GRAVITY * mass, 0.0f
    };
    NewtonBodySetForce(body, vector);
}

static void NewtonTransformCallback(const NewtonBody* body, const float* const matrix, int thredindex) {
    MyNode* node = (MyNode*)NewtonBodyGetUserData(body);
    float matrix[16];
    NewtonBodyGetMatrix(body, matrix);
    float quaternion[4];
    NewtonBodyGetRotation(body, quaternion);

    node.location = CC3VectorMake(matrix[12], matrix[13], matrix[14]);
    node.quaternion = CC3Vector4Make(quaternion[3], quaternion[0], quaternion[1], quaternion[2]);
    // ほんとは行列を直接代入したかったけど、やりかたがよくわからんかった
}

@implementation MyNode

- (void)setupPhysics:(NewtonWorld*)world {
    NewtonCollision* col = NewtonCreateBox(world, 1.0f, 1.0f, 1.0f, 0, NULL);
    body = NewtonCreateBody(world, col, self.transformMatrix.glMatrix);
    NewtonReleaseCollision(world, col);

    NewtonBodySetUserData(body, self);
    NewtonBodySetMassMatrix(body, 1.0f, 1.0f, 1.0f, 1.0f);
    NewtonBodySetForceAndTorqueCallback(body, &NewtonGravityCallback);
    NewtonBodySetTransformCallback(body, &NewtonTransformCallback);
}

@end

できたー!

まとめ

NewtonのMac/iOS対応は適当なので、自分でがんばろう!

追記

Quaternionを使う場合は、どこかで回転方向を逆にしないとうまく動かないかも。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4