├── Editor.meta ├── Editor ├── SkyboxBlenderEditor.cs └── SkyboxBlenderEditor.cs.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Scripts.meta ├── Scripts ├── SkyboxBlender.cs └── SkyboxBlender.cs.meta ├── Shaders.meta └── Shaders ├── SkyboxBlender.shader └── SkyboxBlender.shader.meta /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 13402b2e357223446bc2d35890e354b4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/SkyboxBlenderEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | [CustomEditor(typeof(SkyboxBlender))] 7 | public class SkyboxBlenderEditor : Editor 8 | { 9 | SerializedProperty skyBox1; 10 | SerializedProperty skyBox2; 11 | 12 | SerializedProperty blendedSkybox; 13 | SerializedProperty exposure; 14 | SerializedProperty rotation; 15 | SerializedProperty tint; 16 | SerializedProperty invertColors; 17 | SerializedProperty blendMode; 18 | SerializedProperty blend; 19 | 20 | SerializedProperty bindOnStart; 21 | SerializedProperty updateLightingOnStart; 22 | SerializedProperty updateLightingEveryFrame; 23 | SerializedProperty updateReflectionsOnStart; 24 | SerializedProperty updateReflectionsEveryFrame; 25 | 26 | SerializedProperty reflectionResolution; 27 | 28 | private void OnEnable() 29 | { 30 | skyBox1 = serializedObject.FindProperty("skyBox1"); 31 | skyBox2 = serializedObject.FindProperty("skyBox2"); 32 | 33 | blendedSkybox = serializedObject.FindProperty("blendedSkybox"); 34 | exposure = serializedObject.FindProperty("exposure"); 35 | rotation = serializedObject.FindProperty("rotation"); 36 | tint = serializedObject.FindProperty("tint"); 37 | invertColors = serializedObject.FindProperty("invertColors"); 38 | blendMode = serializedObject.FindProperty("blendMode"); 39 | blend = serializedObject.FindProperty("blend"); 40 | 41 | bindOnStart = serializedObject.FindProperty("bindOnStart"); 42 | updateLightingOnStart = serializedObject.FindProperty("updateLightingOnStart"); 43 | updateLightingEveryFrame = serializedObject.FindProperty("updateLightingEveryFrame"); 44 | updateReflectionsOnStart = serializedObject.FindProperty("updateReflectionsOnStart"); 45 | updateReflectionsEveryFrame = serializedObject.FindProperty("updateReflectionsEveryFrame"); 46 | 47 | reflectionResolution = serializedObject.FindProperty("reflectionResolution"); ; 48 | } 49 | 50 | public override void OnInspectorGUI() 51 | { 52 | SkyboxBlender skyboxBlender = (SkyboxBlender)target; 53 | 54 | serializedObject.Update(); 55 | 56 | //Input skyboxes 57 | EditorGUILayout.BeginVertical("HelpBox"); 58 | EditorGUILayout.LabelField("Input Skyboxes", EditorStyles.boldLabel); 59 | EditorGUI.indentLevel++; 60 | 61 | EditorGUILayout.PropertyField(skyBox1); 62 | EditorGUILayout.PropertyField(skyBox2); 63 | 64 | EditorGUILayout.Space(); 65 | EditorGUILayout.PropertyField(bindOnStart); 66 | if (GUILayout.Button("Bind Textures")) { skyboxBlender.BindTextures(); } 67 | 68 | EditorGUILayout.Space(); 69 | EditorGUI.indentLevel--; 70 | EditorGUILayout.EndVertical(); 71 | 72 | //Blended skyboxes 73 | EditorGUILayout.BeginVertical("HelpBox"); 74 | EditorGUILayout.LabelField("Blended Skybox", EditorStyles.boldLabel); 75 | EditorGUI.indentLevel++; 76 | 77 | EditorGUILayout.PropertyField(blendedSkybox); 78 | EditorGUILayout.PropertyField(exposure); 79 | EditorGUILayout.PropertyField(rotation); 80 | EditorGUILayout.PropertyField(tint); 81 | EditorGUILayout.PropertyField(invertColors); 82 | EditorGUILayout.PropertyField(blendMode); 83 | EditorGUILayout.PropertyField(blend); 84 | 85 | EditorGUILayout.Space(); 86 | EditorGUI.indentLevel--; 87 | EditorGUILayout.EndVertical(); 88 | 89 | //Environment lighting 90 | EditorGUILayout.BeginVertical("HelpBox"); 91 | EditorGUILayout.LabelField("Environment Lighting", EditorStyles.boldLabel); 92 | EditorGUI.indentLevel++; 93 | 94 | EditorGUILayout.PropertyField(updateLightingOnStart); 95 | EditorGUILayout.PropertyField(updateLightingEveryFrame); 96 | if (GUILayout.Button("Update Lighting")) { skyboxBlender.UpdateLighting(); } 97 | 98 | EditorGUILayout.Space(); 99 | EditorGUI.indentLevel--; 100 | EditorGUILayout.EndVertical(); 101 | 102 | //Environment reflections 103 | EditorGUILayout.BeginVertical("HelpBox"); 104 | EditorGUILayout.LabelField("Environment Reflections", EditorStyles.boldLabel); 105 | EditorGUI.indentLevel++; 106 | 107 | EditorGUILayout.PropertyField(reflectionResolution); 108 | if (GUILayout.Button("Update Probe")) { skyboxBlender.UpdateReflectionProbe(); } 109 | 110 | EditorGUILayout.Space(); 111 | EditorGUILayout.PropertyField(updateReflectionsOnStart); 112 | EditorGUILayout.PropertyField(updateReflectionsEveryFrame); 113 | if (GUILayout.Button("Update Reflections")) { skyboxBlender.UpdateReflections(); } 114 | 115 | EditorGUILayout.Space(); 116 | EditorGUI.indentLevel--; 117 | EditorGUILayout.EndVertical(); 118 | 119 | 120 | serializedObject.ApplyModifiedProperties(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Editor/SkyboxBlenderEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0e97d41b6ffc264d9fb2a6f284ce145 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Barbelot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b63ae4654ec84874388a8b7600bd9681 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity-Skybox-Blender 2 | A tool to blend skyboxes in Unity with realtime environment lighting and reflections updates. 3 | 4 | ## How to use 5 | 6 | 1. Add the SkyboxBlender.cs script to an object in your scene. 7 | 2. Assign the two input skybox materials to blend to the SkyboxBlender. 8 | 2. Create a new material with the SkyboxBlender/BlendedSkybox shader. 9 | 3. Assign the newly created material to the SkyboxBlender and to your scene skybox. 10 | 5. Blend ! 11 | 12 | ## Useful information 13 | 14 | - To update the reflection probe resolution after changing it, use the Update Probe button. 15 | - The script executes in edit mode to visualize the blend result in the editor, you can disable it by removing the [ExecuteInEditMode] tag in the SkyboxBlender script. 16 | - The input skyboxes materials are expected to use the Unity built-in Skybox/6-sided shader. 17 | - The SkyboxBlender script set the Environment Reflections Source to Custom. If you remove the script and your scene is all black, set the Environment Reflections Source back to Skybox in the Lighting tab, as described [here](https://github.com/Barbelot/Unity-Skybox-Blender/issues/1). 18 | 19 | ## Known Issues 20 | 21 | - The reflection update does not always work properly when not updating every frames. 22 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0aa993b781da13940aeceeba7ca6acd9 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f472385305e1ddf408dc6e6bb41c406b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/SkyboxBlender.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.Rendering; 5 | 6 | [ExecuteInEditMode] 7 | public class SkyboxBlender : MonoBehaviour { 8 | 9 | [SerializeField] public enum BlendMode { Linear, Smoothstep, Maximum, Add, Substract, Multiply } 10 | [SerializeField] public enum ProbeResolution { _16, _32, _64, _128, _256, _512, _1024, _2048 } 11 | 12 | //[Header("Input Skyboxes")] 13 | [SerializeField] public Material skyBox1; 14 | [SerializeField] public Material skyBox2; 15 | 16 | //[Header("Blended Skybox")] 17 | [SerializeField] public Material blendedSkybox; 18 | [SerializeField] [Range(0, 8)] public float exposure = 1; 19 | [SerializeField] [Range(0, 360)] public float rotation = 0; 20 | [SerializeField] public Color tint = Color.white; 21 | [SerializeField] [Range(0, 1)] public float invertColors = 0; 22 | [SerializeField] public BlendMode blendMode = BlendMode.Linear; 23 | [SerializeField] [Range(0, 1)] public float blend = 0; 24 | 25 | [SerializeField] public bool bindOnStart = true; 26 | [SerializeField] public bool updateLightingOnStart = true; 27 | [SerializeField] public bool updateLightingEveryFrame = true; 28 | [SerializeField] public bool updateReflectionsOnStart = true; 29 | [SerializeField] public bool updateReflectionsEveryFrame = true; 30 | 31 | [SerializeField] public ProbeResolution reflectionResolution = ProbeResolution._128; 32 | 33 | private ReflectionProbe probeComponent = null; 34 | private GameObject probeGameObject = null; 35 | private Cubemap blendedCubemap = null; 36 | private int renderId = -1; 37 | 38 | #region MonoBehaviour Functions 39 | 40 | // Use this for initialization 41 | void Start () { 42 | 43 | if (bindOnStart) 44 | BindTextures(); 45 | 46 | //Update the material parameters 47 | UpdateBlendedMaterialParameters(); 48 | 49 | if (updateLightingOnStart) 50 | UpdateLighting(); 51 | 52 | if (updateReflectionsOnStart) 53 | UpdateReflections(); 54 | } 55 | 56 | // Update is called once per frame 57 | void Update () { 58 | 59 | //Update material parameters 60 | UpdateBlendedMaterialParameters(); 61 | 62 | //Update lighting 63 | if (updateLightingEveryFrame) 64 | UpdateLighting(); 65 | 66 | //Update reflections 67 | if (updateReflectionsEveryFrame) 68 | UpdateReflections(); 69 | } 70 | 71 | /* 72 | private void OnValidate() 73 | { 74 | if (!updateInEditMode) 75 | return; 76 | 77 | Update(); 78 | } 79 | */ 80 | 81 | #endregion 82 | 83 | /// 84 | /// Get the probe resolution value 85 | /// 86 | int GetProbeResolution(ProbeResolution probeResolution) 87 | { 88 | switch (probeResolution) 89 | { 90 | case ProbeResolution._16: 91 | return 16; 92 | case ProbeResolution._32: 93 | return 32; 94 | case ProbeResolution._64: 95 | return 64; 96 | case ProbeResolution._128: 97 | return 128; 98 | case ProbeResolution._256: 99 | return 256; 100 | case ProbeResolution._512: 101 | return 512; 102 | case ProbeResolution._1024: 103 | return 1024; 104 | case ProbeResolution._2048: 105 | return 2048; 106 | default: 107 | return 128; 108 | } 109 | } 110 | 111 | /// 112 | /// Create a reflection probe gameobject and setup the cubemap for environment reflections 113 | /// 114 | void CreateReflectionProbe() 115 | { 116 | //Search for the reflection probe object 117 | probeGameObject = GameObject.Find("Skybox Blender Reflection Probe"); 118 | 119 | if (!probeGameObject) 120 | { 121 | //Create the gameobject if its not here 122 | probeGameObject = new GameObject("Skybox Blender Reflection Probe"); 123 | probeGameObject.transform.parent = gameObject.transform; 124 | // Use a location such that the new Reflection Probe will not interfere with other Reflection Probes in the scene. 125 | probeGameObject.transform.position = new Vector3(0, -1000, 0); 126 | } 127 | 128 | probeComponent = probeGameObject.GetComponent(); 129 | 130 | if (probeComponent) 131 | { 132 | DestroyImmediate(probeComponent); 133 | } 134 | 135 | // Create a Reflection Probe that only contains the Skybox. The Update function controls the Reflection Probe refresh. 136 | probeComponent = probeGameObject.AddComponent() as ReflectionProbe; 137 | 138 | } 139 | 140 | /// 141 | /// Update the reflection probe and cubemap 142 | /// 143 | public void UpdateReflectionProbe() 144 | { 145 | //if (!probeGameObject || !probeComponent) 146 | CreateReflectionProbe(); 147 | 148 | probeComponent.resolution = GetProbeResolution(reflectionResolution); 149 | probeComponent.size = new Vector3(1, 1, 1); 150 | probeComponent.cullingMask = 0; 151 | probeComponent.clearFlags = ReflectionProbeClearFlags.Skybox; 152 | probeComponent.mode = ReflectionProbeMode.Realtime; 153 | probeComponent.refreshMode = ReflectionProbeRefreshMode.ViaScripting; 154 | probeComponent.timeSlicingMode = ReflectionProbeTimeSlicingMode.NoTimeSlicing; 155 | 156 | // A cubemap is used as a default specular reflection. 157 | blendedCubemap = new Cubemap(probeComponent.resolution, probeComponent.hdr ? TextureFormat.RGBAHalf : TextureFormat.RGBA32, true); 158 | 159 | //Set the render reflection mode to Custom 160 | RenderSettings.defaultReflectionMode = DefaultReflectionMode.Custom; 161 | RenderSettings.customReflection = blendedCubemap; 162 | } 163 | 164 | /// 165 | /// Update the scene environment lighting 166 | /// 167 | public void UpdateLighting() 168 | { 169 | DynamicGI.UpdateEnvironment(); 170 | } 171 | 172 | /// 173 | /// Update the scene environment reflections 174 | /// 175 | public void UpdateReflections() 176 | { 177 | if (!probeGameObject || !probeComponent) 178 | UpdateReflectionProbe(); 179 | 180 | // The Update function refreshes the Reflection Probe and copies the result to the default specular reflection Cubemap. 181 | 182 | // The texture associated with the real-time Reflection Probe is a render target and RenderSettings.customReflection is a Cubemap. We have to check the support if copying from render targets to Textures is supported. 183 | if ((SystemInfo.copyTextureSupport & CopyTextureSupport.RTToTexture) != 0) 184 | { 185 | // Wait until previous RenderProbe is finished before we refresh the Reflection Probe again. 186 | // renderId is a token used to figure out when the refresh of a Reflection Probe is finished. The refresh of a Reflection Probe can take mutiple frames when time-slicing is used. 187 | if (renderId == -1 || probeComponent.IsFinishedRendering(renderId)) 188 | { 189 | if (probeComponent.IsFinishedRendering(renderId)) 190 | { 191 | //Debug.Log("probeComponent.texture.width = " + probeComponent.texture.width + " blendedCubemap.width = "+ blendedCubemap.width); 192 | //Debug.Log("probeComponent.texture.height = " + probeComponent.texture.height + " blendedCubemap.height = " + blendedCubemap.height); 193 | //Debug.Log("probeComponent.resolution = " + probeComponent.resolution); 194 | // After the previous RenderProbe is finished, we copy the probe's texture to the cubemap and set it as a custom reflection in RenderSettings. 195 | if (probeComponent.texture.width == blendedCubemap.width && probeComponent.texture.height == blendedCubemap.height) 196 | { 197 | Graphics.CopyTexture(probeComponent.texture, blendedCubemap as Texture); 198 | //Debug.Log("Copying"); 199 | } 200 | 201 | RenderSettings.customReflection = blendedCubemap; 202 | } 203 | 204 | renderId = probeComponent.RenderProbe(); 205 | } 206 | } 207 | } 208 | 209 | /// 210 | /// Get the BlendMode index from the enumeration 211 | /// 212 | int GetBlendModeIndex(BlendMode blendMode) 213 | { 214 | switch (blendMode) 215 | { 216 | case BlendMode.Linear: 217 | return 0; 218 | case BlendMode.Smoothstep: 219 | return 5; 220 | case BlendMode.Maximum: 221 | return 1; 222 | case BlendMode.Add: 223 | return 2; 224 | case BlendMode.Substract: 225 | return 3; 226 | case BlendMode.Multiply: 227 | return 4; 228 | default: 229 | return 0; 230 | } 231 | } 232 | 233 | /// 234 | /// Bind the input skyboxes textures to the blended skybox 235 | /// 236 | public void BindTextures() 237 | { 238 | blendedSkybox.SetTexture("_FrontTex_1", skyBox1.GetTexture("_FrontTex")); 239 | blendedSkybox.SetTexture("_BackTex_1", skyBox1.GetTexture("_BackTex")); 240 | blendedSkybox.SetTexture("_LeftTex_1", skyBox1.GetTexture("_LeftTex")); 241 | blendedSkybox.SetTexture("_RightTex_1", skyBox1.GetTexture("_RightTex")); 242 | blendedSkybox.SetTexture("_UpTex_1", skyBox1.GetTexture("_UpTex")); 243 | blendedSkybox.SetTexture("_DownTex_1", skyBox1.GetTexture("_DownTex")); 244 | 245 | blendedSkybox.SetTexture("_FrontTex_2", skyBox2.GetTexture("_FrontTex")); 246 | blendedSkybox.SetTexture("_BackTex_2", skyBox2.GetTexture("_BackTex")); 247 | blendedSkybox.SetTexture("_LeftTex_2", skyBox2.GetTexture("_LeftTex")); 248 | blendedSkybox.SetTexture("_RightTex_2", skyBox2.GetTexture("_RightTex")); 249 | blendedSkybox.SetTexture("_UpTex_2", skyBox2.GetTexture("_UpTex")); 250 | blendedSkybox.SetTexture("_DownTex_2", skyBox2.GetTexture("_DownTex")); 251 | } 252 | 253 | /// 254 | /// Update the material parameters 255 | /// 256 | void UpdateBlendedMaterialParameters() 257 | { 258 | blendedSkybox.SetColor("_Tint", tint); 259 | blendedSkybox.SetFloat("_Exposure", exposure); 260 | blendedSkybox.SetFloat("_Rotation", rotation); 261 | blendedSkybox.SetFloat("_Blend", blend); 262 | blendedSkybox.SetInt("_BlendMode", GetBlendModeIndex(blendMode)); 263 | blendedSkybox.SetFloat("_InvertColors", invertColors); 264 | 265 | } 266 | 267 | } 268 | -------------------------------------------------------------------------------- /Scripts/SkyboxBlender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2188c1e1a74fe3144880e8ca78fa7825 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d21e85467e6c73044befe96cb8a46690 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Shaders/SkyboxBlender.shader: -------------------------------------------------------------------------------- 1 | // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' 2 | 3 | Shader "SkyboxBlender/BlendedSkybox" { 4 | Properties{ 5 | _Tint("Tint Color", Color) = (.5, .5, .5, .5) 6 | [Gamma] _Exposure("Exposure", Range(0, 8)) = 1.0 7 | _Rotation("Rotation", Range(0, 360)) = 0 8 | _Blend("Blend", Range(0.0, 1.0)) = 0.0 9 | _BlendMode("Blend Mode", int) = 0 10 | _InvertColors("Invert Colors", Range(0,1)) = 0 11 | 12 | [NoScaleOffset] _FrontTex_1("Front_1 [+Z] (HDR)", 2D) = "grey" {} 13 | [NoScaleOffset] _BackTex_1("Back_1 [-Z] (HDR)", 2D) = "grey" {} 14 | [NoScaleOffset] _LeftTex_1("Left_1 [+X] (HDR)", 2D) = "grey" {} 15 | [NoScaleOffset] _RightTex_1("Right_1 [-X] (HDR)", 2D) = "grey" {} 16 | [NoScaleOffset] _UpTex_1("Up_1 [+Y] (HDR)", 2D) = "grey" {} 17 | [NoScaleOffset] _DownTex_1("Down_1 [-Y] (HDR)", 2D) = "grey" {} 18 | 19 | [NoScaleOffset] _FrontTex_2("Front_2 [+Z] (HDR)", 2D) = "grey" {} 20 | [NoScaleOffset] _BackTex_2("Back_2 [-Z] (HDR)", 2D) = "grey" {} 21 | [NoScaleOffset] _LeftTex_2("Left_2 [+X] (HDR)", 2D) = "grey" {} 22 | [NoScaleOffset] _RightTex_2("Right_2 [-X] (HDR)", 2D) = "grey" {} 23 | [NoScaleOffset] _UpTex_2("Up_2 [+Y] (HDR)", 2D) = "grey" {} 24 | [NoScaleOffset] _DownTex_2("Down_2 [-Y] (HDR)", 2D) = "grey" {} 25 | } 26 | 27 | SubShader{ 28 | Tags{ "Queue" = "Background" "RenderType" = "Background" "PreviewType" = "Skybox" } 29 | Cull Off ZWrite Off 30 | 31 | CGINCLUDE 32 | #include "UnityCG.cginc" 33 | 34 | half4 _Tint; 35 | half _Exposure; 36 | float _Rotation; 37 | float _Blend; 38 | int _BlendMode; 39 | float _InvertColors; 40 | 41 | float4 RotateAroundYInDegrees(float4 vertex, float degrees) 42 | { 43 | float alpha = degrees * UNITY_PI / 180.0; 44 | float sina, cosa; 45 | sincos(alpha, sina, cosa); 46 | float2x2 m = float2x2(cosa, -sina, sina, cosa); 47 | return float4(mul(m, vertex.xz), vertex.yw).xzyw; 48 | } 49 | 50 | struct appdata_t { 51 | float4 vertex : POSITION; 52 | float2 texcoord : TEXCOORD0; 53 | }; 54 | 55 | struct v2f { 56 | float4 vertex : SV_POSITION; 57 | float2 texcoord : TEXCOORD0; 58 | }; 59 | 60 | v2f vert(appdata_t v) 61 | { 62 | v2f o; 63 | o.vertex = UnityObjectToClipPos(RotateAroundYInDegrees(v.vertex, _Rotation)); 64 | o.texcoord = v.texcoord; 65 | return o; 66 | } 67 | 68 | half4 skybox_frag(v2f i, sampler2D smp1, half4 smpDecode1, sampler2D smp2, half4 smpDecode2) 69 | { 70 | half4 tex1 = tex2D(smp1, i.texcoord); 71 | half4 tex2 = tex2D(smp2, i.texcoord); 72 | 73 | half3 c1 = DecodeHDR(tex1, smpDecode1); 74 | half3 c2 = DecodeHDR(tex2, smpDecode2); 75 | 76 | half3 c = half3(0, 0, 0); 77 | 78 | if (_BlendMode == 0) { 79 | //Linear blend 80 | c = lerp(c1, c2, _Blend); 81 | } else if (_BlendMode == 1) { 82 | //Maximum 83 | c = max(c1 * (1 - _Blend), c2 * _Blend); 84 | } else if (_BlendMode == 2) { 85 | //Add 86 | c = c1 + c2 * _Blend; 87 | } else if (_BlendMode == 3) { 88 | //Substract 89 | c = max(0, c1 - c2 * _Blend); 90 | } else if (_BlendMode == 4) { 91 | //Multiply 92 | c = c1 * lerp(1, c2, _Blend); 93 | } 94 | else if (_BlendMode == 5) { 95 | //Smoothstep 96 | c = lerp(c1, c2, smoothstep(0, 1, _Blend)); 97 | } 98 | 99 | 100 | c = c * _Tint.rgb * unity_ColorSpaceDouble; 101 | c = lerp(c, 1 - c, _InvertColors); 102 | c *= _Exposure; 103 | return half4(c, 1); 104 | } 105 | ENDCG 106 | 107 | Pass{ 108 | CGPROGRAM 109 | 110 | #pragma vertex vert 111 | #pragma fragment frag 112 | 113 | sampler2D _FrontTex_1; 114 | sampler2D _FrontTex_2; 115 | half4 _FrontTex_1_HDR; 116 | half4 _FrontTex_2_HDR; 117 | half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_FrontTex_1, _FrontTex_1_HDR, _FrontTex_2, _FrontTex_2_HDR); } 118 | ENDCG 119 | } 120 | Pass{ 121 | CGPROGRAM 122 | 123 | #pragma vertex vert 124 | #pragma fragment frag 125 | 126 | sampler2D _BackTex_1; 127 | sampler2D _BackTex_2; 128 | half4 _BackTex_1_HDR; 129 | half4 _BackTex_2_HDR; 130 | half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_BackTex_1, _BackTex_1_HDR, _BackTex_2, _BackTex_2_HDR); } 131 | ENDCG 132 | } 133 | Pass{ 134 | CGPROGRAM 135 | 136 | #pragma vertex vert 137 | #pragma fragment frag 138 | 139 | sampler2D _LeftTex_1; 140 | sampler2D _LeftTex_2; 141 | half4 _LeftTex_1_HDR; 142 | half4 _LeftTex_2_HDR; 143 | half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_LeftTex_1, _LeftTex_1_HDR, _LeftTex_2, _LeftTex_2_HDR); } 144 | ENDCG 145 | } 146 | Pass{ 147 | CGPROGRAM 148 | 149 | #pragma vertex vert 150 | #pragma fragment frag 151 | 152 | sampler2D _RightTex_1; 153 | sampler2D _RightTex_2; 154 | half4 _RightTex_1_HDR; 155 | half4 _RightTex_2_HDR; 156 | half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_RightTex_1, _RightTex_1_HDR, _RightTex_2, _RightTex_2_HDR); } 157 | ENDCG 158 | } 159 | Pass{ 160 | CGPROGRAM 161 | 162 | #pragma vertex vert 163 | #pragma fragment frag 164 | 165 | sampler2D _UpTex_1; 166 | sampler2D _UpTex_2; 167 | half4 _UpTex_1_HDR; 168 | half4 _UpTex_2_HDR; 169 | half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_UpTex_1, _UpTex_1_HDR, _UpTex_2, _UpTex_2_HDR); } 170 | ENDCG 171 | } 172 | Pass{ 173 | CGPROGRAM 174 | 175 | #pragma vertex vert 176 | #pragma fragment frag 177 | 178 | sampler2D _DownTex_1; 179 | sampler2D _DownTex_2; 180 | half4 _DownTex_1_HDR; 181 | half4 _DownTex_2_HDR; 182 | half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_DownTex_1, _DownTex_1_HDR, _DownTex_2, _DownTex_2_HDR); } 183 | ENDCG 184 | } 185 | } 186 | } -------------------------------------------------------------------------------- /Shaders/SkyboxBlender.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70efe3856907a7843b5a544e58a7058c 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | --------------------------------------------------------------------------------