[SOLVED]GLSL - Shader Keep Accumulating

Hello, it s me again. I have a small problem, I made a new Shader vert frag and material to control the health bar and mana in my game.

The problem is, the game keep accumulating Shader(m) and the game start lagging.
It accumulate quite fast. i can reach 20 000 in 1 minute.

The code part that seem to make a faillure is when i update the health using this line of code.

@Override
public void simpleUpdate(float tpf) {
    elapsedTime += tpf;
    barMat.setFloat("ValueLeft", elapsedTime);
    if(elapsedTime >= 1f){
        elapsedTime = 0f;
    }
}

I will add all the material and shader just to make sure everyone can explain what i m doing wrong.

MaterialDef Bar {
 
MaterialParameters {
Texture2D DiffuseMap
Vector4 Color
Float ValueLeft
Boolean Use_VertexColor
Vector3 CamPos
// Alpha threshold for fragment discarding
Float AlphaDiscardThreshold

}
 
Technique {
LightMode SinglePass
VertexShader GLSL120:   MatDefs/UI/StatsBar/Bar.vert
FragmentShader GLSL120: MatDefs/UI/StatsBar/Bar.frag
 
WorldParameters {
WorldViewProjectionMatrix
WorldViewMatrix
}
 
Defines {
DIFFUSEMAP : DiffuseMap
VERTEX_COLOR : Use_VertexColor
DISCARD_ALPHA : AlphaDiscardThreshold
COLOR: Color
VALUE_LEFT: ValueLeft
}
 
}
 
 
}

Frag:

#ifdef DIFFUSEMAP
    uniform sampler2D m_DiffuseMap;
    varying vec2 texCoord;
#endif


varying vec4 DiffuseSum;

#ifdef VALUE_LEFT
    uniform float m_ValueLeft;
#endif

#ifdef COLOR
    uniform vec4 m_Color;
#endif

uniform float m_AlphaDiscardThreshold;

void main(void)
{

    #ifdef DIFFUSEMAP
        vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord);
    #else
        vec4 diffuseColor = m_Color;
    #endif

    float alpha = DiffuseSum.a;
    if(alpha < VALUE_LEFT){
        discard;
    }


    gl_FragColor =  diffuseColor;
}

Vert:

uniform mat4 g_WorldViewProjectionMatrix;
uniform mat4 g_WorldViewMatrix;

uniform sampler2D m_DiffuseMap;
uniform vec4 m_Color;
 
attribute vec3 inPosition;
attribute vec2 inTexCoord;
 
 
uniform float m_ValueLeft;

varying vec4 Color;
varying vec4 DiffuseSum;
 
#ifdef VERTEX_COLOR
attribute vec4 inColor;
#endif
 
void main()
{
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);

if(inTexCoord.x >= 0.1)//control les vertext affecter par le movement(tout les vertext en haut de 0.1f en position seront bouger
{
    DiffuseSum = vec4(1,0,0,0);
} else {
    DiffuseSum = vec4(1,0,0,1);
}
//Color = vec4(1,1,1,1);

}

I already had the same problem and i will try to explain what i have understood.

The thing is you setup a variable each frame which is the target of a define. Then each time a variable is changed if this variable has a define associated, the shader is reevaluated which means a new shader is created.

In conclusion each time you change your variable you create a new shader which consume memory.

I avoid this by affecting default value for constant changing variable (each frame) and do all the checking job in the shader.

Ok i get the first part but i don’t get the work around.

Can you Tell by my code what could be change if possible to make this possible? But thank you for the explanation at least i know what to work around for now.

I think i found something here, seem if i read correctly i could probably use a Vector2f and then link this vector pointer to the material definition then modify the value in the vector2f instead to modify the value directly.

Edit: Everything work perfectly after this thank you @haze for the tips, Now i can implement the health bar correctly :smiley:

The key is that changing a variable linked to a define regenerates the shader every time. So if you are changing a value once per frame then you are generating a new shader once per frame.

If you want to change a value once per frame then don’t link it to a define. In fact, I’d go so far to say that if you want to change a particular material parameter relatively often then don’t link it to a define. There is no requirement to do this linking.

There is also no great reason to do this:

#ifdef VALUE_LEFT
    uniform float m_ValueLeft;
#endif

Just let the uniform exist all the time.

Yes I ve done the correction already, I ve read the post i’ve linked and you were explaining most of the stuff there. Everything seem to work quite fine now.

I’m going to try to add a overlaying texture and move the texture coordinate over time to make an animation now :slight_smile:

This is a very cheap way of making nice effects. I did it already :slight_smile:

Btw, you can pass Vector2f and add it directly to your UV

    #ifdef IS_GLOW_DELTA
        gl_FragData[3] = texture2D(m_GlowMap, newTexCoord + m_GlowUVDelta);
    #else
        gl_FragData[3] = texture2D(m_GlowMap, newTexCoord);
    #endif

It lets you to use it with defines without shader recompilation.

Also, you need to remember that for every instance of such animated object you need an instance of the material. It will let you to animate each object in a different way, for example each object can have different value and be at different ‘animation frame’.

3 Likes