85 lines
3.4 KiB
C#

using System.Collections;
using UnityEngine;
namespace NanoBrain.Braitenberg {
public class LightSensor : Sensor {
[Tooltip("If true, perform occlusion checks with raycasts.")]
public bool useOcclusion = true;
[Tooltip("Angle (degrees) for directional sensitivity; 180 = omnidirectional.")]
public float sensitivityAngle = 180f;
[Tooltip("Multiplier to scale final output.")]
public float multiplier = 1f;
protected override float SampleSensor() {
float sum = 0f;
// Get all active lights in scene (Point lights only)
#if UNITY_6000_0_OR_NEWER
Light[] lights = FindObjectsByType<Light>();
#else
Light[] lights = FindObjectsByType<Light>(FindObjectsSortMode.None);
#endif
Vector3 pos = transform.position;
Vector3 forward = transform.forward;
float halfAngleCos = Mathf.Cos(sensitivityAngle * 0.5f * Mathf.Deg2Rad);
int lightCount = 0;
foreach (Light light in lights) {
if (!light.enabled || light.type != LightType.Point)
continue;
// quick distance check
float dist = Vector3.Distance(light.transform.position, pos);
if (dist > this.sensorRange + light.range)
continue; // outside both sensor and light ranges
// angular sensitivity
Vector3 toLight = (light.transform.position - pos).normalized;
if (sensitivityAngle < 180f) {
if (Vector3.Dot(forward, toLight) < halfAngleCos)
continue;
}
// compute light falloff: Unity point lights use inverse squared (physically plausible)
// you can approximate using L.intensity and L.range
float attenuation = 0f;
if (dist < light.range) {
// inverse-square like falloff (avoid divide-by-zero)
attenuation = light.intensity / Mathf.Max(0.01f, dist * dist);
// optionally scale by (1 - dist/range) for a linear blend:
attenuation *= 1f - dist / light.range;
}
else
continue;
// occlusion check
if (useOcclusion) {
Vector3 dir = (light.transform.position - pos).normalized;
float rayDist = Mathf.Min(dist, light.range);
if (Physics.Raycast(pos, dir, out RaycastHit hit, rayDist, senseLayer))
attenuation *= 0f; // completely blocked; or reduce by factor
}
//Debug.DrawRay(this.transform.position, toLight * sensorRange);
// color consideration: convert light color to luminance if needed
float luminance = RGBToLuminance(light.color) * attenuation;
//Debug.Log(luminance);
sum += luminance;
lightCount++;
}
if (lightCount == 0)
return 0;
else
return (sum / lightCount) * multiplier;
}
static float RGBToLuminance(Color c) {
// simple Rec.709 luminance
return 0.2126f * c.r + 0.7152f * c.g + 0.0722f * c.b;
}
}
}