- Home /
Why can I not affect terrain height?
Hey folks. So, I'm trying to learn how to change aspects of Terrain objects in realtime. I've followed [advice][1] from [around][2] the [net][3], but the best information I found came from [this excellent package][4] by @Eric5h5.
I'm temporarily adapting this to work directly with a raycast from the camera, cutting out all the bomb code and just making some magic craters in the terrain...
...or so I intended. In fact, when I click on the terrain, absolutely nothing happens. No terrain changes, and no error messages.
Code follows: using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PointerV2 : MonoBehaviour
{
#region PointerFields
private Camera cam;
private Transform pointObject;
private Transform hitObject;
private Terrain terrain;
public float rayLength = 128.0f;
public LayerMask rayMask; // Set to 'Everything'
#endregion
#region TerraformFields
[Header("Terraform Fields")]
public Texture2D crater; // Alpha channel is used for the shape of the crater
public float craterDepth = 0.5f; // Values of less than 1 make crater shallower, with 0 having no effect on the terrain
private TerrainData terrainData;
private Color[] craterData;
#endregion
#region Methods
private void Awake()
{
cam = GetComponent<Camera>();
}
// Use this for initialization
void Start()
{
hitObject = GameObject.Find("HitObject").GetComponent<Transform>();
pointObject = GameObject.Find("PointObject").GetComponent<Transform>();
terrain = GameObject.Find("Terrain").GetComponent<Terrain>();
terrainData = terrain.terrainData;
craterData = crater.GetPixels();
for (int i = 0; i < craterData.Length; i++)
{
craterData[i].a *= craterDepth;
}
}
// Update is called once per frame
void Update()
{
Ray screenRay = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit rayHit;
if (Physics.Raycast(screenRay, out rayHit, rayLength, rayMask, QueryTriggerInteraction.Collide))
{
Debug.DrawLine(screenRay.origin, rayHit.point, Color.cyan);
}
if (rayHit.transform)
{
if (rayHit.transform.CompareTag("Terrain"))
{
// Set position of purple sphere
pointObject.position = rayHit.point;
if (Input.GetMouseButtonDown(0))
{
Crater(rayHit.point.x, rayHit.point.z);
}
}
}
}
void Crater(float hitX, float hitZ)
{
// Get heightmap coordinates from hit point
int x = (int)Mathf.Lerp(0, terrainData.heightmapWidth, Mathf.InverseLerp(0, terrainData.size.x, hitX));
int z = (int)Mathf.Lerp(0, terrainData.heightmapHeight, Mathf.InverseLerp(0, terrainData.size.z, hitZ));
// Make sure crater area stays within bounds of heightmap
x = Mathf.Clamp(x, crater.width / 2, terrainData.heightmapWidth - crater.width / 2);
z = Mathf.Clamp(z, crater.height / 2, terrainData.heightmapHeight - crater.height / 2);
// Get terrain heightmap data from area surrounding hit point
var tData = terrainData.GetHeights(x - crater.width / 2, z - crater.height / 2, crater.width, crater.height);
// Subtract crater from heightmap data
for (int i = 0; i < crater.height; i++)
{
for (int j = 0; j < crater.width; j++)
{
Debug.Log("Writing crater data to tData");
tData[i, j] = tData[i, j] - craterData[i * crater.width + j].a; // Can't do "tData -= craterData[]"; generates error
// tData[i,j] -= craterData[i * crater.width + j].a;
}
}
// Write modified heightmap data back to the terrain
terrainData.SetHeights(x - crater.width / 2, z - crater.height / 2, tData);
}
#endregion
}
I'm very new to the process of changing maps during play, and I have great hopes for how I can build shaders to take advantage of these methods. First, though, I need to make some craters...!
Any help, greatly appreciated!
--Rev [1]: https://answers.unity.com/questions/285816/change-terrain-texture-and-tree-at-runtime.html?sort=oldest [2]: https://answers.unity.com/questions/1341730/get-terrain-location-at-raycast-point.html [3]: https://answers.unity.com/questions/9248/how-to-translate-world-coordinates-to-terrain-coor.html [4]: https://forum.unity.com/threads/can-you-realtime-terraform-inside-a-unity-game.10611/#post-75260