godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.4k stars 21.26k forks source link

Fog volume breaks additive unshaded materials #56374

Closed unfa closed 1 year ago

unfa commented 2 years ago

Godot version

4.0 dev

System information

Arch Linux, KDE Plasma, Radeon RX580, amdgpu driver

Issue description

The plane is textured with a radial gradient and should produce a smooth transition between nothing and white. The fog volume however breaks that and makes edges of the mesh clearly visible, which is not what the mesh is supposed to look like.

1: this is the expected look 2: this is the unexpected look when fog volume interacts with the additive unshaded mesh

image

Steps to reproduce

  1. Create an unshaded additive material with a gradient from black to color.
  2. Add a fog volume and enable fog volume in Environment settings
  3. Make the fog volume overlap the mesh
  4. See as the mesh looses it's indented look

Minimal reproduction project

Fog Volume Additive.zip

clayjohn commented 2 years ago

I don't think this is a bug. The mesh in your example is opaque and set to additive. Additive blending specifies that the resulting color from the shader should be added to whatever is behind it in the render target. In this case, the fog is calculated as part of the mesh's color (making it so the object is no longer plain black) and then added to the fog that is behind it.

The solution is to use a transparent mesh that fades to (0,0,0,0) instead of an opaque mesh that fades to black (0,0,0,1).

To me the big question that arises is, should unshaded meshes receive fog? The issue here arises because the fog color is calculated even for the black parts of the additive mesh.

unfa commented 2 years ago

@clayjohn Thanks, I now understand why this happens. And I think I have an idea on how to avoid it.

BTW, non-volumetric fog also does this: image

Versus: image

Calinou commented 1 year ago

There's a disable_fog render mode you can use in custom shaders, but it's not exposed as a property in BaseMaterial3D. If it's exposed, we could make fog affect unshaded materials, but the documentation would advise you to disable fog on the material in most situations.

Edit: disable_fog is exposed in BaseMaterial3D since 4.2.

Quotring from https://github.com/godotengine/godot/issues/69268:

Fog does not affect unshaded materials in Godot 3, so unless I'm missing something this should not be happening in Godot 4 either

Fog on unshaded materials is a controversial thing – see https://github.com/godotengine/godot/pull/29141. There is no universally right approach here, as many people do need fog to apply on unshaded materials (e.g. in games with a retro art style that don't rely on real-time lighting at all). You may also be using unshaded as a cheap approximation of emissive materials, and you want fog to apply on those materials as well.

EzraT commented 1 year ago

@Calinou Godot4 beta 6 does not seem to recognize a "disable_fog" render mode currently, and if it does exist it would be very helpful if it could indeed also be exposed to BaseMaterial3D, so the old Godot 3 behavior can still be used.

someguynamedjosh commented 1 year ago

For additive materials it looks like you can add:

ALBEDO -= FOG.rgb;

at the end of the shader to remove the fog.

unfa commented 1 year ago

Hmm. Right now have all my additive materials switched to emissive shaded. But.. I get a dark overlay from the parts that should be transparent, even without any fog. Can't win :D

RPicster commented 1 year ago

Hm, from my point of view, this is a bigger problem then it get's credit. It's not possible making a good looking particle effect like e.g. Fire while using fog.

It will change the way the material appears and makes the edges visible. image

From my point of view, disable_fog should be the default and could be exposed as a flag in the StandardMaterial3D. The situations where you want this behaviour are more rare than the situations where it is the expected behaviour (especially with blend_add.

Can we gather some examples of Sitations where one or the other behaviour would be preferable?

unfa commented 1 year ago

I had to get rid of all volumetric fog from Liblast, because no matter what I do I can't get it to not screw up all the unshaded billboards.

bertodelrio256 commented 1 year ago

For additive materials it looks like you can add:

ALBEDO -= FOG.rgb;

at the end of the shader to remove the fog.

This worked for me. additive particles look correct in fog now.

LauraWebdev commented 1 year ago

Having the same problem using a StandardMaterial3D, unshaded and set to additive.

image

@bertodelrio256 @joshua-maros how did you implement your solution?

bertodelrio256 commented 1 year ago

Having the same problem using a StandardMaterial3D, unshaded and set to additive.

image

@bertodelrio256 @joshua-maros how did you implement your solution?

this will not work on a StandardMaterial3D as the fog logic is hard coded. You can right click on your material instance on the mesh and click "convert to shadermaterial" then open the shader code and add ALBEDO -= FOG.rgb at the end of the fragment() function

LauraWebdev commented 1 year ago

@bertodelrio256 Wonderful, thank you very much! image

Calinou commented 1 year ago

@clayjohn Should we add a toggle in StandardMaterial3D that performs ALBEDO -= FOG.rgb? Perhaps this could be exposed as a Fog Affect enum property:

clayjohn commented 1 year ago

disable_fog

I really think we should just add a disable_fog render mode like we have in sky shaders and then expose a toggle in StandardMaterial3D. ALBEDO -= FOG.rgb is a nice workaround, but its not something we should integrate into the engine code as it is a total hack.

I'm not sure why fog is affecting unshaded materials in the first place. In 3.x unshaded materials were not affected by fog. In hindsight, we probably should have just made 4.0 match 3.x, but here we are. I don't want to break compatibility at this point, so the best solution is to allow users to disable fog

LauraWebdev commented 1 year ago

I don't want to break compatibility at this point

Is that a realistic situation? At this state, without this hack, unshaded additive materials are just broken, how would a fix break compatibility (genuinely trying to understand here)?

Calinou commented 1 year ago

At this state, without this hack, unshaded additive materials are just broken, how would a fix break compatibility (genuinely trying to understand here)?

Unshaded materials don't necessarily use the additive blend mode, and additive blend mode materials aren't necessarily unshaded. Some people may now be relying on the current behavior in 4.x, so changing it breaks expectations.

In my experience, you don't want unshaded materials to always ignore fog (when using unshaded opaque materials to improve rendering performance), and you sometimes want shaded materials to ignore fog (e.g. to allow players to be better seen in low-density fog). This is why exposing an enum that would adjust a disable_fog spatial shader render mode makes the most sense to me.

LauraWebdev commented 1 year ago

At this state, without this hack, unshaded additive materials are just broken, how would a fix break compatibility (genuinely trying to understand here)?

Unshaded materials don't necessarily use the additive blend mode, and additive blend mode materials aren't necessarily unshaded. Some people may now be relying on the current behavior in 4.x, so changing it breaks expectations.

In my experience, you don't want unshaded materials to always ignore fog (when using unshaded opaque materials to improve rendering performance), and you sometimes want shaded materials to ignore fog (e.g. to allow players to be better seen in low-density fog). This is why exposing an enum that would adjust a disable_fog spatial shader render mode makes the most sense to me.

Makes sense. Would you say implementing a fix only for this use case (where we know it's just broken) would be out of the question? I can't think of a situation where you would create an unshaded additive Material and actually just want it to be white. (Unless of course the project structure doesn't allow for such pinpointed fixes)

QbieShay commented 1 year ago

Adding to this, it seems like the consensus is that it should be a flag, because it should be on for some cases, off for others.

clayjohn commented 1 year ago

To add a new render mode:

define the mode here: https://github.com/godotengine/godot/blob/ff5c884153d1c15bde3ee87aa295e52bec3a6340/servers/rendering/shader_types.cpp#L229-L230

Add a render mode define here: https://github.com/godotengine/godot/blob/ff5c884153d1c15bde3ee87aa295e52bec3a6340/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp#L709 here: https://github.com/godotengine/godot/blob/ff5c884153d1c15bde3ee87aa295e52bec3a6340/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp#L612 and here: https://github.com/godotengine/godot/blob/ff5c884153d1c15bde3ee87aa295e52bec3a6340/drivers/gles3/storage/material_storage.cpp#L1360

And add the corresponding defines to the shaders

Calinou commented 1 year ago

I'd also recommend adding a Disable Fog property to BaseMaterial3D, so you can toggle this on built-in materials.

lemilonkh commented 1 year ago

Is someone working on this? Otherwise I would give it a shot as it is affecting the visuals of my game quite heavily.

jitspoe commented 6 months ago

For additive blending, I really think we should be using a fog color of 0, regardless of what the fog color is set to, that way stuff that has additive blending (like fire FX) will fade out in the distance with everything else covered by fog. I can't think of a scenario where you'd want the fog additively blending onto the scene -- that should probably not be the default behavior and there could be an option to switch to that behavior if so desired, but I think it should "just work" (and fade) by default.