cocos2d-x 3.1から実装されたSprite3D
を使ってて偶然発見したマニアックな知見を共有
3DSprite
例えば、歯車のようなモデルを表示して、回転させたいと思う。
モデルはBlenderで作成した。
Size visibleSize = Director::getInstance()->getVisibleSize();
auto gear = Sprite3D::create("model/gear.obj");
gear->setPosition(visibleSize.width / 2.0, visibleSize.height / 2.0);
auto rotation = RotateBy::create(10, Vec3(0, 360, 0));
gear->runAction(RepeatForever::create(rotation));
this->addChild(gear);
うまく回転する
問題:傾けたモデルを回転させようとすると軸がおかしくなる
しかし、このままだと見栄えが悪いので、おもむろに歯車を傾けて回転するようにしたい。
そっちの方が立体感が出てカッコイイ
Size visibleSize = Director::getInstance()->getVisibleSize();
auto gear = Sprite3D::create("model/gear.obj");
gear->setPosition(visibleSize.width / 2.0, visibleSize.height / 2.0);
// X軸、Z軸に対して30度ずつ回転
gear->setRotation3D(Vec3(30, 0, 30));
auto rotation = RotateBy::create(10, Vec3(0, 360, 0));
gear->runAction(RepeatForever::create(rotation));
this->addChild(gear);
回るけどなにやら回転軸がおかしい!
モデル自体のY軸ではなく、絶対座標のY軸が回転軸として使われてしまっているような挙動をする。これじゃない!
解決策
中のコード見て、なんとか解決しないかなぁとか、PR送ろうかなぁと思っていたんですが、なかなか手に負えず。
これは難しい問題だと思いきや、意外と簡単な方法で解決した。
Size visibleSize = Director::getInstance()->getVisibleSize();
auto gear = Sprite3D::create("model/gear.obj");
// 空の親ノードを作る
auto wrapper = Node::create();
wrapper->setPosition(visibleSize.width / 2.0, visibleSize.height / 2.0);
// 親ノードを回転させる
wrapper->setRotation3D(Vec3(30, 0, 30));
auto rotation = RotateBy::create(10, Vec3(0, 360, 0));
// 回転アニメーションは歯車に付ける
gear->runAction(RepeatForever::create(rotation));
wrapper->addChild(gear);
this->addChild(wrapper);
空ノードを作り、そちらを回転させてから、子ノードに対して回転アニメーションを適応させたら上手く行った。
Unityとかで良くやる、Empty GameObjectでモデルをラップして回転させる、みたいなテクニックがほぼそのまま使えるようだ。
position3D
やrotation3D
は、なぜかSprite3D
ではなくNode
のメソッドになっていたのはこういうことだったのか。
どうでもいいですけど、cocos2d::Sprite3D
みたいなネームスペース気持ち悪いですね。3D機能が充実したら分離されるのだろうか・・・・・・。