I am interested in converting an arbitrary 3D position computed at run time in the fragment shader to its corresponding UV coordinates. Notice that the 3D position I am interested in is NOT a 3D vertex present in the VBO, but an arbitrary 3D location that may lay somewhere inside one of the triangles of the mesh.

What is the best way to perform this 3D to UV mapping? I am thinking of looking at the vertices of the face where the 3D point is, and interpolate its UV coordinates using the distance between the 3D point and the 3D vertices as a weights, but I have a feeling I may be overthinking this problem.

Ideally, I want to do it in a GLSL fragment shader. Does any body have any suggestion, example code, or better idea to solve this problem?

  • \$\begingroup\$ For how many points do you want to do that? Just a few? \$\endgroup\$ – dsilva.vinicius Mar 17 '14 at 19:21
  • \$\begingroup\$ @dsilva.vinicius for each fragment... \$\endgroup\$ – Dan Mar 18 '14 at 8:41
  • \$\begingroup\$ Why? The way you stated it is a bit too generalized as there is only a valid UV parameter on the surface of your meshes. You might have to scan all your polygons with distance functions, and then project onto the nearest one and solve for the barycentric coordinates. (If you truly mean "arbitrary" positions and have nothing else to make it easier, my hunch though it that this is an XY problem question) \$\endgroup\$ – MickLH Mar 18 '14 at 14:57

Do you know which triangle the point is in, and do you have access to the vertex data for that triangle (namely positions and UVs)? If so, this is a fairly simple problem, and is doable in the fragment shader on powerful enough hardware (it's going to be too math-heavy for mobile devices, most likely).

If you don't know which triangle to use, you have to figure that out first - which makes the problem a lot more complicated, and probably not something you can reasonably do in a fragment shader if there are more than a handful of triangles.

However, assuming you know which triangle you're in, here's how you'd do it. I won't write out the code explicitly, assuming you can fill in the details yourself.

  1. Find the barycentric coordinates of the point, with respect to the triangle. These are essentially distances to each edge, but remapped to the [0, 1] range so that the coordinate is 1 at the edge and 0 at the opposing vertex. You can do it by calculating the plane equation for a plane perpendicular to the edge (use the cross product of the triangle's normal with the edge vector), then calculate the point's distance from that plane, then scale and remap it based on the opposing vertex's distance from the plane. Do this for each edge.

  2. Use the barycentric coordinates to interpolate the vertex UVs. This takes the form of

    finalUV = UV0*bary0 + UV1*bary1 + UV2*bary2

    where UV0, UV1, UV2 are the vertex UVs and bary0, bary1, bary2 are the barycentric coordinates for each vertex (derived from the distance to the opposing edge as seen in step 1).

  • \$\begingroup\$ Thanks Nathan! I actually found a very similar question/answer here. In the current implementation I can't access to the triangles in the fragment shader, however I think I can work it out by manually passing the VBO arrays and using gl_VerteixID to figure out which vertex is being proceeded. I am not too sure how to do it, but will give it a think. Do you think it is possible? \$\endgroup\$ – Dan Mar 18 '14 at 9:29

Your problem seems trivial, so maybe I'm missing something.

As you say that you want to compute the UVs for each fragment, I'm assuming that you are interested in the UVs of the fragment itself.

Are you assigning UVs to your vertices or are computing them procedurally?

In the first case, you will need to assign the UVs of each vertex in a varying variable. The hardware will automatically interpolate it's value for each fragment based on its barycentric coordinates and the interpolation mode. In the latter case, calculate the UVs in the vertex shader and assign the result to a varying variable in order to receive an interpolated value again in the fragment shader.

  • \$\begingroup\$ You are missing something. I want to do the operation the other way around! Having a 3D position (not vertex!) I want to get its UV coordinates. Have a look at Nathan's answer, he is quite right. \$\endgroup\$ – Dan Mar 18 '14 at 9:50

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.