How do I tint objects with the colour of my lightmap?

For an idea of what I’m trying to do, see this screenshot of Half-Life:

Notice how the marine on the right is tinted the colour of the level’s lightmap, while the other models are a different colour.

How do I automatically apply this same effect to models in the Unity engine? I’m not using realtime shadows at all, so being able to do this will really help with the look of my game. I know about light probes, but those are the exact opposite of what I want to do; placing them is far too time-consuming and difficult for a rather poor result.

By using light probes.
Use legacy light probes to get the effect from the screenshot, or APV to make it look more modern and per pixel

I understand light probes (at least a little bit), but why can’t Unity do this automatically if a game engine from 1996 is able to?

Because it has to be baked and it might bring performance issues if used poorly (eg breaking batching).
The tool is there, if you need it, use it

I’m guessing Half Life 1 sampled the lightmap directly underneath the characters? Graphics have advanced a bit since that era, and many games switched to using light probes, like the person above me mentions.

You can implement something like what Half Life does yourself if you’d like. I wrote a quick n’ dirty little script to demonstrate:

using UnityEngine;

public class SampleLightmapUnder : MonoBehaviour
{
    void Update()
    {
        // Shoot a ray downwards
        Physics.Raycast(transform.position, Vector3.down, out var hit);
      
        // Get mesh renderer of the hit object, presumably the ground
        var mr = hit.collider.GetComponent<MeshRenderer>();

        // Get lightmap of the renderer
        var lightmap = LightmapSettings.lightmaps[mr.lightmapIndex].lightmapColor;

        // Sample the lightmap at the hit point
        var sampleUV = hit.lightmapCoord;
        var sampleColor = lightmap.GetPixelBilinear(sampleUV.x, sampleUV.y);

        // Set the color of the object to the sampled color
        GetComponent<MeshRenderer>().material.color = sampleColor;
    }
}

Note: This does require the lightmapped meshes being hit to have a Mesh Collider (in order to use RaycastHit.lightmapCoord), and also requires the lightmap textures to have Read/Write enabled in their import settings.

1 Like