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
相关产品推荐
相关产品推荐

