cocos2d x-sprite3d
TRANSCRIPT
Sprite3D Tips@第5回cocos2d-x勉強会 株式会社アカツキ 河野 洋志
自己紹介• 河野 洋志(こうの ひろし)
• 株式会社アカツキ エンジニア
• サウザンドメモリーズを担当
• 主にサーバサイド
• Ruby on Rails, MySQL, Redis, AWS, etc…
• cocos2d-x…? C++…?
残念ながら…
• サウザンドメモリーズはcocos2d-x製ではありません
• 弊社ではcocos2d-xを利用した別のプロジェクトが進行中です!
!?
• ということで…
• 本来開発・運用で得られた知見をお話できればベストだったのですが知見ゼロ
• cocos2d-x界隈で最近おもしろそうなものないかなーということで ver 3.1 で新しく追加されたSprite3Dについて簡単にご紹介したいと思います
目次• cocos2d-x Ver 3.1で追加されたSprite3Dクラスの紹介
• Sprite3Dの使い方
• シェーダー拡張
• Sprite3Dで(まだ?)できないこと
目次• cocos2d-x Ver 3.1で追加されたSprite3Dクラスの紹介
• Sprite3Dの使い方
• シェーダー拡張
• Sprite3Dで(まだ?)できないこと
Sprite3Dとは
• 3Dモデルをスプライトとして扱うことができるクラス
• 対応フォーマットは .obj
• 呼び出し時にテクスチャ画像をsetするauto model3d = Sprite3D::create("sample.obj");!model3d->setTexture(“sample.png”);
API
• 3D APIはもちろん、これまでの2Dスプライトで使えたAPIはほとんど使える
• Sprite3DクラスはSpriteクラス同様Nodeクラスを継承しているため
• 移動、拡縮、その他アクションなど
Position3D• z軸は手前が正、奥が負
• パースがかかっているので、設定したx, yよりも手前側は画面縁に、奥側は画面中央寄りに配置される
auto model_a = Sprite3D::create("sample.obj");!model_a->setTexture("sample.png");!model_a->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height * 2 / 3, 400));!this->addChild(model_a);!!auto model_b = Sprite3D::create("samle.obj");!model3_b->setTexture("samle.png");!model3_b->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height / 2, 0));!this->addChild(model_b);!!auto model_c = Sprite3D::create("samle.obj");!model3_c->setTexture("samle.png");!model3_c->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height * 1 / 3, -400));!this->addChild(model_c);
model_a
model_b
model_c
Rotation3D• Vec3を渡して3次元的なrotationを設定できる
auto model_a = Sprite3D::create("sample.obj");!model_a->setTexture("sample.png");!model_a->setRotation3D(Vec3(90.0f, 0.0f, 0.0f));!model_a->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height * 2 / 3, 0));!model_a->setScale(15);!this->addChild(model_a);!!auto model_b = Sprite3D::create("sample.obj");!model_b->setTexture("sample.png");!model_b->setRotation3D(Vec3(0.0f, 90.0f, 0.0f));!model_b->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height / 2, 0));!model_b->setScale(15);!this->addChild(model_b);!!auto model_c = Sprite3D::create("sample.obj");!model_c->setTexture("sample.png");!model_c->setRotation3D(Vec3(0.0f, 0.0f, 90.0f));!model_c->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height / 3, 0));!model_c->setScale(15);!this->addChild(model_c);
移動・拡縮• 移動
!
!
• 拡縮
void HelloWorld::onTouchesEnded(const std::vector<cocos2d::Touch *> &touches, cocos2d::Event *event)!{! for (auto touch: touches) {! auto location = touch->getLocation();! auto action = MoveTo::create(0.5f, location);! model3d->runAction(action);! }!}
void HelloWorld::onTouchesEnded(const std::vector<cocos2d::Touch *> &touches, cocos2d::Event *event)!{! for (auto touch: touches) {! auto location = touch->getLocation();! auto seq = Sequence::create(ScaleTo::create(0.1f, 75.f),! ScaleTo::create(0.1f, 30.f),! ScaleTo::create(0.1f, 45.f), NULL);! model3d->runAction(seq);! }!}
回転• z軸方向にしか回転してくれない
!
!
• Vec3クラスを渡すと3次元的に回転できる
void HelloWorld::onTouchesEnded(const std::vector<cocos2d::Touch *> &touches, cocos2d::Event *event)!{! for (auto touch: touches) {! auto location = touch->getLocation();! auto action = RotateBy::create(0.5f, 360);! model3d->runAction(action);! }!}
void HelloWorld::onTouchesEnded(const std::vector<cocos2d::Touch *> &touches, cocos2d::Event *event)!{! for (auto touch: touches) {! auto location = touch->getLocation();! auto action = RotateBy::create(0.5f, Vec3(location.x, location.y, 30));! model3d->runAction(action);! }!}
回転(余談)!
• 上記メソッドを使うとペラペラになって面白い
RotateBy::create(float duration, float deltaAngleZ_X, float deltaAngleZ_Y);
目次• cocos2d-x Ver 3.1で追加されたSprite3Dクラスの紹介
• Sprite3Dの使い方
• シェーダー拡張
• Sprite3Dで(まだ?)できないこと
シェーダー拡張• シェーダーを拡張することでトゥーンレンダリング(っぽいこと)などができるようになる
シェーダ拡張• cpp-testの中に含まれるEffect3DOutlineクラスについて解説していきます
• cocos2d-x/tests/cpp-tests/Classes/Sprite3DTest
• 3Dプログラミングについては詳しくないので詳しいところまでソースは追いません…(追えませんでした)
• 間違いがあれば是非指摘してください
3DEffectクラス• 3Dエフェクトに関する抽象クラス
class Effect3D : public Ref!{!public:! virtual void drawWithSprite(EffectSprite3D* sprite, const Mat4 &transform) = 0;!protected:! Effect3D() : _glProgramState(nullptr) {}! virtual ~Effect3D()! {! CC_SAFE_RELEASE(_glProgramState);! }!protected:! GLProgramState* _glProgramState;!};!
• OpenGLシェーダを格納する _glProgramState プロパティを持つ
• シェーダを描画する drawWithSprite() メソッド
3DEffectOutlineクラス• シェーダーを読み込んで描画を実行するクラス
class Effect3DOutline: public Effect3D!{!public:! static Effect3DOutline* create();! ! void setOutlineColor(const Vec3& color);! ! void setOutlineWidth(float width);! ! void drawWithSprite(EffectSprite3D* sprite, const Mat4 &transform);! !protected:! ! Effect3DOutline();! virtual ~Effect3DOutline();! ! bool init();! ! Vec3 _outlineColor;! float _outlineWidth;!public:! static const std::string _vertShaderFile;! static const std::string _fragShaderFile;! static const std::string _keyInGLProgramCache;! static GLProgram* getOrCreateProgram();! !};!
• 初期化時にシェーダーを読み込む
• drawWithSprite()の実装もこのクラスにあります
シェーダ• Resources/Shaders3D 以下に配置
• OutLine.frag
• OutLine.vert
uniform vec3 OutLineColor;!uniform vec4 u_color;!!void main(void)!{! gl_FragColor = vec4(OutLineColor,1.0) * u_color;!}
attribute vec4 a_position;!attribute vec3 a_normal;!uniform float OutlineWidth;!!void main(void)!{! vec4 pos = CC_MVPMatrix * a_position;! vec4 normalproj = CC_MVPMatrix * vec4(a_normal, 0);! normalproj = normalize(normalproj);! pos.xy += normalproj.xy * (OutlineWidth * (pos.z * 0.5 + 0.5));! ! gl_Position = pos;!}
EffectSprite3Dクラス• Sprite3Dクラスを継承して3DEffectを追加できるように拡張
class EffectSprite3D : public Sprite3D!{!public:! static EffectSprite3D* createFromObjFileAndTexture(const std::string& objFilePath, const std::string& textureFilePath);! void setEffect3D(Effect3D* effect);! void addEffect(Effect3D* effect, ssize_t order);! void eraseEffect(Effect3D* effect);! ssize_t getEffectCount() const;! Effect3D* getEffect(ssize_t index) const;! virtual void draw(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override;!protected:! EffectSprite3D();! virtual ~EffectSprite3D();! ! std::vector<std::tuple<ssize_t,Effect3D*,CustomCommand>> _effects;! Effect3D* _defaultEffect;! CustomCommand _command;!};!
EffectSprite3Dクラス• 使い方
auto model = EffectSprite3D::createFromObjFileAndTexture("sample.obj", "sample.png");!model->setScale(45);!model->setRotation3D(Vec3(265.0f, 265.0f, 265.0f));!model->setPosition3D(Vec3(visibleSize.width / 2, visibleSize.height / 2, 0));!!auto effect = Effect3DOutline::create();!effect->setOutlineColor(Vec3(1,1,0));!effect->setOutlineWidth(0.03f);!model->addEffect(effect, 1);! !this->addChild(model);
目次• cocos2d-x Ver 3.1で追加されたSprite3Dクラスの紹介
• Sprite3Dの使い方
• シェーダー拡張
• Sprite3Dで(まだ?)できないこと
できないこと• タップイベントの取得
• getBoundBox()でRectが取得できない
• 物理演算
• アニメーション
• モデルの表示、アクション以上のことはできない
auto position = model3d->getPosition3D();!CCLOG("position: X:%f Y:%f Z:%f", position.x, position.y, position.z);!auto rect = model3d->getBoundingBox();!CCLOG("bounding box: MinX:%f MaxX:%f MinY:%f MaxY:%f", rect.getMinX(), rect.getMaxX(), rect.getMinY(), rect.getMaxY());!!// cocos2d: position: X:320.000000 Y:480.000000 Z:0.000000!// cocos2d: bounding box: MinX:320.000000 MaxX:320.000000 MinY:480.000000 MaxY:480.000000
おや、cocos2d-xのようすが…
期待ag…と思ったらマージされてたhttps://github.com/cocos2d/cocos2d-x/pull/7085
こいつ…動くぞ!
Animation3D• Animate3DクラスはActionとして実装されている
• Animation3DからAction(Animate3D)をcreateする
• .c3t フォーマットに対応
auto animation = Animation3D::getOrCreate("Sprite3DTest/girl.c3t");!if (animation)!{! auto animate = Animate3D::create(animation); ! auto spawn = Spawn::create(animate, RotateBy::create(animation->getDuration(), Vec3(0.0f, 90.0f, 0.0f)), NULL);! sprite->runAction(RepeatForever::create(spawn));!}
まとめ• Sprite3Dについて簡単に紹介しました
• Position, Rotate, Action, etc…
• つい先日アニメーションもマージされたので、今後に期待
• でもここまでやるならUni(ry
参考
• cocos2d-x公式のサンプルプロジェクト
• https://github.com/cocos2d/cocos2d-x/tree/v3/tests/cpp-tests/Classes/Sprite3DTest
• EarthWarrior3D
• https://github.com/chukong/EarthWarrior3D
ご清聴ありがとうございました