A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Xml.Linq;
4using UnityEngine.Experimental.Rendering;
5
6namespace UnityEngine.Rendering
7{
8 /// <summary>
9 /// Common code for all Data-Driven Lens Flare used
10 /// </summary>
11 public sealed class LensFlareCommonSRP
12 {
13 private static LensFlareCommonSRP m_Instance = null;
14 private static readonly object m_Padlock = new object();
15 /// <summary>
16 /// Class describing internal information stored to describe a shown LensFlare
17 /// </summary>
18 internal class LensFlareCompInfo
19 {
20 /// <summary>
21 /// Index used to compute Occlusion in a fixed order
22 /// </summary>
23 internal int index;
24
25 /// <summary>
26 /// Component used
27 /// </summary>
28 internal LensFlareComponentSRP comp;
29
30 internal LensFlareCompInfo(int idx, LensFlareComponentSRP cmp)
31 {
32 index = idx;
33 comp = cmp;
34 }
35 }
36
37 private static List<LensFlareCompInfo> m_Data = new List<LensFlareCompInfo>();
38 private static List<int> m_AvailableIndicies = new List<int>();
39
40 /// <summary>
41 /// Max lens-flares-with-occlusion supported
42 /// </summary>
43 public static int maxLensFlareWithOcclusion = 128;
44
45
46 /// <summary>
47 /// With TAA Occlusion jitter depth, thought frame on HDRP.
48 /// So we do a "unanimity vote" for occlusion thought 'maxLensFlareWithOcclusionTemporalSample' frame
49 /// Important to keep this value maximum of 8
50 /// If this value change that could implies an implementation modification on:
51 /// com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LensFlareMergeOcclusionDataDriven.compute
52 /// </summary>
53 public static int maxLensFlareWithOcclusionTemporalSample = 8;
54
55 /// <summary>
56 /// Set to 1 to enable temporal sample merge.
57 /// Set to 0 to disable temporal sample merge (must support 16 bit textures, and the occlusion merge must be written in the last texel (vertical) of the lens flare texture.
58 /// </summary>
59 public static int mergeNeeded = 1;
60
61 /// <summary>
62 /// occlusion texture either provided or created automatically by the SRP for lens flare.
63 /// Texture width is the max number of lens flares that have occlusion (x axis the lens flare index).
64 /// y axis is the number of samples (maxLensFlareWithOcclusionTemporalSample) plus the number of merge results.
65 /// Merge results must be done by the SRP and stored in the [(lens flareIndex), (maxLensFlareWithOcclusionTemporalSample + 1)] coordinate.
66 /// Note: It's not supported on OpenGL3 and OpenGLCore
67 /// </summary>
68 public static RTHandle occlusionRT = null;
69
70 private static int frameIdx = 0;
71
72 internal static readonly int _FlareOcclusionPermutation = Shader.PropertyToID("_FlareOcclusionPermutation");
73 internal static readonly int _FlareOcclusionRemapTex = Shader.PropertyToID("_FlareOcclusionRemapTex");
74 internal static readonly int _FlareOcclusionTex = Shader.PropertyToID("_FlareOcclusionTex");
75 internal static readonly int _FlareOcclusionIndex = Shader.PropertyToID("_FlareOcclusionIndex");
76 internal static readonly int _FlareCloudOpacity = Shader.PropertyToID("_FlareCloudOpacity");
77 internal static readonly int _FlareSunOcclusionTex = Shader.PropertyToID("_FlareSunOcclusionTex");
78 internal static readonly int _FlareTex = Shader.PropertyToID("_FlareTex");
79 internal static readonly int _FlareColorValue = Shader.PropertyToID("_FlareColorValue");
80 internal static readonly int _FlareData0 = Shader.PropertyToID("_FlareData0");
81 internal static readonly int _FlareData1 = Shader.PropertyToID("_FlareData1");
82 internal static readonly int _FlareData2 = Shader.PropertyToID("_FlareData2");
83 internal static readonly int _FlareData3 = Shader.PropertyToID("_FlareData3");
84 internal static readonly int _FlareData4 = Shader.PropertyToID("_FlareData4");
85 internal static readonly int _FlareData5 = Shader.PropertyToID("_FlareData5");
86 internal static readonly int _FlareRadialTint = Shader.PropertyToID("_FlareRadialTint");
87
88 internal static readonly int _ViewId = Shader.PropertyToID("_ViewId");
89
90 internal static readonly int _LensFlareScreenSpaceBloomMipTexture = Shader.PropertyToID("_LensFlareScreenSpaceBloomMipTexture");
91 internal static readonly int _LensFlareScreenSpaceResultTexture = Shader.PropertyToID("_LensFlareScreenSpaceResultTexture");
92 internal static readonly int _LensFlareScreenSpaceSpectralLut = Shader.PropertyToID("_LensFlareScreenSpaceSpectralLut");
93 internal static readonly int _LensFlareScreenSpaceStreakTex = Shader.PropertyToID("_LensFlareScreenSpaceStreakTex");
94 internal static readonly int _LensFlareScreenSpaceMipLevel = Shader.PropertyToID("_LensFlareScreenSpaceMipLevel");
95 internal static readonly int _LensFlareScreenSpaceTintColor = Shader.PropertyToID("_LensFlareScreenSpaceTintColor");
96 internal static readonly int _LensFlareScreenSpaceParams1 = Shader.PropertyToID("_LensFlareScreenSpaceParams1");
97 internal static readonly int _LensFlareScreenSpaceParams2 = Shader.PropertyToID("_LensFlareScreenSpaceParams2");
98 internal static readonly int _LensFlareScreenSpaceParams3 = Shader.PropertyToID("_LensFlareScreenSpaceParams3");
99 internal static readonly int _LensFlareScreenSpaceParams4 = Shader.PropertyToID("_LensFlareScreenSpaceParams4");
100 internal static readonly int _LensFlareScreenSpaceParams5 = Shader.PropertyToID("_LensFlareScreenSpaceParams5");
101
102 private LensFlareCommonSRP()
103 {
104 }
105
106 private static readonly bool s_SupportsLensFlare16bitsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, GraphicsFormatUsage.Render);
107 private static readonly bool s_SupportsLensFlare32bitsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, GraphicsFormatUsage.Render);
108
109 /// <summary>
110 /// Check if we can use an OcclusionRT
111 /// </summary>
112 /// <returns>return true if we can have the OcclusionRT</returns>
113 static public bool IsOcclusionRTCompatible()
114 {
115#if UNITY_SERVER
116 return false;
117#else
118 return SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3 &&
119 SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLCore &&
120 SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null &&
121 SystemInfo.graphicsDeviceType != GraphicsDeviceType.WebGPU &&
122 (s_SupportsLensFlare16bitsFormat || s_SupportsLensFlare32bitsFormat); //Caching this, because SupportsRenderTextureFormat allocates memory. Go figure.
123#endif
124 }
125
126 static GraphicsFormat GetOcclusionRTFormat()
127 {
128 // SystemInfo.graphicsDeviceType == {GraphicsDeviceType.Direct3D12, GraphicsDeviceType.GameCoreXboxSeries, GraphicsDeviceType.XboxOneD3D12, GraphicsDeviceType.PlayStation5, ...}
129 if (s_SupportsLensFlare16bitsFormat)
130 return GraphicsFormat.R16_SFloat;
131 else
132 // Needed a R32_SFloat for Metal or/and DirectX < 11.3
133 return GraphicsFormat.R32_SFloat;
134 }
135
136 /// <summary>
137 /// Initialization function which must be called by the SRP.
138 /// </summary>
139 static public void Initialize()
140 {
141 frameIdx = 0;
142 if (IsOcclusionRTCompatible())
143 {
144 // The height of occlusion texture is:
145 // - '1': when no temporal accumulation
146 // - 'maxLensFlareWithOcclusionTemporalSample + 1': for temporal accumulation, useful when TAA enabled
147 if (occlusionRT == null)
148 {
149 occlusionRT = RTHandles.Alloc(
150 width: maxLensFlareWithOcclusion,
151 height: Mathf.Max(mergeNeeded * (maxLensFlareWithOcclusionTemporalSample + 1), 1),
152 format: GetOcclusionRTFormat(),
153 slices: TextureXR.slices,
154 enableRandomWrite: true,
155 dimension: TextureDimension.Tex2DArray);
156 }
157 }
158 }
159
160 /// <summary>
161 /// Disposal function, must be called by the SRP to release all internal textures.
162 /// </summary>
163 static public void Dispose()
164 {
165 if (IsOcclusionRTCompatible())
166 {
167 if (occlusionRT != null)
168 {
169 RTHandles.Release(occlusionRT);
170 occlusionRT = null;
171 }
172 }
173 }
174
175 /// <summary>
176 /// Current unique instance
177 /// </summary>
178 public static LensFlareCommonSRP Instance
179 {
180 get
181 {
182 if (m_Instance == null)
183 {
184 lock (m_Padlock)
185 {
186 if (m_Instance == null)
187 {
188 m_Instance = new LensFlareCommonSRP();
189 }
190 }
191 }
192 return m_Instance;
193 }
194 }
195
196 private System.Collections.Generic.List<LensFlareCompInfo> Data { get { return LensFlareCommonSRP.m_Data; } }
197
198 /// <summary>
199 /// Check if we have at least one Lens Flare added on the pool
200 /// </summary>
201 /// <returns>true if no Lens Flare were added</returns>
202 public bool IsEmpty()
203 {
204 return Data.Count == 0;
205 }
206
207 int GetNextAvailableIndex()
208 {
209 if (m_AvailableIndicies.Count == 0)
210 return m_Data.Count;
211 else
212 {
213 int nextIndex = m_AvailableIndicies[m_AvailableIndicies.Count - 1];
214 m_AvailableIndicies.RemoveAt(m_AvailableIndicies.Count - 1);
215 return nextIndex;
216 }
217 }
218
219 /// <summary>
220 /// Add a new lens flare component on the pool.
221 /// </summary>
222 /// <param name="newData">The new data added</param>
223 public void AddData(LensFlareComponentSRP newData)
224 {
225 Debug.Assert(Instance == this, "LensFlareCommonSRP can have only one instance");
226
227 if (!m_Data.Exists(x => x.comp == newData))
228 {
229 m_Data.Add(new LensFlareCompInfo(GetNextAvailableIndex(), newData));
230 }
231 }
232
233 /// <summary>
234 /// Remove a lens flare data which exist in the pool.
235 /// </summary>
236 /// <param name="data">The data which exist in the pool</param>
237 public void RemoveData(LensFlareComponentSRP data)
238 {
239 Debug.Assert(Instance == this, "LensFlareCommonSRP can have only one instance");
240
241 LensFlareCompInfo info = m_Data.Find(x => x.comp == data);
242 if (info != null)
243 {
244 int newIndex = info.index;
245 m_Data.Remove(info);
246 m_AvailableIndicies.Add(newIndex);
247 if (m_Data.Count == 0)
248 m_AvailableIndicies.Clear();
249 }
250 }
251
252
253 /// <summary>
254 /// Attenuation by Light Shape for Point Light
255 /// </summary>
256 /// <returns>Attenuation Factor</returns>
257 static public float ShapeAttenuationPointLight()
258 {
259 return 1.0f;
260 }
261
262 /// <summary>
263 /// Attenuation by Light Shape for Directional Light
264 /// </summary>
265 /// <param name="forward">Forward Vector of Directional Light</param>
266 /// <param name="wo">Vector pointing to the eye</param>
267 /// <returns>Attenuation Factor</returns>
268 static public float ShapeAttenuationDirLight(Vector3 forward, Vector3 wo)
269 {
270 return Mathf.Max(Vector3.Dot(-forward, wo), 0.0f);
271 }
272
273 /// <summary>
274 /// Attenuation by Light Shape for Spot Light with Cone Shape
275 /// </summary>
276 /// <param name="forward">Forward Vector of Directional Light</param>
277 /// <param name="wo">Vector pointing to the eye</param>
278 /// <param name="spotAngle">The angle of the light's spotlight cone in degrees.</param>
279 /// <param name="innerSpotPercent01">Get the inner spot radius between 0 and 1.</param>
280 /// <returns>Attenuation Factor</returns>
281 static public float ShapeAttenuationSpotConeLight(Vector3 forward, Vector3 wo, float spotAngle, float innerSpotPercent01)
282 {
283 float outerDot = Mathf.Max(Mathf.Cos(0.5f * spotAngle * Mathf.Deg2Rad), 0.0f);
284 float innerDot = Mathf.Max(Mathf.Cos(0.5f * spotAngle * Mathf.Deg2Rad * innerSpotPercent01), 0.0f);
285 float dot = Mathf.Max(Vector3.Dot(forward, wo), 0.0f);
286 return Mathf.Clamp01((dot - outerDot) / (innerDot - outerDot));
287 }
288
289 /// <summary>
290 /// Attenuation by Light Shape for Spot Light with Box Shape
291 /// </summary>
292 /// <param name="forward">Forward Vector of Directional Light</param>
293 /// <param name="wo">Vector pointing to the eye</param>
294 /// <returns>Attenuation Factor</returns>
295 static public float ShapeAttenuationSpotBoxLight(Vector3 forward, Vector3 wo)
296 {
297 return Mathf.Max(Mathf.Sign(Vector3.Dot(forward, wo)), 0.0f);
298 }
299
300 /// <summary>
301 /// Attenuation by Light Shape for Spot Light with Pyramid Shape
302 /// </summary>
303 /// <param name="forward">Forward Vector of Directional Light</param>
304 /// <param name="wo">Vector pointing to the eye</param>
305 /// <returns>Attenuation Factor</returns>
306 static public float ShapeAttenuationSpotPyramidLight(Vector3 forward, Vector3 wo)
307 {
308 return ShapeAttenuationSpotBoxLight(forward, wo);
309 }
310
311 /// <summary>
312 /// Attenuation by Light Shape for Area Light with Tube Shape
313 /// </summary>
314 /// <param name="lightPositionWS">World Space position of the Light</param>
315 /// <param name="lightSide">Vector pointing to the side (right or left) or the light</param>
316 /// <param name="lightWidth">Width (half extent) of the tube light</param>
317 /// <param name="cam">Camera rendering the Tube Light</param>
318 /// <returns>Attenuation Factor</returns>
319 static public float ShapeAttenuationAreaTubeLight(Vector3 lightPositionWS, Vector3 lightSide, float lightWidth, Camera cam)
320 {
321 // Ref: https://hal.archives-ouvertes.fr/hal-02155101/document
322 // Listing 1.6. Analytic line-diffuse integration.
323 float Fpo(float d, float l)
324 {
325 return l / (d * (d * d + l * l)) + Mathf.Atan(l / d) / (d * d);
326 }
327
328 float Fwt(float d, float l)
329 {
330 return l * l / (d * (d * d + l * l));
331 }
332
333 Vector3 p1Global = lightPositionWS + lightSide * lightWidth * 0.5f;
334 Vector3 p2Global = lightPositionWS - lightSide * lightWidth * 0.5f;
335 Vector3 p1Front = lightPositionWS + cam.transform.right * lightWidth * 0.5f;
336 Vector3 p2Front = lightPositionWS - cam.transform.right * lightWidth * 0.5f;
337
338 Vector3 p1World = cam.transform.InverseTransformPoint(p1Global);
339 Vector3 p2World = cam.transform.InverseTransformPoint(p2Global);
340 Vector3 p1WorldFront = cam.transform.InverseTransformPoint(p1Front);
341 Vector3 p2WorldFront = cam.transform.InverseTransformPoint(p2Front);
342
343 float DiffLineIntegral(Vector3 p1, Vector3 p2)
344 {
345 float diffIntegral;
346 // tangent
347 Vector3 wt = (p2 - p1).normalized;
348 // clamping
349 if (p1.z <= 0.0 && p2.z <= 0.0)
350 {
351 diffIntegral = 0.0f;
352 }
353 else
354 {
355 if (p1.z < 0.0)
356 p1 = (p1 * p2.z - p2 * p1.z) / (+p2.z - p1.z);
357 if (p2.z < 0.0)
358 p2 = (-p1 * p2.z + p2 * p1.z) / (-p2.z + p1.z);
359 // parameterization
360 float l1 = Vector3.Dot(p1, wt);
361 float l2 = Vector3.Dot(p2, wt);
362 // shading point orthonormal projection on the line
363 Vector3 po = p1 - l1 * wt;
364 // distance to line
365 float d = po.magnitude;
366 // integral
367 float integral = (Fpo(d, l2) - Fpo(d, l1)) * po.z + (Fwt(d, l2) - Fwt(d, l1)) * wt.z;
368 diffIntegral = integral / Mathf.PI;
369 }
370
371 return diffIntegral;
372 }
373
374 float frontModulation = DiffLineIntegral(p1WorldFront, p2WorldFront);
375 float worldModulation = DiffLineIntegral(p1World, p2World);
376
377 return frontModulation > 0.0f ? worldModulation / frontModulation : 1.0f;
378 }
379
380 static float ShapeAttenuateForwardLight(Vector3 forward, Vector3 wo)
381 {
382 return Mathf.Max(Vector3.Dot(forward, wo), 0.0f);
383 }
384
385 /// <summary>
386 /// Attenuation by Light Shape for Area Light with Rectangular Shape
387 /// </summary>
388 /// <param name="forward">Forward Vector of Directional Light</param>
389 /// <param name="wo">Vector pointing to the eye</param>
390 /// <returns>Attenuation Factor</returns>
391 static public float ShapeAttenuationAreaRectangleLight(Vector3 forward, Vector3 wo)
392 {
393 return ShapeAttenuateForwardLight(forward, wo);
394 }
395
396 /// <summary>
397 /// Attenuation by Light Shape for Area Light with Disc Shape
398 /// </summary>
399 /// <param name="forward">Forward Vector of Directional Light</param>
400 /// <param name="wo">Vector pointing to the eye</param>
401 /// <returns>Attenuation Factor</returns>
402 static public float ShapeAttenuationAreaDiscLight(Vector3 forward, Vector3 wo)
403 {
404 return ShapeAttenuateForwardLight(forward, wo);
405 }
406
407 static bool IsLensFlareSRPHidden(Camera cam, LensFlareComponentSRP comp, LensFlareDataSRP data)
408 {
409 if (!comp.enabled ||
410 !comp.gameObject.activeSelf ||
411 !comp.gameObject.activeInHierarchy ||
412 data == null ||
413 data.elements == null ||
414 data.elements.Length == 0 ||
415 comp.intensity <= 0.0f ||
416 ((cam.cullingMask & (1 << comp.gameObject.layer)) == 0))
417 return true;
418
419 return false;
420 }
421
422 /// <summary>
423 /// Compute internal parameters needed to render single flare
424 /// </summary>
425 /// <param name="screenPos">The screen position of the flare.</param>
426 /// <param name="translationScale">The scale of translation applied to the flare.</param>
427 /// <param name="rayOff0">The base offset for the flare ray.</param>
428 /// <param name="vLocalScreenRatio">The ratio of the flare's local screen size.</param>
429 /// <param name="angleDeg">The base angle of rotation for the flare.</param>
430 /// <param name="position">The position along the flare's radial line, relative to the source, where 1.0 represents the edge of the screen.</param>
431 /// <param name="angularOffset">Angular offset applied to the flare's position.</param>
432 /// <param name="positionOffset">The offset from the flare's calculated position.</param>
433 /// <param name="autoRotate">Flag to enable automatic rotation based on flare's position.</param>
434 /// <returns>A Vector4 object representing the shader parameters _FlareData0.</returns>
435 static public Vector4 GetFlareData0(Vector2 screenPos, Vector2 translationScale, Vector2 rayOff0, Vector2 vLocalScreenRatio, float angleDeg, float position, float angularOffset, Vector2 positionOffset, bool autoRotate)
436 {
437 if (!SystemInfo.graphicsUVStartsAtTop)
438 {
439 angleDeg *= -1;
440 positionOffset.y *= -1;
441 }
442
443 float globalCos0 = Mathf.Cos(-angularOffset * Mathf.Deg2Rad);
444 float globalSin0 = Mathf.Sin(-angularOffset * Mathf.Deg2Rad);
445
446 Vector2 rayOff = -translationScale * (screenPos + screenPos * (position - 1.0f));
447 rayOff = new Vector2(globalCos0 * rayOff.x - globalSin0 * rayOff.y,
448 globalSin0 * rayOff.x + globalCos0 * rayOff.y);
449
450 float rotation = angleDeg;
451
452 rotation += 180.0f;
453 if (autoRotate)
454 {
455 Vector2 pos = (rayOff.normalized * vLocalScreenRatio) * translationScale;
456
457 rotation += -Mathf.Rad2Deg * Mathf.Atan2(pos.y, pos.x);
458 }
459 rotation *= Mathf.Deg2Rad;
460 float localCos0 = Mathf.Cos(-rotation);
461 float localSin0 = Mathf.Sin(-rotation);
462
463 return new Vector4(localCos0, localSin0, positionOffset.x + rayOff0.x * translationScale.x, -positionOffset.y + rayOff0.y * translationScale.y);
464 }
465
466 static Vector2 GetLensFlareRayOffset(Vector2 screenPos, float position, float globalCos0, float globalSin0, Vector2 vAspectRatio)
467 {
468 Vector2 rayOff = -(screenPos + screenPos * (position - 1.0f));
469 return new Vector2(globalCos0 * rayOff.x - globalSin0 * rayOff.y,
470 globalSin0 * rayOff.x + globalCos0 * rayOff.y);
471 }
472
473 static Vector3 WorldToViewport(Camera camera, bool isLocalLight, bool isCameraRelative, Matrix4x4 viewProjMatrix, Vector3 positionWS)
474 {
475 if (isLocalLight)
476 {
477 return WorldToViewportLocal(isCameraRelative, viewProjMatrix, camera.transform.position, positionWS);
478 }
479 else
480 {
481 return WorldToViewportDistance(camera, positionWS);
482 }
483 }
484
485 static Vector3 WorldToViewportLocal(bool isCameraRelative, Matrix4x4 viewProjMatrix, Vector3 cameraPosWS, Vector3 positionWS)
486 {
487 Vector3 localPositionWS = positionWS;
488 if (isCameraRelative)
489 {
490 localPositionWS -= cameraPosWS;
491 }
492 Vector4 viewportPos4 = viewProjMatrix * localPositionWS;
493 Vector3 viewportPos = new Vector3(viewportPos4.x, viewportPos4.y, 0f);
494 viewportPos /= viewportPos4.w;
495 viewportPos.x = viewportPos.x * 0.5f + 0.5f;
496 viewportPos.y = viewportPos.y * 0.5f + 0.5f;
497 viewportPos.y = 1.0f - viewportPos.y;
498 viewportPos.z = viewportPos4.w;
499 return viewportPos;
500 }
501
502 static Vector3 WorldToViewportDistance(Camera cam, Vector3 positionWS)
503 {
504 Vector4 camPos = cam.worldToCameraMatrix * positionWS;
505 Vector4 viewportPos4 = cam.projectionMatrix * camPos;
506 Vector3 viewportPos = new Vector3(viewportPos4.x, viewportPos4.y, 0f);
507 viewportPos /= viewportPos4.w;
508 viewportPos.x = viewportPos.x * 0.5f + 0.5f;
509 viewportPos.y = viewportPos.y * 0.5f + 0.5f;
510 viewportPos.z = viewportPos4.w;
511 return viewportPos;
512 }
513
514 /// <summary>
515 /// Check if at least one LensFlareComponentSRP request occlusion from background clouds
516 /// </summary>
517 /// <param name="cam">Camera</param>
518 /// <returns>true if cloud occlusion is requested</returns>
519 static public bool IsCloudLayerOpacityNeeded(Camera cam)
520 {
521 if (Instance.IsEmpty())
522 return false;
523
524#if UNITY_EDITOR
525 if (cam.cameraType == CameraType.SceneView)
526 {
527 // Determine whether the "Animated Materials" checkbox is checked for the current view.
528 for (int i = 0; i < UnityEditor.SceneView.sceneViews.Count; i++) // Using a foreach on an ArrayList generates garbage ...
529 {
530 var sv = UnityEditor.SceneView.sceneViews[i] as UnityEditor.SceneView;
531 if (sv.camera == cam && !sv.sceneViewState.flaresEnabled)
532 {
533 return false;
534 }
535 }
536 }
537#endif
538
539 foreach (LensFlareCompInfo info in Instance.Data)
540 {
541 if (info == null || info.comp == null)
542 continue;
543
544 LensFlareComponentSRP comp = info.comp;
545 LensFlareDataSRP data = comp.lensFlareData;
546
547 if (IsLensFlareSRPHidden(cam, comp, data) ||
548 !comp.useOcclusion ||
549 (comp.useOcclusion && comp.sampleCount == 0))
550 continue;
551
552 if (comp.environmentOcclusion)
553 return true;
554 }
555
556 return false;
557 }
558
559 static void SetOcclusionPermutation(CommandBuffer cmd, bool useFogOpacityOcclusion, int _FlareSunOcclusionTex, Texture sunOcclusionTexture)
560 {
561 uint occlusionPermutation = (uint)(LensFlareOcclusionPermutation.Depth);
562
563 if (useFogOpacityOcclusion && sunOcclusionTexture != null)
564 {
565 occlusionPermutation |= (uint)(LensFlareOcclusionPermutation.FogOpacity);
566 cmd.SetGlobalTexture(_FlareSunOcclusionTex, sunOcclusionTexture);
567 }
568
569 int convInt = unchecked((int)occlusionPermutation);
570 cmd.SetGlobalInt(_FlareOcclusionPermutation, convInt);
571 }
572
573#if UNITY_EDITOR
574 static bool IsPrefabStageEnabled()
575 {
576 return UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null;
577 }
578
579 static LensFlareComponentSRP[] GetLensFlareComponents(GameObject go)
580 {
581 return go.GetComponentsInChildren<LensFlareComponentSRP>(false);
582 }
583
584 static bool IsCurrentPrefabLensFlareComponent(GameObject go, LensFlareComponentSRP[] components, LensFlareComponentSRP comp)
585 {
586 foreach (LensFlareComponentSRP x in components)
587 {
588 if (x == comp)
589 return true;
590 }
591
592 return false;
593 }
594#endif
595
596 /// <summary>
597 /// Effective Job of drawing the set of Lens Flare registered
598 /// </summary>
599 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
600 /// <param name="cam">Camera</param>
601 /// <param name="xr">XR Infos</param>
602 /// <param name="xrIndex">Index of the SinglePass XR</param>
603 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
604 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
605 /// <param name="usePanini">Set if use Panani Projection</param>
606 /// <param name="paniniDistance">Distance used for Panini projection</param>
607 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
608 /// <param name="isCameraRelative">Set if camera is relative</param>
609 /// <param name="cameraPositionWS">Camera World Space position</param>
610 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
611 /// <param name="cmd">Command Buffer</param>
612 /// <param name="taaEnabled">Set if TAA is enabled</param>
613 /// <param name="hasCloudLayer">Unused</param>
614 /// <param name="cloudOpacityTexture">Unused</param>
615 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
616 /// <param name="_FlareOcclusionTex">ShaderID for the FlareOcclusionTex</param>
617 /// <param name="_FlareCloudOpacity">ShaderID for the FlareCloudOpacity</param>
618 /// <param name="_FlareOcclusionIndex">ShaderID for the FlareOcclusionIndex</param>
619 /// <param name="_FlareTex">ShaderID for the FlareTex</param>
620 /// <param name="_FlareColorValue">ShaderID for the FlareColor</param>
621 /// <param name="_FlareSunOcclusionTex">ShaderID for the _FlareSunOcclusionTex</param>
622 /// <param name="_FlareData0">ShaderID for the FlareData0</param>
623 /// <param name="_FlareData1">ShaderID for the FlareData1</param>
624 /// <param name="_FlareData2">ShaderID for the FlareData2</param>
625 /// <param name="_FlareData3">ShaderID for the FlareData3</param>
626 /// <param name="_FlareData4">ShaderID for the FlareData4</param>
627 [Obsolete("Use ComputeOcclusion without _FlareOcclusionTex.._FlareData4 parameters.")]
628 static public void ComputeOcclusion(Material lensFlareShader, Camera cam, XRPass xr, int xrIndex,
629 float actualWidth, float actualHeight,
630 bool usePanini, float paniniDistance, float paniniCropToFit, bool isCameraRelative,
631 Vector3 cameraPositionWS,
632 Matrix4x4 viewProjMatrix,
633 UnsafeCommandBuffer cmd,
634 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture,
635 int _FlareOcclusionTex, int _FlareCloudOpacity, int _FlareOcclusionIndex, int _FlareTex, int _FlareColorValue, int _FlareSunOcclusionTex, int _FlareData0, int _FlareData1, int _FlareData2, int _FlareData3, int _FlareData4)
636 {
637 ComputeOcclusion(
638 lensFlareShader, cam, xr, xrIndex,
639 actualWidth, actualHeight,
640 usePanini, paniniDistance, paniniCropToFit, isCameraRelative,
641 cameraPositionWS,
642 viewProjMatrix,
643 cmd.m_WrappedCommandBuffer,
644 taaEnabled, hasCloudLayer, cloudOpacityTexture, sunOcclusionTexture,
645 _FlareOcclusionTex, _FlareCloudOpacity, _FlareOcclusionIndex, _FlareTex, _FlareColorValue, _FlareSunOcclusionTex, _FlareData0, _FlareData1, _FlareData2, _FlareData3, _FlareData4);
646 }
647
648 /// <summary>
649 /// Effective Job of drawing the set of Lens Flare registered
650 /// </summary>
651 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
652 /// <param name="cam">Camera</param>
653 /// <param name="xr">XRPass data.</param>
654 /// <param name="xrIndex">XR multipass ID.</param>
655 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
656 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
657 /// <param name="usePanini">Set if use Panani Projection</param>
658 /// <param name="paniniDistance">Distance used for Panini projection</param>
659 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
660 /// <param name="isCameraRelative">Set if camera is relative</param>
661 /// <param name="cameraPositionWS">Camera World Space position</param>
662 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
663 /// <param name="cmd">Command Buffer</param>
664 /// <param name="taaEnabled">Set if TAA is enabled</param>
665 /// <param name="hasCloudLayer">Unused</param>
666 /// <param name="cloudOpacityTexture">Unused</param>
667 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
668 static public void ComputeOcclusion(Material lensFlareShader, Camera cam, XRPass xr, int xrIndex,
669 float actualWidth, float actualHeight,
670 bool usePanini, float paniniDistance, float paniniCropToFit, bool isCameraRelative,
671 Vector3 cameraPositionWS,
672 Matrix4x4 viewProjMatrix,
673 UnsafeCommandBuffer cmd,
674 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture)
675 {
676 ComputeOcclusion(
677 lensFlareShader, cam, xr, xrIndex,
678 actualWidth, actualHeight,
679 usePanini, paniniDistance, paniniCropToFit, isCameraRelative,
680 cameraPositionWS,
681 viewProjMatrix,
682 cmd.m_WrappedCommandBuffer,
683 taaEnabled, hasCloudLayer, cloudOpacityTexture, sunOcclusionTexture);
684 }
685
686 /// <summary>
687 /// Effective Job of drawing the set of Lens Flare registered
688 /// </summary>
689 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
690 /// <param name="cam">Camera</param>
691 /// <param name="xr">XRPass data.</param>
692 /// <param name="xrIndex">XR multipass ID.</param>
693 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
694 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
695 /// <param name="usePanini">Set if use Panani Projection</param>
696 /// <param name="paniniDistance">Distance used for Panini projection</param>
697 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
698 /// <param name="isCameraRelative">Set if camera is relative</param>
699 /// <param name="cameraPositionWS">Camera World Space position</param>
700 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
701 /// <param name="cmd">Command Buffer</param>
702 /// <param name="taaEnabled">Set if TAA is enabled</param>
703 /// <param name="hasCloudLayer">Unused</param>
704 /// <param name="cloudOpacityTexture">Unused</param>
705 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
706 /// <param name="_FlareOcclusionTex">ShaderID for the FlareOcclusionTex</param>
707 /// <param name="_FlareCloudOpacity">ShaderID for the FlareCloudOpacity</param>
708 /// <param name="_FlareOcclusionIndex">ShaderID for the FlareOcclusionIndex</param>
709 /// <param name="_FlareTex">ShaderID for the FlareTex</param>
710 /// <param name="_FlareColorValue">ShaderID for the FlareColor</param>
711 /// <param name="_FlareSunOcclusionTex">ShaderID for the _FlareSunOcclusionTex</param>
712 /// <param name="_FlareData0">ShaderID for the FlareData0</param>
713 /// <param name="_FlareData1">ShaderID for the FlareData1</param>
714 /// <param name="_FlareData2">ShaderID for the FlareData2</param>
715 /// <param name="_FlareData3">ShaderID for the FlareData3</param>
716 /// <param name="_FlareData4">ShaderID for the FlareData4</param>
717 [Obsolete("Use ComputeOcclusion without _FlareOcclusionTex.._FlareData4 parameters.")]
718 static public void ComputeOcclusion(Material lensFlareShader, Camera cam, XRPass xr, int xrIndex,
719 float actualWidth, float actualHeight,
720 bool usePanini, float paniniDistance, float paniniCropToFit, bool isCameraRelative,
721 Vector3 cameraPositionWS,
722 Matrix4x4 viewProjMatrix,
723 Rendering.CommandBuffer cmd,
724 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture,
725 int _FlareOcclusionTex, int _FlareCloudOpacity, int _FlareOcclusionIndex, int _FlareTex, int _FlareColorValue, int _FlareSunOcclusionTex, int _FlareData0, int _FlareData1, int _FlareData2, int _FlareData3, int _FlareData4)
726 {
727 ComputeOcclusion(lensFlareShader, cam, xr, xrIndex,
728 actualWidth, actualHeight,
729 usePanini, paniniDistance, paniniCropToFit, isCameraRelative,
730 cameraPositionWS,
731 viewProjMatrix,
732 cmd,
733 taaEnabled, hasCloudLayer, cloudOpacityTexture, sunOcclusionTexture);
734 }
735
736 static bool ForceSingleElement(LensFlareDataElementSRP element)
737 {
738 return !element.allowMultipleElement
739 || element.count == 1
740 || element.flareType == SRPLensFlareType.Ring;
741 }
742
743 /// <summary>
744 /// Effective Job of drawing the set of Lens Flare registered
745 /// </summary>
746 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
747 /// <param name="cam">Camera</param>
748 /// <param name="xr">XRPass data.</param>
749 /// <param name="xrIndex">XR multipass ID.</param>
750 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
751 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
752 /// <param name="usePanini">Set if use Panani Projection</param>
753 /// <param name="paniniDistance">Distance used for Panini projection</param>
754 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
755 /// <param name="isCameraRelative">Set if camera is relative</param>
756 /// <param name="cameraPositionWS">Camera World Space position</param>
757 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
758 /// <param name="cmd">Command Buffer</param>
759 /// <param name="taaEnabled">Set if TAA is enabled</param>
760 /// <param name="hasCloudLayer">Unused</param>
761 /// <param name="cloudOpacityTexture">Unused</param>
762 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
763 static public void ComputeOcclusion(Material lensFlareShader, Camera cam, XRPass xr, int xrIndex,
764 float actualWidth, float actualHeight,
765 bool usePanini, float paniniDistance, float paniniCropToFit, bool isCameraRelative,
766 Vector3 cameraPositionWS,
767 Matrix4x4 viewProjMatrix,
768 Rendering.CommandBuffer cmd,
769 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture)
770 {
771 if (!IsOcclusionRTCompatible())
772 return;
773
774 xr.StopSinglePass(cmd);
775
776#if UNITY_EDITOR
777 bool inPrefabStage = IsPrefabStageEnabled();
778 UnityEditor.SceneManagement.PrefabStage prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
779 GameObject prefabGameObject = null;
780 LensFlareComponentSRP[] prefabStageLensFlares = null;
781 if (prefabStage != null)
782 {
783 prefabGameObject = prefabStage.prefabContentsRoot;
784 if (prefabGameObject == null)
785 return;
786 prefabStageLensFlares = GetLensFlareComponents(prefabGameObject);
787 if (prefabStageLensFlares.Length == 0)
788 {
789 return;
790 }
791 }
792#endif
793
794 if (Instance.IsEmpty())
795 return;
796
797#if UNITY_EDITOR
798 if (cam.cameraType == CameraType.SceneView)
799 {
800 // Determine whether the "Animated Materials" checkbox is checked for the current view.
801 for (int i = 0; i < UnityEditor.SceneView.sceneViews.Count; i++) // Using a foreach on an ArrayList generates garbage ...
802 {
803 var sv = UnityEditor.SceneView.sceneViews[i] as UnityEditor.SceneView;
804 if (sv.camera == cam && !sv.sceneViewState.flaresEnabled)
805 {
806 return;
807 }
808 }
809 }
810#endif
811
812 Vector2 screenSize = new Vector2(actualWidth, actualHeight);
813 float screenRatio = screenSize.x / screenSize.y;
814 Vector2 vScreenRatio = new Vector2(screenRatio, 1.0f);
815
816#if ENABLE_VR && ENABLE_XR_MODULE
817 if (xr.enabled && xr.singlePassEnabled)
818 {
819 CoreUtils.SetRenderTarget(cmd, occlusionRT, depthSlice: xrIndex);
820 cmd.SetGlobalInt(_ViewId, xrIndex);
821 }
822 else
823#endif
824 {
825 CoreUtils.SetRenderTarget(cmd, occlusionRT);
826 if (xr.enabled) // multipass
827 cmd.SetGlobalInt(_ViewId, xr.multipassId);
828 else
829 cmd.SetGlobalInt(_ViewId, -1);
830 }
831
832 if (!taaEnabled)
833 {
834 cmd.ClearRenderTarget(false, true, Color.black);
835 }
836
837 float dx = 1.0f / ((float)maxLensFlareWithOcclusion);
838 float dy = 1.0f / ((float)(maxLensFlareWithOcclusionTemporalSample + mergeNeeded));
839 float halfx = 0.5f / ((float)maxLensFlareWithOcclusion);
840 float halfy = 0.5f / ((float)(maxLensFlareWithOcclusionTemporalSample + mergeNeeded));
841
842 foreach (LensFlareCompInfo info in m_Data)
843 {
844 if (info == null || info.comp == null)
845 continue;
846
847 LensFlareComponentSRP comp = info.comp;
848 LensFlareDataSRP data = comp.lensFlareData;
849
850 if (IsLensFlareSRPHidden(cam, comp, data) ||
851 !comp.useOcclusion ||
852 (comp.useOcclusion && comp.sampleCount == 0))
853 continue;
854
855#if UNITY_EDITOR
856 if (inPrefabStage && !IsCurrentPrefabLensFlareComponent(prefabGameObject, prefabStageLensFlares, comp))
857 {
858 continue;
859 }
860#endif
861
862 Light light = null;
863 if (!comp.TryGetComponent<Light>(out light))
864 light = null;
865
866 Vector3 positionWS;
867 Vector3 viewportPos;
868
869 bool isDirLight = false;
870 if (light != null && light.type == LightType.Directional)
871 {
872 positionWS = -light.transform.forward * cam.farClipPlane;
873 isDirLight = true;
874 }
875 else
876 {
877 positionWS = comp.transform.position;
878 }
879
880 viewportPos = WorldToViewport(cam, !isDirLight, isCameraRelative, viewProjMatrix, positionWS);
881
882 if (usePanini && cam == Camera.main)
883 {
884 viewportPos = DoPaniniProjection(viewportPos, actualWidth, actualHeight, cam.fieldOfView, paniniCropToFit, paniniDistance);
885 }
886
887 if (viewportPos.z < 0.0f)
888 continue;
889
890 if (!comp.allowOffScreen)
891 {
892 if (viewportPos.x < 0.0f || viewportPos.x > 1.0f ||
893 viewportPos.y < 0.0f || viewportPos.y > 1.0f)
894 continue;
895 }
896
897 Vector3 diffToObject = positionWS - cameraPositionWS;
898 // Check if the light is forward, can be an issue with,
899 // the math associated to Panini projection
900 if (Vector3.Dot(cam.transform.forward, diffToObject) < 0.0f)
901 {
902 continue;
903 }
904 float distToObject = diffToObject.magnitude;
905 float coefDistSample = distToObject / comp.maxAttenuationDistance;
906 float coefScaleSample = distToObject / comp.maxAttenuationScale;
907 float distanceAttenuation = !isDirLight && comp.distanceAttenuationCurve.length > 0 ? comp.distanceAttenuationCurve.Evaluate(coefDistSample) : 1.0f;
908 float scaleByDistance = !isDirLight && comp.scaleByDistanceCurve.length >= 1 ? comp.scaleByDistanceCurve.Evaluate(coefScaleSample) : 1.0f;
909
910 Vector3 dir;
911 if (isDirLight)
912 dir = comp.transform.forward;
913 else
914 dir = (cam.transform.position - comp.transform.position).normalized;
915 Vector3 screenPosZ = WorldToViewport(cam, !isDirLight, isCameraRelative, viewProjMatrix, positionWS + dir * comp.occlusionOffset);
916
917 float adjustedOcclusionRadius = isDirLight ? comp.celestialProjectedOcclusionRadius(cam) : comp.occlusionRadius;
918 Vector2 occlusionRadiusEdgeScreenPos0 = (Vector2)viewportPos;
919 Vector2 occlusionRadiusEdgeScreenPos1 = (Vector2)WorldToViewport(cam, !isDirLight, isCameraRelative, viewProjMatrix, positionWS + cam.transform.up * adjustedOcclusionRadius);
920 float occlusionRadius = (occlusionRadiusEdgeScreenPos1 - occlusionRadiusEdgeScreenPos0).magnitude;
921
922 cmd.SetGlobalVector(_FlareData1, new Vector4(occlusionRadius, comp.sampleCount, screenPosZ.z, actualHeight / actualWidth));
923
924 SetOcclusionPermutation(cmd, comp.environmentOcclusion, _FlareSunOcclusionTex, sunOcclusionTexture);
925 cmd.EnableShaderKeyword("FLARE_COMPUTE_OCCLUSION");
926
927 Vector2 screenPos = new Vector2(2.0f * viewportPos.x - 1.0f, -(2.0f * viewportPos.y - 1.0f));
928 if (!SystemInfo.graphicsUVStartsAtTop && isDirLight)
929 screenPos.y = -screenPos.y;
930
931 Vector2 radPos = new Vector2(Mathf.Abs(screenPos.x), Mathf.Abs(screenPos.y));
932 float radius = Mathf.Max(radPos.x, radPos.y); // l1 norm (instead of l2 norm)
933 float radialsScaleRadius = comp.radialScreenAttenuationCurve.length > 0 ? comp.radialScreenAttenuationCurve.Evaluate(radius) : 1.0f;
934
935 float compIntensity = comp.intensity * radialsScaleRadius * distanceAttenuation;
936
937 if (compIntensity <= 0.0f)
938 continue;
939
940 float globalCos0 = Mathf.Cos(0.0f);
941 float globalSin0 = Mathf.Sin(0.0f);
942
943 float position = 0.0f;
944
945 float usedGradientPosition = Mathf.Clamp01(1.0f - 1e-6f);
946
947 cmd.SetGlobalVector(_FlareData3, new Vector4(comp.allowOffScreen ? 1.0f : -1.0f, usedGradientPosition, Mathf.Exp(Mathf.Lerp(0.0f, 4.0f, 1.0f)), 1.0f / 3.0f));
948
949 Vector2 rayOff = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0, vScreenRatio);
950 Vector4 flareData0 = GetFlareData0(screenPos, Vector2.one, rayOff, vScreenRatio, 0.0f, position, 0.0f, Vector2.zero, false);
951
952 cmd.SetGlobalVector(_FlareData0, flareData0);
953 cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, 0.0f, 0.0f));
954
955 Rect rect;
956 if (taaEnabled)
957 rect = new Rect() { x = info.index, y = frameIdx + mergeNeeded, width = 1, height = 1 };
958 else
959 rect = new Rect() { x = info.index, y = 0, width = 1, height = 1 };
960 cmd.SetViewport(rect);
961
962 Blitter.DrawQuad(cmd, lensFlareShader, lensFlareShader.FindPass("LensFlareOcclusion"));
963 }
964
965 // Clear the remaining buffer if not TAA the whole OcclusionRT is already cleared
966 if (taaEnabled)
967 {
968 CoreUtils.SetRenderTarget(cmd, occlusionRT, depthSlice: xrIndex);
969 cmd.SetViewport(new Rect() { x = m_Data.Count, y = 0, width = (maxLensFlareWithOcclusion - m_Data.Count), height = (maxLensFlareWithOcclusionTemporalSample + mergeNeeded) });
970 cmd.ClearRenderTarget(false, true, Color.black);
971 }
972
973 ++frameIdx;
974 frameIdx %= maxLensFlareWithOcclusionTemporalSample;
975
976 xr.StartSinglePass(cmd);
977 }
978
979 /// <summary>
980 /// Function that process a single element of a LensFlareDataSRP, this function is used on scene/game view and on the inspector for the thumbnail.
981 /// </summary>
982 /// <param name="element">Single LensFlare asset we need to process.</param>
983 /// <param name="cmd">Command Buffer.</param>
984 /// <param name="globalColorModulation">Color Modulation from Component?</param>
985 /// <param name="light">Light used for the modulation of this singe element.</param>
986 /// <param name="compIntensity">Intensity from Component.</param>
987 /// <param name="scale">Scale from component</param>
988 /// <param name="lensFlareShader">Shader used on URP or HDRP.</param>
989 /// <param name="screenPos">Screen Position</param>
990 /// <param name="compAllowOffScreen">Allow Lens Flare offscreen</param>
991 /// <param name="vScreenRatio">Screen Ratio</param>
992 /// <param name="flareData1">_FlareData1 used internally by the shader.</param>
993 /// <param name="preview">true if we are on preview on the inspector</param>
994 /// <param name="depth">Depth counter for recursive call of 'ProcessLensFlareSRPElementsSingle'.</param>
995 public static void ProcessLensFlareSRPElementsSingle(LensFlareDataElementSRP element, Rendering.CommandBuffer cmd, Color globalColorModulation, Light light,
996 float compIntensity, float scale, Material lensFlareShader, Vector2 screenPos, bool compAllowOffScreen, Vector2 vScreenRatio, Vector4 flareData1, bool preview, int depth)
997 {
998 if (element == null ||
999 element.visible == false ||
1000 (element.lensFlareTexture == null && element.flareType == SRPLensFlareType.Image) ||
1001 element.localIntensity <= 0.0f ||
1002 element.count <= 0 ||
1003 (element.flareType == SRPLensFlareType.LensFlareDataSRP && element.lensFlareDataSRP == null))
1004 return;
1005
1006 if (element.flareType == SRPLensFlareType.LensFlareDataSRP && element.lensFlareDataSRP != null)
1007 {
1008 ProcessLensFlareSRPElements(ref element.lensFlareDataSRP.elements, cmd, globalColorModulation, light, compIntensity, scale, lensFlareShader, screenPos, compAllowOffScreen, vScreenRatio, flareData1, preview, depth + 1);
1009 return;
1010 }
1011
1012 Color colorModulation = globalColorModulation;
1013 if (light != null && element.modulateByLightColor)
1014 {
1015 if (light.useColorTemperature)
1016 colorModulation *= light.color * Mathf.CorrelatedColorTemperatureToRGB(light.colorTemperature);
1017 else
1018 colorModulation *= light.color;
1019 }
1020
1021 Color curColor = colorModulation;
1022
1023 float currentIntensity = element.localIntensity * compIntensity;
1024
1025 if (currentIntensity <= 0.0f)
1026 return;
1027
1028 Texture texture = element.lensFlareTexture;
1029 float usedAspectRatio;
1030 if (element.flareType == SRPLensFlareType.Image)
1031 usedAspectRatio = element.preserveAspectRatio ? ((((float)texture.height) / (float)texture.width)) : 1.0f;
1032 else
1033 usedAspectRatio = 1.0f;
1034
1035 float rotation = element.rotation;
1036
1037 Vector2 elemSizeXY;
1038 if (element.preserveAspectRatio)
1039 {
1040 if (usedAspectRatio >= 1.0f)
1041 {
1042 elemSizeXY = new Vector2(element.sizeXY.x / usedAspectRatio, element.sizeXY.y);
1043 }
1044 else
1045 {
1046 elemSizeXY = new Vector2(element.sizeXY.x, element.sizeXY.y * usedAspectRatio);
1047 }
1048 }
1049 else
1050 {
1051 elemSizeXY = new Vector2(element.sizeXY.x, element.sizeXY.y);
1052 }
1053 float scaleSize = 0.1f; // Arbitrary value
1054 Vector2 size = new Vector2(elemSizeXY.x, elemSizeXY.y);
1055 float combinedScale = scaleSize * element.uniformScale * scale;
1056 size *= combinedScale;
1057
1058 curColor *= element.tint;
1059
1060 float angularOffset = SystemInfo.graphicsUVStartsAtTop ? element.angularOffset : -element.angularOffset;
1061 float globalCos0 = Mathf.Cos(-angularOffset * Mathf.Deg2Rad);
1062 float globalSin0 = Mathf.Sin(-angularOffset * Mathf.Deg2Rad);
1063
1064 float position = 2.0f * element.position;
1065
1066 SRPLensFlareBlendMode blendMode = element.blendMode;
1067 int materialPass;
1068#if UNITY_EDITOR
1069 if (!preview)
1070#endif
1071 {
1072 if (blendMode == SRPLensFlareBlendMode.Additive)
1073 materialPass = lensFlareShader.FindPass("LensFlareAdditive");
1074 else if (blendMode == SRPLensFlareBlendMode.Screen)
1075 materialPass = lensFlareShader.FindPass("LensFlareScreen");
1076 else if (blendMode == SRPLensFlareBlendMode.Premultiply)
1077 materialPass = lensFlareShader.FindPass("LensFlarePremultiply");
1078 else if (blendMode == SRPLensFlareBlendMode.Lerp)
1079 materialPass = lensFlareShader.FindPass("LensFlareLerp");
1080 else
1081 materialPass = lensFlareShader.FindPass("LensFlareOcclusion");
1082 }
1083#if UNITY_EDITOR
1084 else
1085 {
1086 if (element.inverseSDF)
1087 materialPass = lensFlareShader.FindPass("FlarePreviewInverted");
1088 else
1089 materialPass = lensFlareShader.FindPass("FlarePreviewNotInverted");
1090 }
1091#endif
1092
1093 flareData1.x = (float)element.flareType;
1094 if (ForceSingleElement(element))
1095 cmd.SetGlobalVector(_FlareData1, flareData1);
1096
1097 if (element.flareType == SRPLensFlareType.Circle ||
1098 element.flareType == SRPLensFlareType.Polygon ||
1099 element.flareType == SRPLensFlareType.Ring)
1100 {
1101 if (element.inverseSDF)
1102 {
1103 cmd.EnableShaderKeyword("FLARE_INVERSE_SDF");
1104 }
1105 else
1106 {
1107 cmd.DisableShaderKeyword("FLARE_INVERSE_SDF");
1108 }
1109 }
1110 else
1111 {
1112 cmd.DisableShaderKeyword("FLARE_INVERSE_SDF");
1113 }
1114
1115 if (element.lensFlareTexture != null)
1116 cmd.SetGlobalTexture(_FlareTex, element.lensFlareTexture);
1117
1118 if (element.tintColorType != SRPLensFlareColorType.Constant)
1119 cmd.SetGlobalTexture(_FlareRadialTint, element.tintGradient.GetTexture());
1120
1121 float usedGradientPosition = Mathf.Clamp01((1.0f - element.edgeOffset) - 1e-6f);
1122 if (element.flareType == SRPLensFlareType.Polygon)
1123 usedGradientPosition = Mathf.Pow(usedGradientPosition + 1.0f, 5);
1124
1125 Vector2 ComputeLocalSize(Vector2 rayOff, Vector2 rayOff0, Vector2 curSize, AnimationCurve distortionCurve)
1126 {
1127 Vector2 rayOffZ = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0, vScreenRatio);
1128 Vector2 localRadPos;
1129 float localRadius;
1130 if (!element.distortionRelativeToCenter)
1131 {
1132 localRadPos = (rayOff - rayOff0) * 0.5f;
1133 localRadius = Mathf.Clamp01(Mathf.Max(Mathf.Abs(localRadPos.x), Mathf.Abs(localRadPos.y))); // l1 norm (instead of l2 norm)
1134 }
1135 else
1136 {
1137 localRadPos = screenPos + (rayOff + new Vector2(element.positionOffset.x, -element.positionOffset.y)) * element.translationScale;
1138 localRadius = Mathf.Clamp01(localRadPos.magnitude); // l2 norm (instead of l1 norm)
1139 }
1140
1141 float localLerpValue = Mathf.Clamp01(distortionCurve.Evaluate(localRadius));
1142 return new Vector2(Mathf.Lerp(curSize.x, element.targetSizeDistortion.x * combinedScale / usedAspectRatio, localLerpValue),
1143 Mathf.Lerp(curSize.y, element.targetSizeDistortion.y * combinedScale, localLerpValue));
1144 }
1145
1146 float usedSDFRoundness = element.sdfRoundness;
1147
1148 Vector4 data3 =
1149 new Vector4(compAllowOffScreen ? 1.0f : -1.0f,
1150 usedGradientPosition,
1151 Mathf.Exp(Mathf.Lerp(0.0f, 4.0f, Mathf.Clamp01(1.0f - element.fallOff))),
1152 element.flareType == SRPLensFlareType.Ring ? element.ringThickness : 1.0f / (float)element.sideCount);
1153 cmd.SetGlobalVector(_FlareData3, data3);
1154 if (element.flareType == SRPLensFlareType.Polygon)
1155 {
1156 float invSide = 1.0f / (float)element.sideCount;
1157 float rCos = Mathf.Cos(Mathf.PI * invSide);
1158 float roundValue = rCos * usedSDFRoundness;
1159 float r = rCos - roundValue;
1160 float an = 2.0f * Mathf.PI * invSide;
1161 float he = r * Mathf.Tan(0.5f * an);
1162 cmd.SetGlobalVector(_FlareData4, new Vector4(usedSDFRoundness, r, an, he));
1163 }
1164 else if (element.flareType == SRPLensFlareType.Ring)
1165 {
1166 cmd.SetGlobalVector(_FlareData4, new Vector4(element.noiseAmplitude, element.noiseFrequency, element.noiseSpeed, 0.0f));
1167 }
1168 else
1169 {
1170 cmd.SetGlobalVector(_FlareData4, new Vector4(usedSDFRoundness, 0.0f, 0.0f, 0.0f));
1171 }
1172
1173 cmd.SetGlobalVector(_FlareData5, new Vector4((float)(element.tintColorType), currentIntensity, element.shapeCutOffSpeed, element.shapeCutOffRadius));
1174 if (ForceSingleElement(element))
1175 {
1176 Vector2 localSize = size;
1177 Vector2 rayOff = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0, vScreenRatio);
1178 if (element.enableRadialDistortion)
1179 {
1180 Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0, vScreenRatio);
1181 localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
1182 }
1183 Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, rayOff, vScreenRatio, rotation, position, angularOffset, element.positionOffset, element.autoRotate);
1184
1185 cmd.SetGlobalVector(_FlareData0, flareData0);
1186 cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
1187 cmd.SetGlobalVector(_FlareColorValue, curColor);
1188
1189 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
1190 }
1191 else
1192 {
1193 float dLength = 2.0f * element.lengthSpread / ((float)(element.count - 1));
1194
1195 if (element.distribution == SRPLensFlareDistribution.Uniform)
1196 {
1197 float uniformAngle = 0.0f;
1198 for (int elemIdx = 0; elemIdx < element.count; ++elemIdx)
1199 {
1200 Vector2 localSize = size;
1201 Vector2 rayOff = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0, vScreenRatio);
1202 if (element.enableRadialDistortion)
1203 {
1204 Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0, vScreenRatio);
1205 localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
1206 }
1207
1208 float timeScale = element.count >= 2 ? ((float)elemIdx) / ((float)(element.count - 1)) : 0.5f;
1209
1210 Color col = element.colorGradient.Evaluate(timeScale);
1211
1212 Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, rayOff, vScreenRatio, rotation + uniformAngle, position, angularOffset, element.positionOffset, element.autoRotate);
1213 cmd.SetGlobalVector(_FlareData0, flareData0);
1214
1215 flareData1.y = (float)elemIdx;
1216 cmd.SetGlobalVector(_FlareData1, flareData1);
1217 cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
1218 cmd.SetGlobalVector(_FlareColorValue, curColor * col);
1219
1220 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
1221 position += dLength;
1222 uniformAngle += element.uniformAngle;
1223 }
1224 }
1225 else if (element.distribution == SRPLensFlareDistribution.Random)
1226 {
1227 Random.State backupRandState = UnityEngine.Random.state;
1228 Random.InitState(element.seed);
1229 Vector2 side = new Vector2(globalSin0, globalCos0);
1230 side *= element.positionVariation.y;
1231 float RandomRange(float min, float max)
1232 {
1233 return Random.Range(min, max);
1234 }
1235
1236 for (int elemIdx = 0; elemIdx < element.count; ++elemIdx)
1237 {
1238 float localIntensity = RandomRange(-1.0f, 1.0f) * element.intensityVariation + 1.0f;
1239
1240 Vector2 rayOff = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0, vScreenRatio);
1241 Vector2 localSize = size;
1242 if (element.enableRadialDistortion)
1243 {
1244 Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0, vScreenRatio);
1245 localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
1246 }
1247
1248 localSize += localSize * (element.scaleVariation * RandomRange(-1.0f, 1.0f));
1249
1250 Color randCol = element.colorGradient.Evaluate(RandomRange(0.0f, 1.0f));
1251
1252 Vector2 localPositionOffset = element.positionOffset + RandomRange(-1.0f, 1.0f) * side;
1253
1254 float localRotation = rotation + RandomRange(-Mathf.PI, Mathf.PI) * element.rotationVariation;
1255
1256 if (localIntensity > 0.0f)
1257 {
1258 Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, rayOff, vScreenRatio, localRotation, position, angularOffset, localPositionOffset, element.autoRotate);
1259 cmd.SetGlobalVector(_FlareData0, flareData0);
1260 flareData1.y = (float)elemIdx;
1261 cmd.SetGlobalVector(_FlareData1, flareData1);
1262 cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
1263 cmd.SetGlobalVector(_FlareColorValue, curColor * randCol * localIntensity);
1264
1265 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
1266 }
1267
1268 position += dLength;
1269 position += 0.5f * dLength * RandomRange(-1.0f, 1.0f) * element.positionVariation.x;
1270 }
1271 Random.state = backupRandState;
1272 }
1273 else if (element.distribution == SRPLensFlareDistribution.Curve)
1274 {
1275 for (int elemIdx = 0; elemIdx < element.count; ++elemIdx)
1276 {
1277 float timeScale = element.count >= 2 ? ((float)elemIdx) / ((float)(element.count - 1)) : 0.5f;
1278
1279 Color col = element.colorGradient.Evaluate(timeScale);
1280
1281 float positionSpacing = element.positionCurve.length > 0 ? element.positionCurve.Evaluate(timeScale) : 1.0f;
1282
1283 float localPos = position + 2.0f * element.lengthSpread * positionSpacing;
1284 Vector2 rayOff = GetLensFlareRayOffset(screenPos, localPos, globalCos0, globalSin0, vScreenRatio);
1285 Vector2 localSize = size;
1286 if (element.enableRadialDistortion)
1287 {
1288 Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0, vScreenRatio);
1289 localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
1290 }
1291 float sizeCurveValue = element.scaleCurve.length > 0 ? element.scaleCurve.Evaluate(timeScale) : 1.0f;
1292 localSize *= sizeCurveValue;
1293
1294 float angleFromCurve = element.uniformAngleCurve.Evaluate(timeScale) * (180.0f - (180.0f / (float)element.count));
1295
1296 Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, rayOff, vScreenRatio, rotation + angleFromCurve, localPos, angularOffset, element.positionOffset, element.autoRotate);
1297 cmd.SetGlobalVector(_FlareData0, flareData0);
1298 flareData1.y = (float)elemIdx;
1299 cmd.SetGlobalVector(_FlareData1, flareData1);
1300 cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
1301 cmd.SetGlobalVector(_FlareColorValue, curColor * col);
1302
1303 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
1304 }
1305 }
1306 }
1307 }
1308
1309 static void ProcessLensFlareSRPElements(ref LensFlareDataElementSRP[] elements, Rendering.CommandBuffer cmd, Color globalColorModulation, Light light,
1310 float compIntensity, float scale, Material lensFlareShader, Vector2 screenPos, bool compAllowOffScreen, Vector2 vScreenRatio, Vector4 flareData1, bool preview, int depth)
1311 {
1312 if (depth > 16)
1313 {
1314 Debug.LogWarning("LensFlareSRPAsset contains too deep recursive asset (> 16). Be careful to not have recursive aggregation, A contains B, B contains A, ... which will produce an infinite loop.");
1315 return;
1316 }
1317
1318 foreach (LensFlareDataElementSRP element in elements)
1319 {
1320 ProcessLensFlareSRPElementsSingle(element, cmd, globalColorModulation, light, compIntensity, scale, lensFlareShader, screenPos, compAllowOffScreen, vScreenRatio, flareData1, preview, depth);
1321 }
1322 }
1323
1324 /// <summary>
1325 /// Effective Job of drawing the set of Lens Flare registered
1326 /// </summary>
1327 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1328 /// <param name="cam">Camera</param>
1329 /// <param name="viewport">Viewport used for rendering and XR applied.</param>
1330 /// <param name="xr">XRPass data.</param>
1331 /// <param name="xrIndex">XR multipass ID.</param>
1332 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1333 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1334 /// <param name="usePanini">Set if use Panani Projection</param>
1335 /// <param name="paniniDistance">Distance used for Panini projection</param>
1336 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
1337 /// <param name="isCameraRelative">Set if camera is relative</param>
1338 /// <param name="cameraPositionWS">Camera World Space position</param>
1339 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
1340 /// <param name="cmd">Command Buffer</param>
1341 /// <param name="taaEnabled">Set if TAA is enabled</param>
1342 /// <param name="hasCloudLayer">Unused</param>
1343 /// <param name="cloudOpacityTexture">Unused</param>
1344 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
1345 /// <param name="colorBuffer">Source Render Target which contains the Color Buffer</param>
1346 /// <param name="GetLensFlareLightAttenuation">Delegate to which return return the Attenuation of the light based on their shape which uses the functions ShapeAttenuation...(...), must reimplemented per SRP</param>
1347 /// <param name="_FlareOcclusionTex">ShaderID for the FlareOcclusionTex</param>
1348 /// <param name="_FlareOcclusionIndex">ShaderID for the FlareOcclusionIndex</param>
1349 /// <param name="_FlareOcclusionRemapTex">ShaderID for the OcclusionRemap</param>
1350 /// <param name="_FlareCloudOpacity">ShaderID for the FlareCloudOpacity</param>
1351 /// <param name="_FlareSunOcclusionTex">ShaderID for the _FlareSunOcclusionTex</param>
1352 /// <param name="_FlareTex">ShaderID for the FlareTex</param>
1353 /// <param name="_FlareColorValue">ShaderID for the FlareColor</param>
1354 /// <param name="_FlareData0">ShaderID for the FlareData0</param>
1355 /// <param name="_FlareData1">ShaderID for the FlareData1</param>
1356 /// <param name="_FlareData2">ShaderID for the FlareData2</param>
1357 /// <param name="_FlareData3">ShaderID for the FlareData3</param>
1358 /// <param name="_FlareData4">ShaderID for the FlareData4</param>
1359 /// <param name="debugView">Debug View which setup black background to see only Lens Flare</param>
1360 [Obsolete("Use DoLensFlareDataDrivenCommon without _FlareOcclusionRemapTex.._FlareData4 parameters.")]
1361 static public void DoLensFlareDataDrivenCommon(Material lensFlareShader, Camera cam, Rect viewport, XRPass xr, int xrIndex,
1362 float actualWidth, float actualHeight,
1363 bool usePanini, float paniniDistance, float paniniCropToFit,
1364 bool isCameraRelative,
1365 Vector3 cameraPositionWS,
1366 Matrix4x4 viewProjMatrix,
1367 UnsafeCommandBuffer cmd,
1368 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture,
1369 Rendering.RenderTargetIdentifier colorBuffer,
1370 System.Func<Light, Camera, Vector3, float> GetLensFlareLightAttenuation,
1371 int _FlareOcclusionRemapTex, int _FlareOcclusionTex, int _FlareOcclusionIndex,
1372 int _FlareCloudOpacity, int _FlareSunOcclusionTex,
1373 int _FlareTex, int _FlareColorValue, int _FlareData0, int _FlareData1, int _FlareData2, int _FlareData3, int _FlareData4,
1374 bool debugView)
1375 {
1376 DoLensFlareDataDrivenCommon(lensFlareShader, cam, viewport, xr, xrIndex,
1377 actualWidth, actualHeight,
1378 usePanini, paniniDistance, paniniCropToFit,
1379 isCameraRelative,
1380 cameraPositionWS,
1381 viewProjMatrix,
1382 cmd,
1383 taaEnabled, hasCloudLayer, cloudOpacityTexture, sunOcclusionTexture,
1384 colorBuffer,
1385 GetLensFlareLightAttenuation,
1386 debugView);
1387 }
1388
1389 /// <summary>
1390 /// Effective Job of drawing the set of Lens Flare registered
1391 /// </summary>
1392 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1393 /// <param name="cam">Camera</param>
1394 /// <param name="viewport">Viewport used for rendering and XR applied.</param>
1395 /// <param name="xr">XRPass data.</param>
1396 /// <param name="xrIndex">XR multipass ID.</param>
1397 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1398 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1399 /// <param name="usePanini">Set if use Panani Projection</param>
1400 /// <param name="paniniDistance">Distance used for Panini projection</param>
1401 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
1402 /// <param name="isCameraRelative">Set if camera is relative</param>
1403 /// <param name="cameraPositionWS">Camera World Space position</param>
1404 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
1405 /// <param name="cmd">Command Buffer</param>
1406 /// <param name="taaEnabled">Set if TAA is enabled</param>
1407 /// <param name="hasCloudLayer">Unused</param>
1408 /// <param name="cloudOpacityTexture">Unused</param>
1409 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
1410 /// <param name="colorBuffer">Source Render Target which contains the Color Buffer</param>
1411 /// <param name="GetLensFlareLightAttenuation">Delegate to which return return the Attenuation of the light based on their shape which uses the functions ShapeAttenuation...(...), must reimplemented per SRP</param>
1412 /// <param name="debugView">Debug View which setup black background to see only Lens Flare</param>
1413 static public void DoLensFlareDataDrivenCommon(Material lensFlareShader, Camera cam, Rect viewport, XRPass xr, int xrIndex,
1414 float actualWidth, float actualHeight,
1415 bool usePanini, float paniniDistance, float paniniCropToFit,
1416 bool isCameraRelative,
1417 Vector3 cameraPositionWS,
1418 Matrix4x4 viewProjMatrix,
1419 UnsafeCommandBuffer cmd,
1420 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture,
1421 Rendering.RenderTargetIdentifier colorBuffer,
1422 System.Func<Light, Camera, Vector3, float> GetLensFlareLightAttenuation,
1423 bool debugView)
1424 {
1425 DoLensFlareDataDrivenCommon(lensFlareShader, cam, viewport, xr, xrIndex,
1426 actualWidth, actualHeight,
1427 usePanini, paniniDistance, paniniCropToFit,
1428 isCameraRelative,
1429 cameraPositionWS,
1430 viewProjMatrix,
1431 cmd.m_WrappedCommandBuffer,
1432 taaEnabled, hasCloudLayer, cloudOpacityTexture, sunOcclusionTexture,
1433 colorBuffer,
1434 GetLensFlareLightAttenuation,
1435 debugView);
1436 }
1437
1438 /// <summary>
1439 /// Effective Job of drawing the set of Lens Flare registered
1440 /// </summary>
1441 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1442 /// <param name="cam">Camera</param>
1443 /// <param name="viewport">Viewport used for rendering and XR applied.</param>
1444 /// <param name="xr">XRPass data.</param>
1445 /// <param name="xrIndex">XR multipass ID.</param>
1446 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1447 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1448 /// <param name="usePanini">Set if use Panani Projection</param>
1449 /// <param name="paniniDistance">Distance used for Panini projection</param>
1450 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
1451 /// <param name="isCameraRelative">Set if camera is relative</param>
1452 /// <param name="cameraPositionWS">Camera World Space position</param>
1453 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
1454 /// <param name="cmd">Command Buffer</param>
1455 /// <param name="taaEnabled">Set if TAA is enabled</param>
1456 /// <param name="hasCloudLayer">Unused</param>
1457 /// <param name="cloudOpacityTexture">Unused</param>
1458 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
1459 /// <param name="colorBuffer">Source Render Target which contains the Color Buffer</param>
1460 /// <param name="GetLensFlareLightAttenuation">Delegate to which return return the Attenuation of the light based on their shape which uses the functions ShapeAttenuation...(...), must reimplemented per SRP</param>
1461 /// <param name="_FlareOcclusionTex">ShaderID for the FlareOcclusionTex</param>
1462 /// <param name="_FlareOcclusionIndex">ShaderID for the FlareOcclusionIndex</param>
1463 /// <param name="_FlareOcclusionRemapTex">ShaderID for the OcclusionRemap</param>
1464 /// <param name="_FlareCloudOpacity">ShaderID for the FlareCloudOpacity</param>
1465 /// <param name="_FlareSunOcclusionTex">ShaderID for the _FlareSunOcclusionTex</param>
1466 /// <param name="_FlareTex">ShaderID for the FlareTex</param>
1467 /// <param name="_FlareColorValue">ShaderID for the FlareColor</param>
1468 /// <param name="_FlareData0">ShaderID for the FlareData0</param>
1469 /// <param name="_FlareData1">ShaderID for the FlareData1</param>
1470 /// <param name="_FlareData2">ShaderID for the FlareData2</param>
1471 /// <param name="_FlareData3">ShaderID for the FlareData3</param>
1472 /// <param name="_FlareData4">ShaderID for the FlareData4</param>
1473 /// <param name="debugView">Debug View which setup black background to see only Lens Flare</param>
1474 [Obsolete("Use DoLensFlareDataDrivenCommon without _FlareOcclusionRemapTex.._FlareData4 parameters.")]
1475 static public void DoLensFlareDataDrivenCommon(Material lensFlareShader, Camera cam, Rect viewport, XRPass xr, int xrIndex,
1476 float actualWidth, float actualHeight,
1477 bool usePanini, float paniniDistance, float paniniCropToFit,
1478 bool isCameraRelative,
1479 Vector3 cameraPositionWS,
1480 Matrix4x4 viewProjMatrix,
1481 Rendering.CommandBuffer cmd,
1482 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture,
1483 Rendering.RenderTargetIdentifier colorBuffer,
1484 System.Func<Light, Camera, Vector3, float> GetLensFlareLightAttenuation,
1485 int _FlareOcclusionRemapTex, int _FlareOcclusionTex, int _FlareOcclusionIndex,
1486 int _FlareCloudOpacity, int _FlareSunOcclusionTex,
1487 int _FlareTex, int _FlareColorValue, int _FlareData0, int _FlareData1, int _FlareData2, int _FlareData3, int _FlareData4,
1488 bool debugView)
1489 {
1490 DoLensFlareDataDrivenCommon(lensFlareShader, cam, viewport, xr, xrIndex,
1491 actualWidth, actualHeight,
1492 usePanini, paniniDistance, paniniCropToFit,
1493 isCameraRelative,
1494 cameraPositionWS,
1495 viewProjMatrix,
1496 cmd,
1497 taaEnabled, hasCloudLayer, cloudOpacityTexture, sunOcclusionTexture,
1498 colorBuffer,
1499 GetLensFlareLightAttenuation,
1500 debugView);
1501 }
1502
1503 /// <summary>
1504 /// Effective Job of drawing the set of Lens Flare registered
1505 /// </summary>
1506 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1507 /// <param name="cam">Camera</param>
1508 /// <param name="viewport">Viewport used for rendering and XR applied.</param>
1509 /// <param name="xr">XRPass data.</param>
1510 /// <param name="xrIndex">XR multipass ID.</param>
1511 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1512 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1513 /// <param name="usePanini">Set if use Panani Projection</param>
1514 /// <param name="paniniDistance">Distance used for Panini projection</param>
1515 /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
1516 /// <param name="isCameraRelative">Set if camera is relative</param>
1517 /// <param name="cameraPositionWS">Camera World Space position</param>
1518 /// <param name="viewProjMatrix">View Projection Matrix of the current camera</param>
1519 /// <param name="cmd">Command Buffer</param>
1520 /// <param name="taaEnabled">Set if TAA is enabled</param>
1521 /// <param name="hasCloudLayer">Unused</param>
1522 /// <param name="cloudOpacityTexture">Unused</param>
1523 /// <param name="sunOcclusionTexture">Sun Occlusion Texture from VolumetricCloud on HDRP or null</param>
1524 /// <param name="colorBuffer">Source Render Target which contains the Color Buffer</param>
1525 /// <param name="GetLensFlareLightAttenuation">Delegate to which return return the Attenuation of the light based on their shape which uses the functions ShapeAttenuation...(...), must reimplemented per SRP</param>
1526 /// <param name="debugView">Debug View which setup black background to see only Lens Flare</param>
1527 static public void DoLensFlareDataDrivenCommon(Material lensFlareShader, Camera cam, Rect viewport, XRPass xr, int xrIndex,
1528 float actualWidth, float actualHeight,
1529 bool usePanini, float paniniDistance, float paniniCropToFit,
1530 bool isCameraRelative,
1531 Vector3 cameraPositionWS,
1532 Matrix4x4 viewProjMatrix,
1533 Rendering.CommandBuffer cmd,
1534 bool taaEnabled, bool hasCloudLayer, Texture cloudOpacityTexture, Texture sunOcclusionTexture,
1535 Rendering.RenderTargetIdentifier colorBuffer,
1536 System.Func<Light, Camera, Vector3, float> GetLensFlareLightAttenuation,
1537 bool debugView)
1538 {
1539#if UNITY_EDITOR
1540 bool inPrefabStage = IsPrefabStageEnabled();
1541 UnityEditor.SceneManagement.PrefabStage prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
1542 GameObject prefabGameObject = null;
1543 LensFlareComponentSRP[] prefabStageLensFlares = null;
1544 if (prefabStage != null)
1545 {
1546 prefabGameObject = prefabStage.prefabContentsRoot;
1547 if (prefabGameObject == null)
1548 return;
1549 prefabStageLensFlares = GetLensFlareComponents(prefabGameObject);
1550 if (prefabStageLensFlares.Length == 0)
1551 {
1552 return;
1553 }
1554 }
1555#endif
1556
1557 xr.StopSinglePass(cmd);
1558
1559 Vector2 vScreenRatio;
1560
1561 if (Instance.IsEmpty())
1562 return;
1563
1564#if UNITY_EDITOR
1565 if (cam.cameraType == CameraType.SceneView)
1566 {
1567 // Determine whether the "Animated Materials" checkbox is checked for the current view.
1568 for (int i = 0; i < UnityEditor.SceneView.sceneViews.Count; i++) // Using a foreach on an ArrayList generates garbage ...
1569 {
1570 var sv = UnityEditor.SceneView.sceneViews[i] as UnityEditor.SceneView;
1571 if (sv.camera == cam && !sv.sceneViewState.flaresEnabled)
1572 {
1573 return;
1574 }
1575 }
1576 }
1577#endif
1578
1579 Vector2 screenSize = new Vector2(actualWidth, actualHeight);
1580 float screenRatio = screenSize.x / screenSize.y;
1581 vScreenRatio = new Vector2(screenRatio, 1.0f);
1582
1583#if ENABLE_VR && ENABLE_XR_MODULE
1584 if (xr.enabled && xr.singlePassEnabled)
1585 {
1586 CoreUtils.SetRenderTarget(cmd, colorBuffer, depthSlice: xrIndex);
1587 cmd.SetGlobalInt(_ViewId, xrIndex);
1588 }
1589 else
1590#endif
1591 {
1592 CoreUtils.SetRenderTarget(cmd, colorBuffer);
1593 if (xr.enabled) // multipass
1594 cmd.SetGlobalInt(_ViewId, xr.multipassId);
1595 else
1596 cmd.SetGlobalInt(_ViewId, 0);
1597 }
1598
1599 cmd.SetViewport(viewport);
1600 if (debugView)
1601 {
1602 // Background pitch black to see only the Flares
1603 cmd.ClearRenderTarget(false, true, Color.black);
1604 }
1605
1606 foreach (LensFlareCompInfo info in m_Data)
1607 {
1608 if (info == null || info.comp == null)
1609 continue;
1610
1611 LensFlareComponentSRP comp = info.comp;
1612 LensFlareDataSRP data = comp.lensFlareData;
1613
1614 if (IsLensFlareSRPHidden(cam, comp, data))
1615 continue;
1616
1617#if UNITY_EDITOR
1618 if (inPrefabStage && !IsCurrentPrefabLensFlareComponent(prefabGameObject, prefabStageLensFlares, comp))
1619 {
1620 continue;
1621 }
1622#endif
1623
1624 Light light = null;
1625 if (!comp.TryGetComponent<Light>(out light))
1626 light = null;
1627
1628 Vector3 positionWS;
1629 Vector3 viewportPos;
1630
1631 bool isDirLight = false;
1632 if (light != null && light.type == LightType.Directional)
1633 {
1634 positionWS = -light.transform.forward * cam.farClipPlane;
1635 isDirLight = true;
1636 }
1637 else
1638 {
1639 positionWS = comp.transform.position;
1640 }
1641
1642 // After positionWS computation, lightOverride do not change the position
1643 if (comp.lightOverride != null)
1644 {
1645 light = comp.lightOverride;
1646 }
1647
1648 viewportPos = WorldToViewport(cam, !isDirLight, isCameraRelative, viewProjMatrix, positionWS);
1649
1650 if (usePanini && cam == Camera.main)
1651 {
1652 viewportPos = DoPaniniProjection(viewportPos, actualWidth, actualHeight, cam.fieldOfView, paniniCropToFit, paniniDistance);
1653 }
1654
1655 if (viewportPos.z < 0.0f)
1656 continue;
1657
1658 if (!comp.allowOffScreen)
1659 {
1660 if (viewportPos.x < 0.0f || viewportPos.x > 1.0f ||
1661 viewportPos.y < 0.0f || viewportPos.y > 1.0f)
1662 continue;
1663 }
1664
1665 Vector3 diffToObject = positionWS - cameraPositionWS;
1666 // Check if the light is forward, can be an issue with,
1667 // the math associated to Panini projection
1668 if (Vector3.Dot(cam.transform.forward, diffToObject) < 0.0f)
1669 {
1670 continue;
1671 }
1672 float distToObject = diffToObject.magnitude;
1673 float coefDistSample = distToObject / comp.maxAttenuationDistance;
1674 float coefScaleSample = distToObject / comp.maxAttenuationScale;
1675 float distanceAttenuation = !isDirLight && comp.distanceAttenuationCurve.length > 0 ? comp.distanceAttenuationCurve.Evaluate(coefDistSample) : 1.0f;
1676 float scaleByDistance = !isDirLight && comp.scaleByDistanceCurve.length >= 1 ? comp.scaleByDistanceCurve.Evaluate(coefScaleSample) : 1.0f;
1677
1678 Color globalColorModulation = Color.white;
1679
1680 if (light != null)
1681 {
1682 if (comp.attenuationByLightShape)
1683 globalColorModulation *= GetLensFlareLightAttenuation(light, cam, -diffToObject.normalized);
1684 }
1685
1686 Vector2 screenPos = new Vector2(2.0f * viewportPos.x - 1.0f, -(2.0f * viewportPos.y - 1.0f));
1687
1688 if(!SystemInfo.graphicsUVStartsAtTop && isDirLight) // Y-flip for OpenGL & directional light
1689 screenPos.y = -screenPos.y;
1690
1691 Vector2 radPos = new Vector2(Mathf.Abs(screenPos.x), Mathf.Abs(screenPos.y));
1692 float radius = Mathf.Max(radPos.x, radPos.y); // l1 norm (instead of l2 norm)
1693 float radialsScaleRadius = comp.radialScreenAttenuationCurve.length > 0 ? comp.radialScreenAttenuationCurve.Evaluate(radius) : 1.0f;
1694
1695 float compIntensity = comp.intensity * radialsScaleRadius * distanceAttenuation;
1696
1697 if (compIntensity <= 0.0f)
1698 continue;
1699
1700 globalColorModulation *= distanceAttenuation;
1701
1702 Vector3 dir = (cam.transform.position - comp.transform.position).normalized;
1703 Vector3 screenPosZ = WorldToViewport(cam, !isDirLight, isCameraRelative, viewProjMatrix, positionWS + dir * comp.occlusionOffset);
1704
1705 float adjustedOcclusionRadius = isDirLight ? comp.celestialProjectedOcclusionRadius(cam) : comp.occlusionRadius;
1706 Vector2 occlusionRadiusEdgeScreenPos0 = (Vector2)viewportPos;
1707 Vector2 occlusionRadiusEdgeScreenPos1 = (Vector2)WorldToViewport(cam, !isDirLight, isCameraRelative, viewProjMatrix, positionWS + cam.transform.up * adjustedOcclusionRadius);
1708 float occlusionRadius = (occlusionRadiusEdgeScreenPos1 - occlusionRadiusEdgeScreenPos0).magnitude;
1709
1710 if (comp.useOcclusion)
1711 {
1712 cmd.SetGlobalTexture(_FlareOcclusionTex, occlusionRT);
1713 cmd.EnableShaderKeyword("FLARE_HAS_OCCLUSION");
1714 }
1715 else
1716 {
1717 cmd.DisableShaderKeyword("FLARE_HAS_OCCLUSION");
1718 }
1719
1720 if (IsOcclusionRTCompatible())
1721 {
1722 cmd.DisableShaderKeyword("FLARE_OPENGL3_OR_OPENGLCORE");
1723 }
1724 else
1725 {
1726 cmd.EnableShaderKeyword("FLARE_OPENGL3_OR_OPENGLCORE");
1727 }
1728
1729 cmd.SetGlobalVector(_FlareOcclusionIndex, new Vector4((float)info.index, 0.0f, 0.0f, 0.0f));
1730 cmd.SetGlobalTexture(_FlareOcclusionRemapTex, comp.occlusionRemapCurve.GetTexture());
1731
1732 Vector4 flareData1 = new Vector4(0.0f, comp.sampleCount, screenPosZ.z, actualHeight / actualWidth);
1733 ProcessLensFlareSRPElements(ref data.elements, cmd, globalColorModulation, light,
1734 compIntensity, scaleByDistance * comp.scale, lensFlareShader,
1735 screenPos, comp.allowOffScreen, vScreenRatio, flareData1, false, 0);
1736 }
1737
1738 xr.StartSinglePass(cmd);
1739 }
1740
1741 /// <summary>
1742 /// Effective Job of drawing Lens Flare Screen Space.
1743 /// </summary>
1744 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1745 /// <param name="cam">Camera</param>
1746 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1747 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1748 /// <param name="tintColor">tintColor to multiply all the flare by</param>
1749 /// <param name="originalBloomTexture">original Bloom texture used to write on at the end of compositing</param>
1750 /// <param name="bloomMipTexture">Bloom mip texture used as data for the effect</param>
1751 /// <param name="spectralLut">spectralLut used for chromatic aberration effect</param>
1752 /// <param name="streakTextureTmp">Texture used for the multiple pass streaks effect</param>
1753 /// <param name="streakTextureTmp2">Texture used for the multiple pass streaks effect</param>
1754 /// <param name="parameters1">globalIntensity, regularIntensity, reverseIntensity, warpedIntensity</param>
1755 /// <param name="parameters2">vignetteEffect, startingPosition, scale, freeSlot</param>
1756 /// <param name="parameters3">samples, sampleDimmer, chromaticAbberationIntensity, chromaticAbberationSamples</param>
1757 /// <param name="parameters4">streaksIntensity, streaksLength, streaksOrientation, streaksThreshold</param>
1758 /// <param name="parameters5">downsampleStreak, warpedFlareScaleX, warpedFlareScaleY, freeSlot</param>
1759 /// <param name="cmd">UnsafeCommandBuffer</param>
1760 /// <param name="result">Result RT for the Lens Flare Screen Space</param>
1761 /// <param name="debugView">Information if we are in debug mode or not</param>
1762 static public void DoLensFlareScreenSpaceCommon(
1763 Material lensFlareShader,
1764 Camera cam,
1765 float actualWidth,
1766 float actualHeight,
1767 Color tintColor,
1768 Texture originalBloomTexture,
1769 Texture bloomMipTexture,
1770 Texture spectralLut,
1771 Texture streakTextureTmp,
1772 Texture streakTextureTmp2,
1773 Vector4 parameters1,
1774 Vector4 parameters2,
1775 Vector4 parameters3,
1776 Vector4 parameters4,
1777 Vector4 parameters5,
1778 UnsafeCommandBuffer cmd,
1779 RTHandle result,
1780 bool debugView)
1781 {
1782 DoLensFlareScreenSpaceCommon(
1783 lensFlareShader,
1784 cam,
1785 actualWidth,
1786 actualHeight,
1787 tintColor,
1788 originalBloomTexture,
1789 bloomMipTexture,
1790 spectralLut,
1791 streakTextureTmp,
1792 streakTextureTmp2,
1793 parameters1,
1794 parameters2,
1795 parameters3,
1796 parameters4,
1797 parameters5,
1798 cmd.m_WrappedCommandBuffer,
1799 result,
1800 debugView);
1801 }
1802
1803 /// <summary>
1804 /// Effective Job of drawing Lens Flare Screen Space.
1805 /// </summary>
1806 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1807 /// <param name="cam">Camera</param>
1808 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1809 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1810 /// <param name="tintColor">tintColor to multiply all the flare by</param>
1811 /// <param name="originalBloomTexture">original Bloom texture used to write on at the end of compositing</param>
1812 /// <param name="bloomMipTexture">Bloom mip texture used as data for the effect</param>
1813 /// <param name="spectralLut">spectralLut used for chromatic aberration effect</param>
1814 /// <param name="streakTextureTmp">Texture used for the multiple pass streaks effect</param>
1815 /// <param name="streakTextureTmp2">Texture used for the multiple pass streaks effect</param>
1816 /// <param name="parameters1">globalIntensity, regularIntensity, reverseIntensity, warpedIntensity</param>
1817 /// <param name="parameters2">vignetteEffect, startingPosition, scale, freeSlot</param>
1818 /// <param name="parameters3">samples, sampleDimmer, chromaticAbberationIntensity, chromaticAbberationSamples</param>
1819 /// <param name="parameters4">streaksIntensity, streaksLength, streaksOrientation, streaksThreshold</param>
1820 /// <param name="parameters5">downsampleStreak, warpedFlareScaleX, warpedFlareScaleY, freeSlot</param>
1821 /// <param name="cmd">Command Buffer</param>
1822 /// <param name="result">Result RT for the Lens Flare Screen Space</param>
1823 /// <param name="_LensFlareScreenSpaceBloomMipTexture">ShaderID for the original bloom texture</param>
1824 /// <param name="_LensFlareScreenSpaceResultTexture">ShaderID for the LensFlareScreenSpaceResultTexture texture</param>
1825 /// <param name="_LensFlareScreenSpaceSpectralLut">ShaderID for the LensFlareScreenSpaceSpectralLut texture</param>
1826 /// <param name="_LensFlareScreenSpaceStreakTex">ShaderID for the LensFlareScreenSpaceStreakTex streak temp texture</param>
1827 /// <param name="_LensFlareScreenSpaceMipLevel">ShaderID for the LensFlareScreenSpaceMipLevel parameter</param>
1828 /// <param name="_LensFlareScreenSpaceTintColor">ShaderID for the LensFlareScreenSpaceTintColor color</param>
1829 /// <param name="_LensFlareScreenSpaceParams1">ShaderID for the LensFlareScreenSpaceParams1</param>
1830 /// <param name="_LensFlareScreenSpaceParams2">ShaderID for the LensFlareScreenSpaceParams2</param>
1831 /// <param name="_LensFlareScreenSpaceParams3">ShaderID for the LensFlareScreenSpaceParams3</param>
1832 /// <param name="_LensFlareScreenSpaceParams4">ShaderID for the LensFlareScreenSpaceParams4</param>
1833 /// <param name="_LensFlareScreenSpaceParams5">ShaderID for the LensFlareScreenSpaceParams5</param>
1834 /// <param name="debugView">Information if we are in debug mode or not</param>
1835 [Obsolete("Use DoLensFlareScreenSpaceCommon without _Shader IDs parameters.")]
1836 static public void DoLensFlareScreenSpaceCommon(
1837 Material lensFlareShader,
1838 Camera cam,
1839 float actualWidth,
1840 float actualHeight,
1841 Color tintColor,
1842 Texture originalBloomTexture,
1843 Texture bloomMipTexture,
1844 Texture spectralLut,
1845 Texture streakTextureTmp,
1846 Texture streakTextureTmp2,
1847 Vector4 parameters1,
1848 Vector4 parameters2,
1849 Vector4 parameters3,
1850 Vector4 parameters4,
1851 Vector4 parameters5,
1852 Rendering.CommandBuffer cmd,
1853 RTHandle result,
1854 int _LensFlareScreenSpaceBloomMipTexture,
1855 int _LensFlareScreenSpaceResultTexture,
1856 int _LensFlareScreenSpaceSpectralLut,
1857 int _LensFlareScreenSpaceStreakTex,
1858 int _LensFlareScreenSpaceMipLevel,
1859 int _LensFlareScreenSpaceTintColor,
1860 int _LensFlareScreenSpaceParams1,
1861 int _LensFlareScreenSpaceParams2,
1862 int _LensFlareScreenSpaceParams3,
1863 int _LensFlareScreenSpaceParams4,
1864 int _LensFlareScreenSpaceParams5,
1865 bool debugView)
1866 {
1867 DoLensFlareScreenSpaceCommon(
1868 lensFlareShader,
1869 cam,
1870 actualWidth,
1871 actualHeight,
1872 tintColor,
1873 originalBloomTexture,
1874 bloomMipTexture,
1875 spectralLut,
1876 streakTextureTmp,
1877 streakTextureTmp2,
1878 parameters1,
1879 parameters2,
1880 parameters3,
1881 parameters4,
1882 parameters5,
1883 cmd,
1884 result,
1885 debugView);
1886 }
1887
1888 /// <summary>
1889 /// Effective Job of drawing Lens Flare Screen Space.
1890 /// </summary>
1891 /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
1892 /// <param name="cam">Camera</param>
1893 /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
1894 /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
1895 /// <param name="tintColor">tintColor to multiply all the flare by</param>
1896 /// <param name="originalBloomTexture">original Bloom texture used to write on at the end of compositing</param>
1897 /// <param name="bloomMipTexture">Bloom mip texture used as data for the effect</param>
1898 /// <param name="spectralLut">spectralLut used for chromatic aberration effect</param>
1899 /// <param name="streakTextureTmp">Texture used for the multiple pass streaks effect</param>
1900 /// <param name="streakTextureTmp2">Texture used for the multiple pass streaks effect</param>
1901 /// <param name="parameters1">globalIntensity, regularIntensity, reverseIntensity, warpedIntensity</param>
1902 /// <param name="parameters2">vignetteEffect, startingPosition, scale, freeSlot</param>
1903 /// <param name="parameters3">samples, sampleDimmer, chromaticAbberationIntensity, chromaticAbberationSamples</param>
1904 /// <param name="parameters4">streaksIntensity, streaksLength, streaksOrientation, streaksThreshold</param>
1905 /// <param name="parameters5">downsampleStreak, warpedFlareScaleX, warpedFlareScaleY, freeSlot</param>
1906 /// <param name="cmd">Command Buffer</param>
1907 /// <param name="result">Result RT for the Lens Flare Screen Space</param>
1908 /// <param name="debugView">Information if we are in debug mode or not</param>
1909 static public void DoLensFlareScreenSpaceCommon(
1910 Material lensFlareShader,
1911 Camera cam,
1912 float actualWidth,
1913 float actualHeight,
1914 Color tintColor,
1915 Texture originalBloomTexture,
1916 Texture bloomMipTexture,
1917 Texture spectralLut,
1918 Texture streakTextureTmp,
1919 Texture streakTextureTmp2,
1920 Vector4 parameters1,
1921 Vector4 parameters2,
1922 Vector4 parameters3,
1923 Vector4 parameters4,
1924 Vector4 parameters5,
1925 Rendering.CommandBuffer cmd,
1926 RTHandle result,
1927 bool debugView)
1928 {
1929
1930 //Multiplying parameters value here for easier maintenance since they are the same numbers between SRPs
1931 parameters2.x = Mathf.Pow(parameters2.x, 0.25f); // Vignette effect
1932 parameters3.z = parameters3.z / 20f; // chromaticAbberationIntensity
1933 parameters4.y = parameters4.y * 10f; // Streak Length
1934 parameters4.z = parameters4.z / 90f; // Streak Orientation
1935 parameters5.y = 1.0f / parameters5.y; // WarpedFlareScale X
1936 parameters5.z = 1.0f / parameters5.z; // WarpedFlareScale Y
1937
1938 cmd.SetViewport(new Rect() { width = actualWidth, height = actualHeight });
1939 if (debugView)
1940 {
1941 // Background pitch black to see only the flares
1942 cmd.ClearRenderTarget(false, true, Color.black);
1943 }
1944
1945#if UNITY_EDITOR
1946 if (cam.cameraType == CameraType.SceneView)
1947 {
1948 // Determine whether the "Flare" checkbox is checked for the current view.
1949 for (int i = 0; i < UnityEditor.SceneView.sceneViews.Count; i++) // Using a foreach on an ArrayList generates garbage ...
1950 {
1951 var sv = UnityEditor.SceneView.sceneViews[i] as UnityEditor.SceneView;
1952 if (sv.camera == cam && !sv.sceneViewState.flaresEnabled)
1953 {
1954 return;
1955 }
1956 }
1957 }
1958#endif
1959
1960 // Multiple scaleX by aspect ratio so that default 1:1 scale for warped flare stays circular (as in data driven lens flare)
1961 float warpedScaleX = parameters5.y;
1962 warpedScaleX *= actualWidth / actualHeight;
1963 parameters5.y = warpedScaleX;
1964
1965 // This is to make sure the streak length is the same in all resolutions
1966 float streaksLength = parameters4.y;
1967 streaksLength *= actualWidth * 0.0005f;
1968 parameters4.y = streaksLength;
1969
1970 // List of the passes in LensFlareScreenSpace.shader
1971 int prefilterPass = lensFlareShader.FindPass("LensFlareScreenSpac Prefilter");
1972 int downSamplePass = lensFlareShader.FindPass("LensFlareScreenSpace Downsample");
1973 int upSamplePass = lensFlareShader.FindPass("LensFlareScreenSpace Upsample");
1974 int compositionPass = lensFlareShader.FindPass("LensFlareScreenSpace Composition");
1975 int writeToBloomPass = lensFlareShader.FindPass("LensFlareScreenSpace Write to BloomTexture");
1976
1977 // Setting the input textures
1978 cmd.SetGlobalTexture(_LensFlareScreenSpaceBloomMipTexture, bloomMipTexture);
1979 cmd.SetGlobalTexture(_LensFlareScreenSpaceSpectralLut, spectralLut);
1980
1981 // Setting parameters of the effects
1982 cmd.SetGlobalVector(_LensFlareScreenSpaceParams1, parameters1);
1983 cmd.SetGlobalVector(_LensFlareScreenSpaceParams2, parameters2);
1984 cmd.SetGlobalVector(_LensFlareScreenSpaceParams3, parameters3);
1985 cmd.SetGlobalVector(_LensFlareScreenSpaceParams4, parameters4);
1986 cmd.SetGlobalVector(_LensFlareScreenSpaceParams5, parameters5);
1987 cmd.SetGlobalColor(_LensFlareScreenSpaceTintColor, tintColor);
1988
1989 // We only do the first 3 pass if StreakIntensity (parameters4.x) is set to something above 0 to save costs
1990 if (parameters4.x > 0)
1991 {
1992 // Prefilter
1993 Rendering.CoreUtils.SetRenderTarget(cmd, streakTextureTmp);
1994 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, prefilterPass);
1995
1996 int maxLevel = Mathf.FloorToInt(Mathf.Log(Mathf.Max(actualHeight, actualWidth), 2.0f));
1997 int maxLevelDownsample = Mathf.Max(1, maxLevel);
1998 int maxLevelUpsample = 2;
1999 int startIndex = 0;
2000 bool even = false;
2001
2002 // Downsample
2003 for (int i = 0; i < maxLevelDownsample; i++)
2004 {
2005 even = (i % 2 == 0);
2006 cmd.SetGlobalInt(_LensFlareScreenSpaceMipLevel, i);
2007 cmd.SetGlobalTexture(_LensFlareScreenSpaceStreakTex, even ? streakTextureTmp : streakTextureTmp2);
2008 Rendering.CoreUtils.SetRenderTarget(cmd, even ? streakTextureTmp2 : streakTextureTmp);
2009
2010 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, downSamplePass);
2011 }
2012
2013 //Since we do a ping pong between streakTextureTmp & streakTextureTmp2, we need to know which texture is the last;
2014 if (even)
2015 startIndex = 1;
2016
2017 //Upsample
2018 for (int i = startIndex; i < (startIndex + maxLevelUpsample); i++)
2019 {
2020 even = (i % 2 == 0);
2021 cmd.SetGlobalInt(_LensFlareScreenSpaceMipLevel, (i - startIndex));
2022 cmd.SetGlobalTexture(_LensFlareScreenSpaceStreakTex, even ? streakTextureTmp : streakTextureTmp2);
2023 Rendering.CoreUtils.SetRenderTarget(cmd, even ? streakTextureTmp2 : streakTextureTmp);
2024
2025 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, upSamplePass);
2026 }
2027
2028 cmd.SetGlobalTexture(_LensFlareScreenSpaceStreakTex, even ? streakTextureTmp2 : streakTextureTmp);
2029 }
2030
2031 // Composition (Flares + Streaks)
2032 Rendering.CoreUtils.SetRenderTarget(cmd, result);
2033 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, compositionPass);
2034
2035 // Final pass, we add the result of the previous pass to the Original Bloom Texture.
2036 cmd.SetGlobalTexture(_LensFlareScreenSpaceResultTexture, result);
2037 Rendering.CoreUtils.SetRenderTarget(cmd, originalBloomTexture);
2038 UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, writeToBloomPass);
2039 }
2040
2041#region Panini Projection
2042 static Vector2 DoPaniniProjection(Vector2 screenPos, float actualWidth, float actualHeight, float fieldOfView, float paniniProjectionCropToFit, float paniniProjectionDistance)
2043 {
2044 Vector2 viewExtents = CalcViewExtents(actualWidth, actualHeight, fieldOfView);
2045 Vector2 cropExtents = CalcCropExtents(actualWidth, actualHeight, fieldOfView, paniniProjectionDistance);
2046
2047 float scaleX = cropExtents.x / viewExtents.x;
2048 float scaleY = cropExtents.y / viewExtents.y;
2049 float scaleF = Mathf.Min(scaleX, scaleY);
2050
2051 float paniniD = paniniProjectionDistance;
2052 float paniniS = Mathf.Lerp(1.0f, Mathf.Clamp01(scaleF), paniniProjectionCropToFit);
2053
2054 Vector2 pos = new Vector2(2.0f * screenPos.x - 1.0f, 2.0f * screenPos.y - 1.0f);
2055
2056 Vector2 projPos = Panini_Generic_Inv(pos * viewExtents, paniniD) / (viewExtents * paniniS);
2057
2058 return new Vector2(0.5f * projPos.x + 0.5f, 0.5f * projPos.y + 0.5f);
2059 }
2060
2061 static Vector2 CalcViewExtents(float actualWidth, float actualHeight, float fieldOfView)
2062 {
2063 float fovY = fieldOfView * Mathf.Deg2Rad;
2064 float aspect = actualWidth / actualHeight;
2065
2066 float viewExtY = Mathf.Tan(0.5f * fovY);
2067 float viewExtX = aspect * viewExtY;
2068
2069 return new Vector2(viewExtX, viewExtY);
2070 }
2071
2072 static Vector2 CalcCropExtents(float actualWidth, float actualHeight, float fieldOfView, float d)
2073 {
2074 // given
2075 // S----------- E--X-------
2076 // | ` ~. /,´
2077 // |-- --- Q
2078 // | ,/ `
2079 // 1 | ,´/ `
2080 // | ,´ / ´
2081 // | ,´ / ´
2082 // |,` / ,
2083 // O /
2084 // | / ,
2085 // d | /
2086 // | / ,
2087 // |/ .
2088 // P
2089 // | ´
2090 // | , ´
2091 // +- ´
2092 //
2093 // have X
2094 // want to find E
2095
2096 float viewDist = 1.0f + d;
2097
2098 Vector2 projPos = CalcViewExtents(actualWidth, actualHeight, fieldOfView);
2099 float projHyp = Mathf.Sqrt(projPos.x * projPos.x + 1.0f);
2100
2101 float cylDistMinusD = 1.0f / projHyp;
2102 float cylDist = cylDistMinusD + d;
2103 Vector2 cylPos = projPos * cylDistMinusD;
2104
2105 return cylPos * (viewDist / cylDist);
2106 }
2107
2108 static Vector2 Panini_Generic_Inv(Vector2 projPos, float d)
2109 {
2110 // given
2111 // S----------- E--X-------
2112 // | ` ~. /,´
2113 // |-- --- Q
2114 // | ,/ `
2115 // 1 | ,´/ `
2116 // | ,´ / ´
2117 // | ,´ / ´
2118 // |,` / ,
2119 // O /
2120 // | / ,
2121 // d | /
2122 // | / ,
2123 // |/ .
2124 // P
2125 // | ´
2126 // | , ´
2127 // +- ´
2128 //
2129 // have X
2130 // want to find E
2131
2132 float viewDist = 1.0f + d;
2133 float projHyp = Mathf.Sqrt(projPos.x * projPos.x + 1.0f);
2134
2135 float cylDistMinusD = 1.0f / projHyp;
2136 float cylDist = cylDistMinusD + d;
2137 Vector2 cylPos = projPos * cylDistMinusD;
2138
2139 return cylPos * (viewDist / cylDist);
2140 }
2141
2142#endregion
2143 }
2144}