RaycastHit.textureCoord --- does the reverse exist?

I have a texture that’s mapped to an object. I’m currently using RaycastHit.textureCoord to collect the UV coordinate based on a point on the in-world object, which is great.

However, I’m stuck finding the reverse.

That is to say… I have an image (world map) that’s textured to a sphere. I’d like a way to click a point on the original 2D texture and see where that uv is mapped to the sphere (x,y,z)

I’m going to guess and say this is difficult because a single uv coordinate/pixel could be covering an area on the 3D object, but I still hoped there was a way to return a point list, or even a bounding area on a surface where the points lie.

It's of course a bit of work but possible ;)

First you have to find the triangle in which the point is located. So first you just need only the uv coordinates of all triangles and do a in-triangle test of the 2d coordinates. If you have the triangle you can calculate the barycentric coordinate of the point inside the triangle and now you simply can use the batycentric coordinate with the world-vector positions to get the world position.

I don't have the time for a full example at the moment, but most of the needed things can be found on this site ;)

edit

Just searched for this old answer where i put an barycentric calculation routine up;

All you need to do is go through all triangles, calculate the barycentric coordinat of your point, check if the point is inside the current triangle and use the barycentric coordinates to get the world position.

Keep in mind that more than one or none of the triangles could be mapped to a certain area of the texture. The function will return an array of mapped position in localspace. The array can contain none, one or multiple points in the meshs localspace that is mapped to the given uv coordinate.

// C#
using UnityEngine;
using System.Collections.Generic;


public static class MeshExtention
{
    public static Vector3 GetBarycentric (Vector2 v1,Vector2 v2,Vector2 v3,Vector2 p)
    {
        Vector3 B = new Vector3();
        B.x = ((v2.y - v3.y)*(p.x-v3.x) + (v3.x - v2.x)*(p.y - v3.y)) /
            ((v2.y-v3.y)*(v1.x-v3.x) + (v3.x-v2.x)*(v1.y -v3.y));
        B.y = ((v3.y - v1.y)*(p.x-v3.x) + (v1.x - v3.x)*(p.y - v3.y)) /
            ((v3.y-v1.y)*(v2.x-v3.x) + (v1.x-v3.x)*(v2.y -v3.y));
        B.z = 1 - B.x - B.y;
        return B;
    }

    public static bool InTriangle(Vector3 barycentric)
    {
        return (barycentric.x >= 0.0f) && (barycentric.x <= 1.0f)
            && (barycentric.y >= 0.0f) && (barycentric.y <= 1.0f)
            && (barycentric.z >= 0.0f); //(barycentric.z <= 1.0f)
    }

    public static Vector3[] GetMappedPoints(this Mesh aMesh, Vector2 aUVPos)
    {
        List<Vector3> result = new List<Vector3>();
        Vector3[] verts = aMesh.vertices;
        Vector2[] uvs = aMesh.uv;
        int[] indices = aMesh.triangles;
        for(int i = 0; i < indices.Length; i += 3)
        {
            int i1 = indices[i  ];
            int i2 = indices[i+1];
            int i3 = indices[i+2];
            Vector3 bary = GetBarycentric(uvs[i1],uvs[i2],uvs[i3],aUVPos);
            if (InTriangle(bary))
            {
                Vector3 localP = bary.x * verts[i1] + bary.y * verts[i2] + bary.z * verts[i3];
                result.Add(localP);
            }
        }
        return result.ToArray();
    }
}

This is an extention method i've just wrote for Unity's Mesh class. Just put this static class into your "Standard Assets" folder and you can use it like this:

// C#
Vector3[] mappedPoints = myMesh.GetMappedPoints(uvPos);

// UnityScript (Javascript)
var mappedPoints = myMesh.GetMappedPoints(uvPos);

I've tested it with Unity's default sphere / cube mesh and like expected on the sphere i get one point on the surface and on the cube six since every side of the cube is mapped to the whole texture.

If you need more information of a position, e.g. the normal vector or triangle index, you can modify the function to return an array of struct (maybe just use the RaycastHit structure) to be able to return more data per point.

ps. Keep in mind that the returned Vectors are in local space. Use transform.TransformPoint() to bring the positions into worldspace if you need to.

Good luck

I never thought about that, so this is total improvisation.
You could create an array of uv points sorted in a clever way, that will allow you to find the closest point when you hit the 2D thing, and that would give you the 3D position of the corresponding vertice (more likely, a triangle). No idea what that’s worth, but I guess you’d rather have more answer than not enough !