abritary uv coord to screen space coord

If I have a triangle on screen, and I know each vertex position in screen space, and each vertex uv coordinate, how would I then create a formula that could take an abritary uv coordinate, and place it on screen?

So if I for instace take the uv coordinate (0.3,0.5), how can I find that coordinates screenspace coordinate?

Simplified:

Data I have:
3 Vertex screen coordinates
3 Vertex Uv coordinates
An abritary uv coordinate (may be outside the triangle)

What I need:
The screen coordinate of the abritary uv coordinate.

I also need to be able to do the reversed action: Take an abritary screen coord (may be outside the given triangle), and translate it to uv space. Again given the above information.

UV coordinates are kind of a percentage, so you could just multiply the UV coordinate by the screen width/height (keeping in mind screen coordinates have an inverted Y axis)

Sorry, but that is not a solution. The actual triangle could be in all sorts of shapes and sizes on screen, depending on where it is seen from. And I may not even have layed out the uv’s uniformly. I need som sort of transformation matrice, based on the corospondance between the uv coordinates, and the vertices screen space coordinates.

You can do this using Physics.Raycast(). RaycastHitInfo objects contain the UV information.

Going the other way is more difficult.

You would have to cycle through all the triangles of your object, and determine whether or not your point lies within the triangle. IF you find a match (remember not every UV coordinate will actually lie within a triangle, also remember you might have multiple triangles that cover that UV coord), then you need to collect the three Vector3s that make up the triangle(s)…

Then you need to “flatten” the triangle and define the three vertices as Vector2’s on the plane defined by the triangle’s normal. Do this by rotating the triangle such that it’s normal faces up (and thus all z values are 0).Save the Quaternion that performs this rotation. (It will be Quaternion.FromTo(triangleNormal, Vector3.up))

Now you should have a “2d” triangle. and from the three vertices you can access the 3 UV points which are represented Vector2s…Next you need to create an affine transform matrix that changes the UV points into the corresponding points on the 2D triangle. Then all you have to do is transform your arbitrary UV coordinate using this matrix, which will give you the 2D coordinate on the surface of the triangle. Then you need to convert this 2D coordinate back to the 3D coordinate by rotating it with the inverse of the Quaternion you saved above…

Phew… I think that’s it. There may be a simpler method but I am not so sure. Why exactly do you need this functionality?

Ok, I solved it. Thanks for replies :slight_smile:

Solution: Downloaded a free c# matrix operation libary (needed to inverse a 3x3 matrix), and used this online post to make some function doing what I need.

It doesn’t take perspektive into account, because I don’t need it to :slight_smile: (I always have my vertex points in same depth for this use)

functions

        Vector2 TransformCoord (Matrix[] inMatrixCoefficients, Vector2 inCoords) {
		
		Vector2 outCoords = new Vector2();
		Matrix inMatrixCoefficientsX = inMatrixCoefficients[0];
		Matrix inMatrixCoefficientsY = inMatrixCoefficients[1];
		
		outCoords.x = (float)inMatrixCoefficientsX[0,0]*inCoords.x + (float)inMatrixCoefficientsX[0,1]*inCoords.y + (float)inMatrixCoefficientsX[0,2];
		outCoords.y = (float)inMatrixCoefficientsY[0,0]*inCoords.x + (float)inMatrixCoefficientsY[0,1]*inCoords.y + (float)inMatrixCoefficientsY[0,2];
		
		return outCoords;
		
	}
	
	Matrix[] MatrixCoefficients (Vector2[] coordsOne, Vector2[] coordsTwo) {
		
		Matrix[] outMatrixCoefficients = new Matrix[2];
		
		Matrix CoefficientsX = new Matrix(1,3);
		Matrix CoefficientsY = new Matrix(1,3);
		
		Matrix A = new Matrix(3,3);
		Matrix B = new Matrix(1,3);
		Matrix C = new Matrix(1,3);
		
		A[0,0] = coordsOne[0].x;
		A[0,1] = coordsOne[1].x;
		A[0,2] = coordsOne[2].x;
		
		A[1,0] = coordsOne[0].y;
		A[1,1] = coordsOne[1].y;
		A[1,2] = coordsOne[2].y;
		
		A[2,0] = 1;
		A[2,1] = 1;
		A[2,2] = 1;
		
		B[0,0] = coordsTwo[0].x;
		B[0,1] = coordsTwo[1].x;
		B[0,2] = coordsTwo[2].x;
		
		C[0,0] = coordsTwo[0].y;
		C[0,1] = coordsTwo[1].y;
		C[0,2] = coordsTwo[2].y;
		
                A = Matrix.Inverse(A);

		CoefficientsX = B * A;
		CoefficientsY = C * A;
		
		outMatrixCoefficients[0] = CoefficientsX;
		outMatrixCoefficients[1] = CoefficientsY;
		
		return outMatrixCoefficients;
	}

Then you just pass screen space position of your three vertices making up your current triangle, and the uv’s of these. This will create a matrix which transforms whatever uv of your choise into a pixel on the screen, or the other way around (if you swap what is passed as “coordsOne” and “coordsTwo”).

So, I’m sure very few will find use for this (I needed it for a very specific task, and it will be a dream to have!), but I owe the forum the solution to be written in here.

Very nice! Neat and tidy. I found that second link as well and thought it would be useful but I didn’t even realize that you could do the scree-space transformation and skip the 3d rotation altogether.

well, as a triangle doesn’t have a local space (it alone defines itself in object space), it would be impossible to determine a rotation factor of the triangle (not impossible if the triangle had the same shape, obviously, but what if the uv was laid out non uniformly with points skewed etc.?), in relation to the uv coordinates. So I knew it would be a matter of point transformations alone, and then a liniear interpolation between these. Now I just have to test my method in depth tomorrow, to see if it really works completely as needed. But it should, the method I use makes sense :slight_smile: