void DrawShadowSettings() { m_ShadowSettingsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_ShadowSettingsFoldout.value, Styles.shadowSettingsText); if (m_ShadowSettingsFoldout.value) { EditorGUI.indentLevel++; m_ShadowDistanceProp.floatValue = Mathf.Max(0.0f, EditorGUILayout.FloatField(Styles.shadowDistanceText, m_ShadowDistanceProp.floatValue)); EditorUtils.Unit unit = EditorUtils.Unit.Metric; if (m_ShadowCascadeCountProp.intValue != 0) { EditorGUI.BeginChangeCheck(); unit = (EditorUtils.Unit)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Working Unit", "Except Max Distance which will be still in meter."), m_State.value); if (EditorGUI.EndChangeCheck()) { m_State.value = unit; } } UniversalRenderPipelineAsset asset = target as UniversalRenderPipelineAsset; EditorGUILayout.IntSlider(m_ShadowCascadeCountProp, UniversalRenderPipelineAsset.k_ShadowCascadeMinCount, UniversalRenderPipelineAsset.k_ShadowCascadeMaxCount, Styles.shadowCascadesText); int cascadeCount = m_ShadowCascadeCountProp.intValue; EditorGUI.indentLevel++; if (cascadeCount == 4) { EditorUtils.DrawCascadeSplitGUI <Vector3>(ref m_ShadowCascade4SplitProp, m_ShadowDistanceProp.floatValue, cascadeCount, unit); } else if (cascadeCount == 3) { EditorUtils.DrawCascadeSplitGUI <Vector2>(ref m_ShadowCascade3SplitProp, m_ShadowDistanceProp.floatValue, cascadeCount, unit); } else if (cascadeCount == 2) { EditorUtils.DrawCascadeSplitGUI <float>(ref m_ShadowCascade2SplitProp, m_ShadowDistanceProp.floatValue, cascadeCount, unit); } else if (cascadeCount == 1) { EditorUtils.DrawCascadeSplitGUI <float>(ref m_ShadowCascade2SplitProp, m_ShadowDistanceProp.floatValue, cascadeCount, unit); } m_ShadowDepthBiasProp.floatValue = EditorGUILayout.Slider(Styles.shadowDepthBias, m_ShadowDepthBiasProp.floatValue, 0.0f, UniversalRenderPipeline.maxShadowBias); m_ShadowNormalBiasProp.floatValue = EditorGUILayout.Slider(Styles.shadowNormalBias, m_ShadowNormalBiasProp.floatValue, 0.0f, UniversalRenderPipeline.maxShadowBias); EditorGUILayout.PropertyField(m_SoftShadowsSupportedProp, Styles.supportsSoftShadows); EditorGUI.indentLevel--; EditorGUILayout.Space(); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); }
/** * Static function to handle the GUI and User input related to the cascade slider. * * @param normalizedCascadePartition The array of partition sizes in the range 0.0f - 1.0f; expects ONE entry if cascades = 2, and THREE if cascades=4 * The last entry will be automatically determined by summing up the array, and doing 1.0f - sum */ public static void HandleCascadeSliderGUI(ref float[] normalizedCascadePartitions, float distance, EditorUtils.Unit unit) { EditorGUI.indentLevel--; EditorGUILayout.BeginHorizontal(); GUILayout.Space(EditorGUI.indentLevel * 15f); // get the inspector width since we need it while drawing the partition rects. // Only way currently is to reserve the block in the layout using GetRect(), and then immediately drawing the empty box // to match the call to GetRect. // From this point on, we move to non-layout based code. var sliderRect = GUILayoutUtility.GetRect(GUIContent.none , s_CascadeSliderBG , GUILayout.Height(kSliderbarTopMargin + kSliderbarHeight + kSliderbarBottomMargin) , GUILayout.ExpandWidth(true)); GUI.Box(sliderRect, GUIContent.none); EditorGUILayout.EndHorizontal(); float currentX = sliderRect.x; float cascadeBoxStartY = sliderRect.y + kSliderbarTopMargin; float cascadeSliderWidth = sliderRect.width - (normalizedCascadePartitions.Length * kPartitionHandleWidth); Color origTextColor = GUI.color; Color origBackgroundColor = GUI.backgroundColor; int colorIndex = -1; // setup the array locally with the last partition float[] adjustedCascadePartitions = new float[normalizedCascadePartitions.Length + 1]; System.Array.Copy(normalizedCascadePartitions, adjustedCascadePartitions, normalizedCascadePartitions.Length); adjustedCascadePartitions[adjustedCascadePartitions.Length - 1] = 1.0f - normalizedCascadePartitions.Sum(); string cascadeText = ""; // check for user input on any of the partition handles // this mechanism gets the current event in the queue... make sure that the mouse is over our control before consuming the event int sliderControlId = GUIUtility.GetControlID(s_CascadeSliderId, FocusType.Passive); Event currentEvent = Event.current; int hotPartitionHandleIndex = -1; // the index of any partition handle that we are hovering over or dragging // draw each cascade partition for (int i = 0; i < adjustedCascadePartitions.Length; ++i) { float currentPartition = adjustedCascadePartitions[i]; colorIndex = (colorIndex + 1) % kCascadeColors.Length; GUI.backgroundColor = kCascadeColors[colorIndex]; float boxLength = (cascadeSliderWidth * currentPartition); // main cascade box Rect partitionRect = new Rect(currentX, cascadeBoxStartY, boxLength, kSliderbarHeight); GUI.Box(partitionRect, GUIContent.none, s_CascadeSliderBG); currentX += boxLength; // cascade box percentage text GUI.color = Color.white; Rect textRect = partitionRect; if (unit == EditorUtils.Unit.Percent) { cascadeText = $"{i+1}\n{currentPartition * 100.0f:F1}%"; } else { var m = currentPartition * distance; cascadeText = $"{i+1}\n{m:F1}m"; } GUI.Label(textRect, cascadeText, s_TextCenteredStyle); // no need to draw the partition handle for last box if (i == adjustedCascadePartitions.Length - 1) { break; } // partition handle GUI.backgroundColor = Color.black; Rect handleRect = partitionRect; handleRect.x = currentX; handleRect.width = kPartitionHandleWidth; GUI.Box(handleRect, GUIContent.none, s_CascadeSliderBG); // we want a thin handle visually (since wide black bar looks bad), but a slightly larger // hit area for easier manipulation Rect handleHitRect = handleRect; handleHitRect.xMin -= kPartitionHandleExtraHitAreaWidth; handleHitRect.xMax += kPartitionHandleExtraHitAreaWidth; if (handleHitRect.Contains(currentEvent.mousePosition)) { hotPartitionHandleIndex = i; } // add regions to slider where the cursor changes to Resize-Horizontal if (s_DragCache == null) { EditorGUIUtility.AddCursorRect(handleHitRect, MouseCursor.ResizeHorizontal, sliderControlId); } currentX += kPartitionHandleWidth; } GUI.color = origTextColor; GUI.backgroundColor = origBackgroundColor; EventType eventType = currentEvent.GetTypeForControl(sliderControlId); switch (eventType) { case EventType.MouseDown: if (hotPartitionHandleIndex >= 0) { s_DragCache = new DragCache(hotPartitionHandleIndex, normalizedCascadePartitions[hotPartitionHandleIndex], currentEvent.mousePosition); if (GUIUtility.hotControl == 0) { GUIUtility.hotControl = sliderControlId; } currentEvent.Use(); // Switch active scene view into shadow cascades visualization mode, once we start // tweaking cascade splits. if (s_RestoreSceneView == null) { s_RestoreSceneView = SceneView.lastActiveSceneView; if (s_RestoreSceneView != null) { s_OldSceneDrawMode = s_RestoreSceneView.cameraMode; #if UNITY_2019_1_OR_NEWER s_OldSceneLightingMode = s_RestoreSceneView.sceneLighting; #else s_OldSceneLightingMode = s_RestoreSceneView.m_SceneLighting; #endif } } } break; case EventType.MouseUp: // mouseUp event anywhere should release the hotcontrol (if it belongs to us), drags (if any) if (GUIUtility.hotControl == sliderControlId) { GUIUtility.hotControl = 0; currentEvent.Use(); } s_DragCache = null; // Restore previous scene view drawing mode once we stop tweaking cascade splits. if (s_RestoreSceneView != null) { s_RestoreSceneView.cameraMode = s_OldSceneDrawMode; #if UNITY_2019_1_OR_NEWER s_RestoreSceneView.sceneLighting = s_OldSceneLightingMode; #else s_RestoreSceneView.m_SceneLighting = s_OldSceneLightingMode; #endif s_RestoreSceneView = null; } break; case EventType.MouseDrag: if (GUIUtility.hotControl != sliderControlId) { break; } // convert the mouse movement to normalized cascade width. Make sure that we are safe to apply the delta before using it. float delta = (currentEvent.mousePosition - s_DragCache.m_LastCachedMousePosition).x / cascadeSliderWidth; bool isLeftPartitionHappy = ((adjustedCascadePartitions[s_DragCache.m_ActivePartition] + delta) > 0.0f); bool isRightPartitionHappy = ((adjustedCascadePartitions[s_DragCache.m_ActivePartition + 1] - delta) > 0.0f); if (isLeftPartitionHappy && isRightPartitionHappy) { s_DragCache.m_NormalizedPartitionSize += delta; normalizedCascadePartitions[s_DragCache.m_ActivePartition] = s_DragCache.m_NormalizedPartitionSize; if (s_DragCache.m_ActivePartition < normalizedCascadePartitions.Length - 1) { normalizedCascadePartitions[s_DragCache.m_ActivePartition + 1] -= delta; } GUI.changed = true; } s_DragCache.m_LastCachedMousePosition = currentEvent.mousePosition; currentEvent.Use(); break; } }