Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement distance fade and transparency #54222

Merged
merged 2 commits into from
Oct 28, 2021

Conversation

JFonS
Copy link
Contributor

@JFonS JFonS commented Oct 25, 2021

Based on #50654, supersedes it.

The built-in ALPHA in spatial shaders comes pre-set with a per-instance transparency value. Multiply by it if you want to keep it.

The transparency value of any given GeometryInstance3D is affected by:

  • Its new transparency property.
  • Its own visibility range when the new visibility_range_fade_mode property is set to "Self".
  • Its parent visibility range when the parent's fade mode is set to "Dependencies".

The "Self" mode will fade-out the instance when reaching the visibility range limits, while the "Dependencies" mode will fade-in its dependencies.

Per-instance transparency is only implemented in the forward clustered renderer, support for mobile should be added in the future.

Quick HLOD fade example:

fade.mp4

JFonS and others added 2 commits October 25, 2021 11:37
The built-in ALPHA in spatial shaders comes pre-set with a per-instance
transparency value. Multiply by it if you want to keep it.

The transparency value of any given GeometryInstance3D is affected by:
   - Its new "transparency" property.
   - Its own visiblity range when the new "visibility_range_fade_mode"
     property is set to "Self".
   - Its parent visibility range when the parent's fade mode is
     set to "Dependencies".

The "Self" mode will fade-out the instance when reaching the visibility
range limits, while the "Dependencies" mode will fade-in its
dependencies.

Per-instance transparency is only implemented in the forward clustered
renderer, support for mobile should be added in the future.

Co-authored-by: reduz <[email protected]>
@Calinou
Copy link
Member

Calinou commented Oct 25, 2021

Is support for dithered fade still planned? I remember reduz talking about a way to set different material transparency modes, including one that would automatically replace alpha blending with dithering. This way, you can also use dithered transparency for traditional materials (even if they don't use LOD).

For instance, having the following options in BaseMaterial3D as an enum:

  • Opaque
  • Alpha Blend (Translucent)
  • Alpha Scissor
  • Alpha Dither

The current implementation is useful, but I fear it'll run into issues with transparency sorting for objects that have multiple materials (or multiple overlapping objects with LOD).

@JFonS
Copy link
Contributor Author

JFonS commented Oct 25, 2021

That sounds useful indeed. Right now, users can implement dithering themselves in a spatial shader by reading the ALPHA built-in and discarding, but having it built-in would be nice.

It should be a matter of adding the "Dithering" option along the other transparency settings and then taking the code from

if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) {
if (!RenderingServer::get_singleton()->is_low_end()) {
code += " {\n";
if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
code += " float fade_distance = abs((INV_CAMERA_MATRIX * WORLD_MATRIX[3]).z);\n";
} else {
code += " float fade_distance=-VERTEX.z;\n";
}
code += " float fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n";
code += " int x = int(FRAGCOORD.x) % 4;\n";
code += " int y = int(FRAGCOORD.y) % 4;\n";
code += " int index = x + y * 4;\n";
code += " float limit = 0.0;\n\n";
code += " if (x < 8) {\n";
code += " if (index == 0) limit = 0.0625;\n";
code += " if (index == 1) limit = 0.5625;\n";
code += " if (index == 2) limit = 0.1875;\n";
code += " if (index == 3) limit = 0.6875;\n";
code += " if (index == 4) limit = 0.8125;\n";
code += " if (index == 5) limit = 0.3125;\n";
code += " if (index == 6) limit = 0.9375;\n";
code += " if (index == 7) limit = 0.4375;\n";
code += " if (index == 8) limit = 0.25;\n";
code += " if (index == 9) limit = 0.75;\n";
code += " if (index == 10) limit = 0.125;\n";
code += " if (index == 11) limit = 0.625;\n";
code += " if (index == 12) limit = 1.0;\n";
code += " if (index == 13) limit = 0.5;\n";
code += " if (index == 14) limit = 0.875;\n";
code += " if (index == 15) limit = 0.375;\n";
code += " }\n\n";
code += " if (fade < limit)\n";
code += " discard;\n";
code += " }\n\n";
}
} else {
code += " ALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n";
}
}
and adapting it to use the per-instance fade value.

Also, some care should be taken so that objects with dithered transparency go into the opaque render list instead of the transparent one.

I'll add it to my backlog, but I have some other things to work on before this. If anyone wants to have a go, feel free :)

@akien-mga akien-mga merged commit e2deec6 into godotengine:master Oct 28, 2021
@akien-mga
Copy link
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants