Comments and answers for "Find UV coordinates of mesh without a raycast"
http://answers.unity.com/questions/1105729/find-uv-coordinates-of-mesh-without-a-raycast.html
The latest comments and answers for the question "Find UV coordinates of mesh without a raycast"Comment by Bunny83 on Bunny83's comment
http://answers.unity.com/comments/1106970/view.html
Great you solved your problem. However your GetBarycentricXZ is still a 2d version. It simply ignores the y axis. $$anonymous$$y 3d version actually works in 3d as well ^^
Ins$$anonymous$$d of changing the 2d version of GetBarycentric to use x and z ins$$anonymous$$d of x and y you could have implemented an extension method of Vector3 like this:
public static class Vector3Extension
{
public static Vector2 XZ(this Vector3 aVec)
{
return new Vector2(aVec.x, aVec.z);
}
}
That way you can simply convert the component x and z of a Vector3 into a Vector2 x and y:
meshdata.Vertices[0].XZ()
Such extensions are useful in several other cases too. You can also implement other variants like: YZ, YX, ZX, ZY and even for Vector3: XZY, ZYX, ...
If you fear the cluttering of the Vector3 struct, you can place that extension class inside a namespace and only include that namespace when you need them.Thu, 03 Dec 2015 06:29:26 GMTBunny83Comment by Gelo_Man on Gelo_Man's comment
http://answers.unity.com/comments/1106923/view.html
Thanks Bunny, first time forum user here so apologies on the formatting:-).
I put all the code together and everything works perfectly. I had done it before I saw your update with the struct, but for posterity here is my method. $$anonymous$$eshData is just a class I have to store all the data used to build the procedural meshes, and GetBarycentricXZ() is just my version of your Vector3 GetBarycentric():
void UVCheck($$anonymous$$eshData meshdata)
{
Texture2D tex = meshdata.$$anonymous$$aterial.mainTexture as Texture2D; //grabs the mesh's texture
Vector3 PlayerPosBarycentric = GetBarycentricXZ(meshdata.Vertices[0], meshdata.Vertices[1], meshdata.Vertices[2], Player.player_position); //deter$$anonymous$$e the player's barycentric coordinates relative to the first triangle of the mesh
if (InTriangle(PlayerPosBarycentric) == true) //if the barycentric coordinates are inside the triangle
{
Vector2 pixelUV = (meshdata.TextureUV[0] * PlayerPosBarycentric.x + meshdata.TextureUV[1] * PlayerPosBarycentric.y + meshdata.TextureUV[2] * PlayerPosBarycentric.z); //multiply the player's barycentric coordinates by the equivalent UV vertices to get the player's position on the UV map.
Color textureColor = tex.GetPixelBilinear(pixelUV.x, pixelUV.y); //grab the color of the UV point
Debug.Log(textureColor);
return; //stop method here
}
PlayerPosBarycentric = GetBarycentricXZ(meshdata.Vertices[2], meshdata.Vertices[3], meshdata.Vertices[0], Player.player_position); //deter$$anonymous$$e the player's barycentric coordinates relative to the second triangle of the mesh
if (InTriangle(PlayerPosBarycentric) == true) //if the barycentric coordinates are inside the triangle
{
Vector2 pixelUV = (meshdata.TextureUV[2] * PlayerPosBarycentric.x + meshdata.TextureUV[3] * PlayerPosBarycentric.y + meshdata.TextureUV[0] * PlayerPosBarycentric.z); //multiply the player's barycentric coordinates by the equivalent UV vertices to get the player's position on the UV map.
Color textureColor = tex.GetPixelBilinear(pixelUV.x, pixelUV.y); //grab the color of the UV point
Debug.Log(textureColor);
return; //stop method here
}
}Thu, 03 Dec 2015 03:24:45 GMTGelo_ManComment by Bunny83 on Bunny83's comment
http://answers.unity.com/comments/1106339/view.html
1. Well, i've written the method as 2d variant since in the original question he wanted to do the reverse: Input UV cordinates, calculate the barycentric coordinates and finally calculate the worldspace coordinates. The method in it's current form only works with 2d coordinates. However since you have 2d coordinates that's not a problem. As you said just swap y and z if you use the x-z-plane. What space your coordinates are in doesn't matter as long as all coordinates are in the same space. So either convert your player position into local space and use the mesh vertices directly, or convert all vertices into world space and use the players worldspace position.
2. As mentioned you can simply swap y and z for world or local space coordinates. However barycentric coordinates always stay the same, so InTriangle will stay as it is. The x, y and z component of the baricentric coordinates have no relation to x, y and z axis. Each component belongs to a corner of your triangle. The value actually specifies the weight of that corner. The 3 components added together will always result in "1.0". If all 3 components are in the range 0 - 1 the specified point is inside the triangle.
3. Yes, you can use the barycentric coordinate to linearly interpolate any vertex parameter: position, normal, uv, tangent, color. As mentioned, each component is the weight of the corresponding corner.
It's possible to calculate the barycentric coordinates from 3d positions as long as all points are in the same plane. If i find the time i'll add a Vector3 variant. However since you only work in 2d, the 2d version requires less calculations ^^.
***edit***
ps: your post was stuck in the moderation queue. You also didn't post a comment but an answer. Answers should answer the question. All posts (questions and answers) have an "Add comment" button underneath and each comment has a reply button on top.Wed, 02 Dec 2015 04:05:44 GMTBunny83Comment by Gelo_Man on Gelo_Man's answer
http://answers.unity.com/comments/1106288/view.html
Hey Bunny83,
Thanks for the detailed answer (and for going through all that math!). I'm trying to implement your scripts and want to double-check a few things. Apologies in advance if I've misunderstood something in your explanation:
1) I just want to confirm that in GetBarycentric(), the first three inputs are the world space coordinates of the triangle vertices and the fourth input is the player's worldspace coordinates. I would run this in order to get the barycentric coordinates of the player in relation to the triangle.
2) $$anonymous$$y scene is effectively 2D but it is on the x-z plane, not the x-y plane. Will GetBarycentric() work if I modify the code to take Vector3's ins$$anonymous$$d of Vector2's (and replace the y coordinates with z coordinates)? How about InTriangle()? Would I just swap the y and z lines?
3) Just to confirm: the final formula in your explanation is simply the barycentric coordinates of the player (deter$$anonymous$$ed above) multiplied by the uv coordinates of the three vertices of the mesh triangle the player is underneath.
Thanks again.Wed, 02 Dec 2015 03:48:55 GMTGelo_ManAnswer by Bunny83
http://answers.unity.com/answers/1106003/view.html
Well, that's quite easy given your restrictions of 2d orthographic projection without rotation. The easiest way is to use barycentric coordinates. All you need [i have already posted over here][1]. Given that all your coordinates are within the same plane (just set z = 0 for all positions) you can simply use GetBarycentric() with the vertex positions of the two triangles and use InTriangle to determine in which triangle the given point is. Once you have the barycentric coordinates of your player and know the triangle you can calculate the uv coordinates by simply using
Vector2 uv = Vert1uv * bary.x + Vert2uv * bary.y +Vert3uv * bary.z;
Of course you need to use the same vertex order you used in GetBarycentric.
***edit***
Here's a 3d version of GetBarycentric:
public static Vector3 GetBarycentric(Vector3 aV1, Vector3 aV2, Vector3 aV3, Vector3 aP)
{
Vector3 a = aV2 - aV3, b = aV1 - aV3, c = aP - aV3;
float aLen = a.x * a.x + a.y * a.y + a.z * a.z;
float bLen = b.x * b.x + b.y * b.y + b.z * b.z;
float ab = a.x * b.x + a.y * b.y + a.z * b.z;
float ca = a.x * c.x + a.y * c.y + a.z * c.z;
float cb = b.x * c.x + b.y * c.y + b.z * c.z;
float d = aLen * bLen - ab * ab;
Vector3 B = new Vector3((aLen * cb - ab * ca), (bLen * ca - ab * cb)) /d;
B.z = 1.0f - B.x - B.y;
return B;
}
It's actually just a couble of dot products, however to save method / operator calls i've written those manually so it's only native float math except for a, b and c.
***second edit***
I just packed everything into a struct. That way it's more clear that barycentric coordinates are not some kind of cartesian coordinates. [I put it on the wiki][2]. The "in triangle check" is now included and can be tested with a simple property. It also has an Interpolate method which simplifies the usage a little bit. I added constructors for Vector2, Vector3 and Vector4 values as well as Color values. So you can feed a reference color and in determines the position in the triangle based on the given vertex colors. Also note Vector4 is treated like a four-dimensional vector and not like "w" normalized Vector3
[1]: http://answers.unity3d.com/answers/46816/view.html
[2]: http://wiki.unity3d.com/index.php/BarycentricTue, 01 Dec 2015 14:54:35 GMTBunny83