Getting UV coordinates from a plane
-
I have the coordinates of the vertexes P1, P2, P3 and P4 that define a rectangular rectangle.
Those coordinates always define a regular rectangular area and the distortion of the plane defined by those coordinates, in the image above, is only due to perspective.
I have those coordinates (P1, P2, P3 and P4) in world-space.
I also have the coordinates of a point C, in world-space, that is not in the plane defined by P1, P2, P3 and P4 but is somewhere between the camera location and the plane defined by P1, P2, P3 and P4.I already have a way to calculate if, seen from the camera, C is inside the boundary defined by P1, P2, P3 and P4, by converting all the coordinates from world to screen-space and checking if the screen-space point C is inside the screen-space triangle P1 - P2 - P3 or triangle P1 - P3 - P4.
So, if P1, P2, P3 and P4 always define a regular rectangle and if C in inside the area defined by P1, P2, P3 and P4 as they are seen from the camera, how can I calculate the uniform coordinates from 0,0 (at P2, for example) to 1,1 (at P4, for example) of the point C, if it was projected to the plane defined by P1, P2, P3 and P4?
I mean, in the example image, I would need to get a result of around 0.8, 0.45 for the location of point C.If the point C screen projection was correspondent to the screen location of point P2, I should get 0,0
If the point C screen projection was correspondent to the screen location of point P1, I should get 1,0
If the point C screen projection was correspondent to the screen location of point P3, I should get 0,1
If the point C screen projection was correspondent to the screen location of point P4, I should get 1,1Basically, I need to calculate the uniform coordinates from 0,0 to 1,1 inside a single regular plane that can be distorted in the view/render due to perspective, of the projection of a point that is between the camera and that plane, onto that plane. However, I don't have the plane as an object, I just have its vertex coordinates.
I hope I explained it all clearly enough.
Can anyone help? Thank you so much. -
Ok, I guess I managed to get a way to obtain UV coordinates from a screen space set of coordinates, using barycentric calculations.
Lets see if I can make it work for the rest of the project. -
I managed to solve this by calculating the barycentric coordinates of the two triangles that form the quadrilateral shape. So, I can check if the point is inside the rectangle and also derive the uv coordinates from the calculated u,v and w components of the barycentric coordinates.
def get_uvs(pw1,pw2,pw3,pw4): # quadrilateral is defined by pw1,pw2,pw3 and pw4 2d vectors, in screen-space vv = 1.0/(2*area(pw1,pw2,pw3)) * (pw1.y*pw3.x - pw1.x*pw3.y + (pw3.y-pw1.y) * p_uv.x + (pw1.x-pw3.x)*p_uv.y) ww = 1.0/(2*area(pw1,pw2,pw3)) * (pw1.x*pw2.y - pw1.y*pw2.x + (pw1.y-pw2.y) * p_uv.x + (pw2.x-pw1.x)*p_uv.y) uu = 1.0 - vv - ww if uu>0 and vv>0 and ww>0: return uu,ww vv = 1.0/(2*area(pw3,pw4,pw1)) * (pw3.y*pw1.x - pw3.x*pw1.y + (pw1.y-pw3.y) * p_uv.x + (pw3.x-pw1.x)*p_uv.y) ww = 1.0/(2*area(pw3,pw4,pw1)) * (pw3.x*pw4.y - pw3.y*pw4.x + (pw3.y-pw4.y) * p_uv.x + (pw4.x-pw3.x)*p_uv.y) uu = 1.0 - vv - ww if uu>0 and vv>0 and ww>0: return = 1.0-uu,1.0-ww return -1,-1 # return negative results if not inside quadrilateral #--------------------------------------------------------- def area(p0, p1, p2): return 0.5*(-p1.y*p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y)+ p1.x*p2.y)
-
Hey @rui_mac,
thank you for reaching out to us. This topic has been assigned to @i_mazlov. I just wanted to stop you there in your tracks. Cinema 4D does not use plain barycentric coordinates but weighted
s, t
coordinates. The interface for that is in a bit weird place in Python, in the hair library. You can check out this thread or wait for Ilia's answer.But you are very likely in a rabbit hole with what you are doing there (did not read all your code, just saw all the barycentric coordinate number pushing).
Cheers,
Ferdinand -
Thank you for the replay, Ferdinand.
By "weighted s, t coordinates" you mean that distribution of the u,v coordinates is not uniform along the quadrilateral?
This project will only work with single face quadrilaterals. I mean, it will always be a regular rectangle and the only distortion it will get is "perspective distortion". In that case, I can use simple barycentric calculations, right? -
Hey @rui_mac,
please wait for Ilia's answer or just help yourself with my old thread there. I cannot take this thread over, I just wanted to make sure that you do not waste time on a route which is a dead end. And no, you cannot use barycentric coordinates as long as you want to match what Cinema does, as it does not use (plain) barycentric coordinates.
Cheers,
Ferdinand -
Hi @rui_mac,
I have to point out that your question is generally out of scope of our support according to the Support Procedures due to being plainly algorithmic question.
I think Ferdinand implicitly assumes you switching from raw trigonometry to using our built-in functions for handling barycentric coordinates, namely GetPolyPointST() in Python and CalculatePolygonPointST() in C++. Of course he's not 100% correct saying that "you can not use barycentric coordinates" You can use them, if you like, but this would require you to implement everything yourself (the way you tried in your code). However, this approach is prone to errors and would only fit as an educational project.
In case you just need to have thinks working, it's recommended to use the functionality that we already have, namely the above mentioned functions. The way they work differs from the conventional definition of the barycentric coordinates (which operate with linear combination of vertices of your object. Wiki for more info: Barycentric coordinates). The difference is in the coordinates space: conventional definition uses vectors from the point C to your vertices Pi, while our implementation uses base vectors of your quad - <P2P3, P2P1> according to your image. This is the reason why they are named differently.
With that's said, I invite you to explore yourself the thread: Discussion on Methods for Calculating the Inner Points of a Quadrilateral, which hopefully answers your questions regarding the GetPolyPointST() function usage. You can particularly check the scene I shared in one of the answers here.
If I understand your initial question right, the only difference you need to account for (comparing to the scene from the thread) is to define points in the GetPolyPointST() function call in the screen space rather than world space (these will effectively turn them into 2D coordinates).
Cheers,
Ilia -
@i_mazlov
Thank you so much, Ilia.
I would never expect to find those function inside the HairLibrary. I performed a search inside the SDK for "barycenter" or "bary" and I only got some stuff about RayCollider and VolumeData. I guess the GetPolyPointST function will be fine and faster than my calculation.
The s and t roughly correspond to the u and v coordinates? -
Hey @rui_mac,
no, they do not match the uvw coordinates. They are weights, please have look at the example I have linked to above, it likely does everything you need.
GetPolyPointST
expects a value in local object coordinates and returns weights for the polygon UVW coordinates. You get then your final coordinate by the bilinear interpolation of the UVW quad over the s,t weights. You can of course technically replicate all the math yourself, but as Ilia has pointed out this would be out of scope of support.Cheers,
Ferdinand