private void DrawBrushPreviews(Terrain terrain, IOnSceneGUI editContext) { Vector2 sampleUV; BrushTransform sampleXform; PaintContext sampleContext = null; Material previewMat = TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial(); // draw sample location brush and create context data to be used when drawing target brush previews if (m_SampleLocation.terrain != null) { sampleUV = TerrainUVFromBrushLocation(m_SampleLocation.terrain, m_SampleLocation.pos); sampleXform = TerrainPaintUtility.CalculateBrushTransform(m_SampleLocation.terrain, sampleUV, commonUI.brushSize, commonUI.brushRotation); sampleContext = TerrainPaintUtility.BeginPaintHeightmap(m_SampleLocation.terrain, sampleXform.GetBrushXYBounds()); TerrainPaintUtilityEditor.DrawBrushPreview(sampleContext, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, editContext.brushTexture, sampleXform, previewMat, 0); } // draw brush preview and mesh preview for current mouse position if (commonUI.isRaycastHitUnderCursorValid) { BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, commonUI.raycastHitUnderCursor.textureCoord, commonUI.brushSize, commonUI.brushRotation); PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, editContext.brushTexture, brushXform, TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial(), 0); if (sampleContext != null && cloneToolProperties.m_PaintHeightmap) { ApplyHeightmap(sampleContext, ctx, brushXform, terrain, editContext.brushTexture, commonUI.brushStrength); RenderTexture.active = ctx.oldRenderTexture; previewMat.SetTexture("_HeightmapOrig", ctx.sourceRenderTexture); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainPaintUtilityEditor.BrushPreview.DestinationRenderTexture, editContext.brushTexture, brushXform, previewMat, 1); } // Restores RenderTexture.active ctx.Cleanup(); } // Restores RenderTexture.active sampleContext?.Cleanup(); }
public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext) { GUILayout.Label("Settings", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); EditorGUILayout.Space(); var cacheFieldWidth = EditorGUIUtility.fieldWidth; var cacheLabelWIdth = EditorGUIUtility.labelWidth; Editor.DrawFoldoutInspector(terrain.materialTemplate, ref m_TemplateMaterialEditor); EditorGUIUtility.fieldWidth = cacheFieldWidth; EditorGUIUtility.labelWidth = cacheLabelWIdth; EditorGUILayout.Space(); if (m_SelectedTerrainLayerIndex == -1) { m_SelectedTerrainLayerIndex = TerrainPaintUtility.FindTerrainLayerIndex(terrain, m_SelectedTerrainLayer); } m_SelectedTerrainLayerIndex = TerrainLayerUtility.ShowTerrainLayersSelectionHelper(terrain, m_SelectedTerrainLayerIndex); EditorGUILayout.Space(); if (EditorGUI.EndChangeCheck()) { m_SelectedTerrainLayer = m_SelectedTerrainLayerIndex != -1 ? terrain.terrainData.terrainLayers[m_SelectedTerrainLayerIndex] : null; Save(true); } TerrainLayerUtility.ShowTerrainLayerGUI(terrain, m_SelectedTerrainLayer, ref m_SelectedTerrainLayerInspector, (m_TemplateMaterialEditor as MaterialEditor)?.customShaderGUI as ITerrainLayerCustomUI); EditorGUILayout.Space(); // Texture painting needs to know the largest of the splat map and the height map, as the result goes to // the splat map, but the height map is used for previewing. int resolution = Mathf.Max(terrain.terrainData.heightmapResolution, terrain.terrainData.alphamapResolution); editContext.ShowBrushesGUI(5, BrushGUIEditFlags.All, resolution); }
void FillButton(Terrain terrain) { Event e = Event.current; GUIContent buttonText = new GUIContent("Fill"); Rect buttonRect = GUILayoutUtility.GetRect(buttonText, GUIStyle.none); if (e.isMouse && buttonRect.Contains(e.mousePosition)) { if (e.type == EventType.MouseDown) { Rect rect = new Rect(0.0f, 0.0f, terrain.terrainData.size.x, terrain.terrainData.size.z); BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, Vector2.one * 0.5f, Mathf.Max(terrain.terrainData.size.x, terrain.terrainData.size.z), 0.0f); DoPaint(terrain, 2.0f, null, rect, brushXform); terrain.terrainData.SetBaseMapDirty(); } } GUI.Button(buttonRect, buttonText); }
public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { commonUI.OnSceneGUI2D(terrain, editContext); if (editContext.hitValidTerrain || commonUI.isInUse) { commonUI.OnSceneGUI(terrain, editContext); if (Event.current.type != EventType.Repaint) { return; } float endWidth = Mathf.Abs(bridgeToolProperties.widthProfile.Evaluate(1.0f)); BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, commonUI.raycastHitUnderCursor.textureCoord, commonUI.brushSize * endWidth, commonUI.brushRotation); PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, editContext.brushTexture, brushXform, TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial(), 0); TerrainPaintUtility.ReleaseContextResources(ctx); } if (Event.current.type != EventType.Repaint) { return; } //display a brush preview at the bridge starting location, using starting size from width profile if (m_StartTerrain != null) { float startWidth = Mathf.Abs(bridgeToolProperties.widthProfile.Evaluate(0.0f)); BrushTransform brushTransform = TerrainPaintUtility.CalculateBrushTransform(m_StartTerrain, m_StartPoint, commonUI.brushSize * startWidth, commonUI.brushRotation); PaintContext sampleContext = TerrainPaintUtility.BeginPaintHeightmap(m_StartTerrain, brushTransform.GetBrushXYBounds()); TerrainPaintUtilityEditor.DrawBrushPreview(sampleContext, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, editContext.brushTexture, brushTransform, TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial(), 0); TerrainPaintUtility.ReleaseContextResources(sampleContext); } }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { commonUI.OnPaint(terrain, editContext); if (commonUI.allowPaint) { Texture brushTexture = editContext.brushTexture; using (IBrushRenderUnderCursor brushRender = new BrushRenderUIGroupUnderCursor(commonUI, "PaintHoles", brushTexture)) { Vector2 halfTexelOffset = new Vector2(0.5f / terrain.terrainData.holesResolution, 0.5f / terrain.terrainData.holesResolution); BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv - halfTexelOffset, commonUI.brushSize, commonUI.brushRotation); PaintContext paintContext = brushRender.AquireHolesTexture(true, brushXform.GetBrushXYBounds()); PaintContext paintContextHeight = brushRender.AcquireHeightmap(false, brushXform.GetBrushXYBounds()); // filter stack Vector3 brushPos = new Vector3(commonUI.raycastHitUnderCursor.point.x, 0, commonUI.raycastHitUnderCursor.point.z); FilterContext fc = new FilterContext(terrain, brushPos, commonUI.brushSize, commonUI.brushRotation); fc.renderTextureCollection.GatherRenderTextures(paintContextHeight.sourceRenderTexture.width, paintContextHeight.sourceRenderTexture.height); RenderTexture filterMaskRT = commonUI.GetBrushMask(fc, paintContextHeight.sourceRenderTexture); Material mat = GetPaintHolesMaterial(); // hold control key to erase float brushStrength = Event.current.control ? commonUI.brushStrength : -commonUI.brushStrength; Vector4 brushParams = new Vector4(brushStrength, 0.0f, 0.0f, 0.0f); mat.SetTexture("_BrushTex", editContext.brushTexture); mat.SetTexture("_FilterTex", filterMaskRT); mat.SetVector("_BrushParams", brushParams); brushRender.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat); brushRender.RenderBrush(paintContext, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.PaintHoles); TerrainPaintUtility.EndPaintHoles(paintContext, "Terrain Paint - Paint Holes"); } } return(true); }
public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext) { GUILayout.Label("Settings", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); EditorGUILayout.Space(); var cacheFieldWidth = EditorGUIUtility.fieldWidth; var cacheLabelWIdth = EditorGUIUtility.labelWidth; Editor.DrawFoldoutInspector(terrain.materialTemplate, ref m_TemplateMaterialEditor); EditorGUIUtility.fieldWidth = cacheFieldWidth; EditorGUIUtility.labelWidth = cacheLabelWIdth; EditorGUILayout.Space(); if (m_SelectedTerrainLayerIndex == -1) { m_SelectedTerrainLayerIndex = TerrainPaintUtility.FindTerrainLayerIndex(terrain, m_SelectedTerrainLayer); } m_SelectedTerrainLayerIndex = TerrainLayerUtility.ShowTerrainLayersSelectionHelper(terrain, m_SelectedTerrainLayerIndex); EditorGUILayout.Space(); if (EditorGUI.EndChangeCheck()) { m_SelectedTerrainLayer = m_SelectedTerrainLayerIndex != -1 ? terrain.terrainData.terrainLayers[m_SelectedTerrainLayerIndex] : null; Save(true); } terrain.materialTemplate.SetFloat("_NumLayersCount", terrain.terrainData.terrainLayers.Length); TerrainLayerUtility.ShowTerrainLayerGUI(terrain, m_SelectedTerrainLayer, ref m_SelectedTerrainLayerInspector, (m_TemplateMaterialEditor as MaterialEditor)?.customShaderGUI as ITerrainLayerCustomUI); EditorGUILayout.Space(); int textureRez = terrain.terrainData.alphamapResolution; editContext.ShowBrushesGUI(5, BrushGUIEditFlags.All, textureRez); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv, editContext.brushSize, 0.0f); PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1); Material mat = GetPaintMaterial(); // apply brush Vector4 brushParams = new Vector4( editContext.brushStrength, m_ErosionStrength, m_MixStrength, 0.0f); mat.SetTexture("_BrushTex", editContext.brushTexture); mat.SetVector("_BrushParams", brushParams); TerrainPaintUtility.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat); Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Ridge Erode"); return(false); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize); TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect); float finalTwistAmount = m_TwistAmount * -0.001f; //scale to a reasonable value and negate so default mode is clockwise if (Event.current.shift) { finalTwistAmount *= -1.0f; } Material mat = GetPaintMaterial(); Vector4 brushParams = new Vector4(editContext.brushStrength, 0.0f, finalTwistAmount, 0.0f); mat.SetTexture("_BrushTex", editContext.brushTexture); mat.SetVector("_BrushParams", brushParams); Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Twist Height"); return(false); }
private void ApplyBrushInternal(IPaintContextRender renderer, PaintContext paintContext, float brushStrength, Texture brushTexture, BrushTransform brushXform, Terrain terrain) { Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial(); float height = stampToolProperties.m_StampHeight / (terrain.terrainData.size.y * 2.0f); if (stampToolProperties.stampDown) { height = -height; } Vector4 brushParams = new Vector4(brushStrength, 0.0f, height, stampToolProperties.m_MaxBlendAdd); mat.SetTexture("_BrushTex", brushTexture); mat.SetVector("_BrushParams", brushParams); var brushMask = RTUtils.GetTempHandle(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat); Utility.SetFilterRT(commonUI, paintContext.sourceRenderTexture, brushMask, mat); renderer.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat); renderer.RenderBrush(paintContext, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.StampHeight); RTUtils.Release(brushMask); }
private void PaintAlphamap(Terrain sampleTerrain, Terrain targetTerrain, BrushTransform sampleXform, BrushTransform targetXform, Material mat) { Rect sampleRect = sampleXform.GetBrushXYBounds(); Rect targetRect = targetXform.GetBrushXYBounds(); int numSampleTerrainLayers = sampleTerrain.terrainData.terrainLayers.Length; for (int i = 0; i < numSampleTerrainLayers; ++i) { TerrainLayer layer = sampleTerrain.terrainData.terrainLayers[i]; if (layer == null) { continue; // nothing to paint if the layer is NULL } PaintContext sampleContext = TerrainPaintUtility.BeginPaintTexture(sampleTerrain, sampleRect, layer); int layerIndex = TerrainPaintUtility.FindTerrainLayerIndex(sampleTerrain, layer); Texture2D layerTexture = TerrainPaintUtility.GetTerrainAlphaMapChecked(sampleTerrain, layerIndex >> 2); PaintContext targetContext = PaintContext.CreateFromBounds(targetTerrain, targetRect, layerTexture.width, layerTexture.height); targetContext.CreateRenderTargets(RenderTextureFormat.R8); targetContext.GatherAlphamap(layer, true); sampleContext.sourceRenderTexture.filterMode = FilterMode.Point; mat.SetTexture("_CloneTex", sampleContext.sourceRenderTexture); mat.SetVector("_SampleUVScaleOffset", ComputeSampleUVScaleOffset(sampleContext, targetContext)); var brushMask = RTUtils.GetTempHandle(targetContext.sourceRenderTexture.width, targetContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat); Utility.SetFilterRT(commonUI, targetContext.sourceRenderTexture, brushMask, mat); TerrainPaintUtility.SetupTerrainToolMaterialProperties(targetContext, targetXform, mat); Graphics.Blit(targetContext.sourceRenderTexture, targetContext.destinationRenderTexture, mat, (int)ShaderPasses.CloneAlphamap); // apply texture modifications and perform cleanup. same thing as calling TerrainPaintUtility.EndPaintTexture targetContext.ScatterAlphamap("Terrain Paint - Clone Brush (Texture)"); // Restores RenderTexture.active targetContext.Cleanup(); RTUtils.Release(brushMask); } }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { if (Event.current.shift) { m_Height = terrain.terrainData.GetInterpolatedHeight(editContext.uv.x, editContext.uv.y) / terrain.terrainData.size.y; editContext.RepaintAllInspectors(); return(true); } Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial(); Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(terrain, editContext.uv, editContext.brushSize); TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushRect); Vector4 brushParams = new Vector4(editContext.brushStrength * 0.01f, 0.5f * m_Height, 0.0f, 0.0f); mat.SetTexture("_BrushTex", editContext.brushTexture); mat.SetVector("_BrushParams", brushParams); Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.SetHeights); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Set Height"); return(true); }
private void ApplyBrushInternal(PaintContext paintContext, IBrushRenderUnderCursor brushRender, float brushStrength, Texture brushTexture, BrushTransform brushTransform, Terrain terrain) { Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial(); #if UNITY_2019_3_OR_NEWER float brushTargetHeight = Mathf.Clamp01((m_TargetHeight - paintContext.heightWorldSpaceMin) / paintContext.heightWorldSpaceSize); Vector4 brushParams = new Vector4(brushStrength * 0.01f, PaintContext.kNormalizedHeightScale * brushTargetHeight, 0.0f, 0.0f); #else float terrainHeight = Mathf.Clamp01((m_TargetHeight - terrain.transform.position.y) / terrain.terrainData.size.y); Vector4 brushParams = new Vector4(brushStrength * 0.01f, 0.5f * terrainHeight, 0.0f, 0.0f); #endif Vector3 brushPos = new Vector3(commonUI.raycastHitUnderCursor.point.x, 0, commonUI.raycastHitUnderCursor.point.z); FilterContext fc = new FilterContext(terrain, brushPos, commonUI.brushSize, commonUI.brushRotation); fc.renderTextureCollection.GatherRenderTextures(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height); RenderTexture filterMaskRT = commonUI.GetBrushMask(fc, paintContext.sourceRenderTexture); mat.SetTexture("_FilterTex", filterMaskRT); mat.SetTexture("_BrushTex", brushTexture); mat.SetVector("_BrushParams", brushParams); brushRender.SetupTerrainToolMaterialProperties(paintContext, brushTransform, mat); brushRender.RenderBrush(paintContext, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.SetHeights); }
public override void OnEnterToolMode(BrushShortcutHandler <BrushShortcutType> shortcutHandler) { base.OnEnterToolMode(shortcutHandler); if (!canUpdateTerrainUnderCursor) { UnlockTerrainUnderCursor(); } shortcutHandler.AddActions(BrushShortcutType.Size, BeginAdjustingSize, EndAdjustingSize); float minBrushWorldSize, maxBrushWorldSize; float mininumTerrainSize = float.MaxValue; int maxTextureResolution = 0; foreach (var terrain in Terrain.activeTerrains) { var terrainData = terrain.terrainData; maxTextureResolution = Mathf.Max(maxTextureResolution, terrainData.heightmapResolution); mininumTerrainSize = Mathf.Min(mininumTerrainSize, terrainData.size.x, terrainData.size.z); } // caculate the minimum / maximum brush ranges from a set of selected terrains TerrainPaintUtility.GetBrushWorldSizeLimits(out minBrushWorldSize, out maxBrushWorldSize, mininumTerrainSize, maxTextureResolution); m_BrushSize.shouldClampMax = false; m_BrushSize.shouldClampMin = false; m_BrushSize.maxClamp = maxBrushWorldSize; m_BrushSize.minClamp = minBrushWorldSize; m_BrushSize.shouldClampMax = true; m_BrushSize.shouldClampMin = true; m_BrushSize.value = GetEditorPrefs("TerrainBrushSize", kDefaultBrushSize); m_BrushSize.minValue = GetEditorPrefs("TerrainBrushSizeMin", 0.0f); m_BrushSize.maxValue = GetEditorPrefs("TerrainBrushSizeMax", 500.0f); //m_BrushSize.mouseSensitivity = GetEditorPrefs("TerrainBrushSizeMouseSensitivity", kDefaultMouseSensitivity); m_JitterHandler.jitter = GetEditorPrefs("TerrainBrushSizeJitter", 0.0f); }
public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { // there's probably more logic we need to handle here if (paintInProgress && (Event.current.type == EventType.MouseUp)) { MaterialManager mgr = terrain.GetComponent <MaterialManager>(); if (mgr != null) { mgr.GetIndexMap().SetIndexMapDirty(); } paintInProgress = false; } // We're only doing painting operations, early out if it's not a repaint if (Event.current.type != EventType.Repaint) { return; } if (editContext.hitValidTerrain) { if (lastUV != editContext.raycastHit.textureCoord) { editContext.Repaint(RepaintFlags.UI); } lastUV = editContext.raycastHit.textureCoord; lastBrushSize = editContext.brushSize; BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.raycastHit.textureCoord, editContext.brushSize, 0.0f); PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1); Material brushPreviewMaterial = GetBrushPreviewMaterial(); Vector4 brushParams = new Vector4(editContext.brushStrength, 0.0f, 0.0f, 0.0f); brushPreviewMaterial.SetVector("_BrushParams", brushParams); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, editContext.brushTexture, brushXform, brushPreviewMaterial, 0); TerrainPaintUtility.ReleaseContextResources(ctx); } }
public PaintContext AcquireTexture(bool writable, Terrain terrain, Rect boundsInTerrainSpace, TerrainLayer layer, int extraBorderPixels = 0) { m_WriteToTexture = writable; m_TextureContext = TerrainPaintUtility.BeginPaintTexture(terrain, boundsInTerrainSpace, layer, extraBorderPixels); return(m_TextureContext); }
public override bool CalculateBrushTransform(Terrain terrain, Vector2 uv, float size, float rotation, out BrushTransform brushTransform) { // TODO: Remove this method and replace the preview with a radius effect and scatter at the correct position... brushTransform = TerrainPaintUtility.CalculateBrushTransform(terrain, uv, size, rotation); return(true); }
public PaintContext AcquireNormalmap(bool writable, Terrain terrain, Rect boundsInTerrainSpace, int extraBorderPixels = 0) { m_NormalmapContext = TerrainPaintUtility.CollectNormals(terrain, boundsInTerrainSpace, extraBorderPixels); return(m_NormalmapContext); }
public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { Init(); // m_rtCollection.DebugGUI( editContext.sceneView ); brushUI.OnSceneGUI2D(terrain, editContext); // only do the rest if user mouse hits valid terrain or they are using the // brush parameter hotkeys to resize, etc if (!editContext.hitValidTerrain && !brushUI.isInUse && !m_editTransform && !debugOrtho) { return; } // update brush UI group brushUI.OnSceneGUI(terrain, editContext); bool justPressedEditKey = m_editTransform && !m_prevEditTransform; bool justReleaseEditKey = m_prevEditTransform && !m_editTransform; m_prevEditTransform = m_editTransform; if (justPressedEditKey) { (brushUI as MeshBrushUIGroup).LockTerrainUnderCursor(true); m_baseHandlePos = brushUI.raycastHitUnderCursor.point; m_handleHeightOffsetWS = 0; } else if (justReleaseEditKey) { (brushUI as MeshBrushUIGroup).UnlockTerrainUnderCursor(); m_handleHeightOffsetWS = 0; } // don't render mesh previews, etc. if the mesh field has not been populated yet if (activeMesh == null) { return; } // dont render preview if this isnt a repaint. losing performance if we do if (Event.current.type == EventType.Repaint) { Terrain currTerrain = brushUI.terrainUnderCursor; Vector2 uv = brushUI.raycastHitUnderCursor.textureCoord; float brushSize = brushUI.brushSize; float brushRotation = brushUI.brushRotation; if (/* debugOrtho || */ brushUI.isRaycastHitUnderCursorValid) { // if(debugOrtho) // { // uv = Vector2.one * .5f; // } BrushTransform brushTransform = TerrainPaintUtility.CalculateBrushTransform(currTerrain, uv, brushSize, brushRotation); PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(brushUI.terrainUnderCursor, brushTransform.GetBrushXYBounds(), 1); Material material = TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial(); // don't draw the brush mask preview // but draw the resulting mesh stamp preview { ApplyBrushInternal(terrain, ctx, brushTransform); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, m_rtCollection[RenderTextureIDs.meshStamp], brushTransform, material, 0); RenderTexture.active = ctx.oldRenderTexture; material.SetTexture("_HeightmapOrig", ctx.sourceRenderTexture); TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushTransform, material); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainPaintUtilityEditor.BrushPreview.DestinationRenderTexture, m_rtCollection[RenderTextureIDs.meshStamp], brushTransform, material, 1); TerrainPaintUtility.ReleaseContextResources(ctx); } } } if (m_editTransform) { EditorGUI.BeginChangeCheck(); { Vector3 prevHandlePosWS = m_baseHandlePos + Vector3.up * m_handleHeightOffsetWS; // draw transform handles float handleSize = HandleUtility.GetHandleSize(prevHandlePosWS); toolSettings.scale = Handles.ScaleHandle(toolSettings.scale, prevHandlePosWS, toolSettings.rotation, handleSize * 1.5f); Quaternion brushRotation = Quaternion.AngleAxis(brushUI.brushRotation, Vector3.up); toolSettings.rotation = Handles.RotationHandle(toolSettings.rotation, prevHandlePosWS); Vector3 currHandlePosWS = Handles.Slider(prevHandlePosWS, Vector3.up, handleSize, Handles.ArrowHandleCap, 1f); float deltaHeight = (currHandlePosWS.y - prevHandlePosWS.y); m_handleHeightOffsetWS += deltaHeight; toolSettings.stampHeight += deltaHeight; } if (EditorGUI.EndChangeCheck()) { editContext.Repaint(); SaveSettings(); } } }
public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext) { GUILayout.Label("Settings", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); m_SplatAlpha = EditorGUILayout.Slider("Target Strength", m_SplatAlpha, 0.0F, 1.0F); EditorGUILayout.Space(); if (m_TemplateMaterialEditor != null && m_TemplateMaterialEditor.target != terrain.materialTemplate) { UnityEngine.Object.DestroyImmediate(m_TemplateMaterialEditor); m_TemplateMaterialEditor = null; } if (m_TemplateMaterialEditor == null && terrain.materialTemplate != null) { m_TemplateMaterialEditor = Editor.CreateEditor(terrain.materialTemplate) as MaterialEditor; m_TemplateMaterialEditor.firstInspectedEditor = true; } if (m_TemplateMaterialEditor != null) { DrawFoldoutEditor(m_TemplateMaterialEditor, kTemplateMaterialEditorControl, ref m_ShowMaterialEditor); EditorGUILayout.Space(); } int layerIndex = TerrainPaintUtility.FindTerrainLayerIndex(terrain, m_SelectedTerrainLayer); layerIndex = TerrainLayerUtility.ShowTerrainLayersSelectionHelper(terrain, layerIndex); EditorGUILayout.Space(); if (EditorGUI.EndChangeCheck()) { if (layerIndex != -1) { m_SelectedTerrainLayer = terrain.terrainData.terrainLayers[layerIndex]; } else { m_SelectedTerrainLayer = null; } if (m_SelectedTerrainLayerInspector != null) { UnityEngine.Object.DestroyImmediate(m_SelectedTerrainLayerInspector); m_SelectedTerrainLayerInspector = null; } if (m_SelectedTerrainLayer != null) { m_SelectedTerrainLayerInspector = Editor.CreateEditor(m_SelectedTerrainLayer) as TerrainLayerInspector; } Save(true); } if (m_SelectedTerrainLayerInspector != null) { var terrainLayerCustomUI = m_TemplateMaterialEditor?.m_CustomShaderGUI as ITerrainLayerCustomUI; if (terrainLayerCustomUI != null) { m_SelectedTerrainLayerInspector.SetCustomUI(terrainLayerCustomUI, terrain); } DrawFoldoutEditor(m_SelectedTerrainLayerInspector, kSelectedTerrainLayerEditorControl, ref m_ShowLayerEditor); EditorGUILayout.Space(); } editContext.ShowBrushesGUI(5); }
public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { commonUI.OnSceneGUI2D(terrain, editContext); #if UNITY_2019_1_OR_NEWER // Don't paint if eyedropper is selected if (m_EyedropperSelected) { EditorGUIUtility.AddCursorRect(new Rect(0, 0, Screen.width, Screen.height), MouseCursor.CustomCursor); editContext.Repaint(); return; } #endif // We're only doing painting operations, early out if it's not a repaint if (!editContext.hitValidTerrain && !commonUI.isInUse) { return; } // update brush UI group commonUI.OnSceneGUI(terrain, editContext); // Don't render preview if this isn't a repaint. losing performance if we do if (Event.current.type != EventType.Repaint) { return; } Texture brushTexture = editContext.brushTexture; using (IBrushRenderPreviewUnderCursor brushRender = new BrushRenderPreviewUIGroupUnderCursor(commonUI, "PaintTextureTool", brushTexture)) { if (brushRender.CalculateBrushTransform(out BrushTransform brushTransform)) //cute. { RenderTexture tmpRT = RenderTexture.active; Rect brushBounds = brushTransform.GetBrushXYBounds(); PaintContext heightmapContext = brushRender.AcquireHeightmap(false, brushBounds, 1); Material brushMaterial = GetBrushPreviewMaterial(); if (commonUI.brushMaskFilterStack.filters.Count > 0) { // Evaluate the brush mask filter stack Vector3 brushPos = new Vector3(commonUI.raycastHitUnderCursor.point.x, 0, commonUI.raycastHitUnderCursor.point.z); FilterContext fc = new FilterContext(terrain, brushPos, commonUI.brushSize, commonUI.brushRotation); fc.renderTextureCollection.GatherRenderTextures(heightmapContext.sourceRenderTexture.width, heightmapContext.sourceRenderTexture.height); RenderTexture filterMaskRT = commonUI.GetBrushMask(fc, heightmapContext.sourceRenderTexture); //Composite the brush texture onto the filter stack result RenderTexture compRT = RenderTexture.GetTemporary(filterMaskRT.descriptor); Material blendMat = GetBlendMaterial(); blendMat.SetTexture("_BlendTex", editContext.brushTexture); blendMat.SetVector("_BlendParams", new Vector4(0.0f, 0.0f, -(commonUI.brushRotation * Mathf.Deg2Rad), 0.0f)); TerrainPaintUtility.SetupTerrainToolMaterialProperties(heightmapContext, brushTransform, blendMat); Graphics.Blit(filterMaskRT, compRT, blendMat, 0); RenderTexture.active = tmpRT; BrushTransform identityBrushTransform = TerrainPaintUtility.CalculateBrushTransform(commonUI.terrainUnderCursor, commonUI.raycastHitUnderCursor.textureCoord, commonUI.brushSize, 0.0f); TerrainPaintUtility.SetupTerrainToolMaterialProperties(heightmapContext, identityBrushTransform, brushMaterial); TerrainPaintUtilityEditor.DrawBrushPreview(heightmapContext, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, compRT, identityBrushTransform, brushMaterial, 0); RenderTexture.ReleaseTemporary(compRT); } brushRender.RenderBrushPreview(heightmapContext, TerrainPaintUtilityEditor.BrushPreview.SourceRenderTexture, brushTransform, TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial(), 0); } } }
public static void EndFillHeightmap(PaintContext ctx, string editorUndoString) { TerrainPaintUtility.EndPaintHeightmap(ctx, editorUndoString); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { Vector2 uv = editContext.uv; //grab the starting position & height if (Event.current.shift) { float height = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y; m_StartPoint = new Vector3(uv.x, uv.y, height); m_StartTerrain = terrain; return(true); } if (!m_StartTerrain || (Event.current.type == EventType.MouseDrag)) { return(true); } //get the target position & height float targetHeight = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y; Vector3 targetPos = new Vector3(uv.x, uv.y, targetHeight); if (terrain != m_StartTerrain) { //figure out the stroke vector in uv,height space Vector2 targetWorld = transformToWorld(terrain, uv); Vector2 targetUVs = transformToUVSpace(m_StartTerrain, targetWorld); targetPos.x = targetUVs.x; targetPos.y = targetUVs.y; } Vector3 stroke = targetPos - m_StartPoint; float strokeLength = stroke.magnitude; int numSplats = (int)(strokeLength / (0.001f * m_Spacing)); Terrain currTerrain = m_StartTerrain; Material mat = GetPaintMaterial(); Vector2 posOffset = new Vector2(0.0f, 0.0f); Vector2 currUV = new Vector2(); Vector4 brushParams = new Vector4(); Vector2 jitterVec = new Vector2(-stroke.z, stroke.x); //perpendicular to stroke direction jitterVec.Normalize(); for (int i = 0; i < numSplats; i++) { float pct = (float)i / (float)numSplats; float widthScale = widthProfile.Evaluate(pct); float heightOffset = heightProfile.Evaluate(pct) / currTerrain.terrainData.size.y; float strengthScale = strengthProfile.Evaluate(pct); float jitterOffset = jitterProfile.Evaluate(pct) / Mathf.Max(currTerrain.terrainData.size.x, currTerrain.terrainData.size.z); Vector3 currPos = m_StartPoint + pct * stroke; //add in jitter offset (needs to happen before tile correction) currPos.x += posOffset.x + jitterOffset * jitterVec.x; currPos.y += posOffset.y + jitterOffset * jitterVec.y; if (currPos.x >= 1.0f && (currTerrain.rightNeighbor != null)) { currTerrain = currTerrain.rightNeighbor; currPos.x -= 1.0f; posOffset.x -= 1.0f; } if (currPos.x <= 0.0f && (currTerrain.leftNeighbor != null)) { currTerrain = currTerrain.leftNeighbor; currPos.x += 1.0f; posOffset.x += 1.0f; } if (currPos.y >= 1.0f && (currTerrain.topNeighbor != null)) { currTerrain = currTerrain.topNeighbor; currPos.y -= 1.0f; posOffset.y -= 1.0f; } if (currPos.y <= 0.0f && (currTerrain.bottomNeighbor != null)) { currTerrain = currTerrain.bottomNeighbor; currPos.y += 1.0f; posOffset.y += 1.0f; } currUV.x = currPos.x; currUV.y = currPos.y; int finalBrushSize = (int)(widthScale * (float)editContext.brushSize); float finalHeight = (m_StartPoint + pct * stroke).z + heightOffset; BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(currTerrain, currUV, finalBrushSize, 0.0f); PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(currTerrain, brushXform.GetBrushXYBounds()); mat.SetTexture("_BrushTex", editContext.brushTexture); brushParams.x = editContext.brushStrength * strengthScale; brushParams.y = 0.5f * finalHeight; mat.SetVector("_BrushParams", brushParams); TerrainPaintUtility.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat); Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Bridge"); } return(false); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { MaterialManager mgr = terrain.GetComponent <MaterialManager>(); if (mgr != null) { // IndexMap indexMap = mgr.GetIndexMap(); // RenderTexture rt= indexMap.GetTempRenderTexture(true); paintInProgress = true; BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv, editContext.brushSize, 0.0f); PaintContext indexCtx = PaintContext.CreateFromBounds(terrain, brushXform.GetBrushXYBounds(), 64, 64, 1); indexCtx.CreateRenderTargets(RenderTextureFormat.ARGB32); PaintContext normalCtx = TerrainPaintUtility.CollectNormals(terrain, brushXform.GetBrushXYBounds(), 2); Material blitMaterial = TerrainPaintUtility.GetBlitMaterial(); indexCtx.Gather( TerrainToIndexMapTexture, new Color(0.0f, 0.0f, 0.0f, 0.0f), blitMaterial, 0, null, // before null); // after // render source -> dest here // RenderTexture.active = ctx.oldRenderTexture; Material paintMaterial = GetPaintMaterial(); float brushStrength = Event.current.shift ? -editContext.brushStrength : editContext.brushStrength; Vector4 brushParams = new Vector4( brushStrength, 0.0f, 0.0f, 0.0f); paintMaterial.SetTexture("_BrushTex", editContext.brushTexture); paintMaterial.SetVector("_BrushParams", brushParams); paintMaterial.SetFloat("materialIndex", materialIndex); paintMaterial.SetTexture("_NormalMap", normalCtx.sourceRenderTexture); Vector4 indexToNormalXform; TerrainPaintUtility.BuildTransformPaintContextUVToPaintContextUV( indexCtx, normalCtx, out indexToNormalXform); paintMaterial.SetVector("_indexToNormalXform", indexToNormalXform); Vector4 xformParams = new Vector4(); xformParams.x = (randomRotation ? minRotation : fixedRotation) / 360.0f; xformParams.y = (randomRotation ? maxRotation : fixedRotation) / 360.0f; paintMaterial.SetVector("_xformParams", xformParams); Vector4 randoms = new Vector4( UnityEngine.Random.Range(0.0f, 1.0f), UnityEngine.Random.Range(0.0f, 1.0f), UnityEngine.Random.Range(0.0f, 1.0f), UnityEngine.Random.Range(0.0f, 1.0f)); paintMaterial.SetVector("_randoms", randoms); TerrainPaintUtility.SetupTerrainToolMaterialProperties(indexCtx, brushXform, paintMaterial); Graphics.Blit(indexCtx.sourceRenderTexture, indexCtx.destinationRenderTexture, paintMaterial, 0); // ctx.ScatterToTexture() // we should do this ... less temp render textures // and users don't have to store render textures at all... indexCtx.Scatter( TerrainToIndexMapRenderTexture, blitMaterial, 0, null, null); normalCtx.Cleanup(); indexCtx.Cleanup(); } /* * BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv, editContext.brushSize, 0.0f); * PaintContext paintContext = TerrainPaintUtility.BeginPaintTexture(terrain, brushXform.GetBrushXYBounds(), m_SelectedTerrainLayer); * if (paintContext == null) * return false; * * Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial(); * * // apply brush * float targetAlpha = 1.0f; // always 1.0 now -- no subtractive painting (we assume this in the ScatterAlphaMap) * Vector4 brushParams = new Vector4(editContext.brushStrength, targetAlpha, 0.0f, 0.0f); * mat.SetTexture("_BrushTex", editContext.brushTexture); * mat.SetVector("_BrushParams", brushParams); * * TerrainPaintUtility.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat); * * Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, (int)TerrainPaintUtility.BuiltinPaintMaterialPasses.PaintTexture); * * TerrainPaintUtility.EndPaintTexture(paintContext, "Terrain Paint - Texture"); */ return(true); }
private void ApplyBrushInternal(Terrain terrain, PaintContext ctx, BrushTransform brushTransform) { m_rtCollection.ReleaseRenderTextures(); m_rtCollection.GatherRenderTextures(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height); Graphics.Blit(ctx.sourceRenderTexture, m_rtCollection[RenderTextureIDs.sourceHeight]); bool needsUpdate = true; // check if mesh or mesh transform changed, otherwise use previous blit if (needsUpdate) { Material mat = GetMaterial(); // build model, view, and projection matrices // if( !debugOrtho ) // { // orthoLeft = -1; // orthoRight = 1; // orthoTop = -1; // orthoBottom = 1; // nearPlane = -1; // } Matrix4x4 toolMatrix = Matrix4x4.TRS(Vector3.zero, toolSettings.rotation, toolSettings.scale); Bounds modelBounds = activeMesh.bounds; float maxModelScale = Mathf.Max(Mathf.Max(modelBounds.size.x, modelBounds.size.y), modelBounds.size.z); // maxModelScale *= Mathf.Sqrt( 2 + maxModelScale * maxModelScale / 4 ) * .5f; // mult so the mesh fits a little better within the camera / stamp texture bounds // maxModelScale /= 1.414f; float x = .5f; float y = .5f; float xy = Mathf.Sqrt(x * x + y * y); float z = .5f; float xyz = Mathf.Sqrt(xy * xy + z * z); maxModelScale *= xyz; // build the model matrix to transform the mesh with. Matrix4x4 model = toolMatrix * Matrix4x4.Scale(Vector3.one / maxModelScale) * Matrix4x4.Translate(-modelBounds.center); // get the world bounds here so we can calculate the needed offset along the up axis // Bounds worldBounds = TransformBounds( model, activeMesh.bounds ); // float localHeightOffset = Mathf.Min( worldBounds.extents.y, toolSettings.stampHeight / brushUI.terrainUnderCursor.terrainData.size.y * .5f ); // Matrix4x4 localHeightOffsetMatrix = Matrix4x4.Translate( Vector3.up * localHeightOffset ); // apply the local height offset // model = localHeightOffsetMatrix * model; Vector3 translate = Vector3.up * toolSettings.stampHeight / brushUI.terrainUnderCursor.terrainData.size.y; // translate = translate / brushUI.brushStrength * .5f; model = Matrix4x4.Translate(translate) * model; // actually render the mesh to texture to be used with the tool shader RenderMeshToRenderTexture(activeMesh, model, m_rtCollection[RenderTextureIDs.meshStamp], mat, 0); // perform actual composite of mesh stamp and terrain source heightmap float brushStrength = Event.current.control ? -brushUI.brushStrength : brushUI.brushStrength; float baseHeight = Event.current.control ? toolSettings.stampHeight / brushUI.terrainUnderCursor.terrainData.size.y * brushUI.brushStrength / .5f : 0; Vector4 brushParams = new Vector4(brushStrength, toolSettings.blendAmount, 0, baseHeight); mat.SetVector("_BrushParams", brushParams); mat.SetTexture("_MeshStampTex", m_rtCollection[RenderTextureIDs.meshStamp]); TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushTransform, mat); Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, mat, 1); Graphics.Blit(ctx.destinationRenderTexture, m_rtCollection[RenderTextureIDs.combinedHeight]); } // restore old render target RenderTexture.active = ctx.oldRenderTexture; }
public static PaintContext CollectNormals(Terrain terrain) { return(TerrainPaintUtility.CollectNormals(terrain, GetTerrainBounds(terrain))); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv, editContext.brushSize, 0.0f); return(DoPaint(terrain, editContext.brushStrength, editContext.brushTexture, brushXform)); }
public static PaintContext BeginFillTexture(Terrain terrain, TerrainLayer inputLayer) { return(TerrainPaintUtility.BeginPaintTexture(terrain, GetTerrainBounds(terrain), inputLayer)); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { commonUI.OnPaint(terrain, editContext); if (!commonUI.allowPaint) { return(true); } if (Event.current.type == EventType.MouseDown) { m_PrevBrushPos = editContext.uv; return(false); } if (Event.current.type == EventType.MouseDrag && m_PreviousEvent == EventType.MouseDrag) { Vector2 uv = editContext.uv; if (commonUI.ScatterBrushStamp(ref terrain, ref uv)) { Material mat = GetPaintMaterial(); Vector2 smudgeDir = uv - m_PrevBrushPos; BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, uv, commonUI.brushSize, commonUI.brushRotation); Vector4 brushParams = new Vector4(commonUI.brushStrength, smudgeDir.x, smudgeDir.y, 0); mat.SetTexture("_BrushTex", editContext.brushTexture); mat.SetVector("_BrushParams", brushParams); //smudge splat map if (m_AffectMaterials) { for (int i = 0; i < terrain.terrainData.terrainLayers.Length; i++) { TerrainLayer layer = terrain.terrainData.terrainLayers[i]; if (layer == null) { continue; // nothing to paint if the layer is NULL } PaintContext sampleContext = TerrainPaintUtility.BeginPaintTexture(terrain, brushXform.GetBrushXYBounds(), layer); Graphics.Blit(sampleContext.sourceRenderTexture, sampleContext.destinationRenderTexture, mat, 0); TerrainPaintUtility.EndPaintTexture(sampleContext, "Terrain Paint - Twist Brush (Texture)"); } } //smudge the height map if (m_AffectHeight) { PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1); TerrainPaintUtility.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat); Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Twist Brush (Height)"); } m_PrevBrushPos = uv; } } m_PreviousEvent = Event.current.type; return(false); }
public static void EndFillTexture(PaintContext ctx, string editorUndoString) { TerrainPaintUtility.EndPaintTexture(ctx, editorUndoString); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { Vector2 uv = editContext.uv; //grab the starting position & height if (Event.current.shift) { //m_Height = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y; float height = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y; m_StartPoint = new Vector3(uv.x, uv.y, height); m_StartTerrain = terrain; return(true); } if (!m_StartTerrain || (Event.current.type == EventType.MouseDrag)) { return(true); } //get the target position & height float targetHeight = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y; Vector3 targetPos = new Vector3(uv.x, uv.y, targetHeight); if (terrain != m_StartTerrain) { //figure out the stroke vector in uv,height space Vector2 targetWorld = transformToWorld(terrain, uv); Vector2 targetUVs = transformToUVSpace(m_StartTerrain, targetWorld); targetPos.x = targetUVs.x; targetPos.y = targetUVs.y; } Vector3 stroke = targetPos - m_StartPoint; float strokeLength = stroke.magnitude; int numSplats = (int)(strokeLength / (0.001f * m_Spacing)); Terrain currTerrain = m_StartTerrain; Material mat = TerrainPaintUtility.GetBuiltinPaintMaterial(); Vector2 posOffset = new Vector2(0.0f, 0.0f); for (int i = 0; i < numSplats; i++) { float pct = (float)i / (float)numSplats; float widthScale = widthProfile.Evaluate(pct); float heightScale = heightProfile.Evaluate(pct); float strengthScale = strengthProfile.Evaluate(pct); Vector3 currPos = m_StartPoint + pct * stroke; currPos.x += posOffset.x; currPos.y += posOffset.y; if (currPos.x >= 1.0f && (currTerrain.rightNeighbor != null)) { currTerrain = currTerrain.rightNeighbor; currPos.x -= 1.0f; posOffset.x -= 1.0f; } if (currPos.x <= 0.0f && (currTerrain.leftNeighbor != null)) { currTerrain = currTerrain.leftNeighbor; currPos.x += 1.0f; posOffset.x += 1.0f; } if (currPos.y >= 1.0f && (currTerrain.topNeighbor != null)) { currTerrain = currTerrain.topNeighbor; currPos.y -= 1.0f; posOffset.y -= 1.0f; } if (currPos.y <= 0.0f && (currTerrain.bottomNeighbor != null)) { currTerrain = currTerrain.bottomNeighbor; currPos.y += 1.0f; posOffset.y += 1.0f; } Vector2 currUV = new Vector2(currPos.x, currPos.y); int finalBrushSize = (int)(widthScale * (float)editContext.brushSize); float finalHeight = (m_StartPoint + heightScale * stroke).z; Rect brushRect = TerrainPaintUtility.CalculateBrushRectInTerrainUnits(currTerrain, currUV, finalBrushSize); TerrainPaintUtility.PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(currTerrain, brushRect); Vector4 brushParams = new Vector4(strengthScale * editContext.brushStrength * 0.01f, 0.5f * finalHeight, 0.0f, editContext.brushRotation); mat.SetTexture("_BrushTex", editContext.brushTexture); mat.SetVector("_BrushParams", brushParams); Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 2); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Bridge"); } return(false); }