Search Issue Tracker

Won't Fix

Won't Fix in 6000.6.X

Votes

0

Found in

6000.0.65f1

6000.3.3f1

6000.4.0b3

6000.5.0a4

6000.6.0a1

Issue ID

UUM-131681

Regression

Yes

Terrain shadows changing shape when they are viewed at a different angle from the same position

Lighting

-

How to reproduce:
1. Open the attached “IN-125410“ project
2. Open the “SampleScene“ Scene
3. In Scene view, position your Scene Camera so the “CentreView“ GameObject is in the center of the Scene view and both “LeftCube“ and “RightCube“ are at the edges of the Scene view and fully visible
4. In Scene view, rotate your Scene Camera so the “RightCube“ is at the center of the Scene view
5. Note how the Terrain shadow looks on the ground
6. In Scene view, rotate your Scene Camera so the “LeftCube“ is at the center of the Scene view
7. Observe the Terrain shadow

Actual result: The Terrain shadow does not have the same shape
Expected result: The Terrain shadow has the same shape

Reproducible with: 2023.2.0a11 (73bfca82bf31), 6000.0.65f1, 6000.3.3f1, 6000.4.0b3, 6000.5.0a4
Not reproducible with: 2023.1.0a1, 2023.2.0a10 (67f0519c7f6d)

Reproducible on: Windows 11
Not reproducible on: No other environments tested

  1. Resolution Note:

    Thank you for reporting a bug to Unity.

    The behavior you are seeing is caused by a performance optimization in the terrain heightmap LOD system. Terrain mesh tessellation is determined per-frame based on the camera frustum. Patches outside the frustum are simplified aggressively to reduce GPU load, and since shadow casting geometry spans a much wider area than what is visible to the camera, those out-of-frustum patches render at a coarser level of detail. When you change camera angle, different patches move in and out of the frustum, and the shadow-casting geometry changes with it. This is working as designed after the optimization was introduced, and we will not be reverting it because the performance impact on large terrain scenes would be too severe.

    You can enforce a minimum tessellation level on terrain patches regardless of frustum visibility using the Terrain.heightmapMinimumLODSimplification property. Setting this to a non-zero value prevents the heightmap from simplifying below a certain detail level even for geometry outside the camera frustum, which stabilizes shadow-caster geometry.

    Attach the following script component to any GameObject in your scene:

    using System.Collections.Generic;
    using UnityEngine;

    public class TerrainMinimumLOD : MonoBehaviour
    {
    // Higher values enforce more detail. Valid range: [0, log2(heightmapResolution / 17)].
    // 0 = no limit (default). Start with 1 or 2 and increase until shadows are stable.
    [SerializeField, Min(0)]
    int m_MinimumLODSimplification = 3;

    readonly Dictionary<Terrain, int> m_OriginalValues = new();

    void OnEnable()
    {
    foreach (var terrain in Terrain.activeTerrains)
    {
    m_OriginalValues[terrain] = terrain.heightmapMinimumLODSimplification;
    terrain.heightmapMinimumLODSimplification = m_MinimumLODSimplification;
    }
    }

    void OnDisable()
    {
    foreach (var (terrain, original) in m_OriginalValues)
    {
    if (terrain != null)
    terrain.heightmapMinimumLODSimplification = original;
    }
    m_OriginalValues.Clear();
    }
    }

    Alternatively, you can set the property directly on each Terrain instance in the Inspector under Basic Terrain > Minimum Detail Limit, or via script:

    foreach (var terrain in Terrain.activeTerrains)
    terrain.heightmapMinimumLODSimplification = 3;

    Tuning guidance
    The valid range is 0 to log2(heightmapResolution / 17). For a 513-resolution heightmap that is 0–4, for a 1025-resolution heightmap it is 0–5. A value of 1 or 2 is usually sufficient to eliminate shadow instability. Be aware that higher values increase the number of vertices the GPU must process for terrain that is not in view, so profile on your target hardware and use the lowest value that resolves the visible artifacts.

    We recognize this is a frustrating regression and apologize for the inconvenience. The workaround above gives you per-terrain control, so you can apply it selectively to only the terrains whose shadows are visible and keep the performance cost minimal.

    We have reviewed the issue carefully, and in this case, the development team is unable to prioritize fixing this bug. There are a number of reasons we make this decision, including the impact and severity of the issue across our user and customer base, and the possibility that future plans may solve the problem in a different way, or that a workaround for the bug may be available.

    Today we will be closing this case. Thank you again for taking the time to report this issue, and please let us know if there is anything else that changes the impact or severity of this issue.

  2. Resolution Note (6000.6.X):

    Thank you for reporting a bug to Unity.

    The behavior you are seeing is caused by a performance optimization in the terrain heightmap LOD system. Terrain mesh tessellation is determined per-frame based on the camera frustum. Patches outside the frustum are simplified aggressively to reduce GPU load, and since shadow casting geometry spans a much wider area than what is visible to the camera, those out-of-frustum patches render at a coarser level of detail. When you change camera angle, different patches move in and out of the frustum, and the shadow-casting geometry changes with it. This is working as designed after the optimization was introduced, and we will not be reverting it because the performance impact on large terrain scenes would be too severe.

    You can enforce a minimum tessellation level on terrain patches regardless of frustum visibility using the Terrain.heightmapMinimumLODSimplification property. Setting this to a non-zero value prevents the heightmap from simplifying below a certain detail level even for geometry outside the camera frustum, which stabilizes shadow-caster geometry.

    Attach the following script component to any GameObject in your scene:

    using System.Collections.Generic;
    using UnityEngine;

    public class TerrainMinimumLOD : MonoBehaviour
    {
    // Higher values enforce more detail. Valid range: [0, log2(heightmapResolution / 17)].
    // 0 = no limit (default). Start with 1 or 2 and increase until shadows are stable.
    [SerializeField, Min(0)]
    int m_MinimumLODSimplification = 3;

    readonly Dictionary<Terrain, int> m_OriginalValues = new();

    void OnEnable()
    {
    foreach (var terrain in Terrain.activeTerrains)
    {
    m_OriginalValues[terrain] = terrain.heightmapMinimumLODSimplification;
    terrain.heightmapMinimumLODSimplification = m_MinimumLODSimplification;
    }
    }

    void OnDisable()
    {
    foreach (var (terrain, original) in m_OriginalValues)
    {
    if (terrain != null)
    terrain.heightmapMinimumLODSimplification = original;
    }
    m_OriginalValues.Clear();
    }
    }

    Alternatively, you can set the property directly on each Terrain instance in the Inspector under Basic Terrain > Minimum Detail Limit, or via script:

    foreach (var terrain in Terrain.activeTerrains)
    terrain.heightmapMinimumLODSimplification = 3;

    Tuning guidance
    The valid range is 0 to log2(heightmapResolution / 17). For a 513-resolution heightmap that is 0–4, for a 1025-resolution heightmap it is 0–5. A value of 1 or 2 is usually sufficient to eliminate shadow instability. Be aware that higher values increase the number of vertices the GPU must process for terrain that is not in view, so profile on your target hardware and use the lowest value that resolves the visible artifacts.

    We recognize this is a frustrating regression and apologize for the inconvenience. The workaround above gives you per-terrain control, so you can apply it selectively to only the terrains whose shadows are visible and keep the performance cost minimal.

    We have reviewed the issue carefully, and in this case, the development team is unable to prioritize fixing this bug. There are a number of reasons we make this decision, including the impact and severity of the issue across our user and customer base, and the possibility that future plans may solve the problem in a different way, or that a workaround for the bug may be available.

    Today we will be closing this case. Thank you again for taking the time to report this issue, and please let us know if there is anything else that changes the impact or severity of this issue.

Add comment

Log in to post comment

All about bugs

View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.