Hi all,
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 OpenGLShaderProgram
and 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
internal 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:
https://github.com/adamstark/JUCE/commit/863cbb749ba321c9bfeaa74736b83fc1e94e92c0
I have seen that the ability to set uniforms in this way has been requested many times (e.g. here & here). So this is clearly something people want.
Let me know your thoughts!
Thanks,
Adam