开发者

Mapping a 3D rectangle to a 2D screen

开发者 https://www.devze.com 2023-02-27 21:28 出处:网络
I\'ve searched SO but I just can\'t figure this out. The other questions didn\'t help or I didn\'t understand them.

I've searched SO but I just can't figure this out. The other questions didn't help or I didn't understand them.

The problem is, I have a bunch of points in a 3D image. The points are for a rectangle, which doesn't look like a rectangle from the 3d camera's view because of perspective. The task is to map the points from that rectangl开发者_运维技巧e to the screen. I've seen some ways which some call "quad to quad transformations" but most of them are for mapping a 2d quadrilateral to another one. But I've got the X, Y and Z coordinates of the rectangle in the real world so I'm looking for some easier ways. Does anyone know any practical algorithm or method of doing this?

If it helps, my 3d camera is actually a Kinect device with OpenNI and NITE middlewares, and I'm using WPF.

Thanks in advance.

edit: I also found the 3d-projection page on Wikipedia that used angles and cosines but that seems to be a difficult way (finding angles in the 3d image) and I'm not sure if it's the real solution or not.


You might want to check out projection matrices

That's how any 3D rasterizer "flattens" 3D volumes on a 2D screen.


See this code to get the projection matrix for a given WPF camera:

private static Matrix3D GetProjectionMatrix(OrthographicCamera camera, double aspectRatio)
{ 
    // This math is identical to what you find documented for
    // D3DXMatrixOrthoRH with the exception that in WPF only
    // the camera's width is specified.  Height is calculated
    // from width and the aspect ratio.
    double w = camera.Width;
    double h = w / aspectRatio;
    double zn = camera.NearPlaneDistance;
    double zf = camera.FarPlaneDistance;
    double m33 = 1 / (zn - zf);
    double m43 = zn * m33;
    return new Matrix3D(
        2 / w, 0, 0, 0,
        0, 2 / h, 0, 0,
        0, 0, m33, 0,
        0, 0, m43, 1);
}

private static Matrix3D GetProjectionMatrix(PerspectiveCamera camera, double aspectRatio)
{ 
    // This math is identical to what you find documented for
    // D3DXMatrixPerspectiveFovRH with the exception that in
    // WPF the camera's horizontal rather the vertical
    // field-of-view is specified.
    double hFoV = MathUtils.DegreesToRadians(camera.FieldOfView);
    double zn = camera.NearPlaneDistance;
    double zf = camera.FarPlaneDistance;
    double xScale = 1 / Math.Tan(hFoV / 2);
    double yScale = aspectRatio * xScale;
    double m33 = (zf == double.PositiveInfinity) ? -1 : (zf / (zn - zf));
    double m43 = zn * m33;
    return new Matrix3D(
        xScale, 0, 0, 0,
        0, yScale, 0, 0,
        0, 0, m33, -1,
        0, 0, m43, 0);
}

/// <summary>
///     Computes the effective projection matrix for the given
///     camera.
/// </summary>
public static Matrix3D GetProjectionMatrix(Camera camera, double aspectRatio)
{
    if (camera == null)
    {
        throw new ArgumentNullException("camera");
    }
    PerspectiveCamera perspectiveCamera = camera as PerspectiveCamera;
    if (perspectiveCamera != null)
    {
        return GetProjectionMatrix(perspectiveCamera, aspectRatio);
    }
    OrthographicCamera orthographicCamera = camera as OrthographicCamera;
    if (orthographicCamera != null)
    {
        return GetProjectionMatrix(orthographicCamera, aspectRatio);
    }
    MatrixCamera matrixCamera = camera as MatrixCamera;
    if (matrixCamera != null)
    {
        return matrixCamera.ProjectionMatrix;
    }
    throw new ArgumentException(String.Format("Unsupported camera type '{0}'.", camera.GetType().FullName), "camera");
}


You could do a basic orthographic projection (I'm thinking in terms of raytracing, so this might not apply to what you're doing):

Mapping a 3D rectangle to a 2D screen

The code is quite intuitive:

for y in image.height:
  for x in image.width:
    ray = new Ray(x, 0, z, Vector(0, 1, 0)) # Pointing forward
    intersection = prism.intersection(ray) # Since you aren't shading, you can check only for intersections.

    image.setPixel(x, y, intersection) # Returns black and white image of prism mapped to plane

You just shoot vectors with a direction of (0, 1, 0) directly out into space and record which ones hit.


I found this. Uses straight forward mathematics instead of matricies.

This is called perspective projection to convert from a 3D vertex to a 2D screen vertex. I used this to help me with my 3D program I have made.

HorizontalFactor = ScreenWidth / Tan(PI / 4)
VerticalFactor = ScreenHeight / Tan(PI / 4)

ScreenX = ((X * HorizontalFactor) / Y) + HalfWidth
ScreenY = ((Z * VerticalFactor) / Y) + HalfHeight

Hope this could help. I think its what you where looking for. Sorry about the formatting (new here)


Mapping points in a 3d world to a 2d screen is part of the job of frameworks like OpenGL and Direct3d. It's called Rasterisation like Heandel said. Perhaps you could use Direct3d?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号