using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace com.rfilkov.components
{
public class FragmentLighting
{
// lighting structures
private Light[] sceneLights = null;
private Bounds lightBounds;
private Vector4[] dirLightData = new Vector4[2];
[SerializeField]
public struct PointLight
{
public Vector4 color;
public float range;
public Vector3 pos;
}
private const int SIZE_POINT_LIGHT = 32;
private const int MAX_POINT_LIGHTS = 8;
[SerializeField]
private PointLight[] pointLights = new PointLight[MAX_POINT_LIGHTS];
private ComputeBuffer pointLightsBuffer = null;
private int pointLightsNumber = 0;
[SerializeField]
public struct SpotLight
{
public Vector4 color;
public Vector3 pos;
public Vector4 dir;
public Vector4 pars;
}
private const int SIZE_SPOT_LIGHT = 60;
private const int MAX_SPOT_LIGHTS = 8;
[SerializeField]
public SpotLight[] spotLights = new SpotLight[MAX_SPOT_LIGHTS];
private ComputeBuffer spotLightsBuffer = null;
private int spotLightsNumber = 0;
const int NUMBER_LIGHTS_MAX = MAX_POINT_LIGHTS / 2 + MAX_SPOT_LIGHTS / 2;
///
/// Sets the scene lights and lighted volume bounds.
///
public void SetLightsAndBounds(Light[] sceneLights, Vector3 centerPos, Vector3 sizeBounds)
{
this.sceneLights = sceneLights;
this.lightBounds = new Bounds(centerPos, sizeBounds);
}
///
/// Releases the used native resources.
///
public void ReleaseResources()
{
if (pointLightsBuffer != null)
{
pointLightsBuffer.Release();
pointLightsBuffer = null;
}
if (spotLightsBuffer != null)
{
spotLightsBuffer.Release();
spotLightsBuffer = null;
}
}
///
/// Updates the lighting parameters of the material.
///
public void UpdateLighting(Material matRenderer, bool bApplyLighting)
{
matRenderer.SetInt("_ApplyLights", bApplyLighting ? 1 : 0);
matRenderer.SetInt("_ApplyShadows", 0);
matRenderer.SetFloat("_Metallic", 0);
ApplyLighting(matRenderer, bApplyLighting);
}
// applies the current lights
private void ApplyLighting(Material matRenderer, bool bApplyLighting)
{
const float interiorCone = 0.1f; // interior cone of the spotlight
dirLightData[1] = Vector4.zero;
int pi = 0;
int si = 0;
if(bApplyLighting)
{
foreach (Light light in sceneLights)
{
if (!light.gameObject.activeInHierarchy || !light.enabled)
continue;
if (light.type == LightType.Directional || Vector3.Distance(lightBounds.center, light.transform.position) < (light.range + lightBounds.extents.x))
{
if (light.type != LightType.Directional && light.shadows != LightShadows.None)
{
light.shadows = LightShadows.None;
}
if (light.type == LightType.Point)
{
if (pi < MAX_POINT_LIGHTS)
{
pointLights[pi].color = light.color * light.intensity;
pointLights[pi].pos = light.gameObject.transform.position;
pointLights[pi].range = light.range;
pi++;
}
}
else if (light.type == LightType.Spot)
{
if (si < MAX_SPOT_LIGHTS)
{
Vector3 vLightFwd = light.gameObject.transform.forward.normalized;
spotLights[si].color = light.color * light.intensity;
spotLights[si].pos = light.gameObject.transform.position;
spotLights[si].dir = new Vector4(vLightFwd.x, vLightFwd.y, vLightFwd.z, Mathf.Cos((light.spotAngle / 2.0f) * Mathf.Deg2Rad));
spotLights[si].pars = new Vector4(light.spotAngle, light.intensity, 1.0f / light.range, interiorCone);
si++;
}
}
else if (light.type == LightType.Directional)
{
Vector3 vLightFwd = light.gameObject.transform.forward.normalized;
dirLightData[0] = new Vector4(vLightFwd.x, vLightFwd.y, vLightFwd.z, 0);
dirLightData[1] = light.color * light.intensity;
}
}
}
}
if (pointLightsBuffer == null)
{
pointLightsBuffer = new ComputeBuffer(MAX_POINT_LIGHTS, SIZE_POINT_LIGHT);
pointLightsBuffer.SetData(pointLights);
matRenderer.SetBuffer("_PointLights", pointLightsBuffer);
}
else
{
pointLightsBuffer.SetData(pointLights);
}
if (spotLightsBuffer == null)
{
spotLightsBuffer = new ComputeBuffer(MAX_SPOT_LIGHTS, SIZE_SPOT_LIGHT);
spotLightsBuffer.SetData(spotLights);
matRenderer.SetBuffer("_SpotLights", spotLightsBuffer);
}
else
{
spotLightsBuffer.SetData(spotLights);
}
pointLightsNumber = pi;
spotLightsNumber = si;
matRenderer.SetInt("_PointLightsNumber", pointLightsNumber);
matRenderer.SetInt("_SpotLightsNumber", spotLightsNumber);
matRenderer.SetVectorArray("_DirectionalLights", dirLightData);
}
}
}