- Home /
Scale box collider to camera view?
I've searched thoroughly for a solution I can understand, but can't seem to figure out how to scale the x/y of a cube (collider) to match that of my camera view at runtime. I'm trying to create a trigger boundary that can scale dynamically depending on the device resolution and aspect ratio. Specifically, when an object leaves the screen, destroy it, bring it back, etc. I have this system working now but the trigger is not connected to the screen size or aspect ratio.
Not sure if I should be using ViewportToScreenPoint, WorldToViewportPoint, Frustum or something else. Any help is appreciated!
Here's what I have now which doesn't work correctly (the cube collider is made tiny at runtime.)
Code
var pos : Vector3 = camera.main.WorldToViewportPoint (transform.position);
transform.localScale.x = pos.x;
transform.localScale.y = pos.y;
Answer by AlucardJay · Aug 08, 2013 at 07:37 AM
The below script will draw debug lines at points on the camera view frustum. From these points you can determine the size and scale for a box collider. You could also use these points to generate a mesh collider.
In a new scene, attach this script to the camera :
#pragma strict
var theCamera : Camera;
var upperDistance : float = 8.5;
var lowerDistance : float = 12.0;
private var tx : Transform;
function Start()
{
if ( !theCamera )
{
theCamera = Camera.main;
}
tx = theCamera.transform;
}
function Update()
{
FindUpperCorners();
FindLowerCorners();
}
function FindUpperCorners()
{
var corners : Vector3[] = GetCorners( upperDistance );
// for debugging
Debug.DrawLine( corners[0], corners[1], Color.yellow ); // UpperLeft -> UpperRight
Debug.DrawLine( corners[1], corners[3], Color.yellow ); // UpperRight -> LowerRight
Debug.DrawLine( corners[3], corners[2], Color.yellow ); // LowerRight -> LowerLeft
Debug.DrawLine( corners[2], corners[0], Color.yellow ); // LowerLeft -> UpperLeft
}
function FindLowerCorners()
{
var corners : Vector3[] = GetCorners( lowerDistance );
// for debugging
Debug.DrawLine( corners[0], corners[1], Color.red );
Debug.DrawLine( corners[1], corners[3], Color.red );
Debug.DrawLine( corners[3], corners[2], Color.red );
Debug.DrawLine( corners[2], corners[0], Color.red );
}
function GetCorners( distance : float ) : Vector3[]
{
var corners : Vector3[] = new Vector3[ 4 ];
var halfFOV : float = ( theCamera.fieldOfView * 0.5 ) * Mathf.Deg2Rad;
var aspect : float = theCamera.aspect;
var height : float = distance * Mathf.Tan( halfFOV );
var width : float = height * aspect;
// UpperLeft
corners[ 0 ] = tx.position - ( tx.right * width );
corners[ 0 ] += tx.up * height;
corners[ 0 ] += tx.forward * distance;
// UpperRight
corners[ 1 ] = tx.position + ( tx.right * width );
corners[ 1 ] += tx.up * height;
corners[ 1 ] += tx.forward * distance;
// LowerLeft
corners[ 2 ] = tx.position - ( tx.right * width );
corners[ 2 ] -= tx.up * height;
corners[ 2 ] += tx.forward * distance;
// LowerRight
corners[ 3 ] = tx.position + ( tx.right * width );
corners[ 3 ] -= tx.up * height;
corners[ 3 ] += tx.forward * distance;
return corners;
}
I found this approach to be a little inaccurate, so I ended up writing the following:
/// <summary>
/// Gets the corners.
/// </summary>
/// <param name="camera">Camera.</param>
/// <param name="distance">Distance.</param>
/// <param name="corners">Corners.</param>
public static void GetCorners(Camera camera, float distance, ref Vector3[] corners)
{
Array.Resize(ref corners, 4);
// Top left
corners[0] = camera.ViewportToWorldPoint(new Vector3(0, 1, distance));
// Top right
corners[1] = camera.ViewportToWorldPoint(new Vector3(1, 1, distance));
// Bottom left
corners[2] = camera.ViewportToWorldPoint(new Vector3(0, 0, distance));
// Bottom right
corners[3] = camera.ViewportToWorldPoint(new Vector3(1, 0, distance));
}
Answer by cdrandin · Aug 07, 2013 at 02:52 AM
You cannot use a box collider to make a collider to fit the shape of the camera view, assuming perspective so it has a frustum shape to it.
The way to do it is if you want poor collider shape just use the box, if you want to make it more to the actual view, you will need to make the frustum yourself and use a mesh collider.
http://en.wikipedia.org/wiki/File:Square_frustum.png
Shouldn't be hard at all, just make a cube in blender, extrude the top to a point and scale the base vertices and stretch it length wise.
I don't know if Unity has this model, but you could do some searching. They only provide basic primitives.
I think a box collider will work fine as all the movement takes place on only the X and Y axis. No depth, therefore the actual shape isn't terribly important I just need the width and height of it to match the view/screen size.
O$$anonymous$$, to match the size of your screen may be not worth the trouble because it all depends on your view and a slight change will make your collider not fit how you want it to. I would say the closes you can do is to run your game and to view both the in game and inspector view and just play around with the size and position of the collider. Like I said, a slight change and the collider won't match. Because you can increase or decrease the FoV, etc. Unless you are doing an orthogonal view, then it will be easy. But you can not map screen coordinate to world coordinates so easily since there bounds are different.
The FOV and position of the camera are fixed and never move. The gameplay takes place within its bounds.