You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

845 lines
33 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.Assertions;
  6. //=================================================================================================
  7. /**
  8. * @brief This class manages all lights for a particular FogVolume.
  9. *
  10. *************************************************************************************************/
  11. public class FogVolumeLightManager : MonoBehaviour
  12. {
  13. public int CurrentLightCount { get; private set; }
  14. public int VisibleLightCount { get; private set; }
  15. public bool DrawDebugData { get; set; }
  16. public bool AlreadyUsesTransformForPoI { get { return m_pointOfInterestTf != null; } }
  17. // Very slow and garbage allocating. Only call this once!
  18. public void FindLightsInScene()
  19. {
  20. CurrentLightCount = 0;
  21. VisibleLightCount = 0;
  22. m_lights.Clear();
  23. m_lightsInFrustum.Clear();
  24. for (int i = 0; i < MaxLightCount; i++)
  25. {
  26. m_lights.Add(new LightData());
  27. m_lightsInFrustum.Add(new LightData());
  28. }
  29. FogVolumeLight[] lights = FindObjectsOfType<FogVolumeLight>();
  30. for (int i = 0; i < lights.Length; i++)
  31. {
  32. Light unityLight = lights[i].GetComponent<Light>();
  33. if (unityLight != null)
  34. {
  35. switch (unityLight.type)
  36. {
  37. case LightType.Point:
  38. {
  39. AddPointLight(unityLight);
  40. lights[i].IsAddedToNormalLight = true;
  41. break;
  42. }
  43. case LightType.Spot:
  44. {
  45. AddSpotLight(unityLight);
  46. lights[i].IsAddedToNormalLight = true;
  47. break;
  48. }
  49. }
  50. }
  51. else
  52. {
  53. if (lights[i].IsPointLight)
  54. {
  55. AddSimulatedPointLight(lights[i]);
  56. lights[i].IsAddedToNormalLight = false;
  57. }
  58. else
  59. {
  60. AddSimulatedSpotLight(lights[i]);
  61. lights[i].IsAddedToNormalLight = false;
  62. }
  63. }
  64. }
  65. }
  66. // Very slow and garbage allocating. Only call this once!
  67. public void FindLightsInFogVolume()
  68. {
  69. CurrentLightCount = 0;
  70. VisibleLightCount = 0;
  71. m_lights.Clear();
  72. m_lightsInFrustum.Clear();
  73. for (int i = 0; i < MaxLightCount; i++)
  74. {
  75. m_lights.Add(new LightData());
  76. m_lightsInFrustum.Add(new LightData());
  77. }
  78. if (m_boxCollider == null) { m_boxCollider = gameObject.GetComponent<BoxCollider>(); }
  79. Bounds boundingBox = m_boxCollider.bounds;
  80. FogVolumeLight[] lights = FindObjectsOfType<FogVolumeLight>();
  81. for (int i = 0; i < lights.Length; i++)
  82. {
  83. if (boundingBox.Intersects(new Bounds(lights[i].gameObject.transform.position,
  84. Vector3.one * LightInVolumeBoundsSize)))
  85. {
  86. Light unityLight = lights[i].GetComponent<Light>();
  87. if (unityLight != null)
  88. {
  89. switch (unityLight.type)
  90. {
  91. case LightType.Point:
  92. {
  93. AddPointLight(unityLight);
  94. lights[i].IsAddedToNormalLight = true;
  95. break;
  96. }
  97. case LightType.Spot:
  98. {
  99. AddSpotLight(unityLight);
  100. lights[i].IsAddedToNormalLight = true;
  101. break;
  102. }
  103. }
  104. }
  105. else
  106. {
  107. if (lights[i].IsPointLight)
  108. {
  109. AddSimulatedPointLight(lights[i]);
  110. lights[i].IsAddedToNormalLight = false;
  111. }
  112. else
  113. {
  114. AddSimulatedSpotLight(lights[i]);
  115. lights[i].IsAddedToNormalLight = false;
  116. }
  117. }
  118. }
  119. }
  120. }
  121. //=============================================================================================
  122. /**
  123. * @brief Add a simulated point light to the manager.
  124. *
  125. * Note that a simulated point light is any GameObject with a SimulatedPointLight component on
  126. * it.
  127. *
  128. * @param _light The SimulatedPointLight component of an existing GameObject.
  129. *
  130. * @return True if the light was added to the managers list of lights.
  131. * @return False if the manager already contains the maximum amount of lights that was
  132. * specified in the constructor.
  133. *
  134. *********************************************************************************************/
  135. public bool AddSimulatedPointLight(FogVolumeLight _light)
  136. {
  137. Assert.IsTrue(CurrentLightCount < MaxLightCount,
  138. "The maximum number of lights is already reached!");
  139. int index = _FindFirstFreeLight();
  140. if (index != InvalidIndex)
  141. {
  142. LightData data = m_lights[index];
  143. CurrentLightCount++;
  144. data.LightType = EFogVolumeLightType.FogVolumePointLight;
  145. data.Transform = _light.transform;
  146. data.Light = null;
  147. data.FogVolumeLight = _light;
  148. data.Bounds = new Bounds(data.Transform.position,
  149. Vector3.one * data.FogVolumeLight.Range * 2.5f);
  150. return true;
  151. }
  152. return false;
  153. }
  154. //=============================================================================================
  155. /**
  156. * @brief Add a simulated spot light to the manager.
  157. *
  158. * Note that a simulated spot light is any GameObject with a SimulatedSpotLight component on
  159. * it.
  160. *
  161. * @param _light The SimulatedSpotLight component of an existing GameObject.
  162. *
  163. * @return True if the light was added to the managers list of lights.
  164. * @return False if the manager already contains the maximum amount of lights that was
  165. * specified in the constructor.
  166. *
  167. *********************************************************************************************/
  168. public bool AddSimulatedSpotLight(FogVolumeLight _light)
  169. {
  170. Assert.IsTrue(CurrentLightCount < MaxLightCount,
  171. "The maximum number of lights is already reached!");
  172. int index = _FindFirstFreeLight();
  173. if (index != InvalidIndex)
  174. {
  175. LightData data = m_lights[index];
  176. CurrentLightCount++;
  177. data.LightType = EFogVolumeLightType.FogVolumeSpotLight;
  178. data.Transform = _light.transform;
  179. data.Light = null;
  180. data.FogVolumeLight = _light;
  181. Vector3 center = data.Transform.position +
  182. data.Transform.forward * data.FogVolumeLight.Range * 0.5f;
  183. data.Bounds = new Bounds(center,
  184. Vector3.one * data.FogVolumeLight.Range *
  185. (0.75f + data.FogVolumeLight.Angle * 0.03f));
  186. return true;
  187. }
  188. return false;
  189. }
  190. //=============================================================================================
  191. /**
  192. * @brief Add an existing point light to the manager.
  193. *
  194. * @param _light The light component of an existing point light.
  195. *
  196. * @return True if the light was added to the managers list of lights.
  197. * @return False if the manager already contains the maximum amount of lights that was
  198. * specified in the constructor.
  199. *
  200. *********************************************************************************************/
  201. public bool AddPointLight(Light _light)
  202. {
  203. Assert.IsTrue(CurrentLightCount < MaxLightCount,
  204. "The maximum number of lights is already reached!");
  205. int index = _FindFirstFreeLight();
  206. if (index != InvalidIndex)
  207. {
  208. LightData data = m_lights[index];
  209. CurrentLightCount++;
  210. data.LightType = EFogVolumeLightType.PointLight;
  211. data.Transform = _light.transform;
  212. data.Light = _light;
  213. data.FogVolumeLight = null;
  214. data.Bounds = new Bounds(data.Transform.position,
  215. Vector3.one * data.Light.range * 2.5f);
  216. return true;
  217. }
  218. return false;
  219. }
  220. //=============================================================================================
  221. /**
  222. * @brief Add an existing spot light to the manager.
  223. *
  224. * @param _light The light component of an existing spot light.
  225. *
  226. * @return True if the light was added to the managers list of lights.
  227. * @return False if the manager already contains the maximum amount of lights that was
  228. * specified in the constructor.
  229. *
  230. *********************************************************************************************/
  231. public bool AddSpotLight(Light _light)
  232. {
  233. Assert.IsTrue(CurrentLightCount < MaxLightCount,
  234. "The maximum number of lights is already reached!");
  235. int index = _FindFirstFreeLight();
  236. if (index != InvalidIndex)
  237. {
  238. LightData data = m_lights[index];
  239. CurrentLightCount++;
  240. data.LightType = EFogVolumeLightType.SpotLight;
  241. data.Transform = _light.transform;
  242. data.Light = _light;
  243. data.FogVolumeLight = null;
  244. Vector3 center = data.Transform.position +
  245. data.Transform.forward * data.Light.range * 0.5f;
  246. data.Bounds = new Bounds(center,
  247. Vector3.one * data.Light.range *
  248. (0.75f + data.Light.spotAngle * 0.03f));
  249. return true;
  250. }
  251. return false;
  252. }
  253. //=============================================================================================
  254. /**
  255. * @brief Removes the light with the specified transform.
  256. *
  257. * Note that nothing will happen if the light is not currently present in the manager.
  258. *
  259. * @param _lightToRemove The light that will be removed from this manager.
  260. *
  261. * @return True if the light was found inside the manager and removed successfully.
  262. * @return False if the light was not found an thus not removed.
  263. *
  264. *********************************************************************************************/
  265. public bool RemoveLight(Transform _lightToRemove)
  266. {
  267. int count = m_lights.Count;
  268. for (int i = 0; i < count; i++)
  269. {
  270. if (ReferenceEquals(m_lights[i].Transform, _lightToRemove))
  271. {
  272. m_lights[i].LightType = EFogVolumeLightType.None;
  273. CurrentLightCount--;
  274. return true;
  275. }
  276. }
  277. return false;
  278. }
  279. //=============================================================================================
  280. /**
  281. * @brief Updates the lights that will be rendered.
  282. *
  283. * Note that this method should be called once per frame, before any data is sent to the
  284. * shaders.
  285. *
  286. *********************************************************************************************/
  287. public void ManualUpdate(ref Plane[] _frustumPlanes)
  288. {
  289. FrustumPlanes = _frustumPlanes;
  290. m_camera = m_fogVolumeData != null ? m_fogVolumeData.GameCamera : null;
  291. if (m_camera == null) { return; }
  292. if (m_boxCollider == null) { m_boxCollider = m_fogVolume.GetComponent<BoxCollider>(); }
  293. if (m_pointOfInterestTf != null) { m_pointOfInterest = m_pointOfInterestTf.position; }
  294. _UpdateBounds();
  295. _FindLightsInFrustum();
  296. if (m_lightsInFrustum.Count > MaxVisibleLights) { _SortLightsInFrustum(); }
  297. _PrepareShaderArrays();
  298. }
  299. //=============================================================================================
  300. /**
  301. * @brief Draws the gizmos if the user wants to see debug data.
  302. *
  303. *********************************************************************************************/
  304. public void OnDrawGizmos()
  305. {
  306. hideFlags = HideFlags.HideInInspector;
  307. if (m_camera == null) { return; }
  308. if (!DrawDebugData) { return; }
  309. Color tempColor = Gizmos.color;
  310. Gizmos.color = Color.green;
  311. for (int i = 0; i < VisibleLightCount; i++)
  312. {
  313. Gizmos.DrawWireCube(m_lightsInFrustum[i].Bounds.center,
  314. m_lightsInFrustum[i].Bounds.size);
  315. }
  316. Gizmos.color = Color.magenta;
  317. Matrix4x4 currentMatrix = Gizmos.matrix;
  318. Gizmos.matrix = Matrix4x4.TRS(m_camera.transform.position,
  319. m_camera.transform.rotation,
  320. Vector3.one);
  321. //Gizmos.matrix = transform.localToWorldMatrix;
  322. Gizmos.DrawFrustum(m_camera.transform.position,
  323. m_camera.fieldOfView,
  324. m_camera.nearClipPlane,
  325. m_fogVolume.PointLightingDistance2Camera,
  326. m_camera.aspect);
  327. Gizmos.color = tempColor;
  328. Gizmos.matrix = currentMatrix;
  329. }
  330. //=============================================================================================
  331. /**
  332. * @brief Sets the multiplier that is applied to the bounding box size of point lights.
  333. *
  334. * @param _cullSizeMultiplier The multiplier that is applied to the AABB of point lights.
  335. *
  336. *********************************************************************************************/
  337. public void SetPointLightCullSizeMultiplier(float _cullSizeMultiplier)
  338. {
  339. m_pointLightCullSizeMultiplier = _cullSizeMultiplier;
  340. }
  341. //=============================================================================================
  342. /**
  343. * @brief Sets the point of interest to a fixed position.
  344. *
  345. * @param _pointOfInterest The point that will be used for prioritizing which lights need to
  346. * be rendered.
  347. *
  348. *********************************************************************************************/
  349. public void SetPointOfInterest(Vector3 _pointOfInterest)
  350. {
  351. m_pointOfInterestTf = null;
  352. m_pointOfInterest = _pointOfInterest;
  353. }
  354. //=============================================================================================
  355. /**
  356. * @brief Sets the point of interest to the specified transform.
  357. *
  358. * The point of interest will be updated from the position of the transform. It is therefore
  359. * not necessary to call this method more than once.
  360. *
  361. *********************************************************************************************/
  362. public void SetPointOfInterest(Transform _pointOfInterest)
  363. {
  364. Assert.IsTrue(_pointOfInterest != null, "_pointOfInterest must not be null!");
  365. m_pointOfInterestTf = _pointOfInterest;
  366. }
  367. //=============================================================================================
  368. /**
  369. * @brief Returns the array that contains all light positions.
  370. *
  371. * Remember to call Update() before using this method, otherwise old data will be sent to the
  372. * shaders.
  373. *
  374. *********************************************************************************************/
  375. public Vector4[] GetLightPositionArray() { return m_lightPos; }
  376. //=============================================================================================
  377. /**
  378. * @brief Returns the array that contains all light rotations.
  379. *
  380. * Remember to call Update() before using this method, otherwise old data will be sent to the
  381. * shaders.
  382. *
  383. *********************************************************************************************/
  384. public Vector4[] GetLightRotationArray() { return m_lightRot; }
  385. //=============================================================================================
  386. /**
  387. * @brief Returns the array that contains all light colors.
  388. *
  389. * Remember to call Update() before using this method, otherwise old data will be sent to the
  390. * shaders.
  391. *********************************************************************************************/
  392. public Color[] GetLightColorArray() { return m_lightColor; }
  393. //=============================================================================================
  394. /**
  395. * @brief Returns the array that contains all light data (intensity, range, spotlight angle,
  396. * none).
  397. *
  398. * Remember to call Update() before using this method, otherwise old data will be sent to the
  399. * shaders.
  400. *
  401. *********************************************************************************************/
  402. public Vector4[] GetLightData() { return m_lightData; }
  403. //=============================================================================================
  404. /**
  405. * @brief Initializes the LightManager with default values.
  406. *
  407. *********************************************************************************************/
  408. public void Initialize()
  409. {
  410. m_fogVolume = gameObject.GetComponent<FogVolume>();
  411. m_fogVolumeData = FindObjectOfType<FogVolumeData>();
  412. m_camera = null;
  413. m_boxCollider = null;
  414. CurrentLightCount = 0;
  415. DrawDebugData = false;
  416. if (m_lights == null)
  417. {
  418. m_lights = new List<LightData>(MaxLightCount);
  419. m_lightsInFrustum = new List<LightData>(MaxLightCount);
  420. for (int i = 0; i < MaxLightCount; i++)
  421. {
  422. m_lights.Add(new LightData());
  423. m_lightsInFrustum.Add(new LightData());
  424. }
  425. }
  426. }
  427. //=============================================================================================
  428. /**
  429. * @brief Clears the LightManager and prepares it toi be reinitialized.
  430. *
  431. *********************************************************************************************/
  432. public void Deinitialize()
  433. {
  434. VisibleLightCount = 0;
  435. DrawDebugData = false;
  436. }
  437. public void SetFrustumPlanes(ref Plane[] _frustumPlanes) { FrustumPlanes = _frustumPlanes; }
  438. #if UNITY_EDITOR
  439. private void Update() { hideFlags = HideFlags.HideInInspector; }
  440. #endif
  441. //=============================================================================================
  442. /**
  443. * @brief Updates the axis aligned bounding boxes of all registered lights.
  444. *
  445. *********************************************************************************************/
  446. private void _UpdateBounds()
  447. {
  448. int count = m_lights.Count;
  449. for (int i = 0; i < count; i++)
  450. {
  451. LightData data = m_lights[i];
  452. if (data.LightType == EFogVolumeLightType.None) { continue; }
  453. switch (data.LightType)
  454. {
  455. case EFogVolumeLightType.None:
  456. {
  457. break;
  458. }
  459. case EFogVolumeLightType.PointLight:
  460. {
  461. data.Bounds = new Bounds(data.Transform.position,
  462. Vector3.one * data.Light.range *
  463. m_pointLightCullSizeMultiplier);
  464. break;
  465. }
  466. case EFogVolumeLightType.SpotLight:
  467. {
  468. Vector3 center = data.Transform.position +
  469. data.Transform.forward * data.Light.range * 0.5f;
  470. data.Bounds = new Bounds(center,
  471. Vector3.one * data.Light.range *
  472. m_pointLightCullSizeMultiplier * 1.25f);
  473. break;
  474. }
  475. case EFogVolumeLightType.FogVolumePointLight:
  476. {
  477. data.Bounds = new Bounds(data.Transform.position,
  478. Vector3.one * data.FogVolumeLight.Range *
  479. m_pointLightCullSizeMultiplier);
  480. break;
  481. }
  482. case EFogVolumeLightType.FogVolumeSpotLight:
  483. {
  484. Vector3 center = data.Transform.position +
  485. data.Transform.forward * data.FogVolumeLight.Range * 0.5f;
  486. data.Bounds = new Bounds(center,
  487. Vector3.one * data.FogVolumeLight.Range *
  488. m_pointLightCullSizeMultiplier * 1.25f);
  489. break;
  490. }
  491. }
  492. }
  493. }
  494. //=============================================================================================
  495. /**
  496. * @brief Finds the first free light in the list of all lights.
  497. *
  498. * Note that this method is necessary to ensure that adding/removing lights does not allocate
  499. * any garbage.
  500. *
  501. *********************************************************************************************/
  502. private int _FindFirstFreeLight()
  503. {
  504. if (CurrentLightCount < MaxLightCount)
  505. {
  506. int count = m_lights.Count;
  507. for (int i = 0; i < count; i++)
  508. {
  509. if (m_lights[i].LightType == EFogVolumeLightType.None) { return i; }
  510. }
  511. }
  512. return InvalidIndex;
  513. }
  514. //=============================================================================================
  515. /**
  516. * @brief Finds all lights that are currently in the view frustum of the camera and calculates
  517. * all necessary data for them.
  518. *
  519. *********************************************************************************************/
  520. private void _FindLightsInFrustum()
  521. {
  522. m_inFrustumCount = 0;
  523. Vector3 CameraPos = m_camera.gameObject.transform.position;
  524. int count = m_lights.Count;
  525. for (int i = 0; i < count; i++)
  526. {
  527. if (m_lights[i].Transform == null) { m_lights[i].LightType = EFogVolumeLightType.None; }
  528. if (m_lights[i].LightType == EFogVolumeLightType.None) { continue; }
  529. float distanceToCamera = (m_lights[i].Transform.position - CameraPos).magnitude;
  530. if (distanceToCamera > m_fogVolume.PointLightingDistance2Camera) { continue; }
  531. switch (m_lights[i].LightType)
  532. {
  533. case EFogVolumeLightType.None:
  534. {
  535. continue;
  536. }
  537. case EFogVolumeLightType.PointLight:
  538. case EFogVolumeLightType.SpotLight:
  539. {
  540. if (m_lights[i].Light.enabled == false) { continue; }
  541. break;
  542. }
  543. case EFogVolumeLightType.FogVolumePointLight:
  544. {
  545. if (m_lights[i].FogVolumeLight.Enabled == false) { continue; }
  546. break;
  547. }
  548. case EFogVolumeLightType.FogVolumeSpotLight:
  549. {
  550. if (m_lights[i].FogVolumeLight.Enabled == false) { continue; }
  551. break;
  552. }
  553. }
  554. if (GeometryUtility.TestPlanesAABB(FrustumPlanes, m_lights[i].Bounds))
  555. {
  556. LightData light = m_lights[i];
  557. Vector3 lightPos = light.Transform.position;
  558. light.SqDistance = (lightPos - m_pointOfInterest).sqrMagnitude;
  559. light.Distance2Camera = (lightPos - CameraPos).magnitude;
  560. m_lightsInFrustum[m_inFrustumCount++] = light;
  561. if (light.FogVolumeLight != null)
  562. {
  563. if (light.LightType == EFogVolumeLightType.FogVolumePointLight &&
  564. !light.FogVolumeLight.IsPointLight)
  565. {
  566. light.LightType = EFogVolumeLightType.FogVolumeSpotLight;
  567. }
  568. else if (light.LightType == EFogVolumeLightType.FogVolumeSpotLight &&
  569. light.FogVolumeLight.IsPointLight)
  570. {
  571. light.LightType = EFogVolumeLightType.FogVolumePointLight;
  572. }
  573. }
  574. }
  575. }
  576. }
  577. //=============================================================================================
  578. /**
  579. * @brief Sorts the lights that are currently within the view frustum of the camera by
  580. * distance to the camera.
  581. *
  582. * This method will only be called when there are more than MaxVisibleLights in the view
  583. * frustum of the camera.
  584. *
  585. *********************************************************************************************/
  586. private void _SortLightsInFrustum()
  587. {
  588. bool finishedSorting = false;
  589. do
  590. {
  591. finishedSorting = true;
  592. for (int i = 0; i < m_inFrustumCount - 1; i++)
  593. {
  594. if (m_lightsInFrustum[i].SqDistance > m_lightsInFrustum[i + 1].SqDistance)
  595. {
  596. LightData tempData = m_lightsInFrustum[i];
  597. m_lightsInFrustum[i] = m_lightsInFrustum[i + 1];
  598. m_lightsInFrustum[i + 1] = tempData;
  599. finishedSorting = false;
  600. }
  601. }
  602. }
  603. while (!finishedSorting);
  604. }
  605. //=============================================================================================
  606. /**
  607. * @brief Prepares the data of the currently visible light and writes it to the arrays that
  608. * can then be sent to the shaders.
  609. *
  610. *********************************************************************************************/
  611. private void _PrepareShaderArrays()
  612. {
  613. VisibleLightCount = 0;
  614. for (int i = 0; i < MaxVisibleLights; i++)
  615. {
  616. if (i >= m_inFrustumCount) { break; }
  617. LightData data = m_lightsInFrustum[i];
  618. switch (data.LightType)
  619. {
  620. case EFogVolumeLightType.FogVolumePointLight:
  621. {
  622. FogVolumeLight light = data.FogVolumeLight;
  623. m_lightPos[i] =
  624. gameObject.transform.InverseTransformPoint(data.Transform.position);
  625. m_lightRot[i] =
  626. gameObject.transform.InverseTransformVector(data.Transform.forward);
  627. m_lightColor[i] = light.Color;
  628. m_lightData[i] =
  629. new Vector4(light.Intensity * m_fogVolume.PointLightsIntensity *
  630. (1.0f - Mathf.Clamp01(data.Distance2Camera / m_fogVolume
  631. .PointLightingDistance2Camera)
  632. ),
  633. light.Range / PointLightRangeDivider,
  634. InvalidSpotLightAngle,
  635. NoData);
  636. VisibleLightCount++;
  637. break;
  638. }
  639. case EFogVolumeLightType.FogVolumeSpotLight:
  640. {
  641. FogVolumeLight light = data.FogVolumeLight;
  642. m_lightPos[i] =
  643. gameObject.transform.InverseTransformPoint(data.Transform.position);
  644. m_lightRot[i] =
  645. gameObject.transform.InverseTransformVector(data.Transform.forward);
  646. m_lightColor[i] = light.Color;
  647. m_lightData[i] =
  648. new Vector4(light.Intensity * m_fogVolume.PointLightsIntensity *
  649. (1.0f - Mathf.Clamp01(data.Distance2Camera / m_fogVolume
  650. .PointLightingDistance2Camera)
  651. ),
  652. light.Range / SpotLightRangeDivider,
  653. light.Angle,
  654. NoData);
  655. VisibleLightCount++;
  656. break;
  657. }
  658. case EFogVolumeLightType.PointLight:
  659. {
  660. Light light = data.Light;
  661. m_lightPos[i] =
  662. gameObject.transform.InverseTransformPoint(data.Transform.position);
  663. m_lightRot[i] =
  664. gameObject.transform.InverseTransformVector(data.Transform.forward);
  665. m_lightColor[i] = light.color;
  666. m_lightData[i] =
  667. new Vector4(light.intensity * m_fogVolume.PointLightsIntensity *
  668. (1.0f - Mathf.Clamp01(data.Distance2Camera / m_fogVolume
  669. .PointLightingDistance2Camera)
  670. ),
  671. light.range / PointLightRangeDivider,
  672. InvalidSpotLightAngle,
  673. NoData);
  674. VisibleLightCount++;
  675. break;
  676. }
  677. case EFogVolumeLightType.SpotLight:
  678. {
  679. Light light = data.Light;
  680. m_lightPos[i] =
  681. gameObject.transform.InverseTransformPoint(data.Transform.position);
  682. m_lightRot[i] =
  683. gameObject.transform.InverseTransformVector(data.Transform.forward);
  684. m_lightColor[i] = light.color;
  685. m_lightData[i] =
  686. new Vector4(light.intensity * m_fogVolume.PointLightsIntensity *
  687. (1.0f - Mathf.Clamp01(data.Distance2Camera / m_fogVolume
  688. .PointLightingDistance2Camera)
  689. ),
  690. light.range / SpotLightRangeDivider,
  691. light.spotAngle,
  692. NoData);
  693. VisibleLightCount++;
  694. break;
  695. }
  696. case EFogVolumeLightType.None:
  697. {
  698. break;
  699. }
  700. }
  701. }
  702. }
  703. private float m_pointLightCullSizeMultiplier = 1.0f;
  704. private FogVolume m_fogVolume = null;
  705. private FogVolumeData m_fogVolumeData = null;
  706. private Camera m_camera = null;
  707. private BoxCollider m_boxCollider = null;
  708. private Transform m_pointOfInterestTf = null;
  709. private Vector3 m_pointOfInterest = Vector3.zero;
  710. private readonly Vector4[] m_lightPos = new Vector4[MaxVisibleLights];
  711. private readonly Vector4[] m_lightRot = new Vector4[MaxVisibleLights];
  712. private readonly Color[] m_lightColor = new Color[MaxVisibleLights];
  713. private readonly Vector4[] m_lightData = new Vector4[MaxVisibleLights];
  714. private List<LightData> m_lights = null;
  715. private List<LightData> m_lightsInFrustum = null;
  716. private int m_inFrustumCount = 0;
  717. private Plane[] FrustumPlanes = null;
  718. private const int InvalidIndex = -1;
  719. private const int MaxVisibleLights = 64;
  720. private const float InvalidSpotLightAngle = -1.0f;
  721. private const float NoData = 0.0f;
  722. private const float PointLightRangeDivider = 5.0f;
  723. private const float SpotLightRangeDivider = 5.0f;
  724. private const int MaxLightCount = 1000;
  725. /// The assumed size of a light. Used by realtime search when searching for lights inside a FV.
  726. private const float LightInVolumeBoundsSize = 5.0f;
  727. protected class LightData
  728. {
  729. public LightData()
  730. {
  731. LightType = EFogVolumeLightType.None;
  732. Light = null;
  733. FogVolumeLight = null;
  734. Transform = null;
  735. SqDistance = 0.0f;
  736. Distance2Camera = 0.0f;
  737. Bounds = new Bounds();
  738. }
  739. public EFogVolumeLightType LightType { get; set; }
  740. public Light Light { get; set; }
  741. public FogVolumeLight FogVolumeLight { get; set; }
  742. public Transform Transform { get; set; }
  743. public float SqDistance { get; set; }
  744. public float Distance2Camera { get; set; }
  745. public Bounds Bounds { get; set; }
  746. }
  747. }