bool ITerrainLayerCustomUI.OnTerrainLayerGUI(TerrainLayer terrainLayer, Terrain terrain) { var terrainLayers = terrain.terrainData.terrainLayers; if (!DoesTerrainUseMaskMaps(terrainLayers)) { return(false); } // Don't use the member field enableHeightBlend as ShaderGUI.OnGUI might not be called if the material UI is folded. bool heightBlend = terrain.materialTemplate.HasProperty(kEnableHeightBlend) && terrain.materialTemplate.GetFloat(kEnableHeightBlend) > 0; terrainLayer.diffuseTexture = EditorGUILayout.ObjectField(styles.diffuseTexture, terrainLayer.diffuseTexture, typeof(Texture2D), false) as Texture2D; TerrainLayerUtility.ValidateDiffuseTextureUI(terrainLayer.diffuseTexture); var diffuseRemapMin = terrainLayer.diffuseRemapMin; var diffuseRemapMax = terrainLayer.diffuseRemapMax; EditorGUI.BeginChangeCheck(); bool enableDensity = false; if (terrainLayer.diffuseTexture != null) { var rect = GUILayoutUtility.GetLastRect(); rect.y += 16 + 4; rect.width = EditorGUIUtility.labelWidth + 64; rect.height = 16; ++EditorGUI.indentLevel; var diffuseTint = new Color(diffuseRemapMax.x, diffuseRemapMax.y, diffuseRemapMax.z); diffuseTint = EditorGUI.ColorField(rect, styles.colorTint, diffuseTint, true, false, false); diffuseRemapMax.x = diffuseTint.r; diffuseRemapMax.y = diffuseTint.g; diffuseRemapMax.z = diffuseTint.b; diffuseRemapMin.x = diffuseRemapMin.y = diffuseRemapMin.z = 0; if (!heightBlend) { rect.y = rect.yMax + 2; enableDensity = EditorGUI.Toggle(rect, styles.opacityAsDensity, diffuseRemapMin.w > 0); } --EditorGUI.indentLevel; } diffuseRemapMax.w = 1; diffuseRemapMin.w = enableDensity ? 1 : 0; if (EditorGUI.EndChangeCheck()) { terrainLayer.diffuseRemapMin = diffuseRemapMin; terrainLayer.diffuseRemapMax = diffuseRemapMax; } terrainLayer.normalMapTexture = EditorGUILayout.ObjectField(styles.normalMapTexture, terrainLayer.normalMapTexture, typeof(Texture2D), false) as Texture2D; TerrainLayerUtility.ValidateNormalMapTextureUI(terrainLayer.normalMapTexture, TerrainLayerUtility.CheckNormalMapTextureType(terrainLayer.normalMapTexture)); if (terrainLayer.normalMapTexture != null) { var rect = GUILayoutUtility.GetLastRect(); rect.y += 16 + 4; rect.width = EditorGUIUtility.labelWidth + 64; rect.height = 16; ++EditorGUI.indentLevel; terrainLayer.normalScale = EditorGUI.FloatField(rect, styles.normalScale, terrainLayer.normalScale); --EditorGUI.indentLevel; } terrainLayer.maskMapTexture = EditorGUILayout.ObjectField(heightBlend ? styles.maskMapTexture : styles.maskMapTextureWithoutHeight, terrainLayer.maskMapTexture, typeof(Texture2D), false) as Texture2D; TerrainLayerUtility.ValidateMaskMapTextureUI(terrainLayer.maskMapTexture); var maskMapRemapMin = terrainLayer.maskMapRemapMin; var maskMapRemapMax = terrainLayer.maskMapRemapMax; ++EditorGUI.indentLevel; EditorGUI.BeginChangeCheck(); m_ShowChannelRemapping = EditorGUILayout.Foldout(m_ShowChannelRemapping, terrainLayer.maskMapTexture != null ? s_Styles.channelRemapping : s_Styles.defaultValues); if (m_ShowChannelRemapping) { if (terrainLayer.maskMapTexture != null) { float min, max; min = maskMapRemapMin.x; max = maskMapRemapMax.x; EditorGUILayout.MinMaxSlider(s_Styles.metallic, ref min, ref max, 0, 1); maskMapRemapMin.x = min; maskMapRemapMax.x = max; min = maskMapRemapMin.y; max = maskMapRemapMax.y; EditorGUILayout.MinMaxSlider(s_Styles.ao, ref min, ref max, 0, 1); maskMapRemapMin.y = min; maskMapRemapMax.y = max; if (heightBlend) { EditorGUILayout.LabelField(styles.height); ++EditorGUI.indentLevel; m_HeightParametrization = (HeightParametrization)EditorGUILayout.EnumPopup(styles.heightParametrization, m_HeightParametrization); if (m_HeightParametrization == HeightParametrization.Amplitude) { // (height - heightBase) * amplitude float amplitude = Mathf.Max(maskMapRemapMax.z - maskMapRemapMin.z, Mathf.Epsilon); // to avoid divide by zero float heightBase = -maskMapRemapMin.z / amplitude; amplitude = EditorGUILayout.FloatField(styles.heightAmplitude, amplitude * 100) / 100; heightBase = EditorGUILayout.FloatField(styles.heightBase, heightBase); maskMapRemapMin.z = -heightBase * amplitude; maskMapRemapMax.z = (1 - heightBase) * amplitude; } else { maskMapRemapMin.z = EditorGUILayout.FloatField(styles.heightMin, maskMapRemapMin.z * 100) / 100; maskMapRemapMax.z = EditorGUILayout.FloatField(styles.heightMax, maskMapRemapMax.z * 100) / 100; } --EditorGUI.indentLevel; } min = maskMapRemapMin.w; max = maskMapRemapMax.w; EditorGUILayout.MinMaxSlider(s_Styles.smoothness, ref min, ref max, 0, 1); maskMapRemapMin.w = min; maskMapRemapMax.w = max; } else { maskMapRemapMin.x = maskMapRemapMax.x = EditorGUILayout.Slider(s_Styles.metallic, maskMapRemapMin.x, 0, 1); maskMapRemapMin.y = maskMapRemapMax.y = EditorGUILayout.Slider(s_Styles.ao, maskMapRemapMin.y, 0, 1); if (heightBlend) { maskMapRemapMin.z = maskMapRemapMax.z = EditorGUILayout.FloatField(s_Styles.heightCm, maskMapRemapMin.z * 100) / 100; } maskMapRemapMin.w = maskMapRemapMax.w = EditorGUILayout.Slider(s_Styles.smoothness, maskMapRemapMin.w, 0, 1); } } if (EditorGUI.EndChangeCheck()) { terrainLayer.maskMapRemapMin = maskMapRemapMin; terrainLayer.maskMapRemapMax = maskMapRemapMax; } --EditorGUI.indentLevel; EditorGUILayout.Space(); TerrainLayerUtility.TilingSettingsUI(terrainLayer); return(true); }
bool ITerrainLayerCustomUI.OnTerrainLayerGUI(TerrainLayer terrainLayer, Terrain terrain) { var terrainLayers = terrain.terrainData.terrainLayers; // Don't use the member field enableHeightBlend as ShaderGUI.OnGUI might not be called if the material UI is folded. // heightblend shouldn't be available if we are in multi-pass mode, because it is guaranteed to be broken. bool heightBlendAvailable = (terrainLayers.Length <= 4); bool heightBlend = heightBlendAvailable && terrain.materialTemplate.HasProperty(kEnableHeightBlend) && (terrain.materialTemplate.GetFloat(kEnableHeightBlend) > 0); terrainLayer.diffuseTexture = EditorGUILayout.ObjectField(styles.diffuseTexture, terrainLayer.diffuseTexture, typeof(Texture2D), false) as Texture2D; TerrainLayerUtility.ValidateDiffuseTextureUI(terrainLayer.diffuseTexture); var diffuseRemapMin = terrainLayer.diffuseRemapMin; var diffuseRemapMax = terrainLayer.diffuseRemapMax; EditorGUI.BeginChangeCheck(); bool enableDensity = false; if (terrainLayer.diffuseTexture != null) { var rect = GUILayoutUtility.GetLastRect(); rect.y += 16 + 4; rect.width = EditorGUIUtility.labelWidth + 64; rect.height = 16; ++EditorGUI.indentLevel; var diffuseTint = new Color(diffuseRemapMax.x, diffuseRemapMax.y, diffuseRemapMax.z); diffuseTint = EditorGUI.ColorField(rect, styles.colorTint, diffuseTint, true, false, false); diffuseRemapMax.x = diffuseTint.r; diffuseRemapMax.y = diffuseTint.g; diffuseRemapMax.z = diffuseTint.b; diffuseRemapMin.x = diffuseRemapMin.y = diffuseRemapMin.z = 0; if (!heightBlend) { rect.y = rect.yMax + 2; enableDensity = EditorGUI.Toggle(rect, styles.opacityAsDensity, diffuseRemapMin.w > 0); } --EditorGUI.indentLevel; } diffuseRemapMax.w = 1; diffuseRemapMin.w = enableDensity ? 1 : 0; if (EditorGUI.EndChangeCheck()) { terrainLayer.diffuseRemapMin = diffuseRemapMin; terrainLayer.diffuseRemapMax = diffuseRemapMax; } // Display normal map UI terrainLayer.normalMapTexture = EditorGUILayout.ObjectField(styles.normalMapTexture, terrainLayer.normalMapTexture, typeof(Texture2D), false) as Texture2D; TerrainLayerUtility.ValidateNormalMapTextureUI(terrainLayer.normalMapTexture, TerrainLayerUtility.CheckNormalMapTextureType(terrainLayer.normalMapTexture)); if (terrainLayer.normalMapTexture != null) { var rect = GUILayoutUtility.GetLastRect(); rect.y += 16 + 4; rect.width = EditorGUIUtility.labelWidth + 64; rect.height = 16; ++EditorGUI.indentLevel; terrainLayer.normalScale = EditorGUI.FloatField(rect, styles.normalScale, terrainLayer.normalScale); --EditorGUI.indentLevel; } // Display the mask map UI and the remap controls terrainLayer.maskMapTexture = EditorGUILayout.ObjectField(heightBlend ? styles.maskMapTexture : styles.maskMapTextureWithoutHeight, terrainLayer.maskMapTexture, typeof(Texture2D), false) as Texture2D; TerrainLayerUtility.ValidateMaskMapTextureUI(terrainLayer.maskMapTexture); var maskMapRemapMin = terrainLayer.maskMapRemapMin; var maskMapRemapMax = terrainLayer.maskMapRemapMax; var smoothness = terrainLayer.smoothness; var metallic = terrainLayer.metallic; ++EditorGUI.indentLevel; EditorGUI.BeginChangeCheck(); m_ShowChannelRemapping = EditorGUILayout.Foldout(m_ShowChannelRemapping, terrainLayer.maskMapTexture != null ? s_Styles.channelRemapping : s_Styles.defaultValues); if (m_ShowChannelRemapping) { if (terrainLayer.maskMapTexture != null) { float min, max; min = maskMapRemapMin.x; max = maskMapRemapMax.x; EditorGUILayout.MinMaxSlider(s_Styles.metallic, ref min, ref max, 0, 1); maskMapRemapMin.x = min; maskMapRemapMax.x = max; min = maskMapRemapMin.y; max = maskMapRemapMax.y; EditorGUILayout.MinMaxSlider(s_Styles.ao, ref min, ref max, 0, 1); maskMapRemapMin.y = min; maskMapRemapMax.y = max; if (heightBlend) { EditorGUILayout.LabelField(styles.height); ++EditorGUI.indentLevel; m_HeightParametrization = (HeightParametrization)EditorGUILayout.EnumPopup(styles.heightParametrization, m_HeightParametrization); if (m_HeightParametrization == HeightParametrization.Amplitude) { // (height - heightBase) * amplitude float amplitude = Mathf.Max(maskMapRemapMax.z - maskMapRemapMin.z, Mathf.Epsilon); // to avoid divide by zero float heightBase = maskMapRemapMin.z / amplitude; amplitude = EditorGUILayout.FloatField(styles.heightAmplitude, amplitude * 100) / 100; heightBase = EditorGUILayout.FloatField(styles.heightBase, heightBase * 100) / 100; maskMapRemapMin.z = heightBase * amplitude; maskMapRemapMax.z = (1.0f - heightBase) * amplitude; } else { maskMapRemapMin.z = EditorGUILayout.FloatField(styles.heightMin, maskMapRemapMin.z * 100) / 100; maskMapRemapMax.z = EditorGUILayout.FloatField(styles.heightMax, maskMapRemapMax.z * 100) / 100; } --EditorGUI.indentLevel; } min = maskMapRemapMin.w; max = maskMapRemapMax.w; EditorGUILayout.MinMaxSlider(s_Styles.smoothness, ref min, ref max, 0, 1); maskMapRemapMin.w = min; maskMapRemapMax.w = max; } else { metallic = EditorGUILayout.Slider(s_Styles.metallic, metallic, 0, 1); // AO and Height are still exclusively controlled via the maskRemap controls // metallic and smoothness have their own values as fields within the LayerData. maskMapRemapMax.y = EditorGUILayout.Slider(s_Styles.ao, maskMapRemapMax.y, 0, 1); if (heightBlend) { maskMapRemapMax.z = EditorGUILayout.FloatField(s_Styles.heightCm, maskMapRemapMax.z * 100) / 100; } // There's a possibility that someone could slide max below the existing min value // so we'll just protect against that by locking the min value down a little bit. // In the case of height (Z), we are trying to set min to no lower than zero value unless // max goes negative. Zero is a good sensible value for the minimum. For AO (Y), we // don't need this extra protection step because the UI blocks us from going negative // anyway. In both cases, pushing the slider below the min value will lock them together, // but min will be "left behind" if you go back up. maskMapRemapMin.y = Mathf.Min(maskMapRemapMin.y, maskMapRemapMax.y); maskMapRemapMin.z = Mathf.Min(Mathf.Max(0, maskMapRemapMin.z), maskMapRemapMax.z); if (TextureHasAlpha(terrainLayer.diffuseTexture)) { GUIStyle warnStyle = new GUIStyle(GUI.skin.label); warnStyle.wordWrap = true; GUILayout.Label("Smoothness is controlled by diffuse alpha channel", warnStyle); } else { smoothness = EditorGUILayout.Slider(s_Styles.smoothness, smoothness, 0, 1); } } } if (EditorGUI.EndChangeCheck()) { terrainLayer.maskMapRemapMin = maskMapRemapMin; terrainLayer.maskMapRemapMax = maskMapRemapMax; terrainLayer.smoothness = smoothness; terrainLayer.metallic = metallic; } --EditorGUI.indentLevel; EditorGUILayout.Space(); TerrainLayerUtility.TilingSettingsUI(terrainLayer); return(true); }