【cocos2d】使用 shader
来源:互联网 发布:cacti不出数据 编辑:程序博客网 时间:2024/05/16 18:44
使用内置 shader
关于 cocos2d-x 创建和使用 shader 的过程可以参考我这篇文章
cocos2d-x shader 源码解析
先上传接下来会用到的几张图片资源,图片来自网上,参考自这篇文章
http://www.cocoachina.com/bbs/read.php?tid=1693873
源图片 colormap.jpg
法线贴图 water_normal.jpg
使用内置 shader 非常简单,直接通过一个 key 值从 GLProgramCache 缓冲区取到一个 GLProgram,然后设置给 Node 即可;默认 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_vertconst char* ccPositionTextureColor_noMVP_vert = STRINGIFY(attribute vec4 a_position;attribute vec2 a_texCoord;attribute vec4 a_color;\n#ifdef GL_ES\nvarying lowp vec4 v_fragmentColor;varying mediump vec2 v_texCoord;\n#else\nvarying vec4 v_fragmentColor;varying vec2 v_texCoord;\n#endif\nvoid main(){ gl_Position = CC_PMatrix * a_position; v_fragmentColor = a_color; v_texCoord = a_texCoord;});
ccPositionTexture_GrayScale_frag 为每一个颜色乘上一个数值,达到变灰的效果
//ccPositionTexture_GrayScale_fragconst char* ccPositionTexture_GrayScale_frag = STRINGIFY(\n#ifdef GL_ES\n\nprecision mediump float;\n\n#endif\n\n\n\nvarying vec4 v_fragmentColor;\n\nvarying vec2 v_texCoord;\n\n\n\nvoid main(void)\n\n{\n \nvec4 c = texture2D(CC_Texture0, v_texCoord);\n \ngl_FragColor.xyz = vec3(0.2126*c.r + 0.7152*c.g + 0.0722*c.b);\n \ngl_FragColor.w = c.w;\n\n}\n);
运行结果
使用自定义 shader
首先,先上完整代码
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
这个着色器。创建一个着色器程序分为四步,第一步,读取着色器源代码;第二步,创建 GLProgram,这里列了两种方式,其实第二种方式就是第一种方式的内部实现,这两种方式是一样的,创建完 GLProgram 之后可以将其添加到 GLProgramCache 缓冲区,这样下次再使用同样的 GLProgram 时直接从缓冲区取即可;第三步,创建 GLProgramState 并设置给结点,这里列出了三种方式,同样前两种方式是一样的,第三种方式不使用 getOrCreateWithGLProgram 方法来获取 GLProgramState,这样就跳过了 GLProgramStateCache 缓冲区;最后一步不是必须的,如果着色器程序中有用到 uniform 变量,则通过 GLProgramState->setUniform*() 来设置它的值。
GLProgramState 默认是使用 GLProgramStateCache 缓冲区来管理的,这样做的好处是不必重复创建一样的 GLProgramState,缺点是一旦 GLProgramState 发生修改,所有使用该着色器的结点都会受影响。下面做个测试,两个精灵使用两个着色器,然后其中一个结点修改 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);}
运行结果
可以看到,改了 sprite2 的 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);}
运行结果
可以看到,改了 sprite2 的 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)
使用自定义 shader 的方式
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")endsprite:setGLProgram(glProgram)local normalTexture = cc.TextureCache:getInstance():addImage("water_normal.jpg")sprite:getGLProgramState():setUniformTexture("u_normalMap", normalTexture)
- cocos2d lua使用 shader
- 【cocos2d】使用 shader
- 在cocos2d中使用shader
- Cocos2d-x lua shader使用
- cocos2d-x中shader的使用
- cocos2d-x中shader的使用
- cocos2d-x shader(1)-基本概念与使用
- cocos2d-x中shader的使用
- cocos2d-x—使用shader使图片背景透明
- 在Cocos2d-x 3.0中使用opengl shader
- cocos2d-x 使用Shader让精灵变灰
- quick-cocos2d使用shader上色置灰问题
- Cocos2d 使用shader创建圆角图片,以及添加投影
- cocos2d-x shader
- cocos2d opengl- Shader
- cocos2d 水波shader
- Cocos2d-X的shader
- 【玩转cocos2d-x之四十】如何在Cocos2d-x 3.0中使用opengl shader?
- MyBatis 框架 2
- recycleview的添加删除
- Gitlab和AD账号集成,账号登录时报错:Invalid credentials
- msp430g2553硬件IIC
- Android自定义Dialog
- 【cocos2d】使用 shader
- poj 3734 Blocks 矩阵乘法优化dp
- 10月25日云栖精选夜读:全世界都在关注中国企业的互联网架构?云栖大会道出了真相
- 【java】手动释放资源问题
- GOJ 1052
- java注解
- 栈基本操作
- MMU
- 分布式架构的演进过程