【cococos 2 d】shaderを使用

32709 ワード

組み込みshaderの使用
cococos 2 d-xのshaderの作成と使用については、この記事のcococos 2 d-x shaderソースコード解析を参照してください.
まず、次に使用するいくつかの画像リソースをアップロードします.画像はネット上から来ています.この文章から参考にしてください.http://www.cocoachina.com/bbs/read.php?tid=1693873
ソース画像jpg
【cocos2d】使用 shader_第1张图片
法線マップwater_normal.jpg
【cocos2d】使用 shader_第2张图片
内蔵shaderを使用するのは簡単で、1つのkey値でGLProgramCacheバッファからGLProgramに直接取り出し、ノードに設定すればいいです.デフォルトshaderのkey値はGLProgramで定義されます
auto sprite = Sprite::create("colormap.jpg");
sprite->setPosition(visibleSize / 2);
addChild(sprite);
auto program = ShaderCache::getInstance()->programForKey(GLProgram::SHADER_NAME_POSITION_GRAYSCALE);
sprite->setShaderProgram(program);

ここで使用するSHADER_NAME_POSITION_GRAYSCALEは、頂点シェーダおよびフラグメントシェーダがそれぞれccPositionTextureColor_noMVP_vertおよびccPositionTexture_GrayScale_fragである画像をグレー表示する機能である.
ccPositionTextureColor_noMVP_vert頂点シェーダにCC_を乗算しないMVPMatrix行列は、デフォルトではこの行列に乗ります.これは2.xローカル座標を世界座標に変換するための習慣.そして3.x頂点はshaderに入る前から変換されているので、このマトリクスに乗らなくてもいいです.バンドだけです.noMVPのシェーダはCC_に乗らないMVPMatrix行列
//ccPositionTextureColor_noMVP_vert
const char* ccPositionTextureColor_noMVP_vert = STRINGIFY(
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;

#ifdef GL_ES
varying lowp vec4 v_fragmentColor; varying mediump vec2 v_texCoord; #else varying vec4 v_fragmentColor; varying vec2 v_texCoord; #endif void main() { gl_Position = CC_PMatrix * a_position; v_fragmentColor = a_color; v_texCoord = a_texCoord; } );

ccPositionTexture_GrayScale_fragは色ごとに数値を乗算し、グレーの効果を達成します.
//ccPositionTexture_GrayScale_frag
const char* ccPositionTexture_GrayScale_frag = STRINGIFY(

#ifdef GL_ES
precision mediump float; #endif varying vec4 v_fragmentColor; varying vec2 v_texCoord; void main(void) vec4 c = texture2D(CC_Texture0, v_texCoord); gl_FragColor.xyz = vec3(0.2126*c.r + 0.7152*c.g + 0.0722*c.b); gl_FragColor.w = c.w; ); );

実行結果
【cocos2d】使用 shader_第3张图片
カスタムシェーダーの使用
まず、完全なコードを先に
auto sprite = Sprite::create("colormap.jpg");
sprite->setPosition(visibleSize / 2);
addChild(sprite);

//   ,        
auto fragSource = (GLchar*)(String::createWithContentsOfFile(FileUtils::getInstance()->fullPathForFilename("water.fs"))->getCString());

//   ,   GLProgram
//     
auto glProgram = GLProgramCache::getInstance()->getProgram("water_frag_shader");
if (!glProgram)
{
	//  1
	//glProgram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource);
	//  2
	glProgram = new GLProgram();
	glProgram->initWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource);
	glProgram->link();
	glProgram->updateUniforms();
	glProgram->autorelease();
	//      
	GLProgramCache::getInstance()->addProgram(glProgram, "water_frag_shader");
}

//   ,      GLProgramState
//  1,       
//sprite->setShaderProgram(glProgram);
//  2,   1  
//auto glProgramState = GLProgramState::getOrCreateWithGLProgram(glProgram);
//sprite->setGLProgramState(glProgramState);
//  3,      
auto glProgramState = GLProgramState::create(glProgram);
sprite->setGLProgramState(glProgramState);

//   ,   uniform     
auto normalMapTexture = TextureCache::getInstance()->addImage("water_normal.jpg");
glProgramState->setUniformTexture("u_normalMap", normalMapTexture);

このプログラムは、クリップシェーダを使用する必要がある水波効果を実現し、頂点シェーダはデフォルトのccPositionTextureColor_noMVP_vertシェーダを使用します.シェーダプログラムを作成するには4つのステップに分かれ、最初のステップはシェーダソースコードを読み込みます.第2歩、GLProgramを作成して、ここで2つの方式を列挙して、実は第2の方式は第1の方式の内部の実現で、この2つの方式は同じで、GLProgramを作成した後にそれをGLProgramCacheバッファに追加することができて、このように次回同じGLProgramを使う時直接バッファから取ればいいです;第3のステップでは、GLProgramStateを作成し、ノードに設定します.ここには3つの方法がリストされています.同じように、前の2つの方法は同じです.第3の方法はgetOrCreateWithGLProgram方法を使用してGLProgramStateを取得しないので、GLProgramStateCacheバッファをスキップします.最後のステップは必須ではありません.シェーダプログラムでuniform変数が使用可能な場合は、GLProgramState->setUniform*()で値を設定します.
GLProgramStateのデフォルトではGLProgramStateCacheバッファを使用して管理されます.このような利点は、同じGLProgramStateを繰り返し作成する必要がないことです.欠点は、GLProgramStateが変更されると、このシェーダを使用するすべてのノードが影響を受けることです.次に、2つのスプライトが2つのシェーダを使用し、1つのノードがGLProgramStateのGLProgramを変更するテストを行います.
void HelloWorld::testMutilShader()
{
	Size visibleSize = Director::getInstance()->getVisibleSize();

	//    Sprite
	auto sprite = Sprite::create("colormap.jpg");
	sprite->setPosition(visibleSize / 2);
	addChild(sprite);

	auto fragSource = (GLchar*)(String::createWithContentsOfFile(FileUtils::getInstance()->fullPathForFilename("water.fs"))->getCString());
	auto glProgram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource);
	sprite->setShaderProgram(glProgram);
	auto normalMapTexture = TextureCache::getInstance()->addImage("water_normal.jpg");
	sprite->getGLProgramState()->setUniformTexture("u_normalMap", normalMapTexture);

	//    Sprite
	auto sprite2 = Sprite::create("colormap.jpg");
	sprite2->setPosition(visibleSize / 4);
	addChild(sprite2);

	sprite2->setShaderProgram(glProgram);

	//      Sprite   GLProgram
	auto newProgram = ShaderCache::getInstance()->programForKey(GLProgram::SHADER_NAME_POSITION_GRAYSCALE);
	sprite2->getGLProgramState()->setGLProgram(newProgram);
}

実行結果
【cocos2d】使用 shader_第4张图片
sprite 2のGLProgramを変更した後、spriteのGLProgramも変更されたことがわかります.同じGLProgramStateを使用しているからです.以下、GLProgramStateCacheを使用しない別の方法に変更します.
void HelloWorld::testMutilShader2()
{
	Size visibleSize = Director::getInstance()->getVisibleSize();

	//    Sprite
	auto sprite = Sprite::create("colormap.jpg");
	sprite->setPosition(visibleSize / 2);
	addChild(sprite);

	auto fragSource = (GLchar*)(String::createWithContentsOfFile(FileUtils::getInstance()->fullPathForFilename("water.fs"))->getCString());
	auto glProgram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource);
	auto glProgramState = GLProgramState::create(glProgram);
	sprite->setGLProgramState(glProgramState);
	auto normalMapTexture = TextureCache::getInstance()->addImage("water_normal.jpg");
	sprite->getGLProgramState()->setUniformTexture("u_normalMap", normalMapTexture);

	//    Sprite
	auto sprite2 = Sprite::create("colormap.jpg");
	sprite2->setPosition(visibleSize / 4);
	addChild(sprite2);

	sprite2->setShaderProgram(glProgram);
	glProgramState = GLProgramState::create(glProgram);
	sprite2->setGLProgramState(glProgramState);
	sprite2->getGLProgramState()->setUniformTexture("u_normalMap", normalMapTexture);

	//      Sprite   GLProgram
	auto newProgram = ShaderCache::getInstance()->programForKey(GLProgram::SHADER_NAME_POSITION_GRAYSCALE);
	sprite2->getGLProgramState()->setGLProgram(newProgram);
}

実行結果
【cocos2d】使用 shader_第5张图片
sprite 2のGLProgramを変更した後、spriteはGLProgramStateが互いに独立しているため、影響を受けないことがわかります.
luaでshaderを使用する
luaでshaderを使うのは基本的にc++と同じで、内蔵shaderを使う方法です
local sprite = display.newSprite("colormap.jpg")
:move(display.center)
:addTo(self)

local glProgram = cc.GLProgramCache:getInstance():getGLProgram("ShaderUIGrayScale")
-- local glProgramState = cc.GLProgramState:getOrCreateWithGLProgram(glProgram)
-- sprite:setGLProgramState(glProgramState)
sprite:setGLProgram(glProgram)

カスタムシェーダーの使用方法
local glProgram = cc.GLProgramCache:getInstance():getGLProgram("water_shader")
if not glProgram then
	glProgram = cc.GLProgram:createWithFilenames("water.vs", "water.fs")
	cc.GLProgramCache:getInstance():addGLProgram(glProgram, "water_shader")
end
sprite:setGLProgram(glProgram)
local normalTexture = cc.TextureCache:getInstance():addImage("water_normal.jpg")
sprite:getGLProgramState():setUniformTexture("u_normalMap", normalTexture)