Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-248194

Only one fog effect can render at a time

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • None
    • 1.18.1, 22w03a, 22w05a, 22w07a, 1.18.2 Pre-release 1, 1.18.2 Pre-release 3, 1.18.2, 22w12a, 22w13a, 22w14a, 22w15a, 22w16b, 22w17a, 22w18a, 22w19a, 1.19 Pre-release 1, 1.19 Pre-release 2, 1.19 Pre-release 3, 1.19 Pre-release 4, 1.19 Pre-release 5, 1.19 Release Candidate 2, 1.19, 22w24a, 1.19.1 Pre-release 1, 1.19.1, 1.19.2, 22w42a, 22w43a, 23w03a, 23w04a, 23w05a, 23w06a, 23w07a, 1.19.4 Pre-release 1, 1.19.4 Pre-release 2, 1.19.4, 23w12a, 23w17a, 23w18a, 1.20 Pre-release 1, 1.20.1, 23w31a, 23w32a, 23w33a, 23w35a, 1.20.2 Pre-release 1, 1.20.2 Pre-release 2, 1.20.2, 23w40a, 23w41a, 23w42a, 23w43a, 23w44a, 24w10a
    • None
    • Confirmed
    • Rendering
    • Normal
    • Gameplay

      Minecraft will only render one fog effect at a time, even if multiple effects should be visible. This leads to several cases where the player can see more clearly then they should normally be able to:

      • A fading Blindness or Darkness effect will take priority over a shadowed, lower-level, still-active effect of the same type
      • A fading Blindness effect will take priority over any Darkness effects
      • The ambient fog is not visible when the player has Blindness or Darkness
        • This results in the player being able to see clearly within the Darkness fog while underwater, as well as in the nether and during the dragon fight in the end at very low render distances
        • More noticeably, this means that underwater fog, nether fog, and dragon-fight end fog are fully inhibited while Blindness is fading out, and while Darkness is fading in or out

      Additionally, under this system, it is not possible to have a smooth transition between fading Blindness/Darkness fog and the ambient fog.

      • For non-overworld fog, the difficulty lies in the fact that the ambient fog and the fading fog effect may be different colors and have differing "densities" (i.e. end distance, beyond which the world is fully obscured, minus start distance, where the fog begins)
      • Overworld (air) fog comes with the additional complication of being cylindrical rather than spherical

      It is possible to fix or mitigate certain cases with small, targeted code adjustments:

      • Blindness/Darkness fog could iterate over the respective effect and any shadowed effects and render based on the one with the highest duration
      • Blindness fog could be de-prioritized in favor of Darkness if its duration is sufficiently low
      • Blindness/Darkness fog could be made to retreat to the correct distance before disappearing. Currently, they retreat to 75% of the player's render distance. When Darkness fog was introduced in 22w12a it retreated to 90%, which improved things in the overworld but worsened them in situations with closer ambient fog; the value was changed to 75% in 22w18a when some Blindness code was reused to fix MC-249527.

      But ultimately, a full rewrite of the fog system is needed. While I'm not a rendering expert, I've done my best to detail what a proper fix might look like below.

      The way it is now, the client chooses one fog effect to render using a bit of if-else logic; with this change it would instead keep track of a list of fog effects. This list always has at least one effect in it: the ambient effect, which can vary based on biome, dimension, time of day and presence in the air or submerged in a liquid. Assuming we have a Color class with the properties r, g, b and a (floats in the range [0, 1]), the FogEffect class would contain the following fields: startDistance (float), endDistance (float), color (Color, a = 1), cylinderHeight (float, 0 for spherical fog effects) and some sort of identifier so that the effects could be modified/removed (i.e. to implement the fading of the Blindness effect). When the fog color for a particular pixel needs to be evaluated, with the float variable distance set to the pixel's world distance to the camera, we run the following:

      float red = 0.0;
      float green = 0.0;
      float blue = 0.0;
      float alpha = 0.0;
      float minEndDistance = Float.POSITIVE_INFINITY;
      int effectsConsidered = 0;
      // Assuming only spherical fog effects
      for(FogEffect e : effectsOrderedAscendingByStartDistance){
          if(e.startDistance > minEndDistance) break;
          minEndDistance = e.endDistance;
          effectsConsidered++;
          red += e.color.r;
          green += e.color.g;
          blue += e.color.b;
          // Fog effect alpha is assumed to be 1.0; this could be easily changed if there were a compelling reason to do so
          alpha = max(alpha, clamp(lerp(e.startDistance, e.endDistance, distance), 0.0, 1.0));
      }
      return new Color(
              red / effectsConsidered,
              green / effectsConsidered,
              blue / effectsConsidered,
              alpha
      );

      This logic should ensure a smooth transition between spherical effects. Obviously cylinderHeight does need to be taken into account somehow;  I'm not sure how to do this off the top of my head.

            Unassigned Unassigned
            clamlol clam lol
            Votes:
            21 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              CHK: