• 2D
  • Godot 4.0 pre-alpha 1: fog of war shader

I am trying to make a texture which is rendered over game objects, but is not rendered at all where it is within a unit's range. I think this should be possible using textures if I pass a lot of uniform information, including the newly supported uniform arrays. My main problem is converting each fragment's coords to world coords and then checking if it is in unit range.

I have also tried Light2D with mask mode as a Fog of War solution. But Light2D in mask mode has complex and unexpected behavior when the lights overlap; that is, when two units can see the same space.

Below's my shader, but I'm not sure it makes sense and it might just be easier to start over, so take it with a grain of salt.

Arrays in shaders are fixed length and can't be extended after being initilalized, right?

And it looks like they can't have a size larger than... something... it seems like?

They are fixed size I believe but I haven't messed with Godot 4 much.

How can I get the global position for this fragment? 4.0 docs says this:

But I don't think that can be right, because no matter how I set the variables, it either shows all the fog or none of it.

Omg, I put it in _ready(), of course the fog doesn't work in the editor! How dumb can I get! It works now!

Now I'm getting this error every frame:

I'm not sure what's going on yet. But commenting out array_length in the shader (and references to it in the for loop) "fixes" it. So uniform ints are weird? Even more confusingly, if you declare the uniform int before the other uniforms, this error is removed?

I should probably state that I'm using 4.0 because it supports uniform arrays, so I can't see how to implement this kind of fog of war without it.

I can't see in the debugger on the local tree that the shadar params were altered, but that's probably just how shader params work.

Current theory is that unit_positions are always filled with zeroes, meaning somehow the set_param doesn't work. This is based off the evidence that changing the vec2(0,0) in the shader code to vec2(1,1) causes the whole thing to be discarded. Night all. Shader code is hard :|

It's weird to think that if I just rendered all this manually I wouldn't be having these problems.

The arrays in GDScript also need a fixed size (even if you just fill them with zero vectors).

I think you're wrong. Append does in fact increase the size of the array. And if you append stuff repeatedly to an empty array [], then print said array, you will find all the stuff you printed.

Yes, in GDScript. But the data you send to the shader needs to be the same size as defined in the shader. That is why you are getting an error. Because you are sending an array of a different size.

Ah okay, my bad. But unit_positions.size() is 1024, same as the shader, same as unit_ranges.size().

Okay, now that bug is gone for some reason, but the uniform array parameters aren't getting set. For example, this does not discard:

despite this:

printing this:

And yet, when I do a similar thing with bools instead of arrays, it does discard:

This is very confusing and frustrating. Maybe I have to give up for now. There doesn't seem to be another way to implement fog of war on multiple units. Maybe I should submit a ticket?

Maybe I should submit a ticket?

Yes, please open an issue on GitHub with a minimal reprodution project attached.