VolumeFog.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. #if UNITY_EDITOR
  4. using UnityEditor;
  5. using UnityEditor.SceneManagement;
  6. #endif
  7. using UnityEngine;
  8. namespace FXV
  9. {
  10. [ExecuteInEditMode]
  11. public class VolumeFog : MonoBehaviour
  12. {
  13. static bool XR_ENABLED = false;
  14. public static void SetEnabledXR(bool enabled)
  15. {
  16. XR_ENABLED = enabled;
  17. }
  18. public enum FogType
  19. {
  20. ViewAligned = 0,
  21. SphericalPos = 1,
  22. SphericalDist = 2,
  23. InvertedSpherical = 8,
  24. InvertedSphericalXHeight = 11,
  25. BoxPos = 3,
  26. BoxDist = 4,
  27. BoxExperimental = 5,
  28. Height = 6,
  29. HeightXBox = 7,
  30. HeightXView = 9,
  31. BoxXView = 10,
  32. };
  33. public enum FogClipping
  34. {
  35. None = 0,
  36. ClipToSkybox = 1,
  37. ClipToBounds = 2
  38. }
  39. public enum FogBlendMode
  40. {
  41. AlphaBlend,
  42. Add
  43. }
  44. public enum FogMeshType
  45. {
  46. Default = 0,
  47. Custom
  48. }
  49. public enum FogFallof
  50. {
  51. Linear = 0,
  52. Smoothed,
  53. Exp,
  54. Exp2
  55. }
  56. public enum FogFunction
  57. {
  58. Default = 0,
  59. Alternative
  60. }
  61. public enum FogRenderMode
  62. {
  63. Simplified = 0,
  64. Default
  65. }
  66. [SerializeField]
  67. FogType fogType = FogType.ViewAligned;
  68. [SerializeField]
  69. float fogMin = 0.0f;
  70. [SerializeField]
  71. float fogMax = 1.0f;
  72. [SerializeField]
  73. float _fogDepth = 1.0f;
  74. public float FogMin
  75. {
  76. get
  77. {
  78. return fogMin;
  79. }
  80. set
  81. {
  82. fogMin = value;
  83. _fogDepth = fogMax - fogMin;
  84. isPropsDirty = true;
  85. }
  86. }
  87. public float FogMax
  88. {
  89. get
  90. {
  91. return fogMax;
  92. }
  93. set
  94. {
  95. fogMax = value;
  96. _fogDepth = fogMax - fogMin;
  97. isPropsDirty = true;
  98. }
  99. }
  100. public float FogDepth
  101. {
  102. get
  103. {
  104. return fogMax - fogMin;
  105. }
  106. set
  107. {
  108. _fogDepth = value;
  109. fogMin = fogMax - value;
  110. isPropsDirty = true;
  111. }
  112. }
  113. [SerializeField]
  114. float secFogMin = 0.0f;
  115. [SerializeField]
  116. float secFogMax = 1.0f;
  117. [SerializeField]
  118. Vector3 worldSize = Vector3.one;
  119. [SerializeField]
  120. FogFallof fogFalloffType = FogFallof.Linear;
  121. [SerializeField, Range(0.5f, 15.0f)]
  122. float fogFalloffCurve = 1.0f;
  123. //[SerializeField]
  124. //int renderQueue = 3100;
  125. [SerializeField, FXV.Internal.fxvSortingLayerAttribute]
  126. string sortingLayer = "Default";
  127. [SerializeField]
  128. int sortingOrder = 0;
  129. [SerializeField]
  130. uint renderingLayerMask = 0xffffffff;
  131. [SerializeField]
  132. Color fogColor = Color.white;
  133. [SerializeField]
  134. FogBlendMode blendType = FogBlendMode.AlphaBlend;
  135. [SerializeField]
  136. FogMeshType fogMeshType = FogMeshType.Default;
  137. [SerializeField]
  138. Mesh customMesh = null;
  139. [SerializeField]
  140. FogClipping fogClipping = FogClipping.None;
  141. [SerializeField]
  142. FogRenderMode renderMode = FogRenderMode.Default;
  143. [SerializeField]
  144. bool affectedByLights = false;
  145. [SerializeField, Range(0.1f, 2.0f)]
  146. float lightScatteringFactor = 1.0f;
  147. [SerializeField, Range(0.0f, 1.0f)]
  148. float lightReflectivity = 1.0f;
  149. [SerializeField, Range(0.0f, 1.0f)]
  150. float lightTransmission = 0.5f;
  151. VolumeFogGroup fogGroup = null;
  152. Renderer myRenderer = null;
  153. MeshFilter myFilter = null;
  154. MaterialPropertyBlock props = null;
  155. bool isPropsDirty = true;
  156. Mesh plane = null;
  157. Mesh renderMesh = null;
  158. bool renderMeshIsProcedural = false;
  159. Bounds rendererLocalBounds;
  160. Transform myTransform;
  161. Vector3 myPosition;
  162. Vector3 boundsOffset = Vector3.zero;
  163. float globalScaleFactor = 1.0f;
  164. private void Start()
  165. {
  166. SetupComponents();
  167. if (myTransform == null)
  168. {
  169. myTransform = transform;
  170. myPosition = transform.position;
  171. }
  172. PrepareFogObject();
  173. myRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
  174. Material mat = GetCachedMaterial(this);
  175. if (myRenderer.sharedMaterial != mat)
  176. {
  177. myRenderer.sharedMaterial = mat;
  178. }
  179. rendererLocalBounds = myRenderer.localBounds;
  180. Camera.onPostRender += CameraFinishedRendering;
  181. }
  182. void SetupComponents()
  183. {
  184. if (myFilter == null)
  185. {
  186. myFilter = GetComponent<MeshFilter>();
  187. if (myFilter == null)
  188. {
  189. myFilter = gameObject.AddComponent<MeshFilter>();
  190. }
  191. myFilter.hideFlags = HideFlags.HideInInspector;
  192. }
  193. if (myRenderer == null)
  194. {
  195. myRenderer = GetComponent<Renderer>();
  196. if (myRenderer == null)
  197. {
  198. myRenderer = gameObject.AddComponent<MeshRenderer>();
  199. }
  200. myRenderer.hideFlags = HideFlags.HideInInspector;
  201. }
  202. }
  203. internal void DestroyAsset(Object assetObject)
  204. {
  205. #if UNITY_EDITOR
  206. if (!Application.isPlaying)
  207. {
  208. DestroyImmediate(assetObject);
  209. }
  210. else
  211. #endif
  212. {
  213. Destroy(assetObject);
  214. }
  215. }
  216. internal void PrepareFogObject()
  217. {
  218. if (IsUsingDepthWorkflow())
  219. {
  220. FogDepth = _fogDepth;
  221. }
  222. else
  223. {
  224. FogDepth = fogMax - fogMin;
  225. }
  226. if (fogGroup != null)
  227. {
  228. VolumeFogGroup parentGroup = GetComponentInParent<VolumeFogGroup>();
  229. if (parentGroup == null)
  230. {
  231. TryUnegisterFromGroup();
  232. }
  233. else if (parentGroup != fogGroup)
  234. {
  235. TryUnegisterFromGroup();
  236. TryRegisterInGroup();
  237. }
  238. }
  239. SetupComponents();
  240. Material mat = GetCachedMaterial(this);
  241. if (myRenderer.sharedMaterial != mat)
  242. {
  243. myRenderer.sharedMaterial = mat;
  244. }
  245. if (myTransform == null)
  246. {
  247. myTransform = transform;
  248. }
  249. myPosition = myTransform.position;
  250. UpdateScale();
  251. if (props == null)
  252. {
  253. CreateMaterialProps();
  254. }
  255. else
  256. {
  257. UpdateMaterialProps();
  258. }
  259. #if UNITY_EDITOR
  260. UnityEditor.EditorApplication.delayCall += _DelayedValidate;
  261. #else
  262. _DelayedValidate();
  263. #endif
  264. }
  265. private void OnValidate()
  266. {
  267. PrepareFogObject();
  268. UpdateScale();
  269. }
  270. internal void _DelayedValidate()
  271. {
  272. UpdateRenderMesh();
  273. }
  274. public bool IsCustomMesh()
  275. {
  276. return fogMeshType == FogMeshType.Custom;
  277. }
  278. public bool IsUsingDepthWorkflow()
  279. {
  280. return (fogType == FogType.InvertedSpherical) || fogType == FogType.InvertedSphericalXHeight;
  281. }
  282. public bool IsSphereShape()
  283. {
  284. return (fogType == FogType.SphericalPos || fogType == FogType.SphericalDist);
  285. }
  286. public bool IsBoxShape()
  287. {
  288. return !IsSphereShape();
  289. }
  290. public bool IsUsingSecondaryParams()
  291. {
  292. return fogType == FogType.HeightXBox || fogType == FogType.HeightXView || fogType == FogType.BoxXView || fogType == FogType.InvertedSphericalXHeight;
  293. }
  294. internal void UpdateRenderMesh()
  295. {
  296. if (this == null)
  297. {
  298. return;
  299. }
  300. if (myFilter == null)
  301. {
  302. myFilter = GetComponent<MeshFilter>();
  303. }
  304. if (renderMesh != null && renderMeshIsProcedural)
  305. {
  306. DestroyAsset(renderMesh);
  307. renderMeshIsProcedural = false;
  308. }
  309. if (IsCustomMesh())
  310. {
  311. myFilter.sharedMesh = customMesh;
  312. renderMesh = customMesh;
  313. worldSize = myRenderer.localBounds.size;
  314. boundsOffset = myRenderer.localBounds.center;
  315. UpdateMaterialProps();
  316. }
  317. else
  318. {
  319. if (IsSphereShape())
  320. {
  321. renderMesh = Resources.GetBuiltinResource<Mesh>("New-Sphere.fbx");
  322. myFilter.sharedMesh = renderMesh;
  323. }
  324. else if (IsBoxShape())
  325. {
  326. renderMesh = Resources.GetBuiltinResource<Mesh>("Cube.fbx");
  327. myFilter.sharedMesh = renderMesh;
  328. }
  329. else
  330. {
  331. InitializeBoxRenderMesh();
  332. myFilter.sharedMesh = renderMesh;
  333. }
  334. boundsOffset = Vector3.zero;
  335. }
  336. rendererLocalBounds = myRenderer.localBounds;
  337. }
  338. internal void UpdateGlobalScaleFactor()
  339. {
  340. Vector3 parentScale = (transform.parent != null) ? transform.parent.lossyScale : Vector3.one;
  341. float maxScale = Mathf.Max(Mathf.Max(parentScale.x, parentScale.y), parentScale.z);
  342. float minScale = Mathf.Min(Mathf.Min(parentScale.x, parentScale.y), parentScale.z);
  343. globalScaleFactor = (minScale + (maxScale - minScale) * 0.5f);
  344. }
  345. internal void UpdateScale()
  346. {
  347. UpdateGlobalScaleFactor();
  348. if (IsCustomMesh())
  349. {
  350. transform.localScale = Vector3.one;
  351. // lock scale for custom mesh
  352. }
  353. else
  354. {
  355. if (IsSphereShape())
  356. {
  357. transform.localScale = Vector3.one * Mathf.Max(fogMin, fogMax) * 2.0f;
  358. }
  359. else if (IsBoxShape())
  360. {
  361. transform.localScale = worldSize;
  362. }
  363. else
  364. {
  365. transform.localScale = Vector3.one;
  366. }
  367. }
  368. }
  369. internal void UpdateTransformScaleChanges()
  370. {
  371. if (IsCustomMesh())
  372. {
  373. transform.localScale = Vector3.one;
  374. // lock scale for custom mesh
  375. }
  376. else
  377. {
  378. if (IsSphereShape())
  379. {
  380. float currentScale = Mathf.Max(fogMin, fogMax) * 2.0f;
  381. bool changed = false;
  382. float r = fogMin / fogMax;
  383. if (transform.localScale.x != currentScale)
  384. {
  385. fogMax = transform.localScale.x * 0.5f;
  386. transform.localScale = Vector3.one * transform.localScale.x;
  387. changed = true;
  388. }
  389. if (transform.localScale.y != currentScale)
  390. {
  391. fogMax = transform.localScale.y * 0.5f;
  392. transform.localScale = Vector3.one * transform.localScale.y;
  393. changed = true;
  394. }
  395. if (transform.localScale.z != currentScale)
  396. {
  397. fogMax = transform.localScale.z * 0.5f;
  398. transform.localScale = Vector3.one * transform.localScale.z;
  399. changed = true;
  400. }
  401. if (changed)
  402. {
  403. fogMin = r * fogMax;
  404. UpdateGlobalScaleFactor();
  405. UpdateMaterialProps();
  406. }
  407. }
  408. else if (IsBoxShape())
  409. {
  410. if (worldSize != transform.localScale)
  411. {
  412. worldSize = transform.localScale;
  413. UpdateGlobalScaleFactor();
  414. UpdateMaterialProps();
  415. }
  416. }
  417. else
  418. {
  419. transform.localScale = Vector3.one;
  420. }
  421. }
  422. }
  423. internal void CreateMaterialProps()
  424. {
  425. props = new MaterialPropertyBlock();
  426. UpdateMaterialProps();
  427. }
  428. internal void UpdateMaterialProps()
  429. {
  430. props.SetColor("_Color", GetFogColor());
  431. props.SetVector("_WorldSize", worldSize * globalScaleFactor);
  432. if (IsCustomMesh())
  433. {
  434. props.SetVector("_LocalSize", worldSize); //worldSize stores local bounds size for custom mesh
  435. props.SetVector("_LocalOffset", boundsOffset);
  436. }
  437. props.SetFloat("_FogMin", fogMin * globalScaleFactor);
  438. props.SetFloat("_FogMax", fogMax * globalScaleFactor);
  439. props.SetFloat("_FogFalloff", GetFogFalloffParam());
  440. if (IsUsingSecondaryParams())
  441. {
  442. props.SetFloat("_SecFogMin", secFogMin * globalScaleFactor);
  443. props.SetFloat("_SecFogMax", secFogMax * globalScaleFactor);
  444. }
  445. if (IsAffectedByLights())
  446. {
  447. props.SetFloat("_LightScatteringFactor", GetLightScatteringFactor());
  448. props.SetFloat("_LightReflectivity", GetLightReflectivity());
  449. props.SetFloat("_LightTransmission", GetLightTransmission());
  450. }
  451. isPropsDirty = true;
  452. }
  453. internal void TryRegisterInGroup()
  454. {
  455. if (fogGroup == null)
  456. {
  457. fogGroup = GetComponentInParent<VolumeFogGroup>();
  458. if (fogGroup)
  459. {
  460. fogGroup.RegisterFogObject(this);
  461. }
  462. }
  463. }
  464. internal void TryUnegisterFromGroup()
  465. {
  466. if (fogGroup)
  467. {
  468. fogGroup.UnregisterFogObject(this);
  469. fogGroup = null;
  470. }
  471. }
  472. private void OnEnable()
  473. {
  474. SetupComponents();
  475. TryRegisterInGroup();
  476. myRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
  477. Camera.onPostRender -= CameraFinishedRendering;
  478. Camera.onPostRender += CameraFinishedRendering;
  479. if (props == null)
  480. {
  481. CreateMaterialProps();
  482. }
  483. else
  484. {
  485. UpdateMaterialProps();
  486. }
  487. }
  488. private void OnDisable()
  489. {
  490. TryUnegisterFromGroup();
  491. Camera.onPostRender -= CameraFinishedRendering;
  492. }
  493. void OnDestroy()
  494. {
  495. if (plane)
  496. {
  497. DestroyAsset(plane);
  498. plane = null;
  499. }
  500. if (renderMesh != null && renderMeshIsProcedural)
  501. {
  502. DestroyAsset(renderMesh);
  503. renderMeshIsProcedural = false;
  504. }
  505. if (fogGroup)
  506. {
  507. fogGroup.UnregisterFogObject(this);
  508. fogGroup = null;
  509. }
  510. props = null;
  511. myRenderer = null;
  512. Camera.onPostRender -= CameraFinishedRendering;
  513. }
  514. public void OnDidApplyAnimationProperties()
  515. {
  516. if (props != null)
  517. {
  518. UpdateMaterialProps();
  519. }
  520. }
  521. private void OnTransformParentChanged()
  522. {
  523. if (props == null)
  524. {
  525. return;
  526. }
  527. UpdateScale();
  528. UpdateMaterialProps();
  529. }
  530. private void Update()
  531. {
  532. }
  533. internal bool RenderCameraPlane(Camera camera)
  534. {
  535. if (IsSphereShape())
  536. {
  537. //TODO: optimize this
  538. float nearOffset = camera.nearClipPlane / Mathf.Cos(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
  539. float radius = Mathf.Max(fogMin, fogMax) * globalScaleFactor + nearOffset;
  540. Vector3 distVec = transform.position - camera.transform.position;
  541. if (distVec.sqrMagnitude < radius * radius)
  542. {
  543. return true;
  544. }
  545. }
  546. else
  547. {
  548. Bounds b = myRenderer.bounds;
  549. b.extents += Vector3.one * (camera.nearClipPlane / Mathf.Cos(camera.fieldOfView * 0.5f * Mathf.Deg2Rad));
  550. return b.Contains(camera.transform.position);
  551. }
  552. return false;
  553. }
  554. private void LateUpdate()
  555. {
  556. UpdateParams();
  557. }
  558. private void OnWillRenderObject()
  559. {
  560. UpdateParams();
  561. if (!Application.isPlaying)
  562. {
  563. UpdateTransformScaleChanges();
  564. }
  565. Camera camera = VolumeFogManager.instance.GetCurrentRenderingCamera();
  566. if (camera)
  567. {
  568. if ((camera.depthTextureMode & DepthTextureMode.Depth) == 0)
  569. {
  570. camera.depthTextureMode |= DepthTextureMode.Depth;
  571. }
  572. if (RenderCameraPlane(camera))
  573. {
  574. if (props == null)
  575. {
  576. CreateMaterialProps();
  577. }
  578. if (plane == null)
  579. {
  580. InitializeCameraMesh();
  581. }
  582. UpdateMesh(camera);
  583. myFilter.sharedMesh = plane;
  584. }
  585. else
  586. {
  587. myFilter.sharedMesh = renderMesh;
  588. }
  589. }
  590. }
  591. private void CameraFinishedRendering(Camera cam)
  592. {
  593. }
  594. void InitializeBoxRenderMesh()
  595. {
  596. Vector3 extents = worldSize * 0.5f;
  597. renderMesh = new Mesh();
  598. renderMesh.name = "ProceduralBox_" + worldSize.x + "_" + worldSize.y + "_" + worldSize.z;
  599. Vector3[] c = new Vector3[8];
  600. c[0] = new Vector3(-extents.x, -extents.y, extents.z);
  601. c[1] = new Vector3(extents.x, -extents.y, extents.z);
  602. c[2] = new Vector3(extents.x, -extents.y, -extents.z);
  603. c[3] = new Vector3(-extents.x, -extents.y, -extents.z);
  604. c[4] = new Vector3(-extents.x, extents.y, extents.z);
  605. c[5] = new Vector3(extents.x, extents.y, extents.z);
  606. c[6] = new Vector3(extents.x, extents.y, -extents.z);
  607. c[7] = new Vector3(-extents.x, extents.y, -extents.z);
  608. Vector3[] vertices = new Vector3[24]
  609. {
  610. c[0], c[1], c[2], c[3], // Bottom
  611. c[7], c[4], c[0], c[3], // Left
  612. c[4], c[5], c[1], c[0], // Front
  613. c[6], c[7], c[3], c[2], // Back
  614. c[5], c[6], c[2], c[1], // Right
  615. c[7], c[6], c[5], c[4] // Top
  616. };
  617. renderMesh.vertices = vertices;
  618. int[] tris = new int[]
  619. {
  620. 3, 1, 0, 3, 2, 1, // Bottom
  621. 7, 5, 4, 7, 6, 5, // Left
  622. 11, 9, 8, 11, 10, 9, // Front
  623. 15, 13, 12, 15, 14, 13, // Back
  624. 19, 17, 16, 19, 18, 17, // Right
  625. 23, 21, 20, 23, 22, 21, // Top
  626. };
  627. renderMesh.triangles = tris;
  628. Vector3 up = Vector3.up;
  629. Vector3 down = Vector3.down;
  630. Vector3 forward = Vector3.forward;
  631. Vector3 back = Vector3.back;
  632. Vector3 left = Vector3.left;
  633. Vector3 right = Vector3.right;
  634. Vector3[] normals = new Vector3[]
  635. {
  636. down, down, down, down, // Bottom
  637. left, left, left, left, // Left
  638. forward, forward, forward, forward, // Front
  639. back, back, back, back, // Back
  640. right, right, right, right, // Right
  641. up, up, up, up // Top
  642. };
  643. renderMesh.normals = normals;
  644. Vector2 uv00 = new Vector2(0f, 0f);
  645. Vector2 uv10 = new Vector2(1f, 0f);
  646. Vector2 uv01 = new Vector2(0f, 1f);
  647. Vector2 uv11 = new Vector2(1f, 1f);
  648. Vector2[] uv = new Vector2[]
  649. {
  650. uv11, uv01, uv00, uv10, // Bottom
  651. uv11, uv01, uv00, uv10, // Left
  652. uv11, uv01, uv00, uv10, // Front
  653. uv11, uv01, uv00, uv10, // Back
  654. uv11, uv01, uv00, uv10, // Right
  655. uv11, uv01, uv00, uv10 // Top
  656. };
  657. renderMesh.uv = uv;
  658. renderMesh.RecalculateBounds();
  659. renderMesh.Optimize();
  660. renderMesh.MarkDynamic();
  661. renderMeshIsProcedural = true;
  662. }
  663. void UpdateBoxRenderMesh()
  664. {
  665. Vector3 extents = worldSize * 0.5f;
  666. Vector3[] c = new Vector3[8];
  667. c[0] = new Vector3(-extents.x, -extents.y, extents.z);
  668. c[1] = new Vector3(extents.x, -extents.y, extents.z);
  669. c[2] = new Vector3(extents.x, -extents.y, -extents.z);
  670. c[3] = new Vector3(-extents.x, -extents.y, -extents.z);
  671. c[4] = new Vector3(-extents.x, extents.y, extents.z);
  672. c[5] = new Vector3(extents.x, extents.y, extents.z);
  673. c[6] = new Vector3(extents.x, extents.y, -extents.z);
  674. c[7] = new Vector3(-extents.x, extents.y, -extents.z);
  675. Vector3[] vertices = new Vector3[24]
  676. {
  677. c[0], c[1], c[2], c[3], // Bottom
  678. c[7], c[4], c[0], c[3], // Left
  679. c[4], c[5], c[1], c[0], // Front
  680. c[6], c[7], c[3], c[2], // Back
  681. c[5], c[6], c[2], c[1], // Right
  682. c[7], c[6], c[5], c[4] // Top
  683. };
  684. renderMesh.vertices = vertices;
  685. }
  686. void InitializeCameraMesh()
  687. {
  688. plane = new Mesh();
  689. Vector3[] vertices = new Vector3[4]
  690. {
  691. new Vector3(-1.0f, -1.0f, 0),
  692. new Vector3(1.0f, -1.0f, 0),
  693. new Vector3(-1.0f, 1.0f, 0),
  694. new Vector3(1.0f, 1.0f, 0)
  695. };
  696. plane.vertices = vertices;
  697. int[] tris = new int[6]
  698. {
  699. // lower left triangle
  700. 0, 2, 1,
  701. // upper right triangle
  702. 2, 3, 1
  703. };
  704. plane.triangles = tris;
  705. Vector3[] normals = new Vector3[4]
  706. {
  707. -Vector3.forward,
  708. -Vector3.forward,
  709. -Vector3.forward,
  710. -Vector3.forward
  711. };
  712. plane.normals = normals;
  713. Vector2[] uv = new Vector2[4]
  714. {
  715. new Vector2(0, 0),
  716. new Vector2(1, 0),
  717. new Vector2(0, 1),
  718. new Vector2(1, 1)
  719. };
  720. plane.uv = uv;
  721. plane.bounds = rendererLocalBounds;
  722. plane.MarkDynamic();
  723. }
  724. void UpdateMesh(Camera camera)
  725. {
  726. float zOffset = 0.001f;
  727. Vector3[] vertices = null;
  728. float stereoSeparationX = (camera.stereoEnabled || XR_ENABLED) ? 3.0f : 0.2f;
  729. float stereoSeparationY = (camera.stereoEnabled || XR_ENABLED) ? 1.0f : 0.2f;
  730. vertices = new Vector3[4]
  731. {
  732. camera.ViewportToWorldPoint( new Vector3(-stereoSeparationX, -stereoSeparationY, camera.nearClipPlane + zOffset) ),
  733. camera.ViewportToWorldPoint( new Vector3(1.0f + stereoSeparationX, -stereoSeparationY, camera.nearClipPlane + zOffset) ),
  734. camera.ViewportToWorldPoint( new Vector3(-stereoSeparationX, 1.0f + stereoSeparationY, camera.nearClipPlane + zOffset) ),
  735. camera.ViewportToWorldPoint( new Vector3(1.0f+stereoSeparationX, 1.0f + stereoSeparationY, camera.nearClipPlane + zOffset) )
  736. };
  737. vertices[0] = transform.InverseTransformPoint(vertices[0]);
  738. vertices[1] = transform.InverseTransformPoint(vertices[1]);
  739. vertices[2] = transform.InverseTransformPoint(vertices[2]);
  740. vertices[3] = transform.InverseTransformPoint(vertices[3]);
  741. plane.vertices = vertices;
  742. plane.bounds = rendererLocalBounds;
  743. }
  744. public void SetFogColor(Color color)
  745. {
  746. if (fogGroup != null && fogGroup.controlsColor)
  747. {
  748. Debug.LogWarning("Setting color for fog object that is controlled by group - this will not take effect");
  749. }
  750. fogColor = color;
  751. props.SetColor("_Color", GetFogColor());
  752. isPropsDirty = true;
  753. }
  754. public FogType GetFogType()
  755. {
  756. return fogType;
  757. }
  758. public float GetFogFalloffParam()
  759. {
  760. return fogGroup != null && fogGroup.controlsFalloffParam ? Mathf.Clamp(fogFalloffCurve * fogGroup.falloffParamMultiplier, 0.5f, 15.0f) : fogFalloffCurve;
  761. }
  762. public Vector3 GetFogBoxSize()
  763. {
  764. return worldSize;
  765. }
  766. public void SetFogBoxSize(Vector3 size)
  767. {
  768. worldSize = size;
  769. }
  770. public Color GetFogColor()
  771. {
  772. return fogGroup != null && fogGroup.controlsColor ? fogGroup.fogColor : fogColor;
  773. }
  774. public VolumeFogGroup GetParentFogGroup()
  775. {
  776. return fogGroup;
  777. }
  778. public void SetAffectedByLights(bool affected)
  779. {
  780. if (fogGroup != null && fogGroup.controlsLighting)
  781. {
  782. Debug.LogWarning("Setting affected by lights for fog object that is controlled by group - this will not take effect");
  783. }
  784. affectedByLights = affected;
  785. Material mat = GetCachedMaterial(this);
  786. if (myRenderer.sharedMaterial != mat)
  787. {
  788. myRenderer.sharedMaterial = mat;
  789. }
  790. UpdateMaterialProps();
  791. }
  792. public bool IsAffectedByLights()
  793. {
  794. return fogGroup != null && fogGroup.controlsLighting ? fogGroup.affectedByLights : affectedByLights;
  795. }
  796. public float GetLightScatteringFactor()
  797. {
  798. return fogGroup != null && fogGroup.controlsLighting ? fogGroup.lightScatteringFactor : lightScatteringFactor;
  799. }
  800. public float GetLightReflectivity()
  801. {
  802. return fogGroup != null && fogGroup.controlsLighting ? fogGroup.lightReflectivity : lightReflectivity;
  803. }
  804. public float GetLightTransmission()
  805. {
  806. return fogGroup != null && fogGroup.controlsLighting ? fogGroup.lightTransmission : lightTransmission;
  807. }
  808. void UpdateParams()
  809. {
  810. if (isPropsDirty)
  811. {
  812. myRenderer.SetPropertyBlock(props);
  813. myRenderer.sortingLayerName = sortingLayer;
  814. myRenderer.sortingOrder = sortingOrder;
  815. myRenderer.renderingLayerMask = renderingLayerMask;
  816. isPropsDirty = false;
  817. }
  818. }
  819. internal string GetMaterialName()
  820. {
  821. string ret = "VF";
  822. ret += IsAffectedByLights() ? "Lit" : "Unlit";
  823. ret += blendType.ToString();
  824. ret += fogType.ToString();
  825. ret += fogFalloffType.ToString();
  826. ret += renderMode.ToString();
  827. ret += fogMeshType.ToString();
  828. ret += fogClipping.ToString();
  829. if (Internal.fxvFogAssetConfig.ActiveRenderPipeline == Internal.fxvFogAssetConfig.Pipeline.URP)
  830. {
  831. ret += "URP";
  832. }
  833. return ret;
  834. }
  835. internal static Dictionary<string, Material> cachedMaterials = new Dictionary<string, Material> ();
  836. internal static Material GetCachedMaterial(VolumeFog fogObject)
  837. {
  838. string materialKey = fogObject.GetMaterialName();
  839. Material mat = null;
  840. if (cachedMaterials.TryGetValue(materialKey, out mat))
  841. {
  842. if (mat == null)
  843. {
  844. mat = CreateMaterial(fogObject);
  845. if (mat)
  846. {
  847. cachedMaterials[materialKey] = mat;
  848. }
  849. }
  850. return mat;
  851. }
  852. string cachePath = "MaterialsCache/" + materialKey;
  853. mat = Resources.Load(cachePath) as Material;
  854. if (mat == null)
  855. {
  856. mat = CreateMaterial(fogObject);
  857. if (mat)
  858. {
  859. #if UNITY_EDITOR
  860. UnityEditor.EditorApplication.delayCall += () =>
  861. {
  862. fogObject._DelayedSaveToCache(materialKey, mat);
  863. };
  864. #endif
  865. cachedMaterials[materialKey] = mat;
  866. }
  867. }
  868. else
  869. {
  870. SetupMaterialKeywords(mat, fogObject);
  871. cachedMaterials[materialKey] = mat;
  872. }
  873. return mat;
  874. }
  875. #if UNITY_EDITOR
  876. internal void _DelayedSaveToCache(string materialKey, Material mat)
  877. {
  878. if (mat == null)
  879. {
  880. Debug.Log("Trying to save null material for key " + materialKey);
  881. return;
  882. }
  883. string saveFolder = Internal.fxvFogAssetConfig.AssetPath + "/Resources/MaterialsCache/";
  884. if (!System.IO.Directory.Exists(saveFolder))
  885. {
  886. System.IO.Directory.CreateDirectory(saveFolder);
  887. }
  888. UnityEditor.AssetDatabase.CreateAsset(mat, saveFolder + materialKey + ".mat");
  889. UnityEditor.AssetDatabase.SaveAssets();
  890. UnityEditor.AssetDatabase.Refresh();
  891. }
  892. #endif
  893. internal static void SetupMaterialKeywords(Material mat, VolumeFog fogObject)
  894. {
  895. mat.SetFloat("_FogType", (float)fogObject.fogType);
  896. var types = System.Enum.GetNames(typeof(VolumeFog.FogType));
  897. foreach (string name in types)
  898. {
  899. mat.DisableKeyword("FXV_FOGTYPE_" + name.ToUpper());
  900. }
  901. mat.EnableKeyword("FXV_FOGTYPE_" + fogObject.fogType.ToString().ToUpper());
  902. mat.SetFloat("_FogFalloffType", (float)fogObject.fogFalloffType);
  903. if (fogObject.fogFalloffType == VolumeFog.FogFallof.Linear)
  904. {
  905. mat.EnableKeyword("FXV_LINEAR_FALLOFF");
  906. }
  907. else if (fogObject.fogFalloffType == VolumeFog.FogFallof.Smoothed)
  908. {
  909. mat.EnableKeyword("FXV_SMOOTHED_FALLOFF");
  910. }
  911. else if (fogObject.fogFalloffType == VolumeFog.FogFallof.Exp)
  912. {
  913. mat.EnableKeyword("FXV_EXP_FALLOFF");
  914. }
  915. else if (fogObject.fogFalloffType == VolumeFog.FogFallof.Exp2)
  916. {
  917. mat.EnableKeyword("FXV_EXP2_FALLOFF");
  918. }
  919. mat.SetFloat("_BlendMode", (float)fogObject.blendType);
  920. if (fogObject.blendType == VolumeFog.FogBlendMode.AlphaBlend)
  921. {
  922. mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
  923. mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  924. mat.SetInt("_ZWrite", 0);
  925. }
  926. else if (fogObject.blendType == VolumeFog.FogBlendMode.Add)
  927. {
  928. mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
  929. mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.One);
  930. mat.SetInt("_ZWrite", 0);
  931. }
  932. mat.SetFloat("_InAirEnabled", (float)fogObject.renderMode);
  933. if (fogObject.renderMode == FogRenderMode.Default)
  934. {
  935. mat.EnableKeyword("FXV_IN_AIR_FOG");
  936. }
  937. mat.SetFloat("_FogMeshType", (float)fogObject.fogMeshType);
  938. if (fogObject.fogMeshType == FogMeshType.Custom)
  939. {
  940. mat.EnableKeyword("FXV_FOG_CUSTOM_MESH");
  941. }
  942. mat.SetFloat("_FogClipping", (float)fogObject.fogClipping);
  943. if (fogObject.fogClipping == FogClipping.ClipToSkybox)
  944. {
  945. mat.EnableKeyword("FXV_FOG_CLIP_SKYBOX");
  946. }
  947. else if (fogObject.fogClipping == FogClipping.ClipToBounds)
  948. {
  949. mat.EnableKeyword("FXV_FOG_CLIP_BOUNDS");
  950. }
  951. mat.enableInstancing = true;
  952. }
  953. internal static Material CreateMaterial(VolumeFog fogObject)
  954. {
  955. Material mat = null;
  956. string shaderVersion = "";
  957. if (Internal.fxvFogAssetConfig.ActiveRenderPipeline == Internal.fxvFogAssetConfig.Pipeline.URP)
  958. {
  959. shaderVersion += "URP";
  960. }
  961. if (fogObject.IsAffectedByLights())
  962. {
  963. Shader shader = Shader.Find("FXV/FXVVolumeFogLit" + shaderVersion);
  964. if (!shader) //this might happen when render pipeline specific package is not imported
  965. {
  966. return null;
  967. }
  968. mat = new Material(shader);
  969. }
  970. else
  971. {
  972. mat = new Material(Shader.Find("FXV/FXVVolumeFog"));
  973. }
  974. SetupMaterialKeywords(mat, fogObject);
  975. return mat;
  976. }
  977. #if UNITY_EDITOR
  978. public static void SetFogType(VolumeFog fogObject, FogType type)
  979. {
  980. fogObject.fogType = type;
  981. fogObject.PrepareFogObject();
  982. }
  983. public static void UpdateFogType(VolumeFog fogObject)
  984. {
  985. fogObject.UpdateRenderMesh();
  986. fogObject.UpdateScale();
  987. }
  988. public static Material SetupFogMaterial(VolumeFog fogObject)
  989. {
  990. Material mat = GetCachedMaterial(fogObject);
  991. Renderer r = fogObject.GetComponent<Renderer>();
  992. if (r.sharedMaterial != mat)
  993. {
  994. r.sharedMaterial = mat;
  995. }
  996. return mat;
  997. }
  998. private void OnDrawGizmosSelected()
  999. {
  1000. Gizmos.color = Color.red;
  1001. if (IsBoxShape())
  1002. {
  1003. Gizmos.DrawWireCube(transform.position + boundsOffset, worldSize);
  1004. }
  1005. else
  1006. {
  1007. Gizmos.DrawWireSphere(transform.position + boundsOffset, fogMax);
  1008. }
  1009. }
  1010. #endif
  1011. }
  1012. }