I’ve run into some problems lately which have highlighted a few issues with JUCE’s support for shaders that I think could be improved.
In short - there isn’t a workable solution currently for displaying shaders in JUCE with the ability to set uniforms in a way that integrates nicely with JUCE’s graphics elements. I know people might point to both
OpenGLGraphicsContextCustomShader, but there are problems with each and I’m going to elaborate here.
OpenGLShaderProgram has a very nice interface and you can do lots with it, including setting uniforms. The problem is that (as far as I understand it) the JUCE graphics commands are not executed immediately but instead placed into some kind of stack and drawn later all together. This means that you can’t use
OpenGLShaderProgram to draw on top of other JUCE components. E.g. If you do a background fill - this will appear on top of and obscure your shader. So
OpenGLShaderProgram is fine for drawing gradient background fills, but it is hard to integrate it with JUCE’s graphics and components. E.g I would like to make a ShaderComponent that draws on top of other components and interacts nicely with the JUCE UI.
OpenGLGraphicsContextCustomShader does partially solve this problem - the
fillRect() function that can be called on it is drawn at the same time as the JUCE graphics elements. However, there is no way to set a uniform on a shader like this that will be applied at the correct time.
OpenGLGraphicsContextCustomShader has a function
getProgram() which returns the
OpenGLShaderProgram. The comments say this “can be called when you’re about to use fillRect, to set up any uniforms/textures that the program may require”. I tried calling
use() on the shader program and setting uniforms, but this ended up giving lots of very weird behaviour where uniforms I was setting affected other graphics that were being drawn - there was flickering and seemingly unrelated components being filled with colours they were not drawn with, etc. Not nice.
I notice that the JUCE demo does not include an example showing that this can be done. Is there something I am missing? Or does this not work correctly? If I am incorrect, perhaps someone can provide an example of how this should be done.
However, it seems to me that the uniforms should really be set at the time
shader.program.use(); is called in
setShader() in the
CurrentShader struct in the file juce_OpenGLGraphicsContext.cpp. I have put together a hacky solution that serves my needs (although I need to maintain a fork of JUCE), but a more comprehensive solution would be needed for JUCE users to properly set a range of different uniform types on shaders that integrate well with the JUCE graphics elements. I don’t recommend my changes as they are purely a demonstration of what makes everything work well for me - nevertheless, I’ve included them here in case they are helpful:
Let me know your thoughts!