cocos2dx 3.0对shader做了一些优化,渲染树也做了一点更改,本来之前刚刚在2.x上摸到了点门路,到了3.0又不能用了。
最近想在一些角色(flash导出的骨骼动画)上添加一些简单的shader效果,本来在2.x上是比较简单的事情,和set到精灵的方法一样。结果到3.0发现不行了。网上也搜了好多,基本都是对精灵的解决方案,没有发现对骨骼动画的解决方法,于是研究了一下,虽然效果出来,但是总觉得不对劲。而且现在对于需要动态改变shader参数,也就是动态改变shader效果并应用在骨骼动画上还没有解决,借此抛砖引大牛,希望帮忙解决一下。
首先上代码
//
//---------shaderArmature.h
///
#include "cocos2d.h"
#include "extensions/cocos-ext.h"
#include "cocostudio/CocoStudio.h"
USING_NS_CC_EXT;
USING_NS_CC;
using namespace cocostudio;
class ShaderArmature : public Armature
{
public:
ShaderArmature();
virtual ~ShaderArmature();
bool init(const std::string& name);
static ShaderArmature *create(const std::string& name) ;
virtual void initShader(bool shaderState);
// void setBackgroundNotification();
virtual void draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) override;
// void listenBackToForeground(Ref *obj);
void setIceState();
void setUsuaState();
void setblurState();
void setbanishState();
void setfrozenState();
void setgrayState();
void setinvisState();
void setmirrorState();
void setpoisonState();
void setstoneState();
protected:
std::string _fragSourceFile;
std::string _vertSourceFile;
GLchar * fragSource;
GLchar * vertSource;
};
//
//------shaderArmature.cpp
//
#include "shaderArmature.h"
ShaderArmature::ShaderArmature(){
}
ShaderArmature::~ShaderArmature(){
}
bool ShaderArmature::init(const std::string& name)
{
return Armature::init(name);
}
ShaderArmature *ShaderArmature::create(const std::string& name)
{
ShaderArmature *armature = new ShaderArmature;
if (armature && armature->init(name))
{
armature->autorelease();
return armature;
}else{
CC_SAFE_DELETE(armature);
return nullptr;
}
}
void ShaderArmature::initShader(bool shaderState){
for (auto& object : _children)
{
if (Bone *bone = dynamic_cast(object))
{
Node *node = bone->getDisplayRenderNode();
if (nullptr == node)
continue;
Skin *skin = static_cast(node);
///-----addCustome shader
if(shaderState){
auto program = new GLProgram();
program->initWithByteArrays(vertSource, fragSource);
skin->setShaderProgram(program);
program->autorelease();
CHECK_GL_ERROR_DEBUG();
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
CHECK_GL_ERROR_DEBUG();
program->link();
CHECK_GL_ERROR_DEBUG();
program->updateUniforms();
CHECK_GL_ERROR_DEBUG();
}else{//addNormal shader
skin->setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
}
}
}
}
void ShaderArmature::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated)
{
Armature::draw(renderer, transform, transformUpdated);
}
void ShaderArmature::setIceState(){
_fragSourceFile ="IceShader.fsh";
_vertSourceFile ="IceShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setUsuaState(){
initShader(false);
}
void ShaderArmature::setblurState(){
_fragSourceFile ="Blur.fsh";
_vertSourceFile ="Blur.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setbanishState(){
_fragSourceFile ="BanishShader.fsh";
_vertSourceFile ="BanishShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setfrozenState(){
_fragSourceFile ="FrozenShader.fsh";
_vertSourceFile ="FrozenShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setgrayState(){
_fragSourceFile ="GrayScalingShader.fsh";
_vertSourceFile ="GrayScalingShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setinvisState(){
_fragSourceFile ="InvisibleShader.fsh";
_vertSourceFile ="InvisibleShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setmirrorState(){
_fragSourceFile ="MirrorShader.fsh";
_vertSourceFile ="MirrorShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setpoisonState(){
_fragSourceFile ="PoisonShader.fsh";
_vertSourceFile ="PoisonShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setstoneState(){
_fragSourceFile ="StoneShader.fsh";
_vertSourceFile ="StoneShader.vsh";
fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
```
这个类写好之后在别的场景create出来即可,也可以自己写一个开关通过setXXstate来切换或者关闭shader。
其中initshader里面的写法是参考了创建armature的时候的写法,遍历里面的skin,每个skin都set一个shader,不知道这种办法对不对。下面的这些setXXXstate就是各种shader的状态,比如中毒效果,石化效果,.vsh和.fsh都是从刀塔传奇的shader里面直接拷过来的,也有一两个效果不好使,但是大部分都是有用的。
现在我想实现一些动态的效果,比如骨骼上面的光影会随参数变化而变化,之前在2.x上已经有一些效果,但是3.0就完全摸不到门路了。希望大牛们看到这个可以给出解决方案,也给一些想把简单shader用在骨骼动画上的人一些思路。