I’m a beginner with c++ & cocos2dx. I’m working on a small race game which I’m applying some custom shaders to. The shaders i use work like a charm but after few calls of the replace scene method I observe some strange behavior. First of all the shader itself slows down a lot but at the same time my fps remains the same. This is a part of AppDelegate where I preload the shader and run the MenuScene:
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLView::create("My Game");
director->setOpenGLView(glview);
}
designResolutionSize = glview->getFrameSize();
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::FIXED_HEIGHT);
initConfigByResolution();
// turn on display FPS
director->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0 / 60);
initConfigsFromFile();
UserDefault::getInstance()->setBoolForKey("App_Paused", false);
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("textures/gui_objects.plist");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("textures/world_objects.plist");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("textures/light_objects.plist");
//static method
auto vhsProgram = AppDelegate::ShaderEffect("shaders/vhs.fsh");
ShaderCache::getInstance()->addGLProgram(vhsProgram, "VHS");
// create a scene. it's an autorelease object
auto scene = MenuScene::createScene();
// run
director->runWithScene(scene);
return true;}
GLProgram* AppDelegate::ShaderEffect(const char *frag){
GLchar * fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(frag).c_str())->getCString();
GLchar * vertexSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename("shaders/vertex.vsh").c_str())->getCString();
auto program = GLProgram::createWithByteArrays(vertexSource, fragSource);
return program;}
This Is the MenuScene part where I’m applying the shader on RenderTexture object and calling replaceScene() method:
bool MenuScene::init(){
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
//----------------------------------------------------------------------------------------
m_pTitleMenu = Layer::create();
addChild(m_pTitleMenu);
//============RenderTexture/Shader================
m_pRenderTexture = RenderTexture::create(designResolutionSize.width, designResolutionSize.height, Texture2D::PixelFormat::RGBA8888);
m_pRenderTexture->setPosition(screenCenter);
m_pRenderTexture->getSprite()->getTexture()->setAliasTexParameters();
auto motionEffect = ShaderCache::getInstance()->getGLProgram("VHS");
auto glProgramState = GLProgramState::getOrCreateWithGLProgram(motionEffect);
glProgramState->setUniformVec2("u_resolution", Vec2(designResolutionSize.width,designResolutionSize.height));
m_pRenderTexture->getSprite()->setGLProgram(motionEffect);
m_pRenderTexture->retain();
//============MainMenuBgr======================
auto turbo = Sprite::createWithSpriteFrameName("turbo.png");
turbo->setAnchorPoint(Vec2(0.5, 1.0));
turbo->setPosition(screenCenter.x, screenCenter.y*2);
turbo->setScale(guiScale);
m_pTitleMenu->addChild(turbo);
//=============StartButton=========================
auto startLabel = Label::createWithTTF("Start", "fonts/SPEERG.ttf", 15*screenScale);
startLabel->runAction(RepeatForever::create(Blink::create(1.0, 1)));
auto startButton = MenuItemLabel::create(startLabel, CC_CALLBACK_1(MenuScene::menuStartCallback,this));
startButton->setPosition(screenCenter.x, screenCenter.y * 0.45);
//=================MainMenu============================
m_pMenu = Menu::create(startButton, NULL);
m_pMenu->setPosition(0.0, 0.0);
m_pTitleMenu->addChild(m_pMenu, 1);
return true;}
void MenuScene::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags){
m_pRenderTexture->beginWithClear(0.09, 0.094, 0.176, 0.0);
m_pTitleMenu->visit(renderer, parentTransform, true);
m_pRenderTexture->end();
m_pRenderTexture->visit(renderer, parentTransform, true);}
void MenuScene::menuStartCallback(Ref *Sender){
m_pRenderTexture->release();
auto scene = MenuScene::createScene();
Director::getInstance()->replaceScene(scene);}
The frag:
uniform vec2 u_resolution;
uniform int u_isGame;
varying vec2 v_texCoord;
vec2 screenDistort(vec2 uv){
uv -= vec2(.5,.5);
uv = uv*1.2*(1./1.2+2.*uv.x*uv.x*uv.y*uv.y*2.0);
uv += vec2(.5,.5);
return uv;}
vec2 scandistort(vec2 uv){
float amplitude = 10.0;
float scan1 = clamp(cos(uv.y * 2.0 + CC_Time[1]), 0.0, 1.0);
float scan2 = clamp(cos(uv.y * 2.0 + CC_Time[1] + 4.0) * amplitude, 0.0, 1.0) ;
float amount = scan1 * scan2 * uv.x;
uv.x -= 0.03 * amount;
return uv;}
vec4 noise(){
vec2 uv = gl_FragCoord.xy / sin(u_resolution.xy * CC_Time[1] * 0.01);
vec2 p = sin(uv * 13.0 + uv.x * CC_Time[1] * sin(uv.y));
vec4 noi = vec4(vec3(p.x * p.y), 1.);
return noi;}
void main(void){
vec2 uv = v_texCoord;
uv = scandistort(uv);
uv = screenDistort(uv);
//rgb offset
float offset = 0.0;
offset = (1.0 + cos(CC_Time[1]*1.0)) * 0.15;
offset *= 1.0 + cos(CC_Time[1]*20.0) * 0.2;
offset = pow(offset, 2.0);
offset *= 0.03;
vec3 col;
col.r = texture2D(CC_Texture0,vec2(uv.x+offset,uv.y)).r;
col.g = texture2D(CC_Texture0,vec2(uv.x,uv.y+offset*2.)).g;
col.b = texture2D(CC_Texture0,vec2(uv.x-offset,uv.y)).b;
//scanlines
col *= 0.9+0.1*sin(20.0*CC_Time[1]-uv.y*800.0);
// phosphor vibrance
col *= 0.97+0.02*sin(110.0*CC_Time[1]);
gl_FragColor = vec4(col,1.0) + (noise() * 0.01);}
What am I doing wrong? Besides my decision to learn programming :D.
I’m testing the app on GoClever QUANTUM4 device with Android 4.2.2 loaded and using Cocos2dx v 3.2.