@@ -21,20 +21,23 @@ public partial class AreaLight : BaseLight, IComparable<AreaLight>
2121 private static readonly float [ , ] offsets = new float [ 4 , 2 ] { { 1 , 1 } , { 1 , - 1 } , { - 1 , - 1 } , { - 1 , 1 } } ;
2222 private const int lutResolution = 64 ;
2323 private const int lutMatrixDim = 3 ;
24+ private static readonly Matrix4x4 rotation180Up = Matrix4x4 . Rotate ( Quaternion . AngleAxis ( 180.0f , Vector3 . up ) ) ;
2425
2526 private static Texture2D transformInvTextureSpecular ;
2627 private static Texture2D transformInvTextureDiffuse ;
2728 private static Texture2D ampDiffAmpSpecFresnel ;
2829
30+ private static int lastAreaLightUpdate = - 1 ;
2931 private static List < AreaLight > activeAreaLights = new ( maxAreaLights ) ;
3032 private static List < AreaLight > activeAreaLightsSorted = new ( maxAreaLights ) ;
3133 private static Vector4 [ ] areaLightData = new Vector4 [ areaLightDataSize * areaLightCount ] ;
3234 private static Matrix4x4 [ ] areaLightVerts = new Matrix4x4 [ areaLightCount ] ;
3335 private static Texture [ ] areaLightCookies = new Texture [ areaLightCount ] ;
34- private static int _AreaLightDataID ;
35- private static int _AreaLightVertsID ;
36- private static int [ ] _AreaLightCookiesIDs = new int [ areaLightCount ] ;
37- private static int lastAreaLightUpdate = - 1 ;
36+ private static int areaLightDataID ;
37+ private static int areaLightVertsID ;
38+ private static int [ ] areaLightCookiesIDs = new int [ areaLightCount ] ;
39+ private static int facingID ;
40+ private static int uvStartsAtTopID ;
3841 private static CullingGroup cullingGroup ;
3942 private static BoundingSphere [ ] boundingSpheres = new BoundingSphere [ maxAreaLights ] ;
4043
@@ -89,6 +92,25 @@ public Vector2 Size
8992 set => size = value ;
9093 }
9194
95+ public enum ForwardFacing
96+ {
97+ PositiveZ ,
98+ NegativeZ ,
99+ }
100+
101+ [ Tooltip ( "The forward direction of the light." ) ]
102+ [ SerializeField ]
103+ private ForwardFacing facing = ForwardFacing . PositiveZ ;
104+
105+ /// <summary>
106+ /// The forward direction of the light.
107+ /// </summary>
108+ public ForwardFacing Facing
109+ {
110+ get => facing ;
111+ set => facing = value ;
112+ }
113+
92114 [ Tooltip ( "Optional texture to use instead of a solid color." ) ]
93115 [ SerializeField ]
94116 private Texture cookie ;
@@ -102,6 +124,19 @@ public Texture Cookie
102124 set => cookie = value ;
103125 }
104126
127+ [ Tooltip ( "Should the texture UV coordinate convention for this cookie have Y starting at the top of the image." ) ]
128+ [ SerializeField ]
129+ private bool cookieUVStartsAtTop = true ;
130+
131+ /// <summary>
132+ /// Should the texture UV coordinate convention for this cookie have Y starting at the top of the image.
133+ /// </summary>
134+ public bool CookieUVStartsAtTop
135+ {
136+ get => cookieUVStartsAtTop ;
137+ set => cookieUVStartsAtTop = value ;
138+ }
139+
105140 [ Tooltip ( "Should the area light have a visualization?" ) ]
106141 [ SerializeField ]
107142 private bool drawLightSource = true ;
@@ -215,14 +250,17 @@ public Camera CullingGroupCamera
215250 /// <inheritdoc/>
216251 protected override void Initialize ( )
217252 {
218- _AreaLightDataID = Shader . PropertyToID ( "_AreaLightData" ) ;
219- _AreaLightVertsID = Shader . PropertyToID ( "_AreaLightVerts" ) ;
253+ areaLightDataID = Shader . PropertyToID ( "_AreaLightData" ) ;
254+ areaLightVertsID = Shader . PropertyToID ( "_AreaLightVerts" ) ;
220255
221- for ( int i = 0 ; i < _AreaLightCookiesIDs . Length ; ++ i )
256+ for ( int i = 0 ; i < areaLightCookiesIDs . Length ; ++ i )
222257 {
223- _AreaLightCookiesIDs [ i ] = Shader . PropertyToID ( $ "_AreaLightCookie{ i } ") ;
258+ areaLightCookiesIDs [ i ] = Shader . PropertyToID ( $ "_AreaLightCookie{ i } ") ;
224259 }
225260
261+ facingID = Shader . PropertyToID ( "_facing" ) ;
262+ uvStartsAtTopID = Shader . PropertyToID ( "_uvStartsAtTop" ) ;
263+
226264 CreateLUTs ( ) ;
227265 UpdateLightSourceVisual ( ) ;
228266
@@ -362,18 +400,23 @@ protected override void UpdateLights(bool forceUpdate = false)
362400
363401 if ( light )
364402 {
365- areaLightData [ dataIndex ] = light . Color ;
403+ var color = light . Color ;
404+ areaLightData [ dataIndex ] = new Vector4 ( color . r ,
405+ color . g ,
406+ color . b ,
407+ light . cookieUVStartsAtTop ? 1.0f : 0.0f ) ;
408+
409+ var lightVerts = new Matrix4x4 ( ) ;
410+ var localToWorld = light . transform . localToWorldMatrix ;
366411
367- // A little bit of bias to prevent the light from lighting itself.
368- const float z = 0.01f ;
412+ if ( light . facing == ForwardFacing . NegativeZ )
413+ {
414+ localToWorld *= rotation180Up ;
415+ }
369416
370- Matrix4x4 lightVerts = new Matrix4x4 ( ) ;
371417 for ( int v = 0 ; v < 4 ; ++ v )
372418 {
373- Vector3 vertex = new Vector3 ( light . size . x * offsets [ v , 0 ] ,
374- light . size . y * offsets [ v , 1 ] ,
375- z ) * 0.5f ;
376- lightVerts . SetRow ( v , light . transform . TransformPoint ( vertex ) ) ;
419+ lightVerts . SetRow ( v , TransformVertex ( v , light . size , localToWorld ) ) ;
377420 }
378421
379422 areaLightVerts [ i ] = lightVerts ;
@@ -397,13 +440,13 @@ protected override void UpdateLights(bool forceUpdate = false)
397440 }
398441 }
399442
400- Shader . SetGlobalVectorArray ( _AreaLightDataID , areaLightData ) ;
401- Shader . SetGlobalMatrixArray ( _AreaLightVertsID , areaLightVerts ) ;
443+ Shader . SetGlobalVectorArray ( areaLightDataID , areaLightData ) ;
444+ Shader . SetGlobalMatrixArray ( areaLightVertsID , areaLightVerts ) ;
402445
403446 // There is no SetGlobalTextureArray so pass in 1 by 1.
404447 for ( int i = 0 ; i < areaLightCookies . Length ; ++ i )
405448 {
406- Shader . SetGlobalTexture ( _AreaLightCookiesIDs [ i ] , areaLightCookies [ i ] ) ;
449+ Shader . SetGlobalTexture ( areaLightCookiesIDs [ i ] , areaLightCookies [ i ] ) ;
407450 }
408451
409452 lastAreaLightUpdate = Time . frameCount ;
@@ -467,6 +510,18 @@ private void OnDrawGizmos()
467510 }
468511#endif
469512
513+ private static Vector3 TransformVertex ( int index , Vector2 size , Matrix4x4 localToWorld )
514+ {
515+ // A little bit of bias to prevent the light from lighting itself.
516+ const float z = 0.01f ;
517+
518+ var vertex = new Vector3 ( size . x * offsets [ index , 0 ] ,
519+ size . y * offsets [ index , 1 ] ,
520+ z ) * 0.5f ;
521+
522+ return localToWorld . MultiplyPoint ( vertex ) ;
523+ }
524+
470525 private static void CreateLUTs ( )
471526 {
472527 if ( transformInvTextureDiffuse == null )
@@ -506,6 +561,8 @@ private void UpdateLightSourceVisual()
506561
507562 lightSourceVisual . sharedMaterial . color = Color ;
508563 lightSourceVisual . sharedMaterial . mainTexture = drawLightSourceCookie ? drawLightSourceCookie : cookie ;
564+ lightSourceVisual . sharedMaterial . SetFloat ( facingID , ( float ) facing ) ;
565+ lightSourceVisual . sharedMaterial . SetFloat ( uvStartsAtTopID , cookieUVStartsAtTop ? 0.0f : 1.0f ) ;
509566 lightSourceVisual . transform . localScale = new Vector3 ( size . x , size . y , 1.0f ) ;
510567 }
511568 else
0 commit comments