OSDN Git Service

Added Assets for main menu
[mindgames/Mindgames_main.git] / Mindgames / Library / PackageCache / com.unity.render-pipelines.core@6.9.0 / Editor / LookDev / Environment.cs
1 using UnityEngine;
2 using System;
3 using UnityEngine.UIElements;
4 using UnityEditor.UIElements;
5 using System.Linq;
6
7 namespace UnityEditor.Rendering.Experimental.LookDev
8 {
9     //[CreateAssetMenu(fileName = "Environment", menuName = "LookDev/Environment", order = 1999)]
10     public class Environment : ScriptableObject
11     {
12         //[TODO: check if the shadow/sky split worth the indirection]
13         //Note: multi-edition is not supported as we cannot draw multiple HDRI
14         [Serializable]
15         public class Shadow
16         {
17             public Cubemap cubemap;
18             // Setup default position to be on the sun in the default HDRI.
19             // This is important as the defaultHDRI don't call the set brightest spot function on first call.
20             [SerializeField]
21             internal float m_Latitude = 60.0f; // [-90..90]
22             [SerializeField]
23             internal float m_Longitude = 299.0f; // [0..360[
24             //public float intensity = 1.0f;
25             public Color color = Color.white;
26
27             public float latitude
28             {
29                 get => m_Latitude;
30                 set => m_Latitude = ClampLatitude(value);
31             }
32
33             internal static float ClampLatitude(float value) => Mathf.Clamp(value, -90, 90);
34
35             public float longitude
36             {
37                 get => m_Longitude;
38                 set => m_Longitude = ClampLongitude(value);
39             }
40
41             internal static float ClampLongitude(float value)
42             {
43                 value = value % 360f;
44                 if (value < 0.0)
45                     value += 360f;
46                 return value;
47             }
48
49             public static implicit operator UnityEngine.Rendering.Experimental.LookDev.Shadow(Shadow shadow)
50                 => shadow == null
51                 ? default
52                 : new UnityEngine.Rendering.Experimental.LookDev.Shadow()
53                 {
54                     cubemap = shadow.cubemap,
55                     sunPosition = new Vector2(shadow.m_Longitude, shadow.m_Latitude),
56                     color = shadow.color
57                 };
58         }
59
60         [Serializable]
61         public class Sky
62         {
63             public Cubemap cubemap;
64             public float rotation = 0.0f;
65             public float exposure = 1f;
66             
67             public static implicit operator UnityEngine.Rendering.Experimental.LookDev.Sky(Sky sky)
68                 => sky == null
69                 ? default
70                 : new UnityEngine.Rendering.Experimental.LookDev.Sky()
71                 {
72                     cubemap = sky.cubemap,
73                     longitudeOffset = sky.rotation,
74                     exposure = sky.exposure
75                 };
76         }
77
78         public Sky sky = new Sky();
79         public Shadow shadow = new Shadow();
80     }
81
82     [CustomEditor(typeof(Environment))]
83     class EnvironmentEditor : Editor
84     {
85         EnvironmentElement m_EnvironmentElement;
86
87         public sealed override VisualElement CreateInspectorGUI()
88             => m_EnvironmentElement = new EnvironmentElement(target as Environment);
89
90         // Don't use ImGUI
91         public sealed override void OnInspectorGUI() { }
92
93         override public Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height)
94             => EnvironmentElement.GetLatLongThumbnailTexture(target as Environment, width);
95     }
96
97     interface IBendable<T>
98     {
99         void Bind(T data);
100     }
101     public class EnvironmentElement : VisualElement, IBendable<Environment>
102     {
103         internal const int k_SkyThumbnailWidth = 200;
104         internal const int k_SkyThumbnailHeight = 100;
105         const int k_SkadowThumbnailWidth = 60;
106         const int k_SkadowThumbnailHeight = 30;
107         const int k_SkadowThumbnailXPosition = 130;
108         const int k_SkadowThumbnailYPosition = 10;
109         static Material s_cubeToLatlongMaterial;
110         static Material cubeToLatlongMaterial
111         {
112             get
113             {
114                 if (s_cubeToLatlongMaterial == null || s_cubeToLatlongMaterial.Equals(null))
115                 {
116                     s_cubeToLatlongMaterial = new Material(Shader.Find("Hidden/LookDev/CubeToLatlong"));
117                 }
118                 return s_cubeToLatlongMaterial;
119             }
120         }
121         
122         VisualElement environmentParams;
123         Environment environment;
124         
125         Image latlong;
126         ObjectField skyCubemapField;
127         FloatSliderField skyRotationOffset;
128         FloatField skyExposureField;
129         ObjectField shadowCubemapField;
130         FloatSliderField shadowSunLatitudeField;
131         FloatSliderField shadowSunLongitudeField;
132         ColorField shadowColor;
133
134         Action OnChangeCallback;
135
136         public Environment target => environment;
137
138         public EnvironmentElement() => Create(withPreview: true);
139         public EnvironmentElement(bool withPreview, Action OnChangeCallback = null)
140         {
141             this.OnChangeCallback = OnChangeCallback;
142             Create(withPreview);
143         }
144
145         public EnvironmentElement(Environment environment)
146         {
147             Create(withPreview: true);
148             Bind(environment);
149         }
150
151         void Create(bool withPreview)
152         {
153             if (withPreview)
154             {
155                 latlong = new Image();
156                 latlong.style.width = k_SkyThumbnailWidth;
157                 latlong.style.height = k_SkyThumbnailHeight;
158                 Add(latlong);
159             }
160
161             environmentParams = GetDefaultInspector();
162             Add(environmentParams);
163         }
164
165         public void Bind(Environment environment)
166         {
167             this.environment = environment;
168             if (environment == null || environment.Equals(null))
169                 return;
170
171             if (latlong != null && !latlong.Equals(null))
172                 latlong.image = GetLatLongThumbnailTexture();
173             skyCubemapField.SetValueWithoutNotify(environment.sky.cubemap);
174             skyRotationOffset.SetValueWithoutNotify(environment.sky.rotation);
175             //[TODO: reenable when shadow composition will be finished]
176             //shadowCubemapField.SetValueWithoutNotify(environment.shadow.cubemap);
177             //shadowSunLatitudeField.SetValueWithoutNotify(environment.shadow.latitude);
178             //shadowSunLongitudeField.SetValueWithoutNotify(environment.shadow.longitude);
179             //shadowColor.SetValueWithoutNotify(environment.shadow.color);
180         }
181
182         public void Bind(Environment environment, Image deportedLatlong)
183         {
184             latlong = deportedLatlong;
185             Bind(environment);
186         }
187
188         public Texture2D GetLatLongThumbnailTexture()
189             => GetLatLongThumbnailTexture(environment, k_SkyThumbnailWidth);
190
191         public static Texture2D GetLatLongThumbnailTexture(Environment environment, int width)
192         {
193             int height = width >> 1;
194             RenderTexture oldActive = RenderTexture.active;
195             RenderTexture temporaryRT = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
196             RenderTexture.active = temporaryRT;
197             cubeToLatlongMaterial.SetTexture("_MainTex", environment.sky.cubemap);
198             cubeToLatlongMaterial.SetVector("_WindowParams",
199                 new Vector4(
200                     height, //height
201                     -1000f, //y position, -1000f to be sure to not have clipping issue (we should not clip normally but don't want to create a new shader)
202                     2f,     //margin value
203                     1f));   //Pixel per Point
204             cubeToLatlongMaterial.SetVector("_CubeToLatLongParams",
205                 new Vector4(
206                     Mathf.Deg2Rad * environment.sky.rotation,    //rotation of the environment in radian
207                     1f,     //alpha
208                     1f,     //intensity
209                     0f));   //LOD
210             cubeToLatlongMaterial.SetPass(0);
211             GL.LoadPixelMatrix(0, width, height, 0);
212             GL.Clear(true, true, Color.black);
213             Rect skyRect = new Rect(0, 0, width, height);
214             Renderer.DrawFullScreenQuad(skyRect);
215
216             if (environment.shadow.cubemap != null)
217             {
218                 cubeToLatlongMaterial.SetTexture("_MainTex", environment.shadow.cubemap);
219                 cubeToLatlongMaterial.SetVector("_WindowParams",
220                     new Vector4(
221                         height, //height
222                         -1000f, //y position, -1000f to be sure to not have clipping issue (we should not clip normally but don't want to create a new shader)
223                         2f,      //margin value
224                         1f));   //Pixel per Point
225                 cubeToLatlongMaterial.SetVector("_CubeToLatLongParams",
226                     new Vector4(
227                         Mathf.Deg2Rad * environment.sky.rotation,    //rotation of the environment in radian
228                         1f,   //alpha
229                         0.3f,   //intensity
230                         0f));   //LOD
231                 cubeToLatlongMaterial.SetPass(0);
232                 int shadowWidth = (int)(width * (k_SkadowThumbnailWidth / (float)k_SkyThumbnailWidth));
233                 int shadowXPosition = (int)(width * (k_SkadowThumbnailXPosition / (float)k_SkyThumbnailWidth));
234                 int shadowYPosition = (int)(width * (k_SkadowThumbnailYPosition / (float)k_SkyThumbnailWidth));
235                 Rect shadowRect = new Rect(
236                     shadowXPosition,
237                     shadowYPosition,
238                     shadowWidth,
239                     shadowWidth >> 1);
240                 Renderer.DrawFullScreenQuad(shadowRect);
241             }
242
243             Texture2D result = new Texture2D(width, height, TextureFormat.ARGB32, false);
244             result.ReadPixels(new Rect(0, 0, width, height), 0, 0, false);
245             result.Apply(false);
246             RenderTexture.active = oldActive;
247             UnityEngine.Object.DestroyImmediate(temporaryRT);
248             return result;
249         }
250         
251         public VisualElement GetDefaultInspector()
252         {
253             VisualElement inspector = new VisualElement() { name = "Inspector" };
254             Foldout skyFoldout = new Foldout()
255             {
256                 text = "Sky"
257             };
258             skyCubemapField = new ObjectField("Sky with Sun");
259             skyCubemapField.allowSceneObjects = false;
260             skyCubemapField.objectType = typeof(Cubemap);
261             skyCubemapField.RegisterValueChangedCallback(evt
262                 => RegisterChange(ref environment.sky.cubemap, evt.newValue as Cubemap, updatePreview: true));
263             skyFoldout.Add(skyCubemapField);
264
265             skyRotationOffset = new FloatSliderField("Rotation", 0f, 360f, 5);
266             skyRotationOffset.RegisterValueChangedCallback(evt
267                 => RegisterChange(ref environment.sky.rotation, evt.newValue, updatePreview: true));
268             skyFoldout.Add(skyRotationOffset);
269             
270             skyExposureField = new FloatField("Exposure");
271             skyExposureField.RegisterValueChangedCallback(evt
272                 => RegisterChange(ref environment.sky.exposure, evt.newValue));
273             skyFoldout.Add(skyExposureField);
274             var style = skyFoldout.Q<Toggle>().style;
275             style.marginLeft = 3;
276             style.unityFontStyleAndWeight = FontStyle.Bold;
277             inspector.Add(skyFoldout);
278
279             //[TODO: reenable when shadow composition will be finished]
280             //Foldout shadowFoldout = new Foldout()
281             //{
282             //    text = "Shadow"
283             //};
284             //shadowCubemapField = new ObjectField("Sky w/o Sun");
285             //shadowCubemapField.allowSceneObjects = false;
286             //shadowCubemapField.objectType = typeof(Cubemap);
287             //shadowCubemapField.RegisterValueChangedCallback(evt
288             //    => RegisterChange(ref environment.shadow.cubemap, evt.newValue as Cubemap, updatePreview: true));
289             //shadowFoldout.Add(shadowCubemapField);
290
291             //shadowColor = new ColorField("Color");
292             //shadowColor.RegisterValueChangedCallback(evt
293             //    => RegisterChange(ref environment.shadow.color, evt.newValue));
294             //shadowFoldout.Add(shadowColor);
295
296             //shadowSunLatitudeField = new FloatSliderField("Sun Latitude", -90f, 90f, 5);
297             //shadowSunLatitudeField.RegisterValueChangedCallback(evt
298             //    => RegisterChange(ref environment.shadow.m_Latitude, Environment.Shadow.ClampLatitude(evt.newValue), shadowSunLatitudeField));
299             //shadowFoldout.Add(shadowSunLatitudeField);
300             
301             //shadowSunLongitudeField = new FloatSliderField("Sun Longitude", 0f, 359.999f, 5);
302             //shadowSunLongitudeField.RegisterValueChangedCallback(evt
303             //    => RegisterChange(ref environment.shadow.m_Longitude, Environment.Shadow.ClampLongitude(evt.newValue), shadowSunLongitudeField));
304             //shadowFoldout.Add(shadowSunLongitudeField);
305
306             //Button sunToBrightess = new Button(()
307             //    => { /* [TODO] */ })
308             //{
309             //    text = "Sun position to brightest"
310             //};
311             //shadowFoldout.Add(sunToBrightess);
312
313             //style = shadowFoldout.Q<Toggle>().style;
314             //style.marginLeft = 3;
315             //style.unityFontStyleAndWeight = FontStyle.Bold;
316             //inspector.Add(shadowFoldout);
317
318             return inspector;
319         }
320         
321         void RegisterChange<TValueType>(ref TValueType reflectedVariable, TValueType newValue, BaseField<TValueType> resyncField = null, bool updatePreview = false)
322         {
323             if (environment == null || environment.Equals(null))
324                 return;
325             reflectedVariable = newValue;
326             resyncField?.SetValueWithoutNotify(newValue);
327             if (updatePreview && latlong != null && !latlong.Equals(null))
328                 latlong.image = GetLatLongThumbnailTexture(environment, k_SkyThumbnailWidth);
329             EditorUtility.SetDirty(environment);
330             OnChangeCallback?.Invoke();
331         }
332
333         void RegisterChange(ref float reflectedVariable, float newValue, FloatSliderField resyncField = null, bool updatePreview = false)
334         {
335             if (environment == null || environment.Equals(null))
336                 return;
337             reflectedVariable = newValue;
338             resyncField?.SetValueWithoutNotify(newValue);
339             if (updatePreview && latlong != null && !latlong.Equals(null))
340                 latlong.image = GetLatLongThumbnailTexture(environment, k_SkyThumbnailWidth);
341             EditorUtility.SetDirty(environment);
342             OnChangeCallback?.Invoke();
343         }
344
345         class FloatSliderField : VisualElement, INotifyValueChanged<float>
346         {
347             Slider slider;
348             FloatField endField;
349             readonly int maxCharLength;
350
351             public float value
352             {
353                 get => slider.value;
354                 set
355                 {
356                     if (value == slider.value)
357                         return;
358
359                     float trunkedValue = TrunkValue(value);
360                     if (trunkedValue == slider.value)
361                         return;
362
363                     if (panel != null)
364                     {
365                         using (ChangeEvent<float> evt = ChangeEvent<float>.GetPooled(slider.value, trunkedValue))
366                         {
367                             evt.target = this;
368                             SetValueWithoutNotify_Internal(trunkedValue);
369                             SendEvent(evt);
370                         }
371                     }
372                     else
373                     {
374                         SetValueWithoutNotify_Internal(trunkedValue);
375                     }
376                 }
377             }
378
379             public FloatSliderField(string label, float start, float end, int maxCharLength = -1)
380             {
381                 this.maxCharLength = maxCharLength;
382                 Add(slider = new Slider(label, start, end));
383                 slider.Add(endField = new FloatField(maxCharLength));
384                 slider.RegisterValueChangedCallback(evt
385                     => endField.SetValueWithoutNotify(TrunkValue(evt.newValue)));
386                 endField.RegisterValueChangedCallback(evt
387                     => slider.SetValueWithoutNotify(TrunkValue(evt.newValue)));
388                 endField.style.marginRight = 0;
389             }
390
391             public void SetValueWithoutNotify(float newValue)
392                 => SetValueWithoutNotify_Internal(TrunkValue(newValue));
393
394             void SetValueWithoutNotify_Internal(float newTrunkedValue)
395             {
396                 //Note: SetValueWithoutNotify do not change the cursor position
397                 // Passing by slider will cause a loop but this loop will be break
398                 //as new value match the legacy one
399                 //slider.SetValueWithoutNotify(newTrunkedValue);
400                 slider.value = newTrunkedValue;
401                 endField.SetValueWithoutNotify(newTrunkedValue);
402             }
403
404             float TrunkValue(float value)
405             {
406                 if (maxCharLength < 0)
407                     return value;
408
409                 int integerRounded = (int)Math.Round(value);
410                 int integerLength = integerRounded.ToString().Length;
411                 if (integerLength + 1 >= maxCharLength)
412                     return integerRounded;
413
414                 int signChar = value < 0f ? 1 : 0;
415                 int integerTrunkedLength = (int)Math.Truncate(value).ToString().Length;
416                 return (float)Math.Round(value, maxCharLength - integerLength - 1 + signChar);
417             }
418         }
419     }
420 }