libra
libra

Reputation: 683

Unity3d, Focus Cam in a rect using project matrix.

So i'm working on this project, that require my camera to view and only view a rect area. So no matter how the camera moves, user can never see outside of the box. I attached this image below to explain my words. aa I went through the Unity Camera API but didn't find anything useful, any suggestions would be appreciated.

Edit: Turns out focus camera in a rect using projection matrix is a physically more accurate way of doing so, but i can't figure out how.

Upvotes: 0

Views: 552

Answers (1)

libra
libra

Reputation: 683

Thanks to Samy Bencherif for providing the Resource.

The code here have a similar feature that should do the job, I will do more digging into it and post a more complete solution once I got time.

http://wiki.unity3d.com/index.php/MirrorReflection4

Edit

I found my solution here. By hpJohn in Unity Forum:

public Transform[] Corners;
public Transform lookTarget;
public bool drawNearCone, drawFrustum;

Camera theCam;

void Start () {
    theCam = camera;
}

void Update () {
    Vector3 pa, pb, pc, pd;
    pa = Corners[0].position; //Bottom-Left
    pb = Corners[1].position; //Bottom-Right
    pc = Corners[2].position; //Top-Left
    pd = Corners[3].position; //Top-Right

    Vector3 pe = theCam.transform.position;// eye position

    Vector3 vr = ( pb - pa ).normalized; // right axis of screen
    Vector3 vu = ( pc - pa ).normalized; // up axis of screen
    Vector3 vn = Vector3.Cross( vr, vu ).normalized; // normal vector of screen

    Vector3 va = pa - pe; // from pe to pa
    Vector3 vb = pb - pe; // from pe to pb
    Vector3 vc = pc - pe; // from pe to pc
    Vector3 vd = pd - pe; // from pe to pd

    float n = -lookTarget.InverseTransformPoint( theCam.transform.position ).z; // distance to the near clip plane (screen)
    float f = theCam.farClipPlane; // distance of far clipping plane
    float d = Vector3.Dot( va, vn ); // distance from eye to screen
    float l = Vector3.Dot( vr, va ) * n / d; // distance to left screen edge from the 'center'
    float r = Vector3.Dot( vr, vb ) * n / d; // distance to right screen edge from 'center'
    float b = Vector3.Dot( vu, va ) * n / d; // distance to bottom screen edge from 'center'
    float t = Vector3.Dot( vu, vc ) * n / d; // distance to top screen edge from 'center'

    Matrix4x4 p = new Matrix4x4(); // Projection matrix
    p[0, 0] = 2.0f * n / ( r - l );
    p[0, 2] = ( r + l ) / ( r - l );
    p[1, 1] = 2.0f * n / ( t - b );
    p[1, 2] = ( t + b ) / ( t - b );
    p[2, 2] = ( f + n ) / ( n - f );
    p[2, 3] = 2.0f * f * n / ( n - f );
    p[3, 2] = -1.0f;

    theCam.projectionMatrix = p; // Assign matrix to camera

    if ( drawNearCone ) { //Draw lines from the camera to the corners f the screen
        Debug.DrawRay( theCam.transform.position, va, Color.blue );
        Debug.DrawRay( theCam.transform.position, vb, Color.blue );
        Debug.DrawRay( theCam.transform.position, vc, Color.blue );
        Debug.DrawRay( theCam.transform.position, vd, Color.blue );
    }

    if ( drawFrustum ) DrawFrustum( theCam ); //Draw actual camera frustum

}

Vector3 ThreePlaneIntersection ( Plane p1, Plane p2, Plane p3 ) { //get the intersection point of 3 planes
    return ( ( -p1.distance * Vector3.Cross( p2.normal, p3.normal ) ) +
            ( -p2.distance * Vector3.Cross( p3.normal, p1.normal ) ) +
            ( -p3.distance * Vector3.Cross( p1.normal, p2.normal ) ) ) /
        ( Vector3.Dot( p1.normal, Vector3.Cross( p2.normal, p3.normal ) ) );
}

void DrawFrustum ( Camera cam ) {
    Vector3[] nearCorners = new Vector3[4]; //Approx'd nearplane corners
    Vector3[] farCorners = new Vector3[4]; //Approx'd farplane corners
    Plane[] camPlanes = GeometryUtility.CalculateFrustumPlanes( cam ); //get planes from matrix
    Plane temp = camPlanes[1]; camPlanes[1] = camPlanes[2]; camPlanes[2] = temp; //swap [1] and [2] so the order is better for the loop

    for ( int i = 0; i < 4; i++ ) {
        nearCorners[i] = ThreePlaneIntersection( camPlanes[4], camPlanes[i], camPlanes[( i + 1 ) % 4] ); //near corners on the created projection matrix
        farCorners[i] = ThreePlaneIntersection( camPlanes[5], camPlanes[i], camPlanes[( i + 1 ) % 4] ); //far corners on the created projection matrix
    }

    for ( int i = 0; i < 4; i++ ) {
        Debug.DrawLine( nearCorners[i], nearCorners[( i + 1 ) % 4], Color.red, Time.deltaTime, false ); //near corners on the created projection matrix
        Debug.DrawLine( farCorners[i], farCorners[( i + 1 ) % 4], Color.red, Time.deltaTime, false ); //far corners on the created projection matrix
        Debug.DrawLine( nearCorners[i], farCorners[i], Color.red, Time.deltaTime, false ); //sides of the created projection matrix
    }
}

Upvotes: 1

Related Questions