Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only. On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live. Read our full announcement for more information and let us know if you have any questions.

Question Get vertices of a face using Raycast?

Discussion in 'Scripting' started by TheGameNewBie, Sep 18, 2020.

  1. TheGameNewBie

    TheGameNewBie

    Joined:
    Jul 27, 2017
    Posts:
    92
    I'm trying to make an in-game Terrain editor.
    The Terrain is not the Unity terrain, it's a plane modified via Noise.
    What I want to do is shoot a ray cast from the center of the screen and get the face at which it collides with the terrain and then move that face downwards.
    I can't seem to get the vertices of the face from the ray cast. I know about RaycastHit.triangleIndex
    But how do I get the four vertices of a face from it?
    Any help?
     
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,606
    Usually for your use-case you dont want to edit the mesh itself. That's just overcomplicating things. Instead edit the underlying data structure (presumably a 2D array of some kind) in which you saved your noise values. Then edit the noise values, and regenerate the mesh for that chunk / terrain tile.

    Other than that, RaycastHit returns you the triangleindex that was hit. In just about all real-life cases you wont actually hit a vertex directly. You could then either move down all vertices that make up that triangle or calculate the closest vertex to the actual hit coordinate and only move that. The results, however, will be underwhelming compared to what i suggested above.
     
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,261
    You get the 3 vertices of the triangle that was hit by doing:

    Code (CSharp):
    1. int v0Index = hit.triangleIndex*3 + 0;
    2. int v1Index = hit.triangleIndex*3 + 1;
    3. int v2Index = hit.triangleIndex*3 + 2;
    Note that a mesh has to be a triangle mesh since your raycast does not hit the rendered mesh, but the MeshCollider. A "face" isn't really a quad but individual triangles. If you want to operate on "quads" you have to determine the 4th vertex yourself. However like Yoreki said it wouldn't make much sense to edit a single triangle or quad. It would make more sense to modify the vertices "around" the point you've hit. Since your plane is most likely a regular grid you can easily determine which vertex indices are around the 3 indices you have found. Editing a mesh is usually done by moving the height values up or down depending on the distance from the hit point so you get a smooth transition.

    In a regular grid you get the x neighbor indices by adding or subtracting 1. You get the y neighbor indices by adding or subtracting the grid width. Of course the width means the vertex count in the x direction, not the triangle or quad count.
     
    Chmyke likes this.
  4. TheGameNewBie

    TheGameNewBie

    Joined:
    Jul 27, 2017
    Posts:
    92
    I think I know what you mean but just in case, Can you elaborate?

    I was intending to do the following:
    Get the indices of the four vertices that the raycast hits.
    I know the mesh is made of Triangles, the difficult part for me is How to get the fourth vertex correct. (That's what I was asking)
    After getting the Indices, change the respective vertices in the 'mesh.vertices' array of the mesh and then reassign the mesh.

    That's what I couldn't figure out. Can you point me in the right direction?

    I tried doing this.
    For e.g.
    The grid is 10 x 10 faces (11 x 11 verts)
    and the triangles are,
    Code (CSharp):
    1. 0, 11, 1
    2. 1, 11, 12
    3. 1, 12, 2
    4. 2, 12, 13
    The raycast gets the third triangle (1, 12, 2). So, then I want the vertex in the fourth triangle (2, 12, 13). This is where I'm stuck. It sometimes gets the right vertex, sometimes gets the wrong one. I'm failing to program the right logic here.

    Correct me If I'm wrong, but wouldn't that be the same as the process I mentioned above? You'll have to regenerate the mesh in both ways?
     
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,261
    Well, there are several ways how you can determine what the fourth vertex is. Since it's a grid the easiest solution is to look at the indices relative to each other. This could require several alignment checks. Though generally once you have the 3 indices you can determine if two vertices are adjacent on a cardinal direction or if they represent the diagonal of a quad. Once you figured that out you know which vertex is the corner opposite to the diagonal. So it's only a matter to either +1 / -1 and +width / -width to get the fourth vertex.

    You can get the x coordinate by taking the modulo of an index by width. You get the y coordinate by dividing the index by width.

    Code (CSharp):
    1. int x = index % width;
    2. int y = index / width;
    Of course for a quad you need 4 vertices that are relative to each other (0,0), (+1,0), (0,+1), (+1,+1). You just need to figure out which one is missing from the 3 you already have.
     
  6. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,606
    Yes and no. It depends a bit on what you intend to do, and what the result is supposed to be. I was thinking along the lines of increasing / decreasing terrain height at some location. Similar to what the old tycoon games did to create holes or mountains. Editing the underlying data and reconstructing the mesh at least guarantees you that the edits look uniform to the rest of your world.
    Custom mesh modifications on the other hand can offer more freedom - but mesh alteration is a highly advanced topic, and it's quite easy for the resulting changes to look unnatural. So yeah, if you want to manually increase or decrease terrain height at some location, alter the data. If your goal is something else, alter the mesh.