// // ShadowTextureRendererEditor.cs // // Dynamic Shadow Projector // // Copyright 2015 NYAHOON GAMES PTE. LTD. All Rights Reserved. // using UnityEngine; using UnityEditor; namespace DynamicShadowProjector.Editor { [CustomEditor(typeof(ShadowTextureRenderer))] public class ShadowTextureRendererEditor : EditorBase { static bool s_showAdvancedOptions = false; void OnEnable() { ShadowTextureRenderer shadowRenderer = target as ShadowTextureRenderer; bool modified = false; if (shadowRenderer.blurShader == null) { shadowRenderer.blurShader = FindMaterial("DynamicShadowProjector/Blit/Blur"); ClearMaterialProperties(shadowRenderer.blurShader); modified = true; } if (shadowRenderer.downsampleShader == null) { shadowRenderer.downsampleShader = FindMaterial("DynamicShadowProjector/Blit/Downsample"); ClearMaterialProperties(shadowRenderer.downsampleShader); modified = true; } if (shadowRenderer.copyMipmapShader == null) { shadowRenderer.copyMipmapShader = FindMaterial("DynamicShadowProjector/Blit/CopyMipmap"); ClearMaterialProperties(shadowRenderer.copyMipmapShader); modified = true; } if (shadowRenderer.eraseShadowShader == null) { shadowRenderer.eraseShadowShader = FindMaterial("DynamicShadowProjector/Blit/EraseShadow"); ClearMaterialProperties(shadowRenderer.eraseShadowShader); modified = true; } Projector projector = shadowRenderer.GetComponent(); if (projector.material != null) { RemoveUnusedMaterialProperties(projector.material); } if (modified) { EditorUtility.SetDirty(shadowRenderer); serializedObject.Update(); } } private SerializedObject m_cameraSerializedObject = null; private Camera m_camera; public override void OnInspectorGUI () { EditorGUILayout.BeginHorizontal(); GUILayout.Label("Online Document"); if (GUILayout.Button("http://nyahoon.com/products/dynamic-shadow-projector/shadow-texture-renderer-component", richTextStyle)) { Application.OpenURL("http://nyahoon.com/products/dynamic-shadow-projector/shadow-texture-renderer-component"); } EditorGUILayout.EndHorizontal(); bool isGUIEnabled = GUI.enabled; EditorGUILayout.PropertyField(serializedObject.FindProperty("m_shadowColor")); EditorGUILayout.IntPopup(serializedObject.FindProperty("m_textureWidth"), s_textureSizeDisplayOption, s_textureSizeOption); EditorGUILayout.IntPopup(serializedObject.FindProperty("m_textureHeight"), s_textureSizeDisplayOption, s_textureSizeOption); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_multiSampling")); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_superSampling")); SerializedProperty prop = serializedObject.FindProperty("m_blurLevel"); EditorGUILayout.IntPopup(prop, s_blurLevelDisplayOption, s_blurLevelOption); ++EditorGUI.indentLevel; GUI.enabled = isGUIEnabled && 0 < prop.intValue; ShadowTextureRenderer shadowRenderer = target as ShadowTextureRenderer; EditorGUILayout.Slider(serializedObject.FindProperty("m_blurSize"), 1.0f, shadowRenderer.blurFilter == ShadowTextureRenderer.BlurFilter.Uniform ? 6.0f : 4.0f); GUI.enabled = isGUIEnabled; --EditorGUI.indentLevel; prop = serializedObject.FindProperty("m_mipLevel"); EditorGUILayout.PropertyField(prop); ++EditorGUI.indentLevel; GUI.enabled = isGUIEnabled && 0 < prop.intValue; SerializedProperty fastBlur = serializedObject.FindProperty("m_singlePassMipmapBlur"); EditorGUILayout.PropertyField(fastBlur); float maxBlurSize; if (fastBlur.boolValue) { maxBlurSize = 1.0f; } else { maxBlurSize = shadowRenderer.blurFilter == ShadowTextureRenderer.BlurFilter.Uniform ? 3.0f : 2.0f; } EditorGUILayout.Slider(serializedObject.FindProperty("m_mipmapBlurSize"), 0.0f, maxBlurSize); if (shadowRenderer.GetComponent() == null) { EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add Fallback Component")) { Undo.AddComponent(shadowRenderer.gameObject); } EditorGUILayout.EndHorizontal(); GUI.enabled = isGUIEnabled; --EditorGUI.indentLevel; } else if (prop.intValue == 0) { GUI.enabled = isGUIEnabled; --EditorGUI.indentLevel; EditorGUILayout.BeginHorizontal(); GUILayout.TextArea("Still has Mipmap Fallback Component!", richTextStyle); if (GUILayout.Button("Remove the Component")) { Undo.DestroyObjectImmediate(shadowRenderer.GetComponent()); } EditorGUILayout.EndHorizontal(); } else { GUI.enabled = isGUIEnabled; --EditorGUI.indentLevel; } prop = serializedObject.FindProperty("m_testViewClip"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Don't update while out of view"); prop.boolValue = EditorGUILayout.Toggle(prop.boolValue); EditorGUILayout.EndHorizontal(); ++EditorGUI.indentLevel; GUI.enabled = isGUIEnabled && prop.boolValue; EditorGUILayout.PropertyField(serializedObject.FindProperty("m_camerasForViewClipTest"), true); GUI.enabled = isGUIEnabled; --EditorGUI.indentLevel; s_showAdvancedOptions = GUILayout.Toggle(s_showAdvancedOptions, "Show Advanced Options"); if (s_showAdvancedOptions) { ++EditorGUI.indentLevel; EditorGUILayout.PropertyField(serializedObject.FindProperty("m_blurFilter")); prop = serializedObject.FindProperty("m_mipmapFalloff"); EditorGUILayout.PropertyField(prop); if (prop.intValue == (int)ShadowTextureRenderer.MipmapFalloff.Custom) { prop = serializedObject.FindProperty("m_customMipmapFalloff"); if (shadowRenderer.customMipmapFalloff != null && shadowRenderer.customMipmapFalloff.Length != prop.arraySize) { serializedObject.Update(); prop = serializedObject.FindProperty("m_customMipmapFalloff"); } EditorGUILayout.PropertyField(prop, true); } float near = EditorGUILayout.FloatField("Near Clip Plane", shadowRenderer.cameraNearClipPlane); if (m_cameraSerializedObject == null) { m_camera = shadowRenderer.GetComponent(); m_cameraSerializedObject = new SerializedObject(shadowRenderer.GetComponent()); } if (near != shadowRenderer.cameraNearClipPlane) { Undo.RecordObject(m_camera, "Inspector"); shadowRenderer.cameraNearClipPlane = near; } bool bShowCamera = (m_camera.hideFlags & HideFlags.HideInInspector) == 0; bool newValue = EditorGUILayout.Toggle("Show Camera in Inspector", bShowCamera); if (bShowCamera != newValue) { if (newValue) { m_camera.hideFlags &= ~HideFlags.HideInInspector; } else { m_camera.hideFlags |= HideFlags.HideInInspector; } } EditorGUILayout.PropertyField(serializedObject.FindProperty("m_blurShader")); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_downsampleShader")); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_copyMipmapShader")); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_preferredTextureFormats"), true); --EditorGUI.indentLevel; } serializedObject.ApplyModifiedProperties(); } private Material m_blitMaterial; private Vector3 m_lastPosition; private Quaternion m_lastRotation; void OnSceneGUI() { ShadowTextureRenderer shadowRenderer = target as ShadowTextureRenderer; if (shadowRenderer.shadowTexture == null || shadowRenderer.GetComponent().material == null) { return; } if (m_lastPosition != shadowRenderer.transform.position || m_lastRotation != shadowRenderer.transform.rotation) { // This function call will have the following error on Unity 5.6.0: // Rendering camera 'XXXX', but calling code does not set it up as current camera (current camera: 'Main Camera') UnityEngine.Camera:Render() // But it seems like there are no way to avoid this error message. shadowRenderer.ForceRenderTexture(); m_lastPosition = shadowRenderer.transform.position; m_lastRotation = shadowRenderer.transform.rotation; } if (m_blitMaterial == null) { m_blitMaterial = FindMaterial("DynamicShadowProjector/Blit/Blit"); } int mipLevel = shadowRenderer.mipLevel + 1; int w = shadowRenderer.textureWidth; int h = shadowRenderer.textureHeight; for (int i = 1; i < mipLevel; ++i) { if ((w >> i) <= 4 || (h >> i) <=4) { mipLevel = i; break; } } int displayWidth = 128; float mipBias = Mathf.Log(displayWidth/w)/Mathf.Log(2.0f); int displayHeight = h*displayWidth/w; int marginSize = 4; int windowWidth = mipLevel * (displayWidth + marginSize) + marginSize; int windowHeight = displayHeight + 2*GUI.skin.window.border.bottom + marginSize; int windowPosX = Screen.width - windowWidth - 10; int windowPosY = Screen.height - windowHeight - GUI.skin.window.border.top - 10; GUI.WindowFunction func = id => { if (Event.current.type.Equals(EventType.Repaint)) { int x = marginSize; int y = GUI.skin.window.border.top; for (int i = 0; i < mipLevel; ++i) { m_blitMaterial.SetFloat("_MipLevel", i); m_blitMaterial.SetFloat("_MipBias", mipBias + i); Graphics.DrawTexture(new Rect(x, y, displayWidth, displayHeight), shadowRenderer.shadowTexture, m_blitMaterial); x += displayWidth + marginSize; } } }; GUI.Window(0, new Rect(windowPosX, windowPosY, windowWidth, windowHeight), func, "Shadow Texture"); } } }