Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've got a script that makes a terrain object and paints it with textures, but I'm having an issue. When I attempt to place game objects (such as the simple water object that unity provides), I use a Raycast to determine the correct height to place the game object, but that just ensures that it is correctly placed at that particular point.

How would I go about flattening the terrain under the game object so that it doesn't go into the terrain or hang out into thin air in the case of hills?

share|improve this question
3  
Find all the vertices that form the terrain triangles under the game object. Make the y coordinate of all those vertices the same. –  Byte56 Jul 3 '13 at 22:24
add comment

2 Answers

As I said in my comment, you'll want to find all the vertices that make up the triangles under your game object and set their y value to the same value.

I'll expand my comment with more detailed steps. I'm not too familiar with Unity, so I don't know the best tools to use for the job, but I believe I can get you started down the right path.

Brute force method:

  1. Cast a grid of rays straight down from your game object. The grid should be tight enough to ensure it won't miss any triangles on the terrain surface.
  2. For each ray that hits something, you can get the triangle in the terrain mesh with the following:

    RaycastHit hit;
    if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
        return;
    
    MeshCollider meshCollider = hit.collider as MeshCollider;
    if (meshCollider == null || meshCollider.sharedMesh == null)
        return;
    
    Mesh mesh = meshCollider.sharedMesh;
    Vector3[] vertices = mesh.vertices;
    int[] triangles = mesh.triangles;
    Vector3 p0 = vertices[triangles[hit.triangleIndex * 3 + 0]];
    Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
    Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
    
  3. p0, p1 and p2 are all the positions of the three vertices that make up the triangle that's been hit. You want to adjust each of those vertices positions to have the same y value. You can either collect all the vertices, then set them all to an average y value, or you can use the initial picked y value you found when placing your game object.

Optimizations:

  • Instead of just casting a grid of rays, you can sweep a collider down from the game object and collect the contact points of the collisions between the game object collider and the terrain collision mesh. Then for each of those contact points, perform the steps above for getting the vertices you want to move.

  • Create your terrain in such a way that each vertex's x and z values are aligned to a grid, and only varies in its y value. Now you can easily get the bounds of your game object and change all the y values of the vertices within those bounds.

That last optimization is really an alternative method that would likely be easy to implement and fairly effective.

share|improve this answer
    
From what I can tell the Terrain (docs.unity3d.com/Documentation/ScriptReference/Terrain.html) object has a TerrainCollider (docs.unity3d.com/Documentation/ScriptReference/…) not a MeshCollider (docs.unity3d.com/Documentation/ScriptReference/…), so it lacks a sharedMesh property that you attempt to use in step 2. I assumed I would need some sort of logic to modify the height map that the terrainData property stores. –  Rapida Jul 13 '13 at 19:28
    
You might check here: forum.unity3d.com/threads/… Also, it seems as though the terrain object has a regular mesh, so the second optimaization may be your best bet. –  Byte56 Jul 13 '13 at 19:35
add comment

Its typically want the ground under the object to be flat and the ground immediately around it to be smoothed.

If the land is made from a grid and the building is axis-aligned, this is much easier.

In the general case, you subdivide triangles the building sits on, and then set the y of all the vertices on the triangles the building sits on to the same y, and then do a midpoint displacement smoothing for all vertices within a certain distance which are not themselves under a building.

I have used this approach to put roads onto a 3D terrain.

You typically want to enforce a minimum separation between buildings in order to have enough land to smooth. Or you might run the algorithm provisionally before placement and see if some threshold of steepness is exceeded and so policing where the user can place buildings.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.