public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { // grab m_MouseOnPatchIndex here to avoid calling again in OnRenderBrushPreview m_MouseOnPatchIndex = PaintDetailsToolUtility.ClampedDetailPatchesGUI(terrain, out var detailMinMaxHeight, out var clampedDetailPatchIconScreenPositions); PaintDetailsToolUtility.DrawClampedDetailPatchGUI(m_MouseOnPatchIndex, clampedDetailPatchIconScreenPositions, detailMinMaxHeight, terrain, editContext); }
public override void OnExitToolMode() { PaintDetailsToolUtility.ResetDetailsUtilityData(); if (m_TargetTerrain != null && m_TargetTerrain.terrainData != null) { var prototypes = m_TargetTerrain.terrainData.detailPrototypes; if (selectedDetail != kInvalidDetail && selectedDetail < m_TargetTerrain.terrainData.detailPrototypes.Length) { m_LastSelectedDetailPrototype = new DetailPrototype(prototypes[selectedDetail]); } } EditorPrefs.SetInt("TerrainSelectedDetail", selectedDetail); EditorPrefs.SetFloat("TerrainDetailStrength", detailStrength); EditorPrefs.SetFloat("TerrainDetailOpacity", detailOpacity); }
private void ShowDetailPrototypeMessages(DetailPrototype detailPrototype, Terrain terrain) { if (!DetailPrototype.IsModeSupportedByRenderPipeline(detailPrototype.renderMode, detailPrototype.useInstancing, out var msg) || !detailPrototype.Validate(out msg)) { EditorGUILayout.HelpBox(msg, MessageType.Error); } else if ((detailPrototype.renderMode != DetailRenderMode.VertexLit || !detailPrototype.useInstancing) && detailPrototype.usePrototypeMesh && detailPrototype.prototype != null && detailPrototype.prototype.TryGetComponent <MeshFilter>(out var meshFilter) && meshFilter.sharedMesh != null) { var maxVertCount = meshFilter.sharedMesh.vertexCount * PaintDetailsToolUtility.GetMaxDetailInstancesPerPatch(terrain.terrainData) * terrain.detailObjectDensity; if (maxVertCount >= 65536) { EditorGUILayout.HelpBox(s_Styles.detailVertexWarning.text, MessageType.Warning); } } }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { if (m_TargetTerrain == null || selectedDetail == kInvalidDetail || selectedDetail >= m_TargetTerrain.terrainData.detailPrototypes.Length) { return(false); } Texture2D brush = editContext.brushTexture as Texture2D; if (brush == null) { Debug.LogError("Brush texture is not a Texture2D."); return(false); } if (m_BrushRep == null) { m_BrushRep = new DetailBrushRepresentation(); } PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv); for (int t = 0; t < ctx.neighborTerrains.Length; ++t) { Terrain ctxTerrain = ctx.neighborTerrains[t]; if (ctxTerrain != null) { int detailPrototype = PaintDetailsToolUtility.FindDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail); if (detailPrototype == kInvalidDetail) { detailPrototype = PaintDetailsToolUtility.CopyDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail); } TerrainData terrainData = ctxTerrain.terrainData; TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrainData, "Terrain - Detail Edit"); int size = (int)Mathf.Max(1.0f, editContext.brushSize * ((float)terrainData.detailResolution / terrainData.size.x)); m_BrushRep.Update(brush, size); float targetStrength = m_DetailsStrength; if (Event.current.shift || Event.current.control) { targetStrength = -targetStrength; } DetailBrushBounds brushBounds = new DetailBrushBounds(terrainData, ctx, size, t); int[] layers = { detailPrototype }; if (targetStrength < 0.0F && !Event.current.control) { layers = terrainData.GetSupportedLayers(brushBounds.min, brushBounds.bounds.size); } for (int i = 0; i < layers.Length; i++) { int[,] alphamap = terrainData.GetDetailLayer(brushBounds.min, brushBounds.bounds.size, layers[i]); for (int y = 0; y < brushBounds.bounds.height; y++) { for (int x = 0; x < brushBounds.bounds.width; x++) { Vector2Int brushOffset = brushBounds.GetBrushOffset(x, y); float opa = detailOpacity * m_BrushRep.GetStrength(brushOffset.x, brushOffset.y); float targetValue = Mathf.Lerp(alphamap[y, x], targetStrength * terrainData.maxDetailScatterPerRes, opa); alphamap[y, x] = Mathf.Min(Mathf.RoundToInt(targetValue - .5f + Random.value), terrainData.maxDetailScatterPerRes); } } terrainData.SetDetailLayer(brushBounds.min, layers[i], alphamap); } } } return(false); }
public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext) { if (s_Styles == null) { s_Styles = new Styles(); } DetailPrototype[] prototypes = terrain.terrainData.detailPrototypes; var detailIcons = PaintDetailsToolUtility.LoadDetailIcons(prototypes); // Detail picker GUILayout.Label(s_Styles.details, EditorStyles.boldLabel); selectedDetail = TerrainInspector.AspectSelectionGridImageAndText(selectedDetail, prototypes.Length, (i, rect, style, controlID) => { bool renderModeSupported = DetailPrototype.IsModeSupportedByRenderPipeline(prototypes[i].renderMode, prototypes[i].useInstancing, out var errorMessage); bool mouseHover = rect.Contains(Event.current.mousePosition); if (Event.current.type == EventType.Repaint) { bool wasEnabled = GUI.enabled; GUI.enabled &= renderModeSupported; style.Draw(rect, detailIcons[i], GUI.enabled && mouseHover && (GUIUtility.hotControl == 0 || GUIUtility.hotControl == controlID), GUI.enabled && GUIUtility.hotControl == controlID, i == selectedDetail, false); GUI.enabled = wasEnabled; } if (!renderModeSupported) { var tmpContent = EditorGUIUtility.TempContent(EditorGUIUtility.GetHelpIcon(MessageType.Error)); tmpContent.tooltip = errorMessage; GUI.Label(new Rect(rect.xMax - 16, rect.yMin + 1, 19, 19), tmpContent); } if (mouseHover) { GUIUtility.mouseUsed = true; GUIStyle.SetMouseTooltip(detailIcons[i].tooltip, rect); } }, 64, s_Styles.noDetailObjectDefined, out var doubleClick); if (doubleClick) { TerrainDetailContextMenus.EditDetail(new MenuCommand(terrain, selectedDetail)); GUIUtility.ExitGUI(); } if (selectedDetail >= 0 && selectedDetail < prototypes.Length) { ShowDetailPrototypeMessages(prototypes[selectedDetail], terrain); } var terrainInspector = TerrainInspector.s_activeTerrainInspectorInstance; GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); TerrainInspector.MenuButton(s_Styles.editDetails, "CONTEXT/TerrainEngineDetails", terrain, selectedDetail); TerrainInspector.ShowRefreshPrototypes(); GUILayout.EndHorizontal(); if (prototypes.Length > 0) { ShowTextureFallbackWarning(ref terrain); } terrainInspector.ShowDetailStats(); EditorGUILayout.Space(); // Brush selector editContext.ShowBrushesGUI(0, BrushGUIEditFlags.Select, 0); // Brush size terrainInspector.brushSize = EditorGUILayout.PowerSlider(s_Styles.brushSize, Mathf.Clamp(terrainInspector.brushSize, 1, 100), 1, 100, 4); detailOpacity = EditorGUILayout.Slider(s_Styles.opacity, detailOpacity, 0, 1); // Strength detailStrength = EditorGUILayout.Slider(s_Styles.detailTargetStrength, detailStrength, 0, 1); // Brush editor editContext.ShowBrushesGUI((int)EditorGUIUtility.singleLineHeight, BrushGUIEditFlags.Inspect); }