@All Community and @stevetranby @dotsquid
I have a very basic shader setup, it run perfectly but after some time it seems to be lagged by gpu. I have no idea what is causing this issue, can any one pls take a look at it.
here is My shader setup
void ShaderSprite::setShaders(std::string fileName){
this->getTexture()->setAntiAliasTexParameters();
if(fileName=="")return;
GLchar * fragmentSource = (GLchar*) String::createWithContentsOfFile( FileUtils::getInstance()->fullPathForFilename( fileName.c_str()).c_str() )->getCString();
// Create a GLProgram with the shader file.
auto p = GLProgram::createWithByteArrays( ccPositionTextureColor_noMVP_vert, fragmentSource );
// Create a GLProgramState from the GLProgram.
auto glProgramState = GLProgramState::getOrCreateWithGLProgram( p );
this->setGLProgramState( glProgramState );
}
ShaderSprite is a Custom class which extends Sprite. And here is my shader.fsh file
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord;
const float speed = 4.0;
const float bendFactor = 0.1;
void main()
{
float height = 1.0 - v_texCoord.y;
float offset = pow(height, 2.5);
// 4 multiply by sin since it gives us nice bending
offset *= (sin(CC_Time[1] * speed) * bendFactor);
vec4 normalColor = texture2D(CC_Texture0, fract(vec2(v_texCoord.x + offset, v_texCoord.y))).rgba;
gl_FragColor = vec4(normalColor);
}
and this is how i use this shader
ShaderSprite *grass2 = ShaderSprite::createSprite("grass2.png", "shader.fsh");
grass2->setScale(2);
grass2->setPosition(Vec2(visibleSize.width/2,visibleSize.height/2));
this->addChild(grass2,8);
I don’t know if this fits your case, but I made the experience that trigonometric functions in shaders can’t handle big values very well.
One way to fix it could be to change renderer/CCGLProgram.cpp
, line 928
(in cocos2d-x-3.6
) from
setUniformLocationWith4f(_builtInUniforms[GLProgram::UNIFORM_TIME], time/10.0, time, time*2, time*4);
to
setUniformLocationWith4f(_builtInUniforms[GLProgram::UNIFORM_TIME], fmodf(time*4.0f, 2.0f*M_PI), time, time*2, time*4);
and changing your shader.fsh
sin function line to
offset *= (sin(CC_Time[0]) * bendFactor);
But only of course if you don’t use CC_Time[0]
somewhere else…
Maybe you don’t even want to use sin()
in your fragment shader and let the CPU handle it in CCGLProgram.cpp
. For example with CC_SinTime[0]
(that would be on line below in CCGLProgram.cpp
: line 929
:
setUniformLocationWith4f(_builtInUniforms[GLProgram::UNIFORM_SIN_TIME], sinf(time*4.0), time/4.0, time/2.0, sinf(time));
And in your shader.fsh
:
offset *= CC_SinTime[0] * bendFactor;
Again: only do this, if you don’t use CC_SinTime[0]
somewhere else…
Thanx for the info, i will check that(i am bit occupied in something else) and try to change my shader accordingly and report back, what i was thinking is passing offset
value as a uniform, and calculate it in update
, any thoughts about that. I am not sure about changing CC_Time[]
, as i am unsure if CC_Time[]
is being used internally by engine itself somewhere else.
As far as I know, CC_Time
isn’t used in any of the default shaders. I changed it in one of my projects and didn’t have any problems.
But you could of course use your own uniform just to be one the safe side.
Calculating offset
in update
won’t work, because it depends on v_texCoord
which is different for every fragment. But you should definitely take speed
and bendFactor
out of the shader since they are constant for every fragment.
Pass a uniform called offsetMultiplier
or something similar… (= sinf(time * speed) * bendFactor
)
I think i will go with offsetMultiplier
approcah, as i can manage my shader behaviour whenever i want it to, i’ll share an update when i am done. Thanx for you time
i did scrap constants and sine calculations from shader and passed them as uniforms. Interestingly sinf(time * speed) * bendFactor)
gives a funny curve, something i didn’t anticipated but fits perfectly in my use case, it gives a more natural feeling. Thanx
Strange. But great it worked out for you.