Maximum ps_3_0 constant register index (224) exceded

I’m trying to write a shader to do fog of war. I first create a fog effect then I apply a mask to crop it from around a light source. It works with a single light source but I may have multiple light sources.

Because I couldnt have multple pixel shaders for each light source mask, I tried building in a bunch of polygon mask checks into the shader. When trying to expand my effect parameters from:

sublime_text_2022-01-02_20-35-29

to:

sublime_text_2022-01-02_20-34-50

I get the following compile error message:

“maximum ps_3_0 constant register index (224) exceeded - Try reducing number of constants referenced”

Can I not create this many parameters of this size for a pixel shader?

Thanks

Shader constants are limited. You could switch to shader model 4 or 5 to increase the number, but you are probably better off with a completely different solution.

Are you looping over all these vertices in the pixel shader? That would be very wasteful, as it happens for every pixel.

You should probably have a separate texture for the fog of war mask (or use the alpha channel of an existing texture). Render all your lights into this mask with additive blending. In the end you combine the mask with the background to get the final image.

I think because I’m using OpenGL I’m limited to ps_3_0.

Do you know any examples that “renders the mask with additive blending then combines the two”? That sounds like it should work but I don’t know how to approach it.

I don’t have an example ready, but here are the basic steps:

  • If your main scene is not rendered to a render target already, create a render target of the same resolution as the backbuffer, set it (GraphicsDevice.SetRenderTarget), then render the scene like you already do.

  • Create a 2nd render target for the mask. Same resolution again, or lower resolution, if you want. You only need one channel, so it could be a single channel surface format, but you can also just use the standard color format, and ignore all but one channel.

  • Set the mask render target like before, clear to black, then set the blend state to additive: GraphicsDevice.BlendState = BlendState.Additive
    Everything you render from now on will add to (brighten) what’s already there, instead of replacing it.

  • Now render all your lights. How to best do that depends on the situation, but generally you render polygons covering the region of influence for each light, in the simplest case a quad. The polygon should probably get some kind of grayscale gradient shading, depending on what you want the light falloff to look like. This gradient could come from textures, or could be calculated in a custom light shader.

  • Now you have your two render targets, one with the background scene, one with the mask. You now switch back to backbuffer rendering (GraphicsDevice.SetRenderTarget(null)) and render a fullscreen quad using a custom pixel shader, that takes both render targets as input, and outputs the final result.

  • As for the final pixel shader, it will have to sample the two render targets and combine them somehow, in the simplest case something like this:
    float3 finalColor = backgroundCol * mask + fogCol * (1-mask);
    This assumes that a white mask means fully visible, a black mask means maximum fog.

Alternatively instead of creating a 2nd render target for the mask, you could try to use the alpha channel from your main render target, if that’s still available.

Thanks I will give that a try.

I’m just thinking, are those clouds for the fog in a separate render target already? If you are happy with standard alpha blending for the fog effect, you could simplify things a bit, at the cost of flexibility. You wouldn’t need the custom composition shader in this case.

You could render the mask into the alpha channel of that cloud render target. Then the normal scene could be rendered into the backbuffer directly, saving the extra render target.
If you then render a fullscreen quad with BlendState.AlphaBlend and the cloud+mask texture, you should get something similar to what you showed in the video.

I hope I’m not confusing you too much with all those details, but there are just multiple ways to do this.

Yes I vaguely understand the theory but I was able to make my current solution work. I will probably take a stab at this approach if my current solution doesn’t work long-term.