Aquarium like camera

Hey there,


for a project I want to create a fishtank, that is as big as the screen it is displayed on. I mean scaling the playarea, like making it as wide and tall as the screen is, without rescaling the other objects. The fish should be always be around the same size.


As I want the Fish to be 3D and move in 3D space i can’t use an orthographic camera. And I would want the fish to be able to get close to the “glass” anywhere on the screen without getting too much distortion. The problem is, that through the pyramid shaped frustum of the perspective camera, fish closer to the screen just vanish when they get out of the frustum even though, they didn’t leave the screen on the horizontal axis, when i make the camera too wide.

Is there any smart way to setup my camera?


Thank you!

Unity - Manual: The Size of the Frustum at a Given Distance from the Camera

With a little bit of tweaking and adjusting, you can ensure that the closest walls (i.e. left/right/top/bottom) of the tank hit right at the edges of the screen at a specific distance. From there, you’ll have depth beginning at your choice of distance from the camera.

With that in mind, you would be able to position boundaries at each corner relative to the screen.


As an example of this:
// C#
// For a script attached to the main camera

// These Transforms (ideally, unit cubes) are named
// based on the idea of looking in
// from the missing side
public Transform leftWall;
public Transform rightWall;
public Transform floor;
public Transform ceiling;
public Transform backWall;

public float tankDepth = 5.0f;
public float distanceToTank = 10.0f;

// Based on a unit cube (1x1x1)
public float wallThickness = 1.0f;

void Start()
{
	// camera parameters
	Camera cam = GetComponent<Camera>();
	Vector3 camPos = transform.position;
	Vector3 up = transform.up;
	Vector3 forward = transform.forward;
	Vector3 right = transform.right;
	
	// Camera frustum information, based on
	// Distance To (Fish) Tank
	float frustumHeight = 2.0f * distanceToTank * Mathf.Tan(cam.fieldOfView * 0.5f * Mathf.Deg2Rad);
	float frustumWidth = frustumHeight * cam.aspect;
	
	// Sizing keys for sides
	float wallDepth = distanceToTank + (tankDepth * 0.5f);
	float halfThickness = wallThickness * 0.5f;
	float doubleThickness = wallThickness * 2.0f;
	float halfHeight = frustumHeight * 0.5f;
	float halfWidth = frustumWidth * 0.5f;
	
	// ceiling and floor are extended beyond the
	// frustum width to include the width of
	// the left and right sides
	ceiling.position = camPos + (up * (halfHeight * halfThickness)) + (forward * wallDepth);
	ceiling.localScale = new Vector3(frustumWidth + doubleThickness, wallThickness, tankDepth);
	ceiling.rotation = transform.rotation;
	
	floor.position = camPos - (up * (halfHeight * halfThickness)) + (forward * wallDepth);
	floor.localScale = new Vector3(frustumWidth + doubleThickness, wallThickness, tankDepth);
	floor.rotation = transform.rotation;
	
	rightWall.position = camPos + (right * (halfWidth + halfThickness)) + (forward * wallDepth);
	rightWall.localScale = new Vector3(wallThickness, frustumHeight, tankDepth);
	rightWall.rotation = transform.rotation;
	
	leftWall.position = camPos - (right * (halfWidth + halfThickness)) + (forward * wallDepth);
	leftWall.localScale = new Vector3(wallThickness, frustumHeight, tankDepth);
	leftWall.rotation = transform.rotation;
	
	// the back wall will extend to fit everything
	// else for convenience in this example
	backWall.position = camPos + (forward * (distance + tankDepth + halfThickness));
	backWall.localScale = new Vector3(frustumWidth + doubleThickness, frustumHeight + doubleThickness, wallThickness);
	backWall.rotation = transform.rotation;
}

With this setup, all you have to tweak are the tankDepth and distanceToTank values and the tank will resize itself accordingly.

Edit: Fixed some formatting