Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Prodedural mesh and UV mapping perspective

Discussion in 'Scripting' started by PMerlaud, Sep 6, 2018.

  1. PMerlaud

    PMerlaud

    Joined:
    Apr 9, 2013
    Posts:
    64
    I'm creating a procedural mesh using this function:
    Code (CSharp):
    1. public void CreatePlane(List<Vector3> points)
    2.     {
    3.         meshPoints = points;
    4.  
    5.         var zValue = points[0].z;
    6.  
    7.         vertices2D = new Vector2[points.Count];
    8.  
    9.         for (int i = 0; i < points.Count; i++)
    10.         {
    11.             vertices2D[i] = new Vector2(points[i].x, points[i].y);
    12.         }
    13.  
    14.         Triangulator tr = new Triangulator(vertices2D);
    15.         int[] indices = tr.Triangulate();
    16.  
    17.         Vector3[] vertices = new Vector3[vertices2D.Length];
    18.         for (int i = 0; i < vertices.Length; i++)
    19.         {
    20.             vertices[i] = new Vector3(vertices2D[i].x, vertices2D[i].y, zValue);
    21.         }
    22.  
    23.         Vector2[] uvs = new Vector2[vertices2D.Length];
    24.         for (var i = 0; i < vertices2D.Length; i++)
    25.         {
    26.             uvs[i] = new Vector2(vertices2D[i].x, vertices2D[i].y);
    27.         }
    28.  
    29.         // Create the mesh
    30.         var mesh = new Mesh();
    31.         mesh.vertices = vertices;
    32.         mesh.triangles = indices;
    33.         mesh.uv = uvs;
    34.         mesh.RecalculateNormals();
    35.         mesh.RecalculateBounds();
    36.  
    37.         // Set up game objects with mesh;
    38.         var planeMesh = new GameObject("Plane");
    39.         var planeRenderer = planeMesh.AddComponent(typeof(MeshRenderer)) as MeshRenderer;
    40.         planeRenderer.material = Resources.Load<Material>("New Material");
    41.         var planeFilter = planeMesh.AddComponent(typeof(MeshFilter)) as MeshFilter;
    42.         planeFilter.mesh = mesh;
    43.     }
    The Triangulator.cs class can be found here.

    The resulting mesh is displayed like this:
    Capture d’écran 2018-09-06 à 09.37.48.png

    As you can see, the UV mapping works, but the texture faces the camera and doesn't match the perspective of the wall I'm trying to recreate.

    Do you have any idea how I should calculate the UVs so the texture is displayed with a correct perspective ?
     
  2. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,077
    In this line:

    Code (CSharp):
    1. vertices[i] = new Vector3(vertices2D[i].x, vertices2D[i].y, zValue);
    You're using the same z value for all the points so it'll end up being flat (without perspective). Judging by the code I would have thought you would have to do:

    Code (CSharp):
    1. vertices[i] = new Vector3(vertices2D[i].x, vertices2D[i].y, points[i].z);
     
  3. PMerlaud

    PMerlaud

    Joined:
    Apr 9, 2013
    Posts:
    64
    Well all the points of my mesh are on the same plane. I create them like so:
    Code (CSharp):
    1. private List<Vector3> positions = new List<Vector3>();
    2.  
    3.     private void Update()
    4.     {
    5.         if (Input.GetMouseButtonUp(0))
    6.         {
    7.             var mousePos = Input.mousePosition;
    8.             mousePos.z = Camera.main.nearClipPlane;
    9.  
    10.             var pos = Camera.main.ScreenToWorldPoint(mousePos);
    11.             positions.Add(pos);
    12.         }
    13.  
    14.         if (Input.GetKeyUp(KeyCode.A))
    15.         {
    16.             CreatePlane(positions);
    17.         }
    18.     }
    That's why I'm using the same z value for all of them.
     
  4. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,077
    Ah, ok - that'll be the issue then. Screen to world point will give a flat projection (because a single screen point can have infinitely different number of world points). What you would want to do is cast a ray from the screen to find the world point that it hits - that would give you the correct Z value and stop you getting that flat projection effect.

    e.g.
    Code (CSharp):
    1. public class ExampleScript : MonoBehaviour {
    2.     public Camera camera;
    3.  
    4.     void Start(){
    5.         RaycastHit hit;
    6.         Ray ray = camera.ScreenPointToRay(Input.mousePosition);
    7.      
    8.         if (Physics.Raycast(ray, out hit)) {
    9.             Transform objectHit = hit.transform;
    10. Vector3 objectHitPoint = hit.point;
    11.          
    12.             // Do something with the object that was hit by the raycast.
    13.         }
    14.     }
    15. }
    https://docs.unity3d.com/Manual/CameraRays.html
     
  5. PMerlaud

    PMerlaud

    Joined:
    Apr 9, 2013
    Posts:
    64
    But the house you see in the background isn't acutally a 3D model, it's just an image. That's why I'm using Camera.ScreenToWorldPoint, with the z value being the near clip plane. I can't use raycast in this case.

    I tried to make a simpler shape and set the UV myself but it gives me a very weird mapping :
    Code (CSharp):
    1. Vector2[] uvs = new Vector2[vertices2D.Length];
    2. uvs[0] = new Vector2(0, 0);
    3. uvs[1] = new Vector2(1, 0);
    4. uvs[2] = new Vector2(0, 1);
    5. uvs[3] = new Vector2(1, 1);
    Capture d’écran 2018-09-06 à 14.03.39.png
     
  6. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,077
    In that case I can't see any easy way to do that - you would need to know the field of view of the original camera to determine the correct perspective to use etc... Maybe someone else can think of an easy way to do that?

    The reason you're getting that weird mapping is because you're doing what the original playstation used to do - non perspective correct texture mapping. To get it to look correct you need to have Z values for each of the corners otherwise you'll get that weird warping effect.

    For example, here's some affine mapping (same Z value for each corner) and perspective correct mapping:

    https://upload.wikimedia.org/wikipedia/commons/5/57/Perspective_correct_texture_mapping.jpg