Support custom outputs for ShaderMaterial

Hi there,

I’m trying to implement a shader that outputs an ivec4 to a RenderTargetTexture with a format of RGBA_INTEGER and type of INT but at the moment I’m limited by the shader preprocessor which automatically adds an out vec4 glFragColor output.

If there’s not currently a way around this, I’m happy to look into making an issue and pull request for this feature.

Thanks!

Welcome aboard!

You can override the default behavior of injecting glFragColor. See how it is done in this PG:

Thanks for this suggestion. I did notice that using #extension GL_EXT_draw_buffers : require would suppress the preprocessor from adding the default glFragColor target though I’m not super keen on that API as GL_EXT_draw_buffers is designed for WebGL1 and doesn’t necessarily express what I’m trying to do when using a single framebuffer.
I wonder if there would be some value in adding a field to IShaderMaterialOptions which would suppress the default output, or perhaps doing something like:

#define CUSTOM_OUTPUT
layout (location = 0) out ivec4 outTarget;

This, however, only solves half of the problem though, because at the moment Babylon doesn’t support clearing render targets with an INT or UNSIGNED_INT type as it requires calling clearBufferiv and clearBufferuiv respectively.
I imagine this would only be a small change to ThinEngine.clear() along the lines of:

(...)
 if (this._currentRenderTarget) {
                const textureFormat = this._currentRenderTarget.texture?.format;
                if (textureFormat === Constants.TEXTUREFORMAT_R_INTEGER ||
                    textureFormat === Constants.TEXTUREFORMAT_RG_INTEGER ||
                    textureFormat === Constants.TEXTUREFORMAT_RGB_INTEGER || 
                    textureFormat === Constants.TEXTUREFORMAT_RGBA_INTEGER) {

                        const textureType = this._currentRenderTarget.texture?.type;
                        if (textureType === Constants.TEXTURETYPE_UNSIGNED_INTEGER ||
                            textureType === Constants.TEXTURETYPE_UNSIGNED_SHORT) {
                                this._gl.clearBufferuiv(this._gl.COLOR, 0, new Uint32Array([color.r, color.g, color.b, color.a]));
                            } else {
                                this._gl.clearBufferiv(this._gl.COLOR, 0, new Int32Array([color.r, color.g, color.b, color.a]))
                            }

                } else {
                    mode |= this._gl.COLOR_BUFFER_BIT;
                }
            } else {
                mode |= this._gl.COLOR_BUFFER_BIT;
            }
(...)

I appreciate your thoughts!

Regarding the fragment output, I think we can detect automatically if there’s already a declaration:

And I did another PR to handle clearing integer textures:

Let me know if it’s ok for you!

1 Like

That looks perfect! Thanks for your help.