You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity 2D中如何判断物体是否被光源照射?

Unity 2D检测物体是否被光源照射的优化方案

不用逐个给光源加匹配形状的触发器,这几个方案更高效:

1. 直接采样光照强度

Unity的2D光照系统可以直接在物体位置采样光照值,判断是否处于照亮状态:

using UnityEngine;
using UnityEngine.Rendering.Universal;

public class LightDetection : MonoBehaviour
{
    [SerializeField] private float lightThreshold = 0.1f; // 低于此值视为未被照亮
    private Light2D[] allLights;

    void Start()
    {
        allLights = FindObjectsOfType<Light2D>();
    }

    void Update()
    {
        bool isLit = false;
        Vector3 worldPos = transform.position;

        // 遍历所有光源,采样物体位置的光照强度
        foreach (var light in allLights)
        {
            // 先判断是否在光源范围内
            float distance = Vector2.Distance(worldPos, light.transform.position);
            if (distance > light.pointLightOuterRadius) continue;

            // 采样光照强度(URP 2D管线适用)
            LightUtility.GetPixelLightmapData(out var lightmapData, LightType.Point);
            Vector2 uv = LightUtility.WorldToLightmapUV(worldPos, light);
            Color lightColor = lightmapData.GetPixelBilinear(uv.x, uv.y);
            
            if (lightColor.grayscale > lightThreshold)
            {
                isLit = true;
                break;
            }
        }

        Debug.Log($"物体是否被照亮:{isLit}");
    }
}

注意:需要确保场景启用了2D光照贴图,且光源设置为参与光照贴图计算;如果是纯实时光照,也可以用Light2D.CalculateLightAmount方法直接计算位置的光照值。

2. 光线投射检测视线+光源范围

通过射线判断物体与光源之间是否有遮挡,同时结合光源的范围和角度(针对聚光灯):

using UnityEngine;

public class LightDetectionRaycast : MonoBehaviour
{
    [SerializeField] private LayerMask obstacleLayer; // 遮挡物的图层
    private Light2D[] allLights;

    void Start()
    {
        allLights = FindObjectsOfType<Light2D>();
    }

    void Update()
    {
        bool isLit = false;
        Vector2 objectPos = transform.position;

        foreach (var light in allLights)
        {
            Vector2 lightPos = light.transform.position;
            float distance = Vector2.Distance(objectPos, lightPos);

            // 超出光源范围直接跳过
            if (distance > light.pointLightOuterRadius) continue;

            // 聚光灯额外判断角度
            if (light.lightType == LightType.Spot)
            {
                Vector2 directionToObject = (objectPos - lightPos).normalized;
                float angle = Vector2.Angle(light.transform.up, directionToObject);
                if (angle > light.spotAngle / 2) continue;
            }

            // 发射射线检测遮挡(忽略自身和光源的碰撞体)
            RaycastHit2D hit = Physics2D.Raycast(lightPos, objectPos - lightPos, distance, obstacleLayer);
            if (hit.collider == null || hit.collider.gameObject == gameObject)
            {
                isLit = true;
                break;
            }
        }

        Debug.Log($"物体是否被照亮:{isLit}");
    }
}

优势:能精准处理遮挡情况,不受光照贴图分辨率限制;可以优化成只检测物体附近的光源,提升性能。

3. 利用URP 2D光照回调

如果使用URP 2D管线,可以通过光照更新事件实时获取物体的光照状态:

using UnityEngine;
using UnityEngine.Rendering.Universal;

public class LightDetectionCallback : MonoBehaviour
{
    [SerializeField] private float lightThreshold = 0.1f;
    private bool isLit;

    void OnEnable()
    {
        Light2D.LightmapUpdateEvent += OnLightmapUpdated;
    }

    void OnDisable()
    {
        Light2D.LightmapUpdateEvent -= OnLightmapUpdated;
    }

    void OnLightmapUpdated()
    {
        Vector3 worldPos = transform.position;
        Color lightColor = LightUtility.GetLightmapColor(worldPos);
        isLit = lightColor.grayscale > lightThreshold;
        Debug.Log($"物体是否被照亮:{isLit}");
    }
}

适合需要实时响应光照变化的场景,比如光源移动、开关时自动更新状态。


内容的提问来源于stack exchange,提问作者Simone Bernardini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:52:45