はじめまして、今回のエンジニアブログ担当の安藤です。
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); }
実行結果
しっかり3Dになってます。
今回はソースコードが冗長になるので板ポリゴンにしましたが、
頂点を増やして箱型にすると、より3Dっぽさが際立つのではないでしょうか。
次回はcocos2d-xならではの実践テクニックを紹介したいと思います。