126 lines
7.5 KiB
Markdown
126 lines
7.5 KiB
Markdown
|
# Modify the Terrain heightmap
|
||
|
|
||
|
The example code below tells Unity to use the built-in painting Material to modify the Terrain's heightmap, and render a Brush preview in the Scene view.
|
||
|
|
||
|
```
|
||
|
using UnityEngine;
|
||
|
using UnityEditor;
|
||
|
using UnityEditor.TerrainTools;
|
||
|
|
||
|
class CustomTerrainTool : TerrainPaintToolWithOverlays<CustomTerrainTool>
|
||
|
{
|
||
|
private float m_BrushOpacity = 1f;
|
||
|
private float m_BrushSize = 25f;
|
||
|
private float m_BrushRotation = 0f;
|
||
|
|
||
|
// Name of the Terrain Tool. This appears in the tool UI.
|
||
|
public override string GetName()
|
||
|
{
|
||
|
return "Examples/Custom Terrain Tool";
|
||
|
}
|
||
|
|
||
|
// Description for the Terrain Tool. This appears in the tool UI.
|
||
|
public override string GetDescription()
|
||
|
{
|
||
|
return "This is a custom Terrain Tool that modifies the Terrain heightmap.";
|
||
|
}
|
||
|
|
||
|
// Override this function to add UI elements to the tool settings
|
||
|
public override void OnToolSettingsGUI(Terrain terrain, IOnInspectorGUI editContext)
|
||
|
{
|
||
|
m_BrushOpacity = EditorGUILayout.Slider("Opacity", m_BrushOpacity, 0, 1);
|
||
|
m_BrushSize = EditorGUILayout.Slider("Size", m_BrushSize, .001f, 100f);
|
||
|
m_BrushRotation = EditorGUILayout.Slider("Rotation", m_BrushRotation, 0, 360);
|
||
|
}
|
||
|
|
||
|
// Override this function to add UI elements to the inspector UI. If the UI is the same between the Inspector
|
||
|
// and Tool Settings overlay, you can call one from the other.
|
||
|
public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext)
|
||
|
{
|
||
|
OnToolSettingsGUI(terrain, editContext);
|
||
|
}
|
||
|
|
||
|
// Ease of use function for rendering modified Terrain Texture data into a PaintContext. This is used in both OnRenderBrushPreview and OnPaint.
|
||
|
private void RenderIntoPaintContext(UnityEngine.TerrainTools.PaintContext paintContext, Texture brushTexture, UnityEngine.TerrainTools.BrushTransform brushXform)
|
||
|
{
|
||
|
// Get the built-in painting Material reference
|
||
|
Material mat = UnityEngine.TerrainTools.TerrainPaintUtility.GetBuiltinPaintMaterial();
|
||
|
// Bind the current brush texture
|
||
|
mat.SetTexture("_BrushTex", brushTexture);
|
||
|
// Bind the tool-specific shader properties
|
||
|
var opacity = Event.current.control ? -m_BrushOpacity : m_BrushOpacity;
|
||
|
mat.SetVector("_BrushParams", new Vector4(opacity, 0.0f, 0.0f, 0.0f));
|
||
|
// Setup the material for reading from/writing into the PaintContext texture data. This is a necessary step to setup the correct shader properties for appropriately transforming UVs and sampling textures within the shader
|
||
|
UnityEngine.TerrainTools.TerrainPaintUtility.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat);
|
||
|
// Render into the PaintContext's destinationRenderTexture using the built-in painting Material - the id for the Raise/Lower pass is 0.
|
||
|
Graphics.Blit(paintContext.sourceRenderTexture, paintContext.destinationRenderTexture, mat, 0);
|
||
|
}
|
||
|
|
||
|
// Render Tool previews in the SceneView
|
||
|
public override void OnRenderBrushPreview(Terrain terrain, IOnSceneGUI editContext)
|
||
|
{
|
||
|
// Dont render preview if this isnt a Repaint
|
||
|
if (Event.current.type != EventType.Repaint) return;
|
||
|
|
||
|
// Only do the rest if user mouse hits valid terrain
|
||
|
if (!editContext.hitValidTerrain) return;
|
||
|
|
||
|
// Get the current BrushTransform under the mouse position relative to the Terrain
|
||
|
UnityEngine.TerrainTools.BrushTransform brushXform = UnityEngine.TerrainTools.TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.raycastHit.textureCoord, m_BrushSize, m_BrushRotation);
|
||
|
// Get the PaintContext for the current BrushTransform. This has a sourceRenderTexture from which to read existing Terrain texture data.
|
||
|
UnityEngine.TerrainTools.PaintContext paintContext = UnityEngine.TerrainTools.TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1);
|
||
|
// Get the built-in Material for rendering Brush Previews
|
||
|
Material previewMaterial = TerrainPaintUtilityEditor.GetDefaultBrushPreviewMaterial();
|
||
|
// Render the brush preview for the sourceRenderTexture. This will show up as a projected brush mesh rendered on top of the Terrain
|
||
|
TerrainPaintUtilityEditor.DrawBrushPreview(paintContext, TerrainBrushPreviewMode.SourceRenderTexture, editContext.brushTexture, brushXform, previewMaterial, 0);
|
||
|
// Render changes into the PaintContext destinationRenderTexture
|
||
|
RenderIntoPaintContext(paintContext, editContext.brushTexture, brushXform);
|
||
|
// Restore old render target.
|
||
|
RenderTexture.active = paintContext.oldRenderTexture;
|
||
|
// Bind the sourceRenderTexture to the preview Material. This is used to compute deltas in height
|
||
|
previewMaterial.SetTexture("_HeightmapOrig", paintContext.sourceRenderTexture);
|
||
|
// Render a procedural mesh displaying the delta/displacement in height from the source Terrain texture data. When modifying Terrain height, this shows how much the next paint operation will alter the Terrain height
|
||
|
TerrainPaintUtilityEditor.DrawBrushPreview(paintContext, TerrainBrushPreviewMode.DestinationRenderTexture, editContext.brushTexture, brushXform, previewMaterial, 1);
|
||
|
// Cleanup resources
|
||
|
UnityEngine.TerrainTools.TerrainPaintUtility.ReleaseContextResources(paintContext);
|
||
|
}
|
||
|
|
||
|
// Perform painting operations that modify the Terrain texture data
|
||
|
public override bool OnPaint(Terrain terrain, IOnPaint editContext)
|
||
|
{
|
||
|
// Get the current BrushTransform under the mouse position relative to the Terrain
|
||
|
UnityEngine.TerrainTools.BrushTransform brushXform = UnityEngine.TerrainTools.TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv, m_BrushSize, m_BrushRotation);
|
||
|
// Get the PaintContext for the current BrushTransform. This has a sourceRenderTexture from which to read existing Terrain texture data
|
||
|
// and a destinationRenderTexture into which to write new Terrain texture data
|
||
|
UnityEngine.TerrainTools.PaintContext paintContext = UnityEngine.TerrainTools.TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds());
|
||
|
// Call the common rendering function used by OnRenderBrushPreview and OnPaint
|
||
|
RenderIntoPaintContext(paintContext, editContext.brushTexture, brushXform);
|
||
|
// Commit the modified PaintContext with a provided string for tracking Undo operations. This function handles Undo and resource cleanup for you
|
||
|
UnityEngine.TerrainTools.TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Raise or Lower Height");
|
||
|
|
||
|
// Return whether or not Trees and Details should be hidden while painting with this Terrain Tool
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Return true for this property to display the brush attributes overlay
|
||
|
public override bool HasBrushAttributes => true;
|
||
|
|
||
|
// Return true for this property to display the brush selector overlay
|
||
|
public override bool HasBrushMask => true;
|
||
|
|
||
|
// Return true for this property to display the tool settings overlay
|
||
|
public override bool HasToolSettings => true;
|
||
|
|
||
|
// File names of the light theme icons - prepend d_ to the file name to generate dark theme variants.
|
||
|
// Override these to specify your own icon.
|
||
|
// public override string OnIcon => "Assets/Icon_on.png";
|
||
|
// public override string OffIcon => "Assets/Icon_off.png";
|
||
|
|
||
|
// The toolbar category the icon appears under.
|
||
|
public override TerrainCategory Category => TerrainCategory.CustomBrushes;
|
||
|
|
||
|
// Where in the icon list the icon appears.
|
||
|
public override int IconIndex => 100;
|
||
|
}
|
||
|
```
|