| | |
| | | using UnityEngine.Rendering; |
| | | using System.Collections.Generic; |
| | | |
| | | namespace DynamicShadowProjector { |
| | | [ExecuteInEditMode] |
| | | [DisallowMultipleComponent] |
| | | [RequireComponent(typeof(Projector))] |
| | | public class ShadowTextureRenderer : MonoBehaviour { |
| | | public enum TextureMultiSample { |
| | | x1 = 1, |
| | | x2 = 2, |
| | | x4 = 4, |
| | | x8 = 8, |
| | | } |
| | | public enum TextureSuperSample { |
| | | x1 = 1, |
| | | x4 = 2, |
| | | x16 = 4, |
| | | } |
| | | public enum MipmapFalloff { |
| | | None = 0, |
| | | Linear, |
| | | Custom, |
| | | } |
| | | public enum BlurFilter { |
| | | Uniform = 0, |
| | | Gaussian, |
| | | } |
| | | // Serialize Fields |
| | | [SerializeField] |
| | | private TextureMultiSample m_multiSampling = TextureMultiSample.x4; |
| | | [SerializeField] |
| | | private TextureSuperSample m_superSampling = TextureSuperSample.x1; |
| | | [SerializeField] |
| | | private MipmapFalloff m_mipmapFalloff = MipmapFalloff.Linear; |
| | | [SerializeField] |
| | | private BlurFilter m_blurFilter = BlurFilter.Uniform; |
| | | [SerializeField] |
| | | private bool m_testViewClip = true; |
| | | [SerializeField] |
| | | private int m_textureWidth = 64; |
| | | [SerializeField] |
| | | private int m_textureHeight = 64; |
| | | [SerializeField] |
| | | private int m_mipLevel = 0; |
| | | [SerializeField] |
| | | private int m_blurLevel = 1; |
| | | [SerializeField] |
| | | private float m_blurSize = 3; |
| | | [SerializeField] |
| | | private float m_mipmapBlurSize = 0; |
| | | [SerializeField] |
| | | private bool m_singlePassMipmapBlur = false; |
| | | [SerializeField] |
| | | private Color m_shadowColor = new Color(0,0,0,1); |
| | | [SerializeField] |
| | | private Material m_blurShader; |
| | | [SerializeField] |
| | | private Material m_downsampleShader; |
| | | [SerializeField] |
| | | private Material m_copyMipmapShader; |
| | | [SerializeField] |
| | | private Material m_eraseShadowShader; |
| | | [SerializeField] |
| | | private float[] m_customMipmapFalloff; |
| | | [SerializeField] |
| | | private RenderTextureFormat[] m_preferredTextureFormats; |
| | | [SerializeField] |
| | | private Camera[] m_camerasForViewClipTest; |
| | | namespace DynamicShadowProjector |
| | | { |
| | | [ExecuteInEditMode] |
| | | [DisallowMultipleComponent] |
| | | [RequireComponent(typeof(Projector))] |
| | | public class ShadowTextureRenderer : MonoBehaviour |
| | | { |
| | | public enum TextureMultiSample |
| | | { |
| | | x1 = 1, |
| | | x2 = 2, |
| | | x4 = 4, |
| | | x8 = 8, |
| | | } |
| | | public enum TextureSuperSample |
| | | { |
| | | x1 = 1, |
| | | x4 = 2, |
| | | x16 = 4, |
| | | } |
| | | public enum MipmapFalloff |
| | | { |
| | | None = 0, |
| | | Linear, |
| | | Custom, |
| | | } |
| | | public enum BlurFilter |
| | | { |
| | | Uniform = 0, |
| | | Gaussian, |
| | | } |
| | | // Serialize Fields |
| | | [SerializeField] |
| | | private TextureMultiSample m_multiSampling = TextureMultiSample.x4; |
| | | [SerializeField] |
| | | private TextureSuperSample m_superSampling = TextureSuperSample.x1; |
| | | [SerializeField] |
| | | private MipmapFalloff m_mipmapFalloff = MipmapFalloff.Linear; |
| | | [SerializeField] |
| | | private BlurFilter m_blurFilter = BlurFilter.Uniform; |
| | | [SerializeField] |
| | | private bool m_testViewClip = true; |
| | | [SerializeField] |
| | | private int m_textureWidth = 64; |
| | | [SerializeField] |
| | | private int m_textureHeight = 64; |
| | | [SerializeField] |
| | | private int m_mipLevel = 0; |
| | | [SerializeField] |
| | | private int m_blurLevel = 1; |
| | | [SerializeField] |
| | | private float m_blurSize = 3; |
| | | [SerializeField] |
| | | private float m_mipmapBlurSize = 0; |
| | | [SerializeField] |
| | | private bool m_singlePassMipmapBlur = false; |
| | | [SerializeField] |
| | | private Color m_shadowColor = new Color(0, 0, 0, 1); |
| | | [SerializeField] |
| | | private Material m_blurShader; |
| | | [SerializeField] |
| | | private Material m_downsampleShader; |
| | | [SerializeField] |
| | | private Material m_copyMipmapShader; |
| | | [SerializeField] |
| | | private Material m_eraseShadowShader; |
| | | [SerializeField] |
| | | private float[] m_customMipmapFalloff; |
| | | [SerializeField] |
| | | private RenderTextureFormat[] m_preferredTextureFormats; |
| | | [SerializeField] |
| | | private Camera[] m_camerasForViewClipTest; |
| | | |
| | | // public properties |
| | | public TextureMultiSample multiSampling |
| | | { |
| | | get { return m_multiSampling; } |
| | | set { |
| | | if (m_multiSampling != value) { |
| | | m_multiSampling = value; |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | public TextureSuperSample superSampling |
| | | { |
| | | get { return m_superSampling; } |
| | | set { |
| | | if (m_superSampling != value) { |
| | | bool b = useIntermediateTexture; |
| | | m_superSampling = value; |
| | | if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | public int textureWidth |
| | | { |
| | | get { return m_textureWidth; } |
| | | set { |
| | | if (m_textureWidth != value) { |
| | | m_textureWidth = value; |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | public int textureHeight |
| | | { |
| | | get { return m_textureHeight; } |
| | | set { |
| | | if (m_textureHeight != value) { |
| | | m_textureHeight = value; |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | public int mipLevel |
| | | { |
| | | get { return m_mipLevel; } |
| | | set { |
| | | if (m_mipLevel != value) { |
| | | if (m_mipLevel == 0 || value == 0) { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | m_mipLevel = value; |
| | | } |
| | | } |
| | | } |
| | | public int blurLevel |
| | | { |
| | | get { return m_blurLevel; } |
| | | set |
| | | { |
| | | if (m_blurLevel != value) { |
| | | bool b = useIntermediateTexture; |
| | | m_blurLevel = value; |
| | | if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | public float blurSize |
| | | { |
| | | get { return m_blurSize; } |
| | | set { m_blurSize = value; } |
| | | } |
| | | public BlurFilter blurFilter |
| | | { |
| | | get { return m_blurFilter; } |
| | | set { m_blurFilter = value; } |
| | | } |
| | | public float mipmapBlurSize |
| | | { |
| | | get { return m_mipmapBlurSize; } |
| | | set |
| | | { |
| | | m_mipmapBlurSize = value; |
| | | } |
| | | } |
| | | public bool singlePassMipmapBlur { |
| | | get { return m_singlePassMipmapBlur; } |
| | | set { m_singlePassMipmapBlur = value; } |
| | | } |
| | | public MipmapFalloff mipmapFalloff |
| | | { |
| | | get { return m_mipmapFalloff; } |
| | | set |
| | | { |
| | | m_mipmapFalloff = value; |
| | | } |
| | | } |
| | | public float[] customMipmapFalloff |
| | | { |
| | | get { return m_customMipmapFalloff; } |
| | | set |
| | | { |
| | | m_customMipmapFalloff = value; |
| | | } |
| | | } |
| | | public Color shadowColor |
| | | { |
| | | get { return m_shadowColor; } |
| | | set { |
| | | if (m_shadowColor != value) { |
| | | bool b = useIntermediateTexture; |
| | | m_shadowColor = value; |
| | | if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | public Material blurShader |
| | | { |
| | | get { return m_blurShader; } |
| | | set |
| | | { |
| | | m_blurShader = value; |
| | | } |
| | | } |
| | | public Material downsampleShader |
| | | { |
| | | get { return m_downsampleShader; } |
| | | set { m_downsampleShader = value; } |
| | | } |
| | | public Material copyMipmapShader |
| | | { |
| | | get { return m_copyMipmapShader; } |
| | | set |
| | | { |
| | | m_copyMipmapShader = value; |
| | | } |
| | | } |
| | | public Material eraseShadowShader |
| | | { |
| | | get { return m_eraseShadowShader; } |
| | | set { m_eraseShadowShader = value; } |
| | | } |
| | | public RenderTexture shadowTexture |
| | | { |
| | | get { return m_shadowTexture; } |
| | | } |
| | | public bool testViewClip |
| | | { |
| | | get { return m_testViewClip; } |
| | | set { m_testViewClip = value; } |
| | | } |
| | | public Camera[] camerasForViewClipTest |
| | | { |
| | | get { return m_camerasForViewClipTest; } |
| | | set { m_camerasForViewClipTest = value; } |
| | | } |
| | | public float cameraNearClipPlane |
| | | { |
| | | get { |
| | | if (m_camera == null) { |
| | | Initialize(); |
| | | } |
| | | return m_camera.nearClipPlane; |
| | | } |
| | | set { |
| | | if (m_camera == null) { |
| | | Initialize(); |
| | | } |
| | | m_camera.nearClipPlane = value; |
| | | } |
| | | } |
| | | public LayerMask cameraCullingMask |
| | | { |
| | | get { |
| | | if (m_camera == null) { |
| | | Initialize(); |
| | | } |
| | | return m_camera.cullingMask; |
| | | } |
| | | set { |
| | | if (m_camera == null) { |
| | | Initialize(); |
| | | } |
| | | m_camera.cullingMask = value; |
| | | } |
| | | } |
| | | public void SetReplacementShader(Shader shader, string replacementTag) |
| | | { |
| | | if (m_camera == null) { |
| | | Initialize(); |
| | | } |
| | | if (shader != null) { |
| | | m_camera.SetReplacementShader(shader, replacementTag); |
| | | } |
| | | else { |
| | | m_camera.ResetReplacementShader(); |
| | | } |
| | | } |
| | | // public properties |
| | | public TextureMultiSample multiSampling |
| | | { |
| | | get { return m_multiSampling; } |
| | | set |
| | | { |
| | | if (m_multiSampling != value) |
| | | { |
| | | m_multiSampling = value; |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | public TextureSuperSample superSampling |
| | | { |
| | | get { return m_superSampling; } |
| | | set |
| | | { |
| | | if (m_superSampling != value) |
| | | { |
| | | bool b = useIntermediateTexture; |
| | | m_superSampling = value; |
| | | if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) |
| | | { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | public int textureWidth |
| | | { |
| | | get { return m_textureWidth; } |
| | | set |
| | | { |
| | | if (m_textureWidth != value) |
| | | { |
| | | m_textureWidth = value; |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | public int textureHeight |
| | | { |
| | | get { return m_textureHeight; } |
| | | set |
| | | { |
| | | if (m_textureHeight != value) |
| | | { |
| | | m_textureHeight = value; |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | public int mipLevel |
| | | { |
| | | get { return m_mipLevel; } |
| | | set |
| | | { |
| | | if (m_mipLevel != value) |
| | | { |
| | | if (m_mipLevel == 0 || value == 0) |
| | | { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | m_mipLevel = value; |
| | | } |
| | | } |
| | | } |
| | | public int blurLevel |
| | | { |
| | | get { return m_blurLevel; } |
| | | set |
| | | { |
| | | if (m_blurLevel != value) |
| | | { |
| | | bool b = useIntermediateTexture; |
| | | m_blurLevel = value; |
| | | if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) |
| | | { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | public float blurSize |
| | | { |
| | | get { return m_blurSize; } |
| | | set { m_blurSize = value; } |
| | | } |
| | | public BlurFilter blurFilter |
| | | { |
| | | get { return m_blurFilter; } |
| | | set { m_blurFilter = value; } |
| | | } |
| | | public float mipmapBlurSize |
| | | { |
| | | get { return m_mipmapBlurSize; } |
| | | set |
| | | { |
| | | m_mipmapBlurSize = value; |
| | | } |
| | | } |
| | | public bool singlePassMipmapBlur |
| | | { |
| | | get { return m_singlePassMipmapBlur; } |
| | | set { m_singlePassMipmapBlur = value; } |
| | | } |
| | | public MipmapFalloff mipmapFalloff |
| | | { |
| | | get { return m_mipmapFalloff; } |
| | | set |
| | | { |
| | | m_mipmapFalloff = value; |
| | | } |
| | | } |
| | | public float[] customMipmapFalloff |
| | | { |
| | | get { return m_customMipmapFalloff; } |
| | | set |
| | | { |
| | | m_customMipmapFalloff = value; |
| | | } |
| | | } |
| | | public Color shadowColor |
| | | { |
| | | get { return m_shadowColor; } |
| | | set |
| | | { |
| | | if (m_shadowColor != value) |
| | | { |
| | | bool b = useIntermediateTexture; |
| | | m_shadowColor = value; |
| | | if (b != useIntermediateTexture && m_multiSampling != TextureMultiSample.x1) |
| | | { |
| | | SetTexturePropertyDirty(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | public Material blurShader |
| | | { |
| | | get { return m_blurShader; } |
| | | set |
| | | { |
| | | m_blurShader = value; |
| | | } |
| | | } |
| | | public Material downsampleShader |
| | | { |
| | | get { return m_downsampleShader; } |
| | | set { m_downsampleShader = value; } |
| | | } |
| | | public Material copyMipmapShader |
| | | { |
| | | get { return m_copyMipmapShader; } |
| | | set |
| | | { |
| | | m_copyMipmapShader = value; |
| | | } |
| | | } |
| | | public Material eraseShadowShader |
| | | { |
| | | get { return m_eraseShadowShader; } |
| | | set { m_eraseShadowShader = value; } |
| | | } |
| | | public RenderTexture shadowTexture |
| | | { |
| | | get { return m_shadowTexture; } |
| | | } |
| | | public bool testViewClip |
| | | { |
| | | get { return m_testViewClip; } |
| | | set { m_testViewClip = value; } |
| | | } |
| | | public Camera[] camerasForViewClipTest |
| | | { |
| | | get { return m_camerasForViewClipTest; } |
| | | set { m_camerasForViewClipTest = value; } |
| | | } |
| | | public float cameraNearClipPlane |
| | | { |
| | | get |
| | | { |
| | | if (m_camera == null) |
| | | { |
| | | Initialize(); |
| | | } |
| | | return m_camera.nearClipPlane; |
| | | } |
| | | set |
| | | { |
| | | if (m_camera == null) |
| | | { |
| | | Initialize(); |
| | | } |
| | | m_camera.nearClipPlane = value; |
| | | } |
| | | } |
| | | public LayerMask cameraCullingMask |
| | | { |
| | | get |
| | | { |
| | | if (m_camera == null) |
| | | { |
| | | Initialize(); |
| | | } |
| | | return m_camera.cullingMask; |
| | | } |
| | | set |
| | | { |
| | | if (m_camera == null) |
| | | { |
| | | Initialize(); |
| | | } |
| | | m_camera.cullingMask = value; |
| | | } |
| | | } |
| | | public void SetReplacementShader(Shader shader, string replacementTag) |
| | | { |
| | | if (m_camera == null) |
| | | { |
| | | Initialize(); |
| | | } |
| | | if (shader != null) |
| | | { |
| | | m_camera.SetReplacementShader(shader, replacementTag); |
| | | } |
| | | else |
| | | { |
| | | m_camera.ResetReplacementShader(); |
| | | } |
| | | } |
| | | |
| | | private static int s_falloffParamID; |
| | | private static int s_blurOffsetHParamID; |
| | | private static int s_blurOffsetVParamID; |
| | | private static int s_blurWeightHParamID; |
| | | private static int s_blurWeightVParamID; |
| | | private static int s_downSampleBlurOffset0ParamID; |
| | | private static int s_downSampleBlurOffset1ParamID; |
| | | private static int s_downSampleBlurOffset2ParamID; |
| | | private static int s_downSampleBlurOffset3ParamID; |
| | | private static int s_downSampleBlurWeightParamID; |
| | | private Projector m_projector; |
| | | private Material m_projectorMaterial; |
| | | private CommandBuffer m_commandBuffer; |
| | | private RenderTexture m_shadowTexture; |
| | | [SerializeField][HideInInspector] |
| | | private Camera m_camera; |
| | | private bool m_isTexturePropertyChanged; |
| | | private bool m_isVisible = false; |
| | | private bool m_shadowTextureValid = false; |
| | | private static int s_falloffParamID; |
| | | private static int s_blurOffsetHParamID; |
| | | private static int s_blurOffsetVParamID; |
| | | private static int s_blurWeightHParamID; |
| | | private static int s_blurWeightVParamID; |
| | | private static int s_downSampleBlurOffset0ParamID; |
| | | private static int s_downSampleBlurOffset1ParamID; |
| | | private static int s_downSampleBlurOffset2ParamID; |
| | | private static int s_downSampleBlurOffset3ParamID; |
| | | private static int s_downSampleBlurWeightParamID; |
| | | private Projector m_projector; |
| | | private Material m_projectorMaterial; |
| | | private CommandBuffer m_commandBuffer; |
| | | private RenderTexture m_shadowTexture; |
| | | [SerializeField] |
| | | [HideInInspector] |
| | | private Camera m_camera; |
| | | private bool m_isTexturePropertyChanged; |
| | | private bool m_isVisible = false; |
| | | private bool m_shadowTextureValid = false; |
| | | |
| | | public bool isProjectorVisible |
| | | { |
| | | get { return m_isVisible; } |
| | | } |
| | | public bool isProjectorVisible |
| | | { |
| | | get { return m_isVisible; } |
| | | } |
| | | |
| | | // Call SetCommandBufferDirty or UpdateCommandBuffer when child objects are added/deleted/disabled/enabled. |
| | | public void SetTexturePropertyDirty() |
| | | { |
| | | m_isTexturePropertyChanged = true; |
| | | } |
| | | public void CreateRenderTexture() |
| | | { |
| | | 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)) { |
| | | textureFormat = format; |
| | | } |
| | | } |
| | | } |
| | | // create texture |
| | | 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) { |
| | | m_shadowTexture.antiAliasing = 1; |
| | | } |
| | | else { |
| | | m_shadowTexture.antiAliasing = (int)m_multiSampling; |
| | | } |
| | | if (0 < m_mipLevel) { |
| | | m_shadowTexture.useMipMap = true; |
| | | // Call SetCommandBufferDirty or UpdateCommandBuffer when child objects are added/deleted/disabled/enabled. |
| | | public void SetTexturePropertyDirty() |
| | | { |
| | | m_isTexturePropertyChanged = true; |
| | | } |
| | | public void CreateRenderTexture() |
| | | { |
| | | 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)) |
| | | { |
| | | textureFormat = format; |
| | | } |
| | | } |
| | | } |
| | | // create texture |
| | | 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) |
| | | { |
| | | m_shadowTexture.antiAliasing = 1; |
| | | } |
| | | else |
| | | { |
| | | m_shadowTexture.antiAliasing = (int)m_multiSampling; |
| | | } |
| | | if (0 < m_mipLevel) |
| | | { |
| | | m_shadowTexture.useMipMap = true; |
| | | #if UNITY_5_5_OR_NEWER |
| | | m_shadowTexture.autoGenerateMips = false; |
| | | m_shadowTexture.autoGenerateMips = false; |
| | | #else |
| | | m_shadowTexture.generateMips = false; |
| | | #endif |
| | | m_shadowTexture.mipMapBias = 0.0f; |
| | | m_shadowTexture.filterMode = FilterMode.Trilinear; |
| | | } |
| | | 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) { |
| | | m_projector.material.SetTexture("_ShadowTex", m_shadowTexture); |
| | | m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel); |
| | | } |
| | | if (m_camera != null) { |
| | | m_camera.targetTexture = m_shadowTexture; |
| | | } |
| | | m_isTexturePropertyChanged = false; |
| | | } |
| | | public void AddCommandBuffer(CommandBuffer commandBuffer) |
| | | { |
| | | m_camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer); // just in case |
| | | m_camera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer); |
| | | } |
| | | m_shadowTexture.mipMapBias = 0.0f; |
| | | m_shadowTexture.filterMode = FilterMode.Trilinear; |
| | | } |
| | | 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) |
| | | { |
| | | m_projector.material.SetTexture("_ShadowTex", m_shadowTexture); |
| | | m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel); |
| | | } |
| | | if (m_camera != null) |
| | | { |
| | | m_camera.targetTexture = m_shadowTexture; |
| | | } |
| | | m_isTexturePropertyChanged = false; |
| | | } |
| | | public void AddCommandBuffer(CommandBuffer commandBuffer) |
| | | { |
| | | m_camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer); // just in case |
| | | m_camera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer); |
| | | } |
| | | |
| | | public void RemoveCommandBuffer(CommandBuffer commandBuffer) |
| | | { |
| | | m_camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer); |
| | | } |
| | | public void RemoveCommandBuffer(CommandBuffer commandBuffer) |
| | | { |
| | | m_camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer); |
| | | } |
| | | |
| | | static void InitializeShaderPropertyIDs() |
| | | { |
| | | s_falloffParamID = Shader.PropertyToID("_Falloff"); |
| | | s_blurOffsetHParamID = Shader.PropertyToID("_OffsetH"); |
| | | s_blurOffsetVParamID = Shader.PropertyToID("_OffsetV"); |
| | | s_blurWeightHParamID = Shader.PropertyToID("_WeightH"); |
| | | s_blurWeightVParamID = Shader.PropertyToID("_WeightV"); |
| | | s_downSampleBlurOffset0ParamID = Shader.PropertyToID("_Offset0"); |
| | | s_downSampleBlurOffset1ParamID = Shader.PropertyToID("_Offset1"); |
| | | s_downSampleBlurOffset2ParamID = Shader.PropertyToID("_Offset2"); |
| | | s_downSampleBlurOffset3ParamID = Shader.PropertyToID("_Offset3"); |
| | | s_downSampleBlurWeightParamID = Shader.PropertyToID("_Weight"); |
| | | } |
| | | static void InitializeShaderPropertyIDs() |
| | | { |
| | | s_falloffParamID = Shader.PropertyToID("_Falloff"); |
| | | s_blurOffsetHParamID = Shader.PropertyToID("_OffsetH"); |
| | | s_blurOffsetVParamID = Shader.PropertyToID("_OffsetV"); |
| | | s_blurWeightHParamID = Shader.PropertyToID("_WeightH"); |
| | | s_blurWeightVParamID = Shader.PropertyToID("_WeightV"); |
| | | s_downSampleBlurOffset0ParamID = Shader.PropertyToID("_Offset0"); |
| | | s_downSampleBlurOffset1ParamID = Shader.PropertyToID("_Offset1"); |
| | | s_downSampleBlurOffset2ParamID = Shader.PropertyToID("_Offset2"); |
| | | s_downSampleBlurOffset3ParamID = Shader.PropertyToID("_Offset3"); |
| | | s_downSampleBlurWeightParamID = Shader.PropertyToID("_Weight"); |
| | | } |
| | | |
| | | bool useIntermediateTexture |
| | | { |
| | | get { |
| | | return m_superSampling != TextureSuperSample.x1 || 0 < m_blurLevel || HasShadowColor() || (0 < m_mipLevel && m_multiSampling != TextureMultiSample.x1); |
| | | } |
| | | } |
| | | bool Initialize() |
| | | { |
| | | m_isVisible = false; |
| | | if (IsInitialized()) { |
| | | return true; |
| | | } |
| | | m_isTexturePropertyChanged = true; |
| | | InitializeShaderPropertyIDs(); |
| | | m_projector = GetComponent<Projector>(); |
| | | CloneProjectorMaterialIfShared(); |
| | | if (m_camera == null) { |
| | | m_camera = gameObject.GetComponent<Camera>(); |
| | | if (m_camera == null) { |
| | | m_camera = gameObject.AddComponent<Camera>(); |
| | | } |
| | | m_camera.hideFlags = HideFlags.HideInInspector; |
| | | } |
| | | else { |
| | | m_camera.RemoveAllCommandBuffers(); |
| | | } |
| | | m_camera.depth = -100; |
| | | m_camera.cullingMask = 0; |
| | | m_camera.clearFlags = CameraClearFlags.Nothing; |
| | | m_camera.backgroundColor = new Color(1,1,1,0); |
| | | m_camera.useOcclusionCulling = false; |
| | | m_camera.renderingPath = RenderingPath.Forward; |
| | | m_camera.nearClipPlane = 0.01f; |
| | | bool useIntermediateTexture |
| | | { |
| | | get |
| | | { |
| | | return m_superSampling != TextureSuperSample.x1 || 0 < m_blurLevel || HasShadowColor() || (0 < m_mipLevel && m_multiSampling != TextureMultiSample.x1); |
| | | } |
| | | } |
| | | bool Initialize() |
| | | { |
| | | m_isVisible = false; |
| | | if (IsInitialized()) |
| | | { |
| | | return true; |
| | | } |
| | | m_isTexturePropertyChanged = true; |
| | | InitializeShaderPropertyIDs(); |
| | | m_projector = GetComponent<Projector>(); |
| | | CloneProjectorMaterialIfShared(); |
| | | if (m_camera == null) |
| | | { |
| | | m_camera = gameObject.GetComponent<Camera>(); |
| | | if (m_camera == null) |
| | | { |
| | | m_camera = gameObject.AddComponent<Camera>(); |
| | | } |
| | | m_camera.hideFlags = HideFlags.HideInInspector; |
| | | } |
| | | else |
| | | { |
| | | m_camera.RemoveAllCommandBuffers(); |
| | | } |
| | | m_camera.depth = -100; |
| | | m_camera.cullingMask = 0; |
| | | m_camera.clearFlags = CameraClearFlags.Nothing; |
| | | m_camera.backgroundColor = new Color(1, 1, 1, 0); |
| | | m_camera.useOcclusionCulling = false; |
| | | m_camera.renderingPath = RenderingPath.Forward; |
| | | m_camera.nearClipPlane = 0.01f; |
| | | #if UNITY_5_6_OR_NEWER |
| | | m_camera.forceIntoRenderTexture = true; |
| | | m_camera.forceIntoRenderTexture = true; |
| | | #endif |
| | | m_camera.enabled = true; |
| | | CreateRenderTexture(); |
| | | return true; |
| | | } |
| | | m_camera.enabled = true; |
| | | CreateRenderTexture(); |
| | | return true; |
| | | } |
| | | |
| | | bool IsInitialized() |
| | | { |
| | | return m_projector != null && m_camera != null; |
| | | } |
| | | bool IsInitialized() |
| | | { |
| | | return m_projector != null && m_camera != null; |
| | | } |
| | | |
| | | void Awake() |
| | | { |
| | | Initialize(); |
| | | } |
| | | void Awake() |
| | | { |
| | | Initialize(); |
| | | } |
| | | |
| | | void OnEnable() |
| | | { |
| | | if (m_camera != null) { |
| | | m_camera.enabled = true; |
| | | } |
| | | } |
| | | void OnEnable() |
| | | { |
| | | if (m_camera != null) |
| | | { |
| | | m_camera.enabled = true; |
| | | } |
| | | } |
| | | |
| | | void OnDisable() |
| | | { |
| | | if (m_camera != null) { |
| | | m_camera.enabled = false; |
| | | } |
| | | } |
| | | void OnDisable() |
| | | { |
| | | if (m_camera != null) |
| | | { |
| | | m_camera.enabled = false; |
| | | } |
| | | } |
| | | |
| | | void Start() |
| | | { |
| | | void Start() |
| | | { |
| | | #if UNITY_EDITOR |
| | | if (m_testViewClip && Application.isPlaying) |
| | | if (m_testViewClip && Application.isPlaying) |
| | | #else |
| | | if (m_testViewClip) |
| | | #endif |
| | | { |
| | | if (m_camerasForViewClipTest == null || m_camerasForViewClipTest.Length == 0) { |
| | | if (Camera.main != null) { |
| | | m_camerasForViewClipTest = new Camera[1] {Camera.main}; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | { |
| | | if (m_camerasForViewClipTest == null || m_camerasForViewClipTest.Length == 0) |
| | | { |
| | | if (Camera.main != null) |
| | | { |
| | | m_camerasForViewClipTest = new Camera[1] { Camera.main }; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void OnValidate() |
| | | { |
| | | CreateRenderTexture(); |
| | | InitializeShaderPropertyIDs(); |
| | | // check custom mipmap falloff |
| | | 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) { |
| | | m_customMipmapFalloff[i] = ((float)(m_mipLevel - i))/(float)(m_mipLevel + 1); |
| | | } |
| | | } |
| | | else if (m_mipLevel != m_customMipmapFalloff.Length) { |
| | | float[] customFalloff = new float[m_mipLevel]; |
| | | 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; |
| | | float v0 = (j == 0 ? 1.0f : m_customMipmapFalloff[j - 1]); |
| | | float v1 = (j < m_customMipmapFalloff.Length) ? m_customMipmapFalloff[j] : 0.0f; |
| | | customFalloff[i] = Mathf.Lerp(v0, v1, w); |
| | | } |
| | | m_customMipmapFalloff = customFalloff; |
| | | } |
| | | } |
| | | } |
| | | private static HashSet<Material> s_sharedMaterials; |
| | | const HideFlags CLONED_MATERIAL_HIDE_FLAGS = HideFlags.HideAndDontSave; |
| | | void CloneProjectorMaterialIfShared() |
| | | { |
| | | void OnValidate() |
| | | { |
| | | CreateRenderTexture(); |
| | | InitializeShaderPropertyIDs(); |
| | | // check custom mipmap falloff |
| | | 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) |
| | | { |
| | | m_customMipmapFalloff[i] = ((float)(m_mipLevel - i)) / (float)(m_mipLevel + 1); |
| | | } |
| | | } |
| | | else if (m_mipLevel != m_customMipmapFalloff.Length) |
| | | { |
| | | float[] customFalloff = new float[m_mipLevel]; |
| | | 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; |
| | | float v0 = (j == 0 ? 1.0f : m_customMipmapFalloff[j - 1]); |
| | | float v1 = (j < m_customMipmapFalloff.Length) ? m_customMipmapFalloff[j] : 0.0f; |
| | | customFalloff[i] = Mathf.Lerp(v0, v1, w); |
| | | } |
| | | m_customMipmapFalloff = customFalloff; |
| | | } |
| | | } |
| | | } |
| | | private static HashSet<Material> s_sharedMaterials; |
| | | const HideFlags CLONED_MATERIAL_HIDE_FLAGS = HideFlags.HideAndDontSave; |
| | | void CloneProjectorMaterialIfShared() |
| | | { |
| | | #if UNITY_EDITOR |
| | | if (!Application.isPlaying) { |
| | | return; |
| | | } |
| | | if (!Application.isPlaying) |
| | | { |
| | | return; |
| | | } |
| | | #endif |
| | | 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) { |
| | | DestroyImmediate(m_projectorMaterial); |
| | | } |
| | | if (s_sharedMaterials == null) { |
| | | s_sharedMaterials = new HashSet<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 { |
| | | s_sharedMaterials.Add(m_projector.material); |
| | | } |
| | | m_projectorMaterial = m_projector.material; |
| | | } |
| | | 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) |
| | | { |
| | | DestroyImmediate(m_projectorMaterial); |
| | | } |
| | | if (s_sharedMaterials == null) |
| | | { |
| | | s_sharedMaterials = new HashSet<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 |
| | | { |
| | | s_sharedMaterials.Add(m_projector.material); |
| | | } |
| | | m_projectorMaterial = m_projector.material; |
| | | } |
| | | |
| | | void OnDestroy() |
| | | { |
| | | 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) { |
| | | m_projector.material = null; |
| | | } |
| | | DestroyImmediate(m_projectorMaterial); |
| | | } |
| | | } |
| | | if (m_shadowTexture != null) { |
| | | if (m_camera != null) { |
| | | m_camera.targetTexture = null; |
| | | } |
| | | DestroyImmediate(m_shadowTexture); |
| | | m_shadowTexture = null; |
| | | } |
| | | if (m_camera != null) { |
| | | m_camera.RemoveAllCommandBuffers(); |
| | | } |
| | | m_isVisible = false; |
| | | } |
| | | void OnDestroy() |
| | | { |
| | | 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) |
| | | { |
| | | m_projector.material = null; |
| | | } |
| | | DestroyImmediate(m_projectorMaterial); |
| | | } |
| | | } |
| | | if (m_shadowTexture != null) |
| | | { |
| | | if (m_camera != null) |
| | | { |
| | | m_camera.targetTexture = null; |
| | | } |
| | | DestroyImmediate(m_shadowTexture); |
| | | m_shadowTexture = null; |
| | | } |
| | | if (m_camera != null) |
| | | { |
| | | m_camera.RemoveAllCommandBuffers(); |
| | | } |
| | | m_isVisible = false; |
| | | } |
| | | |
| | | bool IsReadyToExecute() |
| | | { |
| | | if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_eraseShadowShader == null) { |
| | | return false; |
| | | } |
| | | 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) { |
| | | return false; |
| | | } |
| | | } |
| | | if (0 < m_mipLevel && (m_copyMipmapShader == null || m_downsampleShader == null)) { |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | bool IsReadyToExecute() |
| | | { |
| | | if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_eraseShadowShader == null) |
| | | { |
| | | return false; |
| | | } |
| | | 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) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | if (0 < m_mipLevel && (m_copyMipmapShader == null || m_downsampleShader == null)) |
| | | { |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | void SetVisible(bool isVisible) |
| | | { |
| | | m_isVisible = isVisible; |
| | | SendMessage("OnVisibilityChanged", isVisible); |
| | | } |
| | | void SetVisible(bool isVisible) |
| | | { |
| | | m_isVisible = isVisible; |
| | | SendMessage("OnVisibilityChanged", isVisible); |
| | | } |
| | | |
| | | #if UNITY_EDITOR |
| | | private bool m_isRenderingFromUpdate = false; |
| | | public void ForceRenderTexture() |
| | | { |
| | | m_isRenderingFromUpdate = true; |
| | | // it is necessary to set camera parameters before Render, because render events will not be invoked if the volume of the view frustum is zero, |
| | | // and there is no chance to fix the camera parameters in OnPreCull function. |
| | | m_camera.orthographic = m_projector.orthographic; |
| | | m_camera.orthographicSize = m_projector.orthographicSize; |
| | | m_camera.fieldOfView = m_projector.fieldOfView; |
| | | m_camera.aspect = m_projector.aspectRatio; |
| | | m_camera.farClipPlane = m_projector.farClipPlane; |
| | | private bool m_isRenderingFromUpdate = false; |
| | | public void ForceRenderTexture() |
| | | { |
| | | m_isRenderingFromUpdate = true; |
| | | // it is necessary to set camera parameters before Render, because render events will not be invoked if the volume of the view frustum is zero, |
| | | // and there is no chance to fix the camera parameters in OnPreCull function. |
| | | m_camera.orthographic = m_projector.orthographic; |
| | | m_camera.orthographicSize = m_projector.orthographicSize; |
| | | m_camera.fieldOfView = m_projector.fieldOfView; |
| | | m_camera.aspect = m_projector.aspectRatio; |
| | | m_camera.farClipPlane = m_projector.farClipPlane; |
| | | #if UNITY_5_6 |
| | | // 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. |
| | | m_camera.targetTexture = null; |
| | | // 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. |
| | | m_camera.targetTexture = null; |
| | | #endif |
| | | m_camera.Render(); |
| | | m_isRenderingFromUpdate = false; |
| | | } |
| | | m_camera.Render(); |
| | | m_isRenderingFromUpdate = false; |
| | | } |
| | | #endif |
| | | void Update() |
| | | { |
| | | void Update() |
| | | { |
| | | #if UNITY_EDITOR |
| | | if (!Application.isPlaying |
| | | && (!m_shadowTextureValid |
| | | || m_camera.orthographic != m_projector.orthographic |
| | | || m_camera.orthographicSize != m_projector.orthographicSize |
| | | || m_camera.fieldOfView != m_projector.fieldOfView |
| | | || m_camera.aspect != m_projector.aspectRatio |
| | | || m_camera.farClipPlane != m_projector.farClipPlane) |
| | | ) { |
| | | ForceRenderTexture(); |
| | | } |
| | | if (!Application.isPlaying |
| | | && (!m_shadowTextureValid |
| | | || m_camera.orthographic != m_projector.orthographic |
| | | || m_camera.orthographicSize != m_projector.orthographicSize |
| | | || 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) { |
| | | m_camera.enabled = true; |
| | | } |
| | | } |
| | | if (m_camera != null && !m_camera.enabled) |
| | | { |
| | | m_camera.enabled = true; |
| | | } |
| | | } |
| | | |
| | | void OnPreCull() |
| | | { |
| | | if (m_projector.material != m_projectorMaterial) { |
| | | // projector material changed. |
| | | CloneProjectorMaterialIfShared(); |
| | | m_projector.material.SetTexture("_ShadowTex", m_shadowTexture); |
| | | m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel); |
| | | } |
| | | void OnPreCull() |
| | | { |
| | | 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)) { |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | if (!IsReadyToExecute()) { |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | if (!IsInitialized() && !Initialize()) { |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | if (m_projector.material == null) { |
| | | if (m_isVisible) { |
| | | SetVisible(false); |
| | | } |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | m_projector.material.SetTexture("_ShadowTex", m_shadowTexture); |
| | | m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel); |
| | | if (!(Application.isPlaying || m_isRenderingFromUpdate)) |
| | | { |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | if (!IsReadyToExecute()) |
| | | { |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | if (!IsInitialized() && !Initialize()) |
| | | { |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | if (m_projector.material == null) |
| | | { |
| | | if (m_isVisible) |
| | | { |
| | | SetVisible(false); |
| | | } |
| | | m_camera.enabled = false; |
| | | return; |
| | | } |
| | | m_projector.material.SetTexture("_ShadowTex", m_shadowTexture); |
| | | m_projector.material.SetFloat("_DSPMipLevel", m_mipLevel); |
| | | #endif |
| | | if (m_isTexturePropertyChanged) { |
| | | CreateRenderTexture(); |
| | | } |
| | | m_camera.orthographic = m_projector.orthographic; |
| | | m_camera.orthographicSize = m_projector.orthographicSize; |
| | | m_camera.fieldOfView = m_projector.fieldOfView; |
| | | m_camera.aspect = m_projector.aspectRatio; |
| | | m_camera.farClipPlane = m_projector.farClipPlane; |
| | | // view clip test |
| | | bool isVisible = true; |
| | | if (!m_projector.enabled) { |
| | | isVisible = false; |
| | | } |
| | | if (m_isTexturePropertyChanged) |
| | | { |
| | | CreateRenderTexture(); |
| | | } |
| | | m_camera.orthographic = m_projector.orthographic; |
| | | m_camera.orthographicSize = m_projector.orthographicSize; |
| | | m_camera.fieldOfView = m_projector.fieldOfView; |
| | | m_camera.aspect = m_projector.aspectRatio; |
| | | m_camera.farClipPlane = m_projector.farClipPlane; |
| | | // view clip test |
| | | bool isVisible = true; |
| | | if (!m_projector.enabled) |
| | | { |
| | | isVisible = false; |
| | | } |
| | | #if UNITY_EDITOR |
| | | else if (m_testViewClip && Application.isPlaying) |
| | | else if (m_testViewClip && Application.isPlaying) |
| | | #else |
| | | else if (m_testViewClip) |
| | | #endif |
| | | { |
| | | 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) { |
| | | 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)); |
| | | Vector3 v3 = m_camera.ViewportToWorldPoint(new Vector3(1,1,m_camera.nearClipPlane)); |
| | | Vector3 v4 = m_camera.ViewportToWorldPoint(new Vector3(0,0,m_camera.farClipPlane)); |
| | | Vector3 v5 = m_camera.ViewportToWorldPoint(new Vector3(1,0,m_camera.farClipPlane)); |
| | | 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) { |
| | | Camera cam = m_camerasForViewClipTest[i]; |
| | | Vector3 min = cam.WorldToViewportPoint(v0); |
| | | if (min.z < 0.0f) { min.x = -min.x; min.y = -min.y; } |
| | | Vector3 max = min; |
| | | Vector3 v = cam.WorldToViewportPoint(v1); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v2); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v3); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v4); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v5); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v6); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v7); |
| | | 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) { |
| | | isVisible = true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if (isVisible != m_isVisible) { |
| | | SetVisible(isVisible); |
| | | } |
| | | if (!isVisible) { |
| | | if (m_camera != null) { |
| | | m_camera.enabled = false; |
| | | } |
| | | if (m_shadowTexture != null && !m_shadowTextureValid) { |
| | | RenderTexture currentRT = RenderTexture.active; |
| | | RenderTexture.active = m_shadowTexture; |
| | | GL.Clear(false, true, new Color(1,1,1,0)); |
| | | m_shadowTextureValid = true; |
| | | RenderTexture.active = currentRT; |
| | | } |
| | | } |
| | | } |
| | | { |
| | | 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) |
| | | { |
| | | 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)); |
| | | Vector3 v3 = m_camera.ViewportToWorldPoint(new Vector3(1, 1, m_camera.nearClipPlane)); |
| | | Vector3 v4 = m_camera.ViewportToWorldPoint(new Vector3(0, 0, m_camera.farClipPlane)); |
| | | Vector3 v5 = m_camera.ViewportToWorldPoint(new Vector3(1, 0, m_camera.farClipPlane)); |
| | | 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) |
| | | { |
| | | Camera cam = m_camerasForViewClipTest[i]; |
| | | Vector3 min = cam.WorldToViewportPoint(v0); |
| | | if (min.z < 0.0f) { min.x = -min.x; min.y = -min.y; } |
| | | Vector3 max = min; |
| | | Vector3 v = cam.WorldToViewportPoint(v1); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v2); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v3); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v4); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v5); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v6); |
| | | 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); |
| | | v = cam.WorldToViewportPoint(v7); |
| | | 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) |
| | | { |
| | | isVisible = true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if (isVisible != m_isVisible) |
| | | { |
| | | SetVisible(isVisible); |
| | | } |
| | | if (!isVisible) |
| | | { |
| | | if (m_camera != null) |
| | | { |
| | | m_camera.enabled = false; |
| | | } |
| | | if (m_shadowTexture != null && !m_shadowTextureValid) |
| | | { |
| | | RenderTexture currentRT = RenderTexture.active; |
| | | RenderTexture.active = m_shadowTexture; |
| | | GL.Clear(false, true, new Color(1, 1, 1, 0)); |
| | | m_shadowTextureValid = true; |
| | | RenderTexture.active = currentRT; |
| | | } |
| | | } |
| | | } |
| | | |
| | | bool HasShadowColor() |
| | | { |
| | | return m_shadowColor.a != 1 || (m_shadowColor.r + shadowColor.g + shadowColor.b) != 0; |
| | | } |
| | | bool HasShadowColor() |
| | | { |
| | | return m_shadowColor.a != 1 || (m_shadowColor.r + shadowColor.g + shadowColor.b) != 0; |
| | | } |
| | | |
| | | void OnPreRender() |
| | | { |
| | | void OnPreRender() |
| | | { |
| | | #if UNITY_EDITOR |
| | | if (!(Application.isPlaying || m_isRenderingFromUpdate)) { |
| | | return; |
| | | } |
| | | if (!(Application.isPlaying || m_isRenderingFromUpdate)) |
| | | { |
| | | return; |
| | | } |
| | | #endif |
| | | if (!m_isVisible) { |
| | | return; |
| | | } |
| | | m_shadowTexture.DiscardContents(); |
| | | 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 { |
| | | 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 { |
| | | public int tap; |
| | | public Vector4 offset; |
| | | public Vector4 weight; |
| | | }; |
| | | static BlurParam GetBlurParam(float blurSize, BlurFilter filter) |
| | | { |
| | | BlurParam param = new BlurParam(); |
| | | if (!m_isVisible) |
| | | { |
| | | return; |
| | | } |
| | | m_shadowTexture.DiscardContents(); |
| | | 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 |
| | | { |
| | | 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 |
| | | { |
| | | public int tap; |
| | | public Vector4 offset; |
| | | public Vector4 weight; |
| | | }; |
| | | static BlurParam GetBlurParam(float blurSize, BlurFilter filter) |
| | | { |
| | | BlurParam param = new BlurParam(); |
| | | |
| | | if (blurSize < 0.1f) { |
| | | param.tap = 3; |
| | | param.offset.x = 0.0f; |
| | | param.offset.y = 0.0f; |
| | | param.offset.z = 0.0f; |
| | | param.offset.w = 0.0f; |
| | | param.weight.x = 1.0f; |
| | | param.weight.y = 0.0f; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | return param; |
| | | } |
| | | // calculate weights |
| | | 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) { |
| | | 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) { |
| | | s_blurWeights[i] *= w; |
| | | } |
| | | } |
| | | else { |
| | | // uniform filter |
| | | float a = 0.5f/(0.5f + blurSize); |
| | | for (int i = 0; i < s_blurWeights.Length; ++i) { |
| | | if (i <= blurSize) { |
| | | s_blurWeights[i] = a; |
| | | } |
| | | else if (i - 1 < blurSize) { |
| | | s_blurWeights[i] = a * (blurSize - (i - 1)); |
| | | } |
| | | else { |
| | | s_blurWeights[i] = 0.0f; |
| | | } |
| | | } |
| | | } |
| | | param.offset.x = 1.0f + s_blurWeights[2]/(s_blurWeights[1] + s_blurWeights[2]); |
| | | param.offset.y = 3.0f + s_blurWeights[4]/(s_blurWeights[3] + s_blurWeights[4]); |
| | | param.offset.z = 5.0f + s_blurWeights[6]/(s_blurWeights[5] + s_blurWeights[6]); |
| | | param.offset.w = 0.0f; |
| | | if (blurSize < 0.1f) |
| | | { |
| | | param.tap = 3; |
| | | param.offset.x = 0.0f; |
| | | param.offset.y = 0.0f; |
| | | param.offset.z = 0.0f; |
| | | param.offset.w = 0.0f; |
| | | param.weight.x = 1.0f; |
| | | param.weight.y = 0.0f; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | return param; |
| | | } |
| | | // calculate weights |
| | | 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) |
| | | { |
| | | 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) |
| | | { |
| | | s_blurWeights[i] *= w; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // uniform filter |
| | | float a = 0.5f / (0.5f + blurSize); |
| | | for (int i = 0; i < s_blurWeights.Length; ++i) |
| | | { |
| | | if (i <= blurSize) |
| | | { |
| | | s_blurWeights[i] = a; |
| | | } |
| | | else if (i - 1 < blurSize) |
| | | { |
| | | s_blurWeights[i] = a * (blurSize - (i - 1)); |
| | | } |
| | | else |
| | | { |
| | | s_blurWeights[i] = 0.0f; |
| | | } |
| | | } |
| | | } |
| | | param.offset.x = 1.0f + s_blurWeights[2] / (s_blurWeights[1] + s_blurWeights[2]); |
| | | param.offset.y = 3.0f + s_blurWeights[4] / (s_blurWeights[3] + s_blurWeights[4]); |
| | | 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) { |
| | | 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; |
| | | param.weight.y = 0.5f - 0.5f*param.weight.x; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | } |
| | | 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; |
| | | param.weight.y = Mathf.Round(255*a*(s_blurWeights[1] + s_blurWeights[2]))/255.0f; |
| | | param.weight.z = 0.5f - (0.5f*param.weight.x + param.weight.y); |
| | | param.weight.w = 0.0f; |
| | | } |
| | | 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; |
| | | param.weight.z = Mathf.Round(255*(s_blurWeights[3] + s_blurWeights[4]))/255.0f; |
| | | param.weight.w = 0.5f - (0.5f*param.weight.x + param.weight.y + param.weight.z); |
| | | } |
| | | return param; |
| | | } |
| | | static BlurParam GetDownsampleBlurParam(float blurSize, BlurFilter filter) |
| | | { |
| | | BlurParam param = new BlurParam(); |
| | | param.tap = 4; |
| | | if (blurSize < 0.1f) { |
| | | param.offset.x = 0.0f; |
| | | param.offset.y = 0.0f; |
| | | param.offset.z = 0.0f; |
| | | param.offset.w = 0.0f; |
| | | param.weight.x = 1.0f; |
| | | param.weight.y = 0.0f; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | return param; |
| | | } |
| | | // calculate weights |
| | | 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) { |
| | | 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) { |
| | | s_blurWeights[i] *= w; |
| | | } |
| | | } |
| | | else { |
| | | // uniform filter |
| | | float a = 0.5f/blurSize; |
| | | for (int i = 0; i < param.tap; ++i) { |
| | | if (i + 1 <= blurSize) { |
| | | s_blurWeights[i] = a; |
| | | } |
| | | else if (i < blurSize) { |
| | | s_blurWeights[i] = a * (blurSize - i); |
| | | } |
| | | else { |
| | | s_blurWeights[i] = 0.0f; |
| | | } |
| | | } |
| | | } |
| | | param.offset.x = 0.5f + s_blurWeights[1]/(s_blurWeights[0] + s_blurWeights[1]); |
| | | param.offset.y = 2.5f + s_blurWeights[3]/(s_blurWeights[2] + s_blurWeights[3]); |
| | | param.offset.z = 0.0f; |
| | | param.offset.w = 0.0f; |
| | | |
| | | param.weight.x = s_blurWeights[0] + s_blurWeights[1]; |
| | | param.weight.y = s_blurWeights[2] + s_blurWeights[3]; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | 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; |
| | | param.weight.y = 0.5f - 0.5f * param.weight.x; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | } |
| | | 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; |
| | | param.weight.y = Mathf.Round(255 * a * (s_blurWeights[1] + s_blurWeights[2])) / 255.0f; |
| | | param.weight.z = 0.5f - (0.5f * param.weight.x + param.weight.y); |
| | | param.weight.w = 0.0f; |
| | | } |
| | | 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; |
| | | param.weight.z = Mathf.Round(255 * (s_blurWeights[3] + s_blurWeights[4])) / 255.0f; |
| | | param.weight.w = 0.5f - (0.5f * param.weight.x + param.weight.y + param.weight.z); |
| | | } |
| | | return param; |
| | | } |
| | | static BlurParam GetDownsampleBlurParam(float blurSize, BlurFilter filter) |
| | | { |
| | | BlurParam param = new BlurParam(); |
| | | param.tap = 4; |
| | | if (blurSize < 0.1f) |
| | | { |
| | | param.offset.x = 0.0f; |
| | | param.offset.y = 0.0f; |
| | | param.offset.z = 0.0f; |
| | | param.offset.w = 0.0f; |
| | | param.weight.x = 1.0f; |
| | | param.weight.y = 0.0f; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | return param; |
| | | } |
| | | // calculate weights |
| | | 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) |
| | | { |
| | | 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) |
| | | { |
| | | s_blurWeights[i] *= w; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // uniform filter |
| | | float a = 0.5f / blurSize; |
| | | for (int i = 0; i < param.tap; ++i) |
| | | { |
| | | if (i + 1 <= blurSize) |
| | | { |
| | | s_blurWeights[i] = a; |
| | | } |
| | | else if (i < blurSize) |
| | | { |
| | | s_blurWeights[i] = a * (blurSize - i); |
| | | } |
| | | else |
| | | { |
| | | s_blurWeights[i] = 0.0f; |
| | | } |
| | | } |
| | | } |
| | | param.offset.x = 0.5f + s_blurWeights[1] / (s_blurWeights[0] + s_blurWeights[1]); |
| | | param.offset.y = 2.5f + s_blurWeights[3] / (s_blurWeights[2] + s_blurWeights[3]); |
| | | param.offset.z = 0.0f; |
| | | param.offset.w = 0.0f; |
| | | |
| | | return param; |
| | | } |
| | | void OnPostRender() |
| | | { |
| | | param.weight.x = s_blurWeights[0] + s_blurWeights[1]; |
| | | param.weight.y = s_blurWeights[2] + s_blurWeights[3]; |
| | | param.weight.z = 0.0f; |
| | | param.weight.w = 0.0f; |
| | | |
| | | return param; |
| | | } |
| | | void OnPostRender() |
| | | { |
| | | #if UNITY_EDITOR |
| | | if (!(Application.isPlaying || m_isRenderingFromUpdate)) { |
| | | return; |
| | | } |
| | | if (!(Application.isPlaying || m_isRenderingFromUpdate)) |
| | | { |
| | | return; |
| | | } |
| | | #endif |
| | | m_camera.clearFlags = CameraClearFlags.Nothing; |
| | | if (!m_isVisible) { |
| | | return; |
| | | } |
| | | RenderTexture srcRT = m_camera.targetTexture; |
| | | m_camera.clearFlags = CameraClearFlags.Nothing; |
| | | if (!m_isVisible) |
| | | { |
| | | return; |
| | | } |
| | | RenderTexture srcRT = m_camera.targetTexture; |
| | | #if UNITY_5_6 |
| | | // 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) { |
| | | m_camera.targetTexture = null; |
| | | } |
| | | // 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) |
| | | { |
| | | m_camera.targetTexture = null; |
| | | } |
| | | #else |
| | | m_camera.targetTexture = m_shadowTexture; |
| | | #endif |
| | | if (m_superSampling != TextureSuperSample.x1 || HasShadowColor()) { |
| | | m_downsampleShader.color = m_shadowColor; |
| | | // downsample |
| | | RenderTexture dstRT; |
| | | if (0 < m_blurLevel) { |
| | | dstRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | dstRT.filterMode = FilterMode.Bilinear; |
| | | } |
| | | else { |
| | | dstRT = m_shadowTexture; |
| | | } |
| | | Graphics.SetRenderTarget(dstRT); |
| | | int pass = m_superSampling == TextureSuperSample.x16 ? 0 : 2; |
| | | Graphics.Blit(srcRT, dstRT, m_downsampleShader, HasShadowColor() ? pass + 1 : pass); |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = dstRT; |
| | | } |
| | | 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) { |
| | | blurSizeV *= texelAspect; |
| | | } |
| | | else { |
| | | blurSizeH /= texelAspect; |
| | | } |
| | | // blur parameters |
| | | BlurParam blurH = GetBlurParam(blurSizeH, m_blurFilter); |
| | | BlurParam blurV = GetBlurParam(blurSizeV, m_blurFilter); |
| | | blurH.tap = (blurH.tap - 3); // index of pass |
| | | blurV.tap = (blurV.tap - 3) + 1; // index of pass |
| | | m_blurShader.SetVector(s_blurOffsetHParamID, blurH.offset); |
| | | m_blurShader.SetVector(s_blurOffsetVParamID, blurV.offset); |
| | | m_blurShader.SetVector(s_blurWeightHParamID, blurH.weight); |
| | | m_blurShader.SetVector(s_blurWeightVParamID, blurV.weight); |
| | | if (m_superSampling != TextureSuperSample.x1 || HasShadowColor()) |
| | | { |
| | | m_downsampleShader.color = m_shadowColor; |
| | | // downsample |
| | | RenderTexture dstRT; |
| | | if (0 < m_blurLevel) |
| | | { |
| | | dstRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | dstRT.filterMode = FilterMode.Bilinear; |
| | | } |
| | | else |
| | | { |
| | | dstRT = m_shadowTexture; |
| | | } |
| | | Graphics.SetRenderTarget(dstRT); |
| | | int pass = m_superSampling == TextureSuperSample.x16 ? 0 : 2; |
| | | Graphics.Blit(srcRT, dstRT, m_downsampleShader, HasShadowColor() ? pass + 1 : pass); |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = dstRT; |
| | | } |
| | | 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) |
| | | { |
| | | blurSizeV *= texelAspect; |
| | | } |
| | | else |
| | | { |
| | | blurSizeH /= texelAspect; |
| | | } |
| | | // blur parameters |
| | | BlurParam blurH = GetBlurParam(blurSizeH, m_blurFilter); |
| | | BlurParam blurV = GetBlurParam(blurSizeV, m_blurFilter); |
| | | blurH.tap = (blurH.tap - 3); // index of pass |
| | | blurV.tap = (blurV.tap - 3) + 1; // index of pass |
| | | m_blurShader.SetVector(s_blurOffsetHParamID, blurH.offset); |
| | | m_blurShader.SetVector(s_blurOffsetVParamID, blurV.offset); |
| | | m_blurShader.SetVector(s_blurWeightHParamID, blurH.weight); |
| | | m_blurShader.SetVector(s_blurWeightVParamID, blurV.weight); |
| | | |
| | | RenderTexture dstRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | dstRT.filterMode = FilterMode.Bilinear; |
| | | srcRT.wrapMode = TextureWrapMode.Clamp; |
| | | dstRT.wrapMode = TextureWrapMode.Clamp; |
| | | Graphics.Blit(srcRT, dstRT, m_blurShader, blurH.tap); |
| | | if (1 < srcRT.antiAliasing) { |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | } |
| | | else { |
| | | srcRT.DiscardContents(); |
| | | } |
| | | 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); |
| | | srcRT.DiscardContents(); |
| | | } |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = m_shadowTexture; |
| | | Graphics.Blit(dstRT, srcRT, m_blurShader, blurV.tap); |
| | | RenderTexture.ReleaseTemporary(dstRT); |
| | | } |
| | | Graphics.SetRenderTarget(m_shadowTexture); |
| | | if (srcRT != m_shadowTexture) { |
| | | Graphics.Blit(srcRT, m_downsampleShader, 2); |
| | | if (m_mipLevel == 0) { |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | } |
| | | } |
| | | EraseShadowOnBoarder(m_textureWidth, m_textureHeight); |
| | | if (0 < m_mipLevel) { |
| | | // setup blur parameters |
| | | BlurParam blurH = new BlurParam(), blurV = new BlurParam(); |
| | | 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) { |
| | | blurSizeV *= texelAspect; |
| | | } |
| | | else { |
| | | blurSizeH /= texelAspect; |
| | | } |
| | | // blur parameters |
| | | 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); |
| | | float a = 0.25f/(weight.x + weight.y + weight.z + weight.w); |
| | | weight.x = Mathf.Round(255*a*weight.x)/255.0f; |
| | | weight.y = Mathf.Round(255*a*weight.y)/255.0f; |
| | | weight.z = Mathf.Round(255*a*weight.z)/255.0f; |
| | | weight.w = 0.25f - weight.x - weight.y - weight.z; |
| | | m_downsampleShader.SetVector(s_downSampleBlurWeightParamID, weight); |
| | | } |
| | | else { |
| | | blurH = GetBlurParam(blurSizeH, m_blurFilter); |
| | | blurV = GetBlurParam(blurSizeV, m_blurFilter); |
| | | blurH.tap = (blurH.tap - 3); // index of pass |
| | | blurV.tap = (blurV.tap - 3) + 1; // index of pass |
| | | m_blurShader.SetVector(s_blurOffsetHParamID, blurH.offset); |
| | | m_blurShader.SetVector(s_blurOffsetVParamID, blurV.offset); |
| | | m_blurShader.SetVector(s_blurWeightHParamID, blurH.weight); |
| | | m_blurShader.SetVector(s_blurWeightVParamID, blurV.weight); |
| | | } |
| | | } |
| | | int w = m_textureWidth >> 1; |
| | | int h = m_textureHeight >> 1; |
| | | 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) { |
| | | SetDownsampleBlurOffsetParams(blurH, blurV, w, h); |
| | | } |
| | | if (srcRT == m_shadowTexture) { |
| | | if (downSampleWithBlur) { |
| | | Graphics.Blit(srcRT, tempRT, m_downsampleShader, 5); |
| | | } |
| | | else { |
| | | Graphics.Blit(srcRT, tempRT, m_copyMipmapShader, 1); |
| | | } |
| | | } |
| | | 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) { |
| | | tempRT = RenderTexture.GetTemporary(w, h, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | tempRT.filterMode = FilterMode.Bilinear; |
| | | tempRT.wrapMode = TextureWrapMode.Clamp; |
| | | srcRT.wrapMode = TextureWrapMode.Clamp; |
| | | Graphics.Blit(srcRT, tempRT, m_blurShader, blurH.tap); |
| | | srcRT.DiscardContents(); |
| | | Graphics.Blit(tempRT, srcRT, m_blurShader, blurV.tap); |
| | | RenderTexture.ReleaseTemporary(tempRT); |
| | | } |
| | | 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) { |
| | | falloff = m_customMipmapFalloff[Mathf.Min(i, m_customMipmapFalloff.Length-1)]; |
| | | } |
| | | m_copyMipmapShader.SetFloat(s_falloffParamID, falloff); |
| | | m_copyMipmapShader.SetFloat(s_falloffParamID, falloff); |
| | | m_shadowTexture.DiscardContents(); // To avoid Tiled GPU perf warning. It just tells GPU not to copy back the rendered image to a tile buffer. It won't destroy the rendered image. |
| | | ++i; |
| | | Graphics.SetRenderTarget(m_shadowTexture, i); |
| | | Graphics.Blit(srcRT, m_copyMipmapShader, 0); |
| | | EraseShadowOnBoarder(w, h); |
| | | w = Mathf.Max(1, w >> 1); |
| | | h = Mathf.Max(1, h >> 1); |
| | | 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) { |
| | | SetDownsampleBlurOffsetParams(blurH, blurV, w, h); |
| | | Graphics.Blit(srcRT, tempRT, m_downsampleShader, 4); |
| | | } |
| | | else { |
| | | Graphics.Blit(srcRT, tempRT, m_downsampleShader, 0); |
| | | } |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = tempRT; |
| | | } |
| | | while (1 <= w || 1 <= h) { |
| | | ++i; |
| | | Graphics.SetRenderTarget(m_shadowTexture, i); |
| | | GL.Clear(false, true, new Color(1,1,1,0)); |
| | | w = w >> 1; |
| | | h = h >> 1; |
| | | } |
| | | } |
| | | m_shadowTextureValid = true; |
| | | } |
| | | void EraseShadowOnBoarder(int w, int h) |
| | | { |
| | | float x = 1.0f - 1.0f/w; |
| | | float y = 1.0f - 1.0f/h; |
| | | m_eraseShadowShader.SetPass(0); |
| | | GL.Begin(GL.LINES); |
| | | GL.Vertex3(-x,-y,0); |
| | | GL.Vertex3( x,-y,0); |
| | | GL.Vertex3( x,-y,0); |
| | | GL.Vertex3( x, y,0); |
| | | GL.Vertex3( x, y,0); |
| | | GL.Vertex3(-x, y,0); |
| | | GL.Vertex3(-x, y,0); |
| | | GL.Vertex3(-x,-y,0); |
| | | GL.End(); |
| | | } |
| | | void SetDownsampleBlurOffsetParams(BlurParam blurH, BlurParam blurV, int w, int h) |
| | | { |
| | | float invW = 0.5f/w; |
| | | float invH = 0.5f/h; |
| | | float offsetX0 = invW * blurH.offset.x; |
| | | float offsetX1 = invW * blurH.offset.y; |
| | | float offsetY0 = invH * blurV.offset.x; |
| | | float offsetY1 = invH * blurV.offset.y; |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset0ParamID, new Vector4(offsetX0, offsetY0, -offsetX0, -offsetY0)); |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset1ParamID, new Vector4(offsetX0, offsetY1, -offsetX0, -offsetY1)); |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset2ParamID, new Vector4(offsetX1, offsetY0, -offsetX1, -offsetY0)); |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset3ParamID, new Vector4(offsetX1, offsetY1, -offsetX1, -offsetY1)); |
| | | } |
| | | } |
| | | RenderTexture dstRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | dstRT.filterMode = FilterMode.Bilinear; |
| | | srcRT.wrapMode = TextureWrapMode.Clamp; |
| | | dstRT.wrapMode = TextureWrapMode.Clamp; |
| | | Graphics.Blit(srcRT, dstRT, m_blurShader, blurH.tap); |
| | | if (1 < srcRT.antiAliasing) |
| | | { |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = RenderTexture.GetTemporary(m_textureWidth, m_textureHeight, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | } |
| | | else |
| | | { |
| | | srcRT.DiscardContents(); |
| | | } |
| | | 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); |
| | | srcRT.DiscardContents(); |
| | | } |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = m_shadowTexture; |
| | | Graphics.Blit(dstRT, srcRT, m_blurShader, blurV.tap); |
| | | RenderTexture.ReleaseTemporary(dstRT); |
| | | } |
| | | Graphics.SetRenderTarget(m_shadowTexture); |
| | | if (srcRT != m_shadowTexture) |
| | | { |
| | | Graphics.Blit(srcRT, m_downsampleShader, 2); |
| | | if (m_mipLevel == 0) |
| | | { |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | } |
| | | } |
| | | EraseShadowOnBoarder(m_textureWidth, m_textureHeight); |
| | | if (0 < m_mipLevel) |
| | | { |
| | | // setup blur parameters |
| | | BlurParam blurH = new BlurParam(), blurV = new BlurParam(); |
| | | 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) |
| | | { |
| | | blurSizeV *= texelAspect; |
| | | } |
| | | else |
| | | { |
| | | blurSizeH /= texelAspect; |
| | | } |
| | | // blur parameters |
| | | 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); |
| | | float a = 0.25f / (weight.x + weight.y + weight.z + weight.w); |
| | | weight.x = Mathf.Round(255 * a * weight.x) / 255.0f; |
| | | weight.y = Mathf.Round(255 * a * weight.y) / 255.0f; |
| | | weight.z = Mathf.Round(255 * a * weight.z) / 255.0f; |
| | | weight.w = 0.25f - weight.x - weight.y - weight.z; |
| | | m_downsampleShader.SetVector(s_downSampleBlurWeightParamID, weight); |
| | | } |
| | | else |
| | | { |
| | | blurH = GetBlurParam(blurSizeH, m_blurFilter); |
| | | blurV = GetBlurParam(blurSizeV, m_blurFilter); |
| | | blurH.tap = (blurH.tap - 3); // index of pass |
| | | blurV.tap = (blurV.tap - 3) + 1; // index of pass |
| | | m_blurShader.SetVector(s_blurOffsetHParamID, blurH.offset); |
| | | m_blurShader.SetVector(s_blurOffsetVParamID, blurV.offset); |
| | | m_blurShader.SetVector(s_blurWeightHParamID, blurH.weight); |
| | | m_blurShader.SetVector(s_blurWeightVParamID, blurV.weight); |
| | | } |
| | | } |
| | | int w = m_textureWidth >> 1; |
| | | int h = m_textureHeight >> 1; |
| | | 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) |
| | | { |
| | | SetDownsampleBlurOffsetParams(blurH, blurV, w, h); |
| | | } |
| | | if (srcRT == m_shadowTexture) |
| | | { |
| | | if (downSampleWithBlur) |
| | | { |
| | | Graphics.Blit(srcRT, tempRT, m_downsampleShader, 5); |
| | | } |
| | | else |
| | | { |
| | | Graphics.Blit(srcRT, tempRT, m_copyMipmapShader, 1); |
| | | } |
| | | } |
| | | 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) |
| | | { |
| | | tempRT = RenderTexture.GetTemporary(w, h, 0, m_shadowTexture.format, RenderTextureReadWrite.Linear); |
| | | tempRT.filterMode = FilterMode.Bilinear; |
| | | tempRT.wrapMode = TextureWrapMode.Clamp; |
| | | srcRT.wrapMode = TextureWrapMode.Clamp; |
| | | Graphics.Blit(srcRT, tempRT, m_blurShader, blurH.tap); |
| | | srcRT.DiscardContents(); |
| | | Graphics.Blit(tempRT, srcRT, m_blurShader, blurV.tap); |
| | | RenderTexture.ReleaseTemporary(tempRT); |
| | | } |
| | | 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) |
| | | { |
| | | falloff = m_customMipmapFalloff[Mathf.Min(i, m_customMipmapFalloff.Length - 1)]; |
| | | } |
| | | m_copyMipmapShader.SetFloat(s_falloffParamID, falloff); |
| | | m_copyMipmapShader.SetFloat(s_falloffParamID, falloff); |
| | | m_shadowTexture.DiscardContents(); // To avoid Tiled GPU perf warning. It just tells GPU not to copy back the rendered image to a tile buffer. It won't destroy the rendered image. |
| | | ++i; |
| | | Graphics.SetRenderTarget(m_shadowTexture, i); |
| | | Graphics.Blit(srcRT, m_copyMipmapShader, 0); |
| | | EraseShadowOnBoarder(w, h); |
| | | w = Mathf.Max(1, w >> 1); |
| | | h = Mathf.Max(1, h >> 1); |
| | | 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) |
| | | { |
| | | SetDownsampleBlurOffsetParams(blurH, blurV, w, h); |
| | | Graphics.Blit(srcRT, tempRT, m_downsampleShader, 4); |
| | | } |
| | | else |
| | | { |
| | | Graphics.Blit(srcRT, tempRT, m_downsampleShader, 0); |
| | | } |
| | | RenderTexture.ReleaseTemporary(srcRT); |
| | | srcRT = tempRT; |
| | | } |
| | | while (1 <= w || 1 <= h) |
| | | { |
| | | ++i; |
| | | Graphics.SetRenderTarget(m_shadowTexture, i); |
| | | GL.Clear(false, true, new Color(1, 1, 1, 0)); |
| | | w = w >> 1; |
| | | h = h >> 1; |
| | | } |
| | | } |
| | | m_shadowTextureValid = true; |
| | | } |
| | | void EraseShadowOnBoarder(int w, int h) |
| | | { |
| | | 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); |
| | | GL.Vertex3(x, -y, 0); |
| | | GL.Vertex3(x, y, 0); |
| | | GL.Vertex3(x, y, 0); |
| | | GL.Vertex3(-x, y, 0); |
| | | GL.Vertex3(-x, y, 0); |
| | | GL.Vertex3(-x, -y, 0); |
| | | GL.End(); |
| | | } |
| | | void SetDownsampleBlurOffsetParams(BlurParam blurH, BlurParam blurV, int w, int h) |
| | | { |
| | | float invW = 0.5f / w; |
| | | float invH = 0.5f / h; |
| | | float offsetX0 = invW * blurH.offset.x; |
| | | float offsetX1 = invW * blurH.offset.y; |
| | | float offsetY0 = invH * blurV.offset.x; |
| | | float offsetY1 = invH * blurV.offset.y; |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset0ParamID, new Vector4(offsetX0, offsetY0, -offsetX0, -offsetY0)); |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset1ParamID, new Vector4(offsetX0, offsetY1, -offsetX0, -offsetY1)); |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset2ParamID, new Vector4(offsetX1, offsetY0, -offsetX1, -offsetY0)); |
| | | m_downsampleShader.SetVector(s_downSampleBlurOffset3ParamID, new Vector4(offsetX1, offsetY1, -offsetX1, -offsetY1)); |
| | | } |
| | | } |
| | | } |