using UnityEngine; using UnityEngine.Profiling; [ExecuteInEditMode] public class ShadowCamera : MonoBehaviour { Camera ThisCamera = null; GameObject Dad = null; FogVolume Fog = null; public RenderTexture RT_Opacity, RT_OpacityBlur, RT_PostProcess; public RenderTexture GetOpacityRT() { return RT_Opacity; } public RenderTexture GetOpacityBlurRT() { return RT_OpacityBlur; } [System.Serializable] public enum TextureSize { _64 = 64, _128 = 128, _256 = 256, _512 = 512, _1024 = 1024 }; public TextureSize SetTextureSize { set { if (value != textureSize) SetQuality(value); } get { return textureSize; } } public TextureSize textureSize = TextureSize._128; /// Blur iterations - larger number means more blur. [Range(0, 10)] public int iterations = 3; /// Blur spread for each iteration. Lower values /// give better looking blur, but require more iterations to /// get large blurs. Value is usually between 0.5 and 1.0. [Range(0.0f, 1)] public float blurSpread = 0.6f; public int Downsampling = 2; void SetQuality(TextureSize value) { textureSize = value; // print((int)textureSize); } Shader blurShader = null; Shader PostProcessShader = null; Material blurMaterial = null; Material postProcessMaterial = null; protected Material BlurMaterial { get { if (blurMaterial == null) { blurMaterial = new Material(blurShader); blurMaterial.hideFlags = HideFlags.DontSave; } return blurMaterial; } } protected Material PostProcessMaterial { get { if (postProcessMaterial == null) { postProcessMaterial = new Material(PostProcessShader); postProcessMaterial.hideFlags = HideFlags.DontSave; } return postProcessMaterial; } } protected void GetRT(ref RenderTexture rt, int size, string name) { // Release existing one ReleaseRT(rt); rt = RenderTexture.GetTemporary(size, size, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear); rt.filterMode = FilterMode.Bilinear; rt.name = name; rt.wrapMode = TextureWrapMode.Repeat; } public void ReleaseRT(RenderTexture rt) { if (rt != null) { RenderTexture.ReleaseTemporary(rt); rt = null; } } // Performs one blur iteration. public void FourTapCone(RenderTexture source, RenderTexture dest, int iteration) { float off = 0.5f + iteration * blurSpread; Graphics.BlitMultiTap(source, dest, BlurMaterial, new Vector2(-off, -off), new Vector2(-off, off), new Vector2(off, off), new Vector2(off, -off) ); } // Downsamples the texture to a quarter resolution. private void DownSample(RenderTexture source, RenderTexture dest) { float off = 1.0f; Graphics.BlitMultiTap(source, dest, BlurMaterial, new Vector2(-off, -off), new Vector2(-off, off), new Vector2(off, off), new Vector2(off, -off) ); } void Blur(RenderTexture Input, int BlurRTSize) { RenderTexture RT_OpacityBlur2 = null; GetRT(ref RT_OpacityBlur, BlurRTSize, "Shadow blurred"); GetRT(ref RT_OpacityBlur2, BlurRTSize, "Shadow blurred"); // Copy source to the smaller texture. DownSample(Input, RT_OpacityBlur); //Graphics.Blit(Input, RT_OpacityBlur); // Blur the small texture for (int i = 0; i < iterations; i++) { FourTapCone(RT_OpacityBlur, RT_OpacityBlur2, i); FogVolumeUtilities.ExtensionMethods.Swap(ref RT_OpacityBlur, ref RT_OpacityBlur2); } Shader.SetGlobalTexture("RT_OpacityBlur", RT_OpacityBlur); Fog.RT_OpacityBlur = RT_OpacityBlur; } void RenderShadowMap() { //ideally, a cheaper version should be rendered here. //So lets render a version with no lighting stuff Profiler.BeginSample(Fog.name + " shadows"); Fog.FogVolumeShader.maximumLOD = 100; SetQuality(textureSize); GetRT(ref RT_Opacity, (int)textureSize, "Opacity"); ThisCamera.targetTexture = RT_Opacity; // print(Fog.ShadowCameraSkippedFrames); ThisCamera.Render(); Fog.RT_Opacity = RT_Opacity; // Shader.SetGlobalTexture("RT_Opacity", RT_Opacity); if (RT_Opacity != null) { GetRT(ref RT_PostProcess, (int)textureSize, "Shadow PostProcess"); PostProcessMaterial.SetFloat("ShadowColor", Fog.ShadowColor.a); // PostProcessMaterial.SetFloat("_jitter", Fog._jitter); Graphics.Blit(RT_Opacity, RT_PostProcess, PostProcessMaterial); // ThisCamera.targetTexture = null; Graphics.Blit(RT_PostProcess, RT_Opacity); //RenderTexture.ReleaseTemporary(RT_Opacity); if (iterations > 0) { Blur(RT_Opacity, (int)textureSize >> Downsampling); } else { Shader.SetGlobalTexture("RT_OpacityBlur", RT_Opacity); Fog.RT_OpacityBlur = RT_Opacity; } Fog.RT_Opacity = RT_Opacity; } //Shader.SetGlobalTexture("RT_Opacity", RT_Opacity); BlurMaterial.SetFloat("ShadowColor", Fog.ShadowColor.a); // back to normal Fog.FogVolumeShader.maximumLOD = 600; Profiler.EndSample(); } void ShaderLoad() { blurShader = Shader.Find("Hidden/Fog Volume/BlurEffectConeTap"); if (blurShader == null) print("Hidden / Fog Volume / BlurEffectConeTap #SHADER ERROR#"); PostProcessShader = Shader.Find("Hidden/Fog Volume/Shadow Postprocess"); if (PostProcessShader == null) print("Hidden/Fog Volume/Shadow Postprocess #SHADER ERROR#"); } void OnEnable() { ShaderLoad(); Dad = transform.parent.gameObject; Fog = Dad.GetComponent(); ThisCamera = gameObject.GetComponent(); ThisCamera.depthTextureMode = DepthTextureMode.Depth; CameraTransform(); } public void CameraTransform() { if (ThisCamera != null) { ThisCamera.orthographicSize = Dad.GetComponent().fogVolumeScale.x / 2; ThisCamera.transform.position = Dad.transform.position; ThisCamera.farClipPlane = Fog.fogVolumeScale.y + Fog.shadowCameraPosition; // print(ThisCamera.farClipPlane); Vector3 VerticalTranslate = new Vector3(0, 0, Fog.fogVolumeScale.y / 2 - Fog.shadowCameraPosition); // print(Fog.ShadowCameraPosition); ThisCamera.transform.Translate(VerticalTranslate, Space.Self); Quaternion target = Quaternion.Euler(90, 0, 0); ThisCamera.transform.rotation = Dad.transform.rotation * target; ThisCamera.enabled = false; if (Fog.SunAttached) { Fog.Sun.transform.rotation = Dad.transform.rotation * target; } } } // Update is called once per frame void Update() { // print(Fog.name + " visibility: " + Fog.IsVisible); if (Fog.IsVisible && Fog.CastShadows)//3.1.7 { if (FogVolumeUtilities.ExtensionMethods.TimeSnap(Fog.ShadowCameraSkippedFrames)) RenderShadowMap(); #if UNITY_EDITOR CameraTransform(); #endif } } void OnDisable() { RenderTexture.active = null; ThisCamera.targetTexture = null; if (RT_Opacity) DestroyImmediate(RT_Opacity); if (RT_OpacityBlur) DestroyImmediate(RT_OpacityBlur); if (RT_PostProcess) DestroyImmediate(RT_PostProcess); if (blurMaterial) DestroyImmediate(blurMaterial); if (postProcessMaterial) DestroyImmediate(postProcessMaterial); } }