Quick answer: Black spots and splotchy artifacts in baked lightmaps are usually caused by overlapping UV coordinates in the lightmap UV channel (UV2). When multiple faces share the same lightmap space, the baking system produces incorrect lighting for those areas.

Here is how to fix Unity lighting baked lightmap looks wrong. You spend hours setting up your scene lighting, hit "Generate Lighting," wait for the bake to finish — and the result looks terrible. Black splotches on walls, visible seams between objects, light bleeding through geometry, washed-out shadows, or your dynamic characters looking completely disconnected from the environment. Baked lighting in Unity is powerful but unforgiving: small configuration mistakes produce dramatic visual artifacts. This guide walks through every common cause and shows you how to fix each one.

UV Overlap and the Lightmap UV Channel

The most common cause of lightmap artifacts is overlapping UV coordinates in the lightmap UV channel (UV2). Lightmap baking works by projecting lighting information onto a 2D texture, using UV2 coordinates to map each surface point to a texel in the lightmap. If two different faces of your mesh map to the same UV2 space, they share the same lightmap texels, and the baker produces averaged or incorrect lighting for both.

This typically happens when you import a 3D model that does not have a dedicated lightmap UV set. The model's regular UV (UV0) is designed for texturing, not lightmapping — it may have overlapping islands, mirrored UVs, or faces packed into a small UV space. These are all fine for textures but disastrous for lightmaps.

The fix is to enable Generate Lightmap UVs in the model's import settings. Select your mesh in the Project window, open the Inspector, and check "Generate Lightmap UVs" under the Model tab. Unity will create a non-overlapping UV2 layout specifically for lightmapping:

// You can also enable lightmap UV generation via script for batch processing
using UnityEditor;
using UnityEngine;

public class LightmapUVFixer
{
    [MenuItem("Tools/Enable Lightmap UVs on Selected")]
    static void EnableLightmapUVs()
    {
        foreach (Object obj in Selection.objects)
        {
            string path = AssetDatabase.GetAssetPath(obj);
            ModelImporter importer = AssetImporter.GetAtPath(path) as ModelImporter;

            if (importer != null)
            {
                importer.generateSecondaryUV = true;

                // Fine-tune the UV generation parameters
                importer.secondaryUVHardAngle = 88f;   // Angle threshold for chart breaks
                importer.secondaryUVPackMargin = 4f;    // Padding between UV islands (texels)
                importer.secondaryUVAngleDistortion = 8f; // Allow some angle distortion
                importer.secondaryUVAreaDistortion = 15f; // Allow some area distortion

                importer.SaveAndReimport();
                Debug.Log("Enabled lightmap UVs for: " + path);
            }
        }
    }
}

The secondaryUVPackMargin parameter is particularly important. It controls the gap between UV islands in the lightmap. If the margin is too small, adjacent charts bleed into each other, causing light or dark halos at the edges. A value of 4 texels works well for most resolutions. For very high-resolution lightmaps (40+ texels per unit), you may need to increase it to 8.

You can visualize the lightmap UVs in the Scene view by selecting the mesh and looking at the UV Charts overlay in the Lighting window. If you see overlapping colored regions, the lightmap UVs have problems. After enabling Generate Lightmap UVs and reimporting, the colored regions should be cleanly separated with no overlap.

Lightmap Resolution and Texels Per Unit

If your baked lighting looks blurry, blocky, or has stair-stepped shadow edges, the lightmap resolution is too low. Lightmap resolution is measured in texels per world unit — a value of 10 means each world unit (1 meter) gets a 10x10 pixel area in the lightmap. For shadows to look clean, you need enough texels to capture the shadow's edge with reasonable fidelity.

Open Window > Rendering > Lighting and look at the Lightmap Resolution setting in the Lightmapping tab. The default is often too low for indoor scenes with sharp shadows:

// Programmatically adjust lightmap settings for different scene types
using UnityEditor;
using UnityEngine;

public class LightmapConfig
{
    [MenuItem("Tools/Lightmap Settings/Indoor High Quality")]
    static void IndoorHighQuality()
    {
        LightmapEditorSettings.bakeResolution = 40f;  // Texels per unit
        LightmapEditorSettings.padding = 4;            // Texel padding between charts
        LightmapEditorSettings.maxAtlasSize = 2048;    // Max lightmap texture size

        // Use GPU lightmapper for faster iteration
        LightmapEditorSettings.lightmapper =
            LightmapEditorSettings.Lightmapper.ProgressiveGPU;

        Debug.Log("Lightmap settings configured for indoor high quality");
    }

    [MenuItem("Tools/Lightmap Settings/Outdoor Standard")]
    static void OutdoorStandard()
    {
        LightmapEditorSettings.bakeResolution = 15f;
        LightmapEditorSettings.padding = 2;
        LightmapEditorSettings.maxAtlasSize = 2048;

        Debug.Log("Lightmap settings configured for outdoor standard");
    }
}

You can also override the lightmap resolution per-object. Select a MeshRenderer, and in the Inspector under Lightmapping, you will find Scale In Lightmap. A value of 1 uses the global resolution. A value of 2 gives that object double the resolution. This is useful for hero objects or walls that are very close to the camera, where you want crisp shadows without increasing the global resolution (which would dramatically increase bake time and lightmap file size).

Conversely, objects that are far away or barely visible (like distant rooftops or the undersides of tables) can use a Scale In Lightmap of 0.5 or even 0.1 to save lightmap space without visible quality loss.

Seams Between Objects

Lightmap seams are visible dark or bright lines where two objects meet. They occur because each object has its own region in the lightmap, and the texels at the edge of one object's chart do not perfectly match the texels at the edge of the adjacent object's chart. The lighting computation for each edge texel samples from slightly different positions, producing slightly different results.

Unity provides several tools to reduce seams. First, in the Lighting window, enable Stitch Seams in the scene's Lightmap Parameters. You can create a custom Lightmap Parameters asset and assign it to specific objects or use it as the scene default:

// Create a Lightmap Parameters asset with seam stitching enabled
// via script for consistency across team members
using UnityEditor;
using UnityEngine;

public class CreateLightmapParams
{
    [MenuItem("Tools/Create Lightmap Parameters")]
    static void Create()
    {
        LightmapParameters lp = new LightmapParameters();

        // Anti-aliasing settings to reduce chart edge artifacts
        lp.antiAliasingSamples = 8;

        // Push-off to prevent self-shadowing artifacts
        lp.pushoff = 0.03f;

        // Backface tolerance - reject samples that hit backfaces
        lp.backFaceTolerance = 0.7f;

        // Resolution multiplier for this parameter set
        lp.resolution = 1f;

        AssetDatabase.CreateAsset(lp,
            "Assets/Settings/DefaultLightmapParams.asset");
        Debug.Log("Created lightmap parameters asset");
    }
}

Second, increase the lightmap padding. Padding is the gap between different objects' UV charts in the lightmap atlas. With insufficient padding, bilinear filtering at the texture edges samples into adjacent charts, causing color bleeding. A padding of 2 texels is the minimum; 4 is recommended for most cases.

Third, for walls and floors that must appear perfectly seamless, consider merging adjacent meshes into a single object. When faces belong to the same mesh, they share a single UV chart in the lightmap, eliminating the seam entirely. You can use ProBuilder or an external modeling tool to merge geometry, or combine meshes at runtime using CombineMeshes.

Light Probe Placement for Dynamic Objects

Baked lightmaps only affect static objects. Dynamic objects — player characters, NPCs, pickups, projectiles — are lit using light probes, which are interpolated sample points of the baked lighting. If your dynamic objects look flat, overly dark, or disconnected from the environment, the problem is almost always light probe placement.

// Visualize light probe influence at runtime to debug placement
using UnityEngine;

public class LightProbeDebug : MonoBehaviour
{
    [SerializeField] private bool showProbeInfo = true;

    void OnGUI()
    {
        if (!showProbeInfo) return;

        Renderer rend = GetComponent<Renderer>();
        if (rend == null) return;

        // Show which light probe data this object is using
        Vector3 probePosition = rend.lightProbeProxyVolumeOverride != null
            ? rend.lightProbeProxyVolumeOverride.transform.position
            : transform.position;

        SphericalHarmonicsL2 probe;
        Vector4 occlusion;
        LightProbes.GetInterpolatedProbe(
            probePosition, rend, out probe);

        // Display probe data on screen
        GUILayout.Label("Probe position: " + probePosition);
        GUILayout.Label("Light probe count: " + LightmapSettings.lightProbes?.count);
    }
}

Light probes must be placed densely enough to capture lighting transitions. At minimum, place probes at every significant lighting boundary: doorways between bright and dark rooms, under overhangs where shadows begin, near colored light sources, and at the corners of rooms. A common pattern is to create a grid of probes throughout the playable space, with additional probes at lighting transition points.

Probes should be placed at the height where characters' centers are, not on the ground. If your character is 2 meters tall, place probes at approximately 1 meter height. For multi-level buildings, you need separate probe layers for each floor. If a probe is placed between floors (inside a wall or ceiling), it will sample incorrect lighting data.

For large objects that span multiple light probe regions (like a vehicle or large creature), use a Light Probe Proxy Volume (LPPV) instead of a single probe. The LPPV samples multiple probes across the object's bounds, preventing the entire object from being lit uniformly by a single interpolated value.

Mixed Lighting Artifacts

Mixed lighting mode bakes indirect lighting into lightmaps while keeping direct light and shadows in real-time. This gives dynamic objects proper shadows but introduces its own set of artifacts if not configured correctly.

The most common mixed lighting artifact is "double shadows" — a baked shadow on the ground plus a real-time shadow from the same light. This happens when you bake with a Mixed light and the Lighting Mode is set incorrectly. The three Mixed Lighting modes in Unity behave very differently:

// Understanding Mixed Lighting modes programmatically
using UnityEngine;
using UnityEngine.Rendering;

public class MixedLightingInfo : MonoBehaviour
{
    void Start()
    {
        // Log the current mixed lighting mode
        var mode = QualitySettings.shadowmaskMode;
        Debug.Log("Shadowmask mode: " + mode);

        // Check all lights in the scene for mixed mode issues
        Light[] lights = FindObjectsByType<Light>(FindObjectsSortMode.None);
        foreach (Light light in lights)
        {
            if (light.lightmapBakeType == LightmapBakeType.Mixed)
            {
                Debug.Log(string.Format(
                    "Mixed light: {0}, Mode: {1}, Shadow Type: {2}",
                    light.name,
                    light.lightmapBakeType,
                    light.shadows));
            }
        }
    }
}

Baked Indirect bakes only indirect lighting (bounced light). Direct lighting and all shadows are real-time. This is the simplest mode and produces the fewest artifacts, but it is also the most expensive at runtime because every shadow is computed per frame.

Subtractive bakes everything into the lightmap and uses a single real-time shadow for the main directional light on dynamic objects. This is the cheapest mode at runtime but produces the most visible artifacts: dynamic object shadows look disconnected from static shadows, and there is a visible "shadow color" tint on baked shadows that rarely matches the real-time shadows.

Shadowmask uses a separate texture (the shadow mask) to store baked shadow information. Dynamic objects cast real-time shadows near the camera and transition to baked shadows at a distance. This produces the best visual quality but uses the most memory due to the extra shadow mask textures.

If you see visual discontinuities between baked and real-time shadows, check the Shadow Distance in Quality Settings. When the real-time shadow distance is shorter than the visible shadow area, you will see shadows pop in or change appearance as the camera moves. Increase the shadow distance or use the Shadowmask mode's distance control to smooth the transition.

Baking Troubleshooting Checklist

When your lightmap does not look right, work through this checklist systematically. Each item addresses a specific failure mode:

// Editor utility to validate lightmap configuration before baking
using UnityEditor;
using UnityEngine;

public class LightmapValidator
{
    [MenuItem("Tools/Validate Lightmap Setup")]
    static void Validate()
    {
        int issues = 0;

        // Check all static renderers
        MeshRenderer[] renderers = Object.FindObjectsByType<MeshRenderer>(
            FindObjectsSortMode.None);

        foreach (MeshRenderer rend in renderers)
        {
            if (!rend.gameObject.isStatic) continue;

            // Check for missing lightmap UVs
            MeshFilter mf = rend.GetComponent<MeshFilter>();
            if (mf != null && mf.sharedMesh != null)
            {
                if (mf.sharedMesh.uv2 == null || mf.sharedMesh.uv2.Length == 0)
                {
                    Debug.LogWarning("Missing lightmap UVs: " +
                        rend.gameObject.name, rend.gameObject);
                    issues++;
                }
            }

            // Check for Scale In Lightmap of 0
            SerializedObject so = new SerializedObject(rend);
            SerializedProperty scaleProp = so.FindProperty(
                "m_ScaleInLightmap");
            if (scaleProp != null && scaleProp.floatValue <= 0f)
            {
                Debug.LogWarning("Scale In Lightmap is 0 for: " +
                    rend.gameObject.name, rend.gameObject);
                issues++;
            }
        }

        // Check for light probe groups
        LightProbeGroup[] probeGroups = Object.FindObjectsByType<LightProbeGroup>(
            FindObjectsSortMode.None);
        if (probeGroups.Length == 0)
        {
            Debug.LogWarning("No Light Probe Groups in scene. Dynamic objects won't receive baked lighting.");
            issues++;
        }

        if (issues == 0)
        {
            Debug.Log("Lightmap validation passed. No issues found.");
        }
        else
        {
            Debug.LogWarning("Lightmap validation found " + issues + " issues.");
        }
    }
}

Beyond code-level fixes, remember these common pitfalls. Objects must be marked as Static (or specifically Contribute GI) to be included in the lightmap bake. A mesh that looks like it should cast shadows but is not marked static will be invisible to the lightmapper. Double-sided materials need special handling — enable "Two Sided" in the material's lightmap settings or the backfaces will appear black in the lightmap. And if your scene uses a skybox for ambient lighting, make sure the skybox material is assigned in the Lighting window's Environment tab, not just on the camera.

"Lightmapping is 80% preparation and 20% waiting for the bake. Get the UVs, resolution, and probe placement right before you hit Generate, and you will save hours of re-baking."

Related Issues

If your lighting looks correct in the editor but wrong in builds, see our guide on fixing pink/magenta materials, which covers shader stripping during the build process that can affect lighting shaders. For performance issues caused by overly detailed lightmaps, fixing texture memory leaks covers how lightmap textures contribute to memory usage and how to keep them manageable. And if your dynamic objects specifically have lighting problems, fixing sprite renderer visibility covers related rendering order issues.

Enable Generate Lightmap UVs on every imported mesh. Every single one. Future you will thank present you.