Shader texture issue (memory related?)

Hi Codeans,

I have hit a shader issue in my current project for which any suggestions would be greatly appreciated…

The context is that I have a large View class which handles the drawing of all my maps and sprites. The maps are 9x the iPad screen size, e.g. 3072x2304 and the user can zoom in and pan around the maps. When the map is selected from the Introduction screen the ‘colour map’ is displayed and then a series of features are drawn on the map, water, grassland, forest, ruins etc. I ‘bake’ the ‘non-interactive’ features into the map using setContext(colourMap) and this all works fine…

The positioning of these features are done based on a greyscale heightmap where I calculate height percentiles, then populate the map at different percentiles with randomised positioning and clustering. The water is done using a shader which is also baked into the colour map by passing in the colour map and the greyscale map and a water level, and just using simple arithmetic to work out whether the heightmap value of the current position on the colour map is below the water level, and if it is then shade it blue…

This all works fine, but I then wanted the ability to raise or lower the water level. So, I created a 1x1 transparent image, applied that to a mesh rectangle the size of the colour map, and applied the same shader…

This appeared to be working fine, and I could then tween the water level value on the fly and the shader did its stuff…

However, when I exit the map (the user can long press and get an Exit or Resume menu that shows all the current statistics) to get back to the Intro screen, and then select either the same, or a different map, it may work a second time, but generally the whole screen suddenly turns blue. Very occasionally I see the correct water level just before it goes blue…

I added some ‘if’ statements around the heightmap check inthe shader and it appears that the elevation map is either not loaded or corrupted, it’s almost as though there is some sort of ‘shader texture cache’ that persists… Debugging the shader is tricky but it appears the heightmap values are zero

What I have done:

  • A lot of profiling to ensure dangling references etc. are cleared when exiting the view
  • My realtime memory display using collectgarbage(…) drops back to a very low value when I am back in the intro screen
  • There are no other global references to the mesh or the shader
  • The colourmaps are 2-3MB in size, the height maps from 0.5-1.5MB

The shader really is very basic, I include it FYI:

void main()
{
    lowp vec4 col = texture2D( texture, vTexCoord); // colour map
    float height = texture2D( elevation, vTexCoord).r; // height map
    if(height == 0.) {
        gl_FragColor = vec4(1,0,0,1);    // test that paints the screen red if elev value is zero
    }
    else {
        if(height <= shaderVal) { // water level check, shaderVal = water level
            // Do the deep blue sea, clamped at a value
            gl_FragColor = vec4(0.2, 0.2, (height/shaderVal)*(height/shaderVal), 0.85/((height/shaderVal)));
            if(gl_FragColor.b < 0.7) {
                gl_FragColor.b = 0.7;
            }
        }  
        else {       
            gl_FragColor = col;
        }
    }  
}

Any thoughts Codeans?

Cheers,
brookesi

@brookesi - my first thought is that if you have multiple meshes, ie the water mesh sits on top of the terrain, the OpenGL can get confused between them when they get too close together.

If you only have one mesh, but you’re colouring it as shown in your shader above, I don’t see a problem with your code. I don’t see where the 1x1 transparent image comes in, however.

I would be checking anything that changes shader settings, but I guess you’ve done that.

Can you post more code, that demonstrates the problem?

btw, you are calculating height/shaderVal 3 x for each pixel. Why not calculate it in Codea and pass it through as a uniform? Saves some effort.

Hi @ignatz,

Thank you, my explanation was not clear. I only have one mesh which is drawn after the colour map is sprited, so the water mesh overlays a sprited image.

The water mesh just has to be a transparent overlay with certain pixels painted blue, so I create this with a 1px transparent image assigned as the texture to the shader on a mesh which is 3072x2304, rather than assign a large transparent image as the shader…if that make sense…

I cant easily post more code as its thousands of lines and dependencies, but I’ll see if I can reproduce this on a simpler project…

Regarding the ‘height’ variable, this is extracted from the heightmap, but I can certainly use a local variable rather thandoing the division three times :wink:

Si

@brookesi - it’s difficult to know without seeing more code, sorry. The most common error would be something that messed with the shader’s texture settings and prevented it working properly, but I’m sure you’ve checked that.