2
\$\begingroup\$

I want to create a road through a c# script in Unity. I created a mesh like this. mesh

The "vertetices" first adds the left and then the right points. Then set the UV the same order and value as "vertetices". Then I got the following result. Figure 1 is the effect I generated, and Figure 2 is the effect I want. result

The road may be less regular, such as a turning situation, but my texture is square, how do I need to display the texture properly?

using UnityEngine;
using System.Collections;
public class MeshHelper
{
    // Use this for initialization
    void Start()
    {
    }
    // Update is called once per frame
    void Update()
    {
    }
    /*
     * 
     */
    private Vector3[] CreateVertices(Vector2[] leftBoundary, Vector2[] rightBoundary)
    {
        int index = 0;
        Vector3[] vertices = new Vector3[leftBoundary.Length + rightBoundary.Length];
        foreach (Vector2 coor in leftBoundary)
        {
            vertices[index] = new Vector3(coor.x, coor.y, 0.0f);
            index++;
        }
        foreach (Vector2 coor in rightBoundary)
        {
            vertices[index] = new Vector3(coor.x, coor.y, 0.0f);
            index++;
        }
        return vertices;
    }
    private Vector2[] CreateUV(Vector2[] leftBoundary, Vector2[] rightBoundary)
    {
        int index = 0;
        Vector2[] vertices = new Vector2[leftBoundary.Length + rightBoundary.Length];
        foreach (Vector2 coor in leftBoundary)
        {
            vertices[index] = new Vector2(coor.x, coor.y);
            index++;
        }
        foreach (Vector2 coor in rightBoundary)
        {
            vertices[index] = new Vector2(coor.x, coor.y);
            index++;
        }
        return vertices;
    }
    private int[] CreateTriangles(Vector2[] leftBoundary, Vector2[] rightBoundary)
    {
        if (leftBoundary.Length == 0 || rightBoundary.Length == 0)
        {
            return null;
        }
        int minLength = leftBoundary.Length > rightBoundary.Length ? rightBoundary.Length : leftBoundary.Length;
        int index = 0;
        int[] triangles = new int[3 * (leftBoundary.Length + rightBoundary.Length)];
        /*
         * Add the tran
         */
        for (int i = 0; i < minLength - 1; i++)
        {
            triangles[index] = i;
            triangles[index + 1] = i + 1;
            triangles[index + 2] = leftBoundary.Length + i;
            triangles[index + 3] = i + 1;
            triangles[index + 4] = leftBoundary.Length + i + 1;
            triangles[index + 5] = leftBoundary.Length + i;
            index += 6;
        }
        /*
         * Add the res tran
         * 
         */
        if (leftBoundary.Length > rightBoundary.Length)
        {
            for (int i = 0; i < leftBoundary.Length - rightBoundary.Length; i++)
            {
                triangles[index] = rightBoundary.Length - 1 + i;
                triangles[index + 1] = rightBoundary.Length + i;
                triangles[index + 2] = leftBoundary.Length + rightBoundary.Length - 1;
                index += 3;
            }
        }
        else
        {
            for (int i = 0; i < rightBoundary.Length - leftBoundary.Length; i++)
            {
                triangles[index] = leftBoundary.Length - 1;
                triangles[index + 1] = 2 * leftBoundary.Length + i;
                triangles[index + 2] = 2 * leftBoundary.Length + i - 1;
                index += 3;
            }
        }
        return triangles;
    }

    /*
     * All road is quadrilateral 
     * 
     */
    public Mesh GetMesh()
    {
        HDMap.Boundary boundary = HDMap._instance.GetHDMap();
        // TODO: How to get uv ?
        Mesh mesh = new Mesh
        {
            vertices = CreateVertices(boundary.left, boundary.right),
            uv = CreateUV(boundary.left, boundary.right),
            triangles = CreateTriangles(boundary.left, boundary.right)
        };
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();
        return mesh;
    }
}

The coordinates are as follows

public class HDMap : MonoBehaviour
{
    public static HDMap _instance;
    public void Awake()
    {
        _instance = this;
    }
    public class Boundary
    {
        public Vector2[] left;
        public Vector2[] right;
    }
    public Boundary GetHDMap()
    {
        Vector2[] left ={
            new Vector2(0.0f,0.0f),
            new Vector2(0.1937856264412403f,0.049468484707176685f),
            new Vector2(0.3875712528824806f,0.09893696941435337f),
            new Vector2(0.5813568793237209f,0.14840545412153006f),
        }

        Vector2[] right={
            new Vector2(-0.8656984844710678f,3.391248462256044f),
            new Vector2(-0.6718908273614943f,3.4407225707545877f),
            new Vector2(-0.47808317036833614f,3.4901966797187924f),
            new Vector2(-0.28427551325876266f,3.539670788217336f),
        }
        Boundary boundary = new Boundary();
        boundary.left = left;
        boundary.right = right;
}
\$\endgroup\$
  • \$\begingroup\$ Can you show us the code which generates the vertex coordinates and then assignes UV coordinates to the vertices? \$\endgroup\$ – Philipp Jun 28 at 8:01
  • \$\begingroup\$ @Philipp Add the code, I can't see the picture, I don't know if it is a network problem. You can see the pic bleow answers.unity.com/questions/1644237/… \$\endgroup\$ – dahohu527 Jun 28 at 8:21
3
\$\begingroup\$

You are setting the UV coordinates to exactly the same coordinates as the vertices. That means when you move a vertex, the texture doesn't move. It always stays perfectly aligned with the world grid. What you actually want is for the texture to stretch and skew so that it always fills the whole road polygon.

So what you need to do is set the UV coordinates of every road square to a full texture ranging from (0, 0) to (1, 1). Looking at the first sketch you posted in the question, the UV coordinates of the first road segment should be:

1: (0, 1)
2: (0, 0)
7: (1, 0)
6: (1, 1)

Then the texture should repeat in the second segment of the road:

2: (0, 1)
3: (0, 0)
8: (1, 0)
7: (1, 1)
\$\endgroup\$
  • \$\begingroup\$ Thx, It works. Another question is that if one side has more points than the other side, the texture looks like an error. Can I merge the extra points into a triangle instead of a lot of triangles?Such vertices and UV numbers may not be right. \$\endgroup\$ – dahohu527 Jun 28 at 9:09
  • \$\begingroup\$ @dahohu527 What do you mean with "the texture looks like an error"? I also wonder how your road generation algorithm can even work at all when the two sides of the road have an unequal numbers of vertices. When this is the result of your input dataset just being that way, then you might want to consider to interpolate additional vertices on the other side to make them equal again. \$\endgroup\$ – Philipp Jun 28 at 9:12
  • \$\begingroup\$ Or is your problem that the road segments have different lengths, so the texture sometimes looks stretched or compressed in the vertical direction? In that case you might want to have the x-axis of the UVs always go from 0 to 1, but make the y-axis dependent on the actual length of the road. \$\endgroup\$ – Philipp Jun 28 at 9:17
  • \$\begingroup\$ Yes, if the two sides are not equal, I will take a smaller side first, so that the points on the two sides are equal and the texture is correct. In the rest, I connected the extra point to the end of the other side into a number of triangles. The texture of this part is wrong. I think you are right. I may need the points on the 2 sides to be as consistent as possible. I seem to have to rethink about it. \$\endgroup\$ – dahohu527 Jun 28 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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