- Home /
WorldToViewportPoint and ViewportToWorldPoint math
I'm having a hard time recreating the exact transformation using just the camera projection and view matrices. I've tried various approaches, using both the camera projection and the GL camera projection.
If everything works right, these two variables, _result and result, should match:
static Vector3 worldToViewportPoint(Vector3 point3D) {
Matrix4x4 P = GL.GetGPUProjectionMatrix(Camera.main.projectionMatrix, false);
Matrix4x4 V = Camera.main.transform.worldToLocalMatrix;
Matrix4x4 VP = P * V;
var result = VP.MultiplyPoint(point3D);
var _result = Camera.main.WorldToViewportPoint(point3D);
return _result;
}
Similarly, I need to calculate the ViewportToWorldPoint, which I imagine I would solve if the method above had the correct matrices. The reason we need this is for a computer vision library running beneath unity using linear algebra.
Answer by victorbisaev · Jan 28, 2018 at 08:51 PM
Try this:
static Vector3 worldToViewportPoint(Vector3 point3D)
{
Matrix4x4 P = Camera.main.projectionMatrix;
Matrix4x4 V = Camera.main.transform.worldToLocalMatrix;
Matrix4x4 VP = P * V;
Vector4 point4 = new Vector4(point3D.x, point3D.y, point3D.z, 1.0f); // turn into (x,y,z,1)
Vector4 result4 = VP * point4; // multiply 4 components
Vector3 result = result4; // store 3 components of the resulting 4 components
// normalize by "-w"
result /= -result4.w;
// clip space => view space
result.x = result.x / 2 + 0.5f;
result.y = result.y / 2 + 0.5f;
// "The z position is in world units from the camera."
result.z = -result4.w;
var _result = Camera.main.WorldToViewportPoint(point3D);
// result == _result
return _result;
}
The idea is to use 4-components matrix operations as V and P are of "Matrix4x4" type. Also please notice regular matrix multiplication "VP * point4" instead of "VP.MultiplyPoint(point3D)"
Answer by joel_cambrian · Jan 28, 2018 at 11:48 PM
@victorbisaev That worked perfectly, thank you. Now for the opposite, view to world point.
I reversed the clip space/view space and am still off. I assume its the denormalization part I'm missing.
static Vector3 viewportToWorldPoint(Vector3 point2D) {
Matrix4x4 P = Camera.main.projectionMatrix;
Matrix4x4 V = Camera.main.transform.worldToLocalMatrix;
Matrix4x4 VP = P * V;
Vector3 point2DCopy = point2D;
// view space => clip space
point2DCopy.x = 2.0f * (point2DCopy.x - 0.5f);
point2DCopy.y = 2.0f * (point2DCopy.y - 0.5f);
Vector4 point4 = new Vector4(point2DCopy.x, point2DCopy.y, point2DCopy.z, 1.0f); // turn into (x,y,z,1)
Vector4 result4 = VP.inverse * point4; // multiply 4 components
Vector3 result = result4; // store 3 components of the resulting 4 components
var _result = Camera.main.ViewportToWorldPoint(point2D);
return _result;
}
First, it needs to figure out should "point2D" be of "Vector2" type? Or of "Vector3" type then what is "Z" in this case for a screen point?
I am placing the winz parameter, or distance, in the z of point2D.
static Vector3 viewportToWorldPoint(Vector3 point3D)
{
$$anonymous$$atrix4x4 P = Camera.main.projection$$anonymous$$atrix;
$$anonymous$$atrix4x4 V = Camera.main.transform.worldToLocal$$anonymous$$atrix;
$$anonymous$$atrix4x4 VP = P * V;
// get projection W by Z
Vector4 projW = P * new Vector4(0, 0, point3D.z, 1);
// restore point4
Vector4 point4 = new Vector4( 1.0f - (point3D.x * 2.0f) , 1.0f - (point3D.y * 2.0f) , projW.z/projW.w , 1);
Vector4 result4 = VP.inverse * point4; // multiply 4 components
Vector3 resultInv = result4 / result4.w; // store 3 components of the resulting 4 components
var _resultInv = Camera.main.ViewportToWorldPoint(point3D);
//resultInv == _resultInv
return _resultInv;
}
Your answer
Follow this Question
Related Questions
undrestanding WorldToScreenPoint and ViewportToWorldPoint 1 Answer
How to get the 2d Poisition (in camera) of the mesh vertices 3 Answers
ViewportToWorldPoint causing object to move 1 Answer
WorldToViewportPoint problem 0 Answers
How to modify the unity camera so that it renders like a GoPro camera 1 Answer