少年修仙传客户端代码仓库
client_Wu Xijin
2018-08-31 5c096b4c1b0ff2ec4d3ebc37b32ca252a92031db
Core/DynamicShadowProjector/ShadowTextureRenderer.cs
@@ -10,28 +10,34 @@
using UnityEngine.Rendering;
using System.Collections.Generic;
namespace DynamicShadowProjector {
namespace DynamicShadowProjector
{
   [ExecuteInEditMode]
   [DisallowMultipleComponent]
   [RequireComponent(typeof(Projector))]
   public class ShadowTextureRenderer : MonoBehaviour {
      public enum TextureMultiSample {
    public class ShadowTextureRenderer : MonoBehaviour
    {
        public enum TextureMultiSample
        {
         x1 = 1,
         x2 = 2,
         x4 = 4,
         x8 = 8,
      }
      public enum TextureSuperSample {
        public enum TextureSuperSample
        {
         x1 = 1,
         x4 = 2,
         x16 = 4,
      }
      public enum MipmapFalloff {
        public enum MipmapFalloff
        {
         None = 0,
         Linear,
         Custom,
      }
      public enum BlurFilter {
        public enum BlurFilter
        {
         Uniform = 0,
         Gaussian,
      }
@@ -81,8 +87,10 @@
      public TextureMultiSample multiSampling
      {
         get { return m_multiSampling; }
         set {
            if (m_multiSampling != value) {
            set
            {
                if (m_multiSampling != value)
                {
               m_multiSampling = value;
               SetTexturePropertyDirty();
            }
@@ -91,11 +99,14 @@
      public TextureSuperSample superSampling
      {
         get { return m_superSampling; }
         set {
            if (m_superSampling != value) {
            set
            {
                if (m_superSampling != value)
                {
               bool b = useIntermediateTexture;
               m_superSampling = value;
               if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) {
                    if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1)
                    {
                  SetTexturePropertyDirty();
               }
            }
@@ -104,8 +115,10 @@
      public int textureWidth
      {
         get { return m_textureWidth; }
         set {
            if (m_textureWidth != value) {
            set
            {
                if (m_textureWidth != value)
                {
               m_textureWidth = value;
               SetTexturePropertyDirty();
            }
@@ -114,8 +127,10 @@
      public int textureHeight
      {
         get { return m_textureHeight; }
         set {
            if (m_textureHeight != value) {
            set
            {
                if (m_textureHeight != value)
                {
               m_textureHeight = value;
               SetTexturePropertyDirty();
            }
@@ -124,9 +139,12 @@
      public int mipLevel
      {
         get { return m_mipLevel; }
         set {
            if (m_mipLevel != value) {
               if (m_mipLevel == 0 || value == 0) {
            set
            {
                if (m_mipLevel != value)
                {
                    if (m_mipLevel == 0 || value == 0)
                    {
                  SetTexturePropertyDirty();
               }
               m_mipLevel = value;
@@ -138,10 +156,12 @@
         get { return m_blurLevel; }
         set
         {
            if (m_blurLevel != value) {
                if (m_blurLevel != value)
                {
               bool b = useIntermediateTexture;
               m_blurLevel = value;
               if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) {
                    if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1)
                    {
                  SetTexturePropertyDirty();
               }
            }
@@ -165,7 +185,8 @@
            m_mipmapBlurSize = value;
         }
      }
      public bool singlePassMipmapBlur {
        public bool singlePassMipmapBlur
        {
         get { return m_singlePassMipmapBlur; }
         set { m_singlePassMipmapBlur = value; }
      }
@@ -188,11 +209,14 @@
      public Color shadowColor
      {
         get { return m_shadowColor; }
         set {
            if (m_shadowColor != value) {
            set
            {
                if (m_shadowColor != value)
                {
               bool b = useIntermediateTexture;
               m_shadowColor = value;
               if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) {
                    if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1)
                    {
                  SetTexturePropertyDirty();
               }
            }
@@ -240,14 +264,18 @@
      }
      public float cameraNearClipPlane
      {
         get {
            if (m_camera == null) {
            get
            {
                if (m_camera == null)
                {
               Initialize();
            }
            return m_camera.nearClipPlane;
         }
         set {
            if (m_camera == null) {
            set
            {
                if (m_camera == null)
                {
               Initialize();
            }
            m_camera.nearClipPlane = value;
@@ -255,14 +283,18 @@
      }
      public LayerMask cameraCullingMask
      {
         get {
            if (m_camera == null) {
            get
            {
                if (m_camera == null)
                {
               Initialize();
            }
            return m_camera.cullingMask;
         }
         set {
            if (m_camera == null) {
            set
            {
                if (m_camera == null)
                {
               Initialize();
            }
            m_camera.cullingMask = value;
@@ -270,13 +302,16 @@
      }
      public void SetReplacementShader(Shader shader, string replacementTag)
      {
         if (m_camera == null) {
            if (m_camera == null)
            {
            Initialize();
         }
         if (shader != null) {
            if (shader != null)
            {
            m_camera.SetReplacementShader(shader, replacementTag);
         }
         else {
            else
            {
            m_camera.ResetReplacementShader();
         }
      }
@@ -295,7 +330,8 @@
      private Material m_projectorMaterial;
      private CommandBuffer m_commandBuffer;
      private RenderTexture m_shadowTexture;
      [SerializeField][HideInInspector]
        [SerializeField]
        [HideInInspector]
      private Camera m_camera;
      private bool m_isTexturePropertyChanged;
      private bool m_isVisible = false;
@@ -313,33 +349,42 @@
      }
      public void CreateRenderTexture()
      {
         if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_projector == null) {
            if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_projector == null)
            {
            return;
         }
         // choose a texture format
         RenderTextureFormat textureFormat = RenderTextureFormat.ARGB32;
         if (m_preferredTextureFormats != null && 0 < m_preferredTextureFormats.Length) {
            foreach (RenderTextureFormat format in m_preferredTextureFormats) {
               if (SystemInfo.SupportsRenderTextureFormat(textureFormat)) {
            if (m_preferredTextureFormats != null && 0 < m_preferredTextureFormats.Length)
            {
                foreach (RenderTextureFormat format in m_preferredTextureFormats)
                {
                    if (SystemInfo.SupportsRenderTextureFormat(textureFormat))
                    {
                  textureFormat = format;
               }
            }
         }
         // create texture
         if (m_shadowTexture != null) {
            if (m_camera != null) {
            if (m_shadowTexture != null)
            {
                if (m_camera != null)
                {
               m_camera.targetTexture = null;
            }
            DestroyImmediate(m_shadowTexture);
         }
         m_shadowTexture = new RenderTexture(m_textureWidth, m_textureHeight, 0, textureFormat, RenderTextureReadWrite.Linear);
         if (useIntermediateTexture) {
            if (useIntermediateTexture)
            {
            m_shadowTexture.antiAliasing = 1;
         }
         else {
            else
            {
            m_shadowTexture.antiAliasing = (int)m_multiSampling;
         }
         if (0 < m_mipLevel) {
            if (0 < m_mipLevel)
            {
            m_shadowTexture.useMipMap = true;
#if UNITY_5_5_OR_NEWER
            m_shadowTexture.autoGenerateMips = false;
@@ -349,18 +394,21 @@
            m_shadowTexture.mipMapBias = 0.0f;
            m_shadowTexture.filterMode = FilterMode.Trilinear;
         }
         else {
            else
            {
            m_shadowTexture.useMipMap = false;
            m_shadowTexture.filterMode = FilterMode.Bilinear;
         }
         m_shadowTexture.wrapMode = TextureWrapMode.Clamp;
         m_shadowTexture.Create();
         m_shadowTextureValid = false;
         if (m_projector.material != null) {
            if (m_projector.material != null)
            {
            m_projector.material.SetTexture("_ShadowTex", m_shadowTexture);
            m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel);
         }
         if (m_camera != null) {
            if (m_camera != null)
            {
            m_camera.targetTexture = m_shadowTexture;
         }
         m_isTexturePropertyChanged = false;
@@ -392,28 +440,33 @@
      bool useIntermediateTexture
      {
         get {
            get
            {
            return m_superSampling != TextureSuperSample.x1 || 0 < m_blurLevel || HasShadowColor() || (0 < m_mipLevel && m_multiSampling != TextureMultiSample.x1);
         }
      }
      bool Initialize()
      {
         m_isVisible = false;
         if (IsInitialized()) {
            if (IsInitialized())
            {
            return true;
         }
         m_isTexturePropertyChanged = true;
         InitializeShaderPropertyIDs();
         m_projector = GetComponent<Projector>();
         CloneProjectorMaterialIfShared();
         if (m_camera == null) {
            if (m_camera == null)
            {
            m_camera = gameObject.GetComponent<Camera>();
            if (m_camera == null) {
                if (m_camera == null)
                {
               m_camera = gameObject.AddComponent<Camera>();
            }
            m_camera.hideFlags = HideFlags.HideInInspector;
         }
         else {
            else
            {
            m_camera.RemoveAllCommandBuffers();
         }
         m_camera.depth = -100;
@@ -443,14 +496,16 @@
      void OnEnable()
      {
         if (m_camera != null) {
            if (m_camera != null)
            {
            m_camera.enabled = true;
         }
      }
      void OnDisable()
      {
         if (m_camera != null) {
            if (m_camera != null)
            {
            m_camera.enabled = false;
         }
      }
@@ -463,8 +518,10 @@
         if (m_testViewClip)
#endif
         {
            if (m_camerasForViewClipTest == null || m_camerasForViewClipTest.Length == 0) {
               if (Camera.main != null) {
                if (m_camerasForViewClipTest == null || m_camerasForViewClipTest.Length == 0)
                {
                    if (Camera.main != null)
                    {
                  m_camerasForViewClipTest = new Camera[1] {Camera.main};
               }
            }
@@ -476,16 +533,21 @@
         CreateRenderTexture();
         InitializeShaderPropertyIDs();
         // check custom mipmap falloff
         if (m_mipmapFalloff == MipmapFalloff.Custom && 0 < m_mipLevel) {
            if (m_customMipmapFalloff == null || m_customMipmapFalloff.Length == 0) {
            if (m_mipmapFalloff == MipmapFalloff.Custom && 0 < m_mipLevel)
            {
                if (m_customMipmapFalloff == null || m_customMipmapFalloff.Length == 0)
                {
               m_customMipmapFalloff = new float[m_mipLevel];
               for (int i = 0; i < m_mipLevel; ++i) {
                    for (int i = 0; i < m_mipLevel; ++i)
                    {
                  m_customMipmapFalloff[i] = ((float)(m_mipLevel - i))/(float)(m_mipLevel + 1);
               }
            }
            else if (m_mipLevel != m_customMipmapFalloff.Length) {
                else if (m_mipLevel != m_customMipmapFalloff.Length)
                {
               float[] customFalloff = new float[m_mipLevel];
               for (int i = 0; i < m_mipLevel; ++i) {
                    for (int i = 0; i < m_mipLevel; ++i)
                    {
                  float oldIndex = ((float)(m_customMipmapFalloff.Length + 1)*(i + 1))/(float)(m_mipLevel + 1);
                  int j = Mathf.FloorToInt(oldIndex);
                  float w = oldIndex - j;
@@ -502,24 +564,30 @@
      void CloneProjectorMaterialIfShared()
      {
#if UNITY_EDITOR
         if (!Application.isPlaying) {
            if (!Application.isPlaying)
            {
            return;
         }
#endif
         if (m_projector.material == null || (m_projector.material.hideFlags == CLONED_MATERIAL_HIDE_FLAGS && m_projector.material == m_projectorMaterial)) {
            if (m_projector.material == null || (m_projector.material.hideFlags == CLONED_MATERIAL_HIDE_FLAGS && m_projector.material == m_projectorMaterial))
            {
            return;
         }
         if (m_projectorMaterial != null && m_projectorMaterial.hideFlags == CLONED_MATERIAL_HIDE_FLAGS) {
            if (m_projectorMaterial != null && m_projectorMaterial.hideFlags == CLONED_MATERIAL_HIDE_FLAGS)
            {
            DestroyImmediate(m_projectorMaterial);
         }
         if (s_sharedMaterials == null) {
            if (s_sharedMaterials == null)
            {
            s_sharedMaterials = new HashSet<Material>();
         }
         if (s_sharedMaterials.Contains(m_projector.material)) {
            if (s_sharedMaterials.Contains(m_projector.material))
            {
            m_projector.material = new Material(m_projector.material);
            m_projector.material.hideFlags = CLONED_MATERIAL_HIDE_FLAGS;
         }
         else {
            else
            {
            s_sharedMaterials.Add(m_projector.material);
         }
         m_projectorMaterial = m_projector.material;
@@ -527,25 +595,32 @@
      void OnDestroy()
      {
         if (m_projectorMaterial != null) {
            if (s_sharedMaterials != null && s_sharedMaterials.Contains(m_projectorMaterial)) {
            if (m_projectorMaterial != null)
            {
                if (s_sharedMaterials != null && s_sharedMaterials.Contains(m_projectorMaterial))
                {
               s_sharedMaterials.Remove(m_projectorMaterial);
            }
            if (m_projectorMaterial.hideFlags == CLONED_MATERIAL_HIDE_FLAGS) {
               if (m_projector.material == m_projectorMaterial) {
                if (m_projectorMaterial.hideFlags == CLONED_MATERIAL_HIDE_FLAGS)
                {
                    if (m_projector.material == m_projectorMaterial)
                    {
                  m_projector.material = null;
               }
               DestroyImmediate(m_projectorMaterial);
            }
         }
         if (m_shadowTexture != null) {
            if (m_camera != null) {
            if (m_shadowTexture != null)
            {
                if (m_camera != null)
                {
               m_camera.targetTexture = null;
            }
            DestroyImmediate(m_shadowTexture);
            m_shadowTexture = null;
         }
         if (m_camera != null) {
            if (m_camera != null)
            {
            m_camera.RemoveAllCommandBuffers();
         }
         m_isVisible = false;
@@ -553,20 +628,26 @@
      bool IsReadyToExecute()
      {
         if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_eraseShadowShader == null) {
            if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_eraseShadowShader == null)
            {
            return false;
         }
         if (0 < m_mipLevel || m_superSampling != TextureSuperSample.x1) {
            if (m_downsampleShader == null) {
            if (0 < m_mipLevel || m_superSampling != TextureSuperSample.x1)
            {
                if (m_downsampleShader == null)
                {
               return false;
            }
         }
         if (0 < m_blurLevel || (0.0f < m_mipmapBlurSize && 0 < m_mipLevel)) {
            if (m_blurShader == null) {
            if (0 < m_blurLevel || (0.0f < m_mipmapBlurSize && 0 < m_mipLevel))
            {
                if (m_blurShader == null)
                {
               return false;
            }
         }
         if (0 < m_mipLevel && (m_copyMipmapShader == null || m_downsampleShader == null)) {
            if (0 < m_mipLevel && (m_copyMipmapShader == null || m_downsampleShader == null))
            {
            return false;
         }
         return true;
@@ -609,38 +690,46 @@
               || m_camera.fieldOfView != m_projector.fieldOfView
               || m_camera.aspect != m_projector.aspectRatio
               || m_camera.farClipPlane != m_projector.farClipPlane)
         ) {
            )
            {
            ForceRenderTexture();
         }
#endif
         if (m_camera != null && !m_camera.enabled) {
            if (m_camera != null && !m_camera.enabled)
            {
            m_camera.enabled = true;
         }
      }
      void OnPreCull()
      {
         if (m_projector.material != m_projectorMaterial) {
            if (m_projector.material != m_projectorMaterial)
            {
            // projector material changed.
            CloneProjectorMaterialIfShared();
            m_projector.material.SetTexture("_ShadowTex", m_shadowTexture);
            m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel);
         }
#if UNITY_EDITOR
         if (!(Application.isPlaying || m_isRenderingFromUpdate)) {
            if (!(Application.isPlaying || m_isRenderingFromUpdate))
            {
            m_camera.enabled = false;
            return;
         }
         if (!IsReadyToExecute()) {
            if (!IsReadyToExecute())
            {
            m_camera.enabled = false;
            return;
         }
         if (!IsInitialized() && !Initialize()) {
            if (!IsInitialized() && !Initialize())
            {
            m_camera.enabled = false;
            return;
         }
         if (m_projector.material == null) {
            if (m_isVisible) {
            if (m_projector.material == null)
            {
                if (m_isVisible)
                {
               SetVisible(false);
            }
            m_camera.enabled = false;
@@ -649,7 +738,8 @@
         m_projector.material.SetTexture("_ShadowTex", m_shadowTexture);
         m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel);
#endif
         if (m_isTexturePropertyChanged) {
            if (m_isTexturePropertyChanged)
            {
            CreateRenderTexture();
         }
         m_camera.orthographic = m_projector.orthographic;
@@ -659,7 +749,8 @@
         m_camera.farClipPlane = m_projector.farClipPlane;
         // view clip test
         bool isVisible = true;
         if (!m_projector.enabled) {
            if (!m_projector.enabled)
            {
            isVisible = false;
         }
#if UNITY_EDITOR
@@ -668,12 +759,15 @@
         else if (m_testViewClip)
#endif
         {
            if (m_camerasForViewClipTest == null || m_camerasForViewClipTest.Length == 0) {
               if (Camera.main != null) {
                if (m_camerasForViewClipTest == null || m_camerasForViewClipTest.Length == 0)
                {
                    if (Camera.main != null)
                    {
                  m_camerasForViewClipTest = new Camera[1] {Camera.main};
               }
            }
            if (m_camerasForViewClipTest != null && 0 < m_camerasForViewClipTest.Length) {
                if (m_camerasForViewClipTest != null && 0 < m_camerasForViewClipTest.Length)
                {
               Vector3 v0 = m_camera.ViewportToWorldPoint(new Vector3(0,0,m_camera.nearClipPlane));
               Vector3 v1 = m_camera.ViewportToWorldPoint(new Vector3(1,0,m_camera.nearClipPlane));
               Vector3 v2 = m_camera.ViewportToWorldPoint(new Vector3(0,1,m_camera.nearClipPlane));
@@ -683,7 +777,8 @@
               Vector3 v6 = m_camera.ViewportToWorldPoint(new Vector3(0,1,m_camera.farClipPlane));
               Vector3 v7 = m_camera.ViewportToWorldPoint(new Vector3(1,1,m_camera.farClipPlane));
               isVisible = false;
               for (int i = 0; i < m_camerasForViewClipTest.Length; ++i) {
                    for (int i = 0; i < m_camerasForViewClipTest.Length; ++i)
                    {
                  Camera cam = m_camerasForViewClipTest[i];
                  Vector3 min = cam.WorldToViewportPoint(v0);
                  if (min.z < 0.0f) { min.x = -min.x; min.y = -min.y; }
@@ -716,21 +811,26 @@
                  if (v.z < 0.0f) { v.x = -v.x; v.y = -v.y; }
                  min.x = Mathf.Min(min.x, v.x); min.y = Mathf.Min(min.y, v.y); min.z = Mathf.Min(min.z, v.z);
                  max.x = Mathf.Max(max.x, v.x); max.y = Mathf.Max(max.y, v.y); max.z = Mathf.Max(max.z, v.z);
                  if (0.0f < max.x && min.x < 1.0f && 0.0f < max.y && min.y < 1.0f && cam.nearClipPlane < max.z && min.z < cam.farClipPlane) {
                        if (0.0f < max.x && min.x < 1.0f && 0.0f < max.y && min.y < 1.0f && cam.nearClipPlane < max.z && min.z < cam.farClipPlane)
                        {
                     isVisible = true;
                     break;
                  }
               }
            }
         }
         if (isVisible != m_isVisible) {
            if (isVisible != m_isVisible)
            {
            SetVisible(isVisible);
         }
         if (!isVisible) {
            if (m_camera != null) {
            if (!isVisible)
            {
                if (m_camera != null)
                {
               m_camera.enabled = false;
            }
            if (m_shadowTexture != null && !m_shadowTextureValid) {
                if (m_shadowTexture != null && !m_shadowTextureValid)
                {
               RenderTexture currentRT = RenderTexture.active;
               RenderTexture.active = m_shadowTexture;
               GL.Clear(false, true, new Color(1,1,1,0));
@@ -748,28 +848,33 @@
      void OnPreRender()
      {
#if UNITY_EDITOR
         if (!(Application.isPlaying || m_isRenderingFromUpdate)) {
            if (!(Application.isPlaying || m_isRenderingFromUpdate))
            {
            return;
         }
#endif
         if (!m_isVisible) {
            if (!m_isVisible)
            {
            return;
         }
         m_shadowTexture.DiscardContents();
         if (useIntermediateTexture) {
            if (useIntermediateTexture)
            {
            int width = m_textureWidth * (int)m_superSampling;
            int height = m_textureHeight * (int)m_superSampling;
            m_camera.targetTexture = RenderTexture.GetTemporary(width, height, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear, (int)m_multiSampling);
            m_camera.targetTexture.filterMode = FilterMode.Bilinear;
         }
         else {
            else
            {
            m_camera.targetTexture = m_shadowTexture;
         }
         m_camera.clearFlags = CameraClearFlags.SolidColor;
      }
      private const int MAX_BLUR_TAP_SIZE = 7;
      private static float[] s_blurWeights = new float[MAX_BLUR_TAP_SIZE];
      struct BlurParam {
        struct BlurParam
        {
         public int tap;
         public Vector4 offset;
         public Vector4 weight;
@@ -778,7 +883,8 @@
      {
         BlurParam param = new BlurParam();
         if (blurSize < 0.1f) {
            if (blurSize < 0.1f)
            {
            param.tap = 3;
            param.offset.x = 0.0f;
            param.offset.y = 0.0f;
@@ -791,31 +897,39 @@
            return param;
         }
         // calculate weights
         if (filter == BlurFilter.Gaussian) {
            if (filter == BlurFilter.Gaussian)
            {
            // gaussian filter
            float a = 1.0f/(2.0f*blurSize*blurSize);
            float totalWeight = 1.0f;
            s_blurWeights[0] = 1.0f;
            for (int i = 1; i < s_blurWeights.Length; ++i) {
                for (int i = 1; i < s_blurWeights.Length; ++i)
                {
               s_blurWeights[i] = Mathf.Exp(-i*i*a);
               totalWeight += 2.0f*s_blurWeights[i];
            }
            float w = 1.0f/totalWeight;
            for (int i = 0; i < s_blurWeights.Length; ++i) {
                for (int i = 0; i < s_blurWeights.Length; ++i)
                {
               s_blurWeights[i] *= w;
            }
         }
         else {
            else
            {
            // uniform filter
            float a = 0.5f/(0.5f + blurSize);
            for (int i = 0; i < s_blurWeights.Length; ++i) {
               if (i <= blurSize) {
                for (int i = 0; i < s_blurWeights.Length; ++i)
                {
                    if (i <= blurSize)
                    {
                  s_blurWeights[i] = a;
               }
               else if (i - 1 < blurSize) {
                    else if (i - 1 < blurSize)
                    {
                  s_blurWeights[i] = a * (blurSize - (i - 1));
               }
               else {
                    else
                    {
                  s_blurWeights[i] = 0.0f;
               }
            }
@@ -825,7 +939,8 @@
         param.offset.z = 5.0f + s_blurWeights[6]/(s_blurWeights[5] + s_blurWeights[6]);
         param.offset.w = 0.0f;
         if (s_blurWeights[3] < 0.02f) {
            if (s_blurWeights[3] < 0.02f)
            {
            param.tap = 3;
            float a = 0.5f/(0.5f*s_blurWeights[0] + s_blurWeights[1] + s_blurWeights[2]);
            param.weight.x = Mathf.Round(255*a*s_blurWeights[0])/255.0f;
@@ -833,7 +948,8 @@
            param.weight.z = 0.0f;
            param.weight.w = 0.0f;
         }
         else if (s_blurWeights[5] < 0.02f) {
            else if (s_blurWeights[5] < 0.02f)
            {
            param.tap = 5;
            float a = 0.5f/(0.5f*s_blurWeights[0] + s_blurWeights[1] + s_blurWeights[2] + s_blurWeights[3] + s_blurWeights[4]);
            param.weight.x = Mathf.Round(255*a*s_blurWeights[0])/255.0f;
@@ -841,7 +957,8 @@
            param.weight.z = 0.5f - (0.5f*param.weight.x + param.weight.y);
            param.weight.w = 0.0f;
         }
         else {
            else
            {
            param.tap = 7;
            param.weight.x = Mathf.Round(255*s_blurWeights[0])/255.0f;
            param.weight.y = Mathf.Round(255*(s_blurWeights[1] + s_blurWeights[2]))/255.0f;
@@ -854,7 +971,8 @@
      {
         BlurParam param = new BlurParam();
         param.tap = 4;
         if (blurSize < 0.1f) {
            if (blurSize < 0.1f)
            {
            param.offset.x = 0.0f;
            param.offset.y = 0.0f;
            param.offset.z = 0.0f;
@@ -866,31 +984,39 @@
            return param;
         }
         // calculate weights
         if (filter == BlurFilter.Gaussian) {
            if (filter == BlurFilter.Gaussian)
            {
            // gaussian filter
            float a = 1.0f/(2.0f*blurSize*blurSize);
            float totalWeight = 0.0f;
            for (int i = 0; i < param.tap; ++i) {
                for (int i = 0; i < param.tap; ++i)
                {
               float x = i + 0.5f;
               s_blurWeights[i] = Mathf.Exp(-x*x*a);
               totalWeight += 2.0f*s_blurWeights[i];
            }
            float w = 1.0f/totalWeight;
            for (int i = 0; i < param.tap; ++i) {
                for (int i = 0; i < param.tap; ++i)
                {
               s_blurWeights[i] *= w;
            }
         }
         else {
            else
            {
            // uniform filter
            float a = 0.5f/blurSize;
            for (int i = 0; i < param.tap; ++i) {
               if (i + 1 <= blurSize) {
                for (int i = 0; i < param.tap; ++i)
                {
                    if (i + 1 <= blurSize)
                    {
                  s_blurWeights[i] = a;
               }
               else if (i < blurSize) {
                    else if (i < blurSize)
                    {
                  s_blurWeights[i] = a * (blurSize - i);
               }
               else {
                    else
                    {
                  s_blurWeights[i] = 0.0f;
               }
            }
@@ -910,12 +1036,14 @@
      void OnPostRender()
      {
#if UNITY_EDITOR
         if (!(Application.isPlaying || m_isRenderingFromUpdate)) {
            if (!(Application.isPlaying || m_isRenderingFromUpdate))
            {
            return;
         }
#endif
         m_camera.clearFlags = CameraClearFlags.Nothing;
         if (!m_isVisible) {
            if (!m_isVisible)
            {
            return;
         }
         RenderTexture srcRT = m_camera.targetTexture;
@@ -923,21 +1051,25 @@
         // workaround for Unity 5.6
         // Unity 5.6 has a bug whereby a temporary render texture does not work if m_camera.targetTexture != null. This bug is fixed in Unity 2017.
         // However, this workaround might conflict with VR support. If you have a problem with VR SDK, please let us know via e-mail (support@nyahoon.com).
         if (srcRT != m_shadowTexture) {
            if (srcRT != m_shadowTexture)
            {
            m_camera.targetTexture = null;
         }
#else
         m_camera.targetTexture = m_shadowTexture;
#endif
         if (m_superSampling != TextureSuperSample.x1 || HasShadowColor()) {
            if (m_superSampling != TextureSuperSample.x1 || HasShadowColor())
            {
            m_downsampleShader.color = m_shadowColor;
            // downsample
            RenderTexture dstRT;
            if (0 < m_blurLevel) {
                if (0 < m_blurLevel)
                {
               dstRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear);
               dstRT.filterMode = FilterMode.Bilinear;
            }
            else {
                else
                {
               dstRT = m_shadowTexture;
            }
            Graphics.SetRenderTarget(dstRT);
@@ -946,15 +1078,18 @@
            RenderTexture.ReleaseTemporary(srcRT);
            srcRT = dstRT;
         }
         if (0 < m_blurLevel) {
            if (0 < m_blurLevel)
            {
            // adjust blur size according to texel aspect
            float texelAspect = (m_projector.aspectRatio * m_textureHeight)/(float)m_textureWidth;
            float blurSizeH = m_blurSize;
            float blurSizeV = m_blurSize;
            if (texelAspect < 1.0f) {
                if (texelAspect < 1.0f)
                {
               blurSizeV *= texelAspect;
            }
            else {
                else
                {
               blurSizeH /= texelAspect;
            }
            // blur parameters
@@ -972,14 +1107,17 @@
            srcRT.wrapMode = TextureWrapMode.Clamp;
            dstRT.wrapMode = TextureWrapMode.Clamp;
            Graphics.Blit(srcRT, dstRT, m_blurShader, blurH.tap);
            if (1 < srcRT.antiAliasing) {
                if (1 < srcRT.antiAliasing)
                {
               RenderTexture.ReleaseTemporary(srcRT);
               srcRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear);
            }
            else {
                else
                {
               srcRT.DiscardContents();
            }
            for (int i = 1; i < m_blurLevel - 1; ++i) {
                for (int i = 1; i < m_blurLevel - 1; ++i)
                {
               Graphics.Blit(dstRT, srcRT, m_blurShader, blurV.tap);
               dstRT.DiscardContents();
               Graphics.Blit(srcRT, dstRT, m_blurShader, blurH.tap);
@@ -991,29 +1129,36 @@
            RenderTexture.ReleaseTemporary(dstRT);
         }
         Graphics.SetRenderTarget(m_shadowTexture);
         if (srcRT != m_shadowTexture) {
            if (srcRT != m_shadowTexture)
            {
            Graphics.Blit(srcRT, m_downsampleShader, 2);
            if (m_mipLevel == 0) {
                if (m_mipLevel == 0)
                {
               RenderTexture.ReleaseTemporary(srcRT);
            }
         }
         EraseShadowOnBoarder(m_textureWidth, m_textureHeight);
         if (0 < m_mipLevel) {
            if (0 < m_mipLevel)
            {
            // setup blur parameters
            BlurParam blurH = new BlurParam(), blurV = new BlurParam();
            if (0.1f < m_mipmapBlurSize) {
                if (0.1f < m_mipmapBlurSize)
                {
               // adjust blur size according to texel aspect
               float texelAspect = (m_projector.aspectRatio * m_textureHeight)/(float)m_textureWidth;
               float blurSizeH = m_mipmapBlurSize;
               float blurSizeV = m_mipmapBlurSize;
               if (texelAspect < 1.0f) {
                    if (texelAspect < 1.0f)
                    {
                  blurSizeV *= texelAspect;
               }
               else {
                    else
                    {
                  blurSizeH /= texelAspect;
               }
               // blur parameters
               if (m_singlePassMipmapBlur) {
                    if (m_singlePassMipmapBlur)
                    {
                  blurH = GetDownsampleBlurParam(2.0f + 2.0f*blurSizeH, m_blurFilter);
                  blurV = GetDownsampleBlurParam(2.0f + 2.0f*blurSizeV, m_blurFilter);
                  Vector4 weight = new Vector4(blurH.weight.x * blurV.weight.x, blurH.weight.x * blurV.weight.y, blurH.weight.y * blurV.weight.x, blurH.weight.y * blurV.weight.y);
@@ -1024,7 +1169,8 @@
                  weight.w = 0.25f - weight.x - weight.y - weight.z;
                  m_downsampleShader.SetVector(s_downSampleBlurWeightParamID, weight);
               }
               else {
                    else
                    {
                  blurH = GetBlurParam(blurSizeH, m_blurFilter);
                  blurV = GetBlurParam(blurSizeV, m_blurFilter);
                  blurH.tap = (blurH.tap - 3); // index of pass
@@ -1040,26 +1186,33 @@
            RenderTexture tempRT = RenderTexture.GetTemporary(w, h, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear);
            tempRT.filterMode = FilterMode.Bilinear;
            bool downSampleWithBlur = m_singlePassMipmapBlur && 0.1f < m_mipmapBlurSize;
            if (downSampleWithBlur) {
                if (downSampleWithBlur)
                {
               SetDownsampleBlurOffsetParams(blurH, blurV, w, h);
            }
            if (srcRT == m_shadowTexture) {
               if (downSampleWithBlur) {
                if (srcRT == m_shadowTexture)
                {
                    if (downSampleWithBlur)
                    {
                  Graphics.Blit(srcRT, tempRT, m_downsampleShader, 5);
               }
               else {
                    else
                    {
                  Graphics.Blit(srcRT, tempRT, m_copyMipmapShader, 1);
               }
            }
            else {
                else
                {
               Graphics.Blit(srcRT, tempRT, m_downsampleShader, downSampleWithBlur ? 4 : 0);
               RenderTexture.ReleaseTemporary(srcRT);
            }
            srcRT = tempRT;
            int i = 0;
            float falloff = 1.0f;
            for ( ; ; ) {
               if (0.1f < m_mipmapBlurSize && !m_singlePassMipmapBlur) {
                for (; ; )
                {
                    if (0.1f < m_mipmapBlurSize && !m_singlePassMipmapBlur)
                    {
                  tempRT = RenderTexture.GetTemporary(w, h, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear);
                  tempRT.filterMode = FilterMode.Bilinear;
                  tempRT.wrapMode = TextureWrapMode.Clamp;
@@ -1069,10 +1222,12 @@
                  Graphics.Blit(tempRT, srcRT, m_blurShader, blurV.tap);
                  RenderTexture.ReleaseTemporary(tempRT);
               }
               if (m_mipmapFalloff == MipmapFalloff.Linear) {
                    if (m_mipmapFalloff == MipmapFalloff.Linear)
                    {
                  falloff = ((float)(m_mipLevel - i))/(m_mipLevel + 1.0f);
               }
               else if (m_mipmapFalloff == MipmapFalloff.Custom && m_customMipmapFalloff != null && 0 < m_customMipmapFalloff.Length) {
                    else if (m_mipmapFalloff == MipmapFalloff.Custom && m_customMipmapFalloff != null && 0 < m_customMipmapFalloff.Length)
                    {
                  falloff = m_customMipmapFalloff[Mathf.Min(i, m_customMipmapFalloff.Length-1)];
               }
               m_copyMipmapShader.SetFloat(s_falloffParamID, falloff);
@@ -1084,23 +1239,27 @@
               EraseShadowOnBoarder(w, h);
               w = Mathf.Max(1, w >> 1);
               h = Mathf.Max(1, h >> 1);
               if (i == m_mipLevel || w <= 4 || h <= 4) {
                    if (i == m_mipLevel || w <= 4 || h <= 4)
                    {
                  RenderTexture.ReleaseTemporary(srcRT);
                  break;
               }
               tempRT = RenderTexture.GetTemporary(w, h, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear);
               tempRT.filterMode = FilterMode.Bilinear;
               if (downSampleWithBlur) {
                    if (downSampleWithBlur)
                    {
                  SetDownsampleBlurOffsetParams(blurH, blurV, w, h);
                  Graphics.Blit(srcRT, tempRT, m_downsampleShader, 4);
               }
               else {
                    else
                    {
                  Graphics.Blit(srcRT, tempRT, m_downsampleShader, 0);
               }
               RenderTexture.ReleaseTemporary(srcRT);
               srcRT = tempRT;
            }
            while (1 <= w || 1 <= h) {
                while (1 <= w || 1 <= h)
                {
               ++i;
               Graphics.SetRenderTarget(m_shadowTexture, i);
               GL.Clear(false, true, new Color(1,1,1,0));
@@ -1114,7 +1273,12 @@
      {
         float x = 1.0f - 1.0f/w;
         float y = 1.0f - 1.0f/h;
            if (m_eraseShadowShader != null)
            {
         m_eraseShadowShader.SetPass(0);
            }
         GL.Begin(GL.LINES);
         GL.Vertex3(-x,-y,0);
         GL.Vertex3( x,-y,0);