エンジニア

cocos2d-xで3Dプログラミング〜導入編〜

投稿日:2013年6月25日 更新日:

はじめまして、今回のエンジニアブログ担当の安藤です。

cocos2d-xはv2.0からOpenGL ES 1.x 系はサポートから外されており、固定パイプラインシェーダを使用することが出来なくなっております。
今回はcocos2d-xのUtilityを効率よく使ってプログラマブルシェーダを実装してみようと思います。

まず、新規プロジェクトを用意してください。
新規作成
cocos2d-xの開発環境の設定〜プロジェクト作成まで(iOS篇)

最初はこのような構成になっているのかと思います。
構成
HelloWorldSceneに追記していきます。
追記したソースコードの解説です。

cocos2d-xの描画インタフェースとテクスチャを追記します。

HelloWorldScene.h

public:
 ...
 vartual void draw();
 cocos2d::CCTexture2D* m_pTexture;

今回は導入編ということで自前でシェーダーは書かず、cocos2d-xのシェーダーを利用します。
同時にポリゴンに貼るテクスチャも生成します。HelloWorld.pngはプロジェクト生成時に自動でリソースに追加されます。

HelloWorldScene.cpp

bool HelloWorld::init(){
...
  // シェーダーをセット  
  CCGLProgram* pProgram = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture);
  this->setShaderProgram(pProgram);

  // テクスチャ生成  
  m_pTexture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png");
  return true;
 }

描画の設定をします。
cocos2d-xの描画パイプラインを利用するので、ポリゴン描画の処理のみ記述します。
シェーダーとのデータのやりとりはccGLEnableVertexAttribs / glVertexAttribPointerで頂点単位情報を
glGetUniformLocation / setUniformLocationWithMatrix4fv で全ての頂点に対して一律に処理される情報を送信しています。
シェーダーオブジェクトはgetShaderProgramで呼び出して使うことができます。

HelloWorldScene.cpp

 // cocos2d-x 描画インタフェース  
 void HelloWorldScene::draw(){
   // 深度テスト有効  
   CCDirector::sharedDirector()->setDepthTest(true);
   // 頂点に座標とテクスチャUVのindex指定  
   ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
   // 設定したシェーダーを使用する  
   this->getShaderProgram()->use();

    // 行列の作成  
    static float yaw = 0;
    yaw += 0.01f;
    kmMat4 matProjection;
    kmMat4 matView;
    kmMat4 matWVP;
    kmMat4 matTrans,matScale,matRota,matWorld;
    kmGLGetMatrix(KM_GL_PROJECTION, &matProjection ); // 射影行列を取得  
    kmGLGetMatrix(KM_GL_MODELVIEW, &matView ); // ビュー行列の取得  
    kmMat4RotationPitchYawRoll(&matRota, 0, yaw, 0);
    kmMat4Translation(&matTrans, 250, 150, 100);
    kmMat4Scaling(&matScale, 1,1,1);
    kmMat4Multiply(&matWVP, &matProjection, &matView);
    kmMat4Multiply(&matWorld, &matTrans, &matRota);
    kmMat4Multiply(&matWorld, &matWorld, &matScale);
    kmMat4Multiply(&matWVP, &matWVP, &matWorld);

    // 作成した行列をシェーダーに送る  
    GLuint matrixId = glGetUniformLocation(this->getShaderProgram()->getProgram(), kCCUniformMVPMatrix_s);
    this->getShaderProgram()->setUniformLocationWithMatrix4fv(matrixId, matWVP.mat, 1);

    // テクスチャのバインド  
    ccGLBindTexture2D( m_pTexture->getName() );

    // 頂点をセット  
    const float x=50,y=50;
    kmVec3 pos[4];
    kmVec2 uv[4];
    glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, 0, pos);
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, uv);

    // 描画  
    kmVec3Fill(&pos[0], -x, -y, 0);
    kmVec3Fill(&pos[1], -x, y, 0);
    kmVec3Fill(&pos[2], x, -y, 0);
    kmVec3Fill(&pos[3], x, y, 0);
    kmVec2Fill(&uv[0], 0, 1);
    kmVec2Fill(&uv[1], 0, 0);
    kmVec2Fill(&uv[2], 1, 1);
    kmVec2Fill(&uv[3], 1, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 }

実行結果
完成1
完成2
しっかり3Dになってます。
今回はソースコードが冗長になるので板ポリゴンにしましたが、
頂点を増やして箱型にすると、より3Dっぽさが際立つのではないでしょうか。

次回はcocos2d-xならではの実践テクニックを紹介したいと思います。

採用情報

ワンダープラネットでは、一緒に働く仲間を幅広い職種で募集しております。

-エンジニア
-

© WonderPlanet Inc.