how to keep an object within screensize so it wont get lost?

hello everybody,

I’m trying to make an application with a friend that allows us to virtually disect an anatomical object (for example this hand model: http://i.imgur.com/evZqizu.jpg)

We are still in early progress, working on the camera movement:
Rotating/zooming is working fine, but we are struggling how to keep the model within screen edges (preferably to let it stop moving at the screen edges so it will be impossible to get lost).

We are using camera movement for the dragging/panning of the model, using this script:

var moveSpeed : float = 0.1;
static var main: Camera;

function start()
{
}
function Update () 
{	
		
     	if (Input.GetMouseButton(1)) {
       	 	transform.Translate(Vector3.right * -Input.GetAxis("Mouse X") * moveSpeed);
        	transform.Translate(transform.up * -Input.GetAxis("Mouse Y") * moveSpeed, Space.World);
    		transform.position = new Vector3(
    		Mathf.Clamp(transform.position.x, -4, 4), 
    		Mathf.Clamp(transform.position.y, -3, 3),
    		transform.position.z);
    		}
}

The general camera script (incl zooming):

var mover : Transform;
var target : Transform;
var distance = 10.0;

var MinDistance=  1.0;
var MaxDistance = 1.0;

var zoomRate = 1;
 
private var x = 0.0;
private var y = 0.0;

function Start () 
{
    var angles = transform.eulerAngles;
    x = angles.y;
    y = angles.x; 
}
        
function LateUpdate() 
{
    if (target) 
 
    var rotation = Quaternion.Euler(y, x, 0);
    var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
   
    transform.rotation = rotation;
    
    transform.position = position + mover.position;  
    
    distance += -Input.GetAxis("Mouse ScrollWheel") * zoomRate * Mathf.Abs(distance);  
    
    distance = Mathf.Clamp(distance, MinDistance, MaxDistance);

For object rotation (bound to the gameobject):

#pragma strict

var xSpeed = 10;
var ySpeed = 10;
private var x = 0.0;
private var y = 0.0;

function Start () 
{
    var angles = transform.eulerAngles;
    x = angles.y;
    y = angles.x;
 
    // Make the rigid body not change rotation
    if (rigidbody)
        rigidbody.freezeRotation = true;

}

function Update () {

    if (Input.GetMouseButton(0)) 
    {
        x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
        y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    }
    
    var rotation = Quaternion.Euler(y, x, 0);

   
    transform.rotation = rotation;
 }

I’m too unexperienced in Unity to figure out how to solve this “edge limitation”, and searching the internet gives me so many different possible solutions, varying from camera.screentoworldpoint / camera.worldtoviewpoint / using camera frustums / clamping, etc, so Id like to give it a try here (clamping isnt what we are looking for sadly)
Apologies if this is something very easy to do, but thanks in advance!

Final cameramovement script:

panning + zooming →

var mover : Transform;
var target : Transform;
var distance = 10.0;
var moveSpeed : float = 0.1;

var MinDistance = -10;
var MaxDistance = 10;

var zoomRate = 1;

var zoom : float = 0.1;
	 
private var x = 0.0;
private var y = 0.0;

function Start () 
{
    var angles = transform.eulerAngles;
    x = angles.y;
    y = angles.x;
 
    // Make the rigid body not change rotation
    if (rigidbody)
        rigidbody.freezeRotation = true;
}

function Update()
{

   if (target) 
 	       	var hit: RaycastHit;
		var headingZ: Vector3 = target.position - camera.transform.position;
    	var distanceZ: float = Vector3.Dot(headingZ, camera.transform.forward);
    	var yZ = 0.5625 * Vector3.Dot(headingZ, camera.transform.forward);
          // zoom in
          if(Input.GetAxis("Mouse ScrollWheel") > 0)
              {
                  transform.Translate(0, 0, 1, Space.World);
                  transform.position = new Vector3 (Mathf.Clamp(transform.position.x, -distanceZ, distanceZ), Mathf.Clamp(transform.position.y, -yZ, yZ), Mathf.Clamp(transform.position.z,-15,0));                    
              }                
              // zoom out
              if(Input.GetAxis("Mouse ScrollWheel") < 0)
              {
                  transform.Translate(0, 0, -1, Space.World);
                  transform.position = new Vector3 (Mathf.Clamp(transform.position.x, -distanceZ, distanceZ), Mathf.Clamp(transform.position.y, -yZ, yZ), Mathf.Clamp(transform.position.z,-15,0));  
              }
      
    		
    

     	if (Input.GetMouseButton(1)) {
       	 	
       	 	var heading: Vector3 = (target.position - camera.transform.position) * 1.05;
       	 	var distance: float = Vector3.Dot(heading, camera.transform.forward);
       	 	var y = 0.5625 * distance;
       	 	
    
    		           	 	transform.Translate(Vector3.right * -Input.GetAxis("Mouse X") * moveSpeed);
        	transform.Translate(transform.up * -Input.GetAxis("Mouse Y") * moveSpeed, Space.World);
    		transform.position = new Vector3(
    		Mathf.Clamp(transform.position.x, -distance, distance), 
    		Mathf.Clamp(transform.position.y, -y, y),
    		transform.position.z);
    		
    		 
    		}
}

static function ClampAngle (angle : float, min : float, max : float) {
    if (angle < -360)
        angle += 360;
    if (angle > 360)
        angle -= 360;
    return Mathf.Clamp (angle, min, max);
}

Rotating →

var xSpeed = 10;
var ySpeed = 10;
private var x = 0.0;
private var y = 0.0;

function Start ()
{
var angles = transform.eulerAngles;
x = angles.y;
y = angles.x;

// Make the rigid body not change rotation
if (rigidbody)
    rigidbody.freezeRotation = true;

}

function Update () {

if (Input.GetMouseButton(0)) 
{
    x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
}

var rotation = Quaternion.Euler(y, -x, 0);


transform.rotation = rotation;

So I’m not sure how to make this work with your current code, perhaps if you explain your desired functionality then I can help tailor this script to your case a little better!

Anyway, the only problem I have found so far with this code is that occasionally the object will go just off screen if you move the mouse very quickly as the change in distance of the object is too much, however it will still only allow you to move the camera back towards viewing the object, so It is still difficulty to loose!

This code would replace BOTH you first and second scripts and is set up to pan with right mouse button, and rotate with middle mouse button:

var moveSensitivity : float = 1;
var rotSensitivity : float = 1;
var zoomSensitivity : float = 1;
var target : Transform;
private var rTarget : Renderer;
private var bTarget : Bounds;
private var main : Camera;
private var mainTransform : Transform;
private var downPos : Vector3;
private var camDownPos : Vector3;
private var mousePos : Vector3;
private var lastMousePos : Vector3;
private var deltaMouseMovement : Vector3;
private var scrollDelta : float;
var restrictedDir : Vector3;
private var dist : float = 10;
private var v : Vector3;
var minDistance : float =  1.0;
var maxDistance : float = 50.0;

function Start(){
	main = camera.main;
	mainTransform = main.transform;
	rTarget = target.renderer;
	bTarget = rTarget.bounds;
}

function Update(){
	//bTarget = rTarget.bounds;
	deltaMouseMovement = Vector3(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"), 0);
	restrictedDir = EliminatedDir(bTarget.center);
	mousePos = Input.mousePosition;
	scrollDelta = -Input.GetAxis("Mouse ScrollWheel") * zoomSensitivity * Mathf.Abs(dist);
	v = Vector3.Project((target.position - mainTransform.position), mainTransform.forward);
	if(restrictedDir != Vector3.zero){
		if((mousePos.x-lastMousePos.x) * restrictedDir.x  > 0){
			mousePos.x = lastMousePos.x;
		}
		if((mousePos.y-lastMousePos.y) * restrictedDir.y  > 0){
			mousePos.y = lastMousePos.y;
		}
		if(scrollDelta > 0){
			dist += scrollDelta;
		}
	}else{
		dist += scrollDelta;
	}
	dist = Mathf.Clamp(dist, minDistance, maxDistance);
	
	if(Input.GetMouseButtonDown(1)){
		downPos = mousePos;
		camDownPos = mainTransform.position;
	}
	if(Input.GetMouseButton(1)){
		mainTransform.position = camDownPos + ((WorldPoint(downPos) - WorldPoint(mousePos))*moveSensitivity);
	}
	if(Input.GetMouseButton(2)){
		transform.RotateAround(target.position, transform.right, -deltaMouseMovement.y*10*rotSensitivity);
		transform.RotateAround(target.position, transform.up, deltaMouseMovement.x*10*rotSensitivity);
	}
	mainTransform.position += (v.magnitude - dist)*v.normalized;
	lastMousePos = mousePos;
}

function WorldPoint(pos : Vector3){
	return main.ScreenToWorldPoint(Vector3(pos.x, pos.y, dist));
}
function EliminatedDir(pos : Vector3){
	var vPoint : Vector3 = main.WorldToViewportPoint(pos);
	var eliminatedDir : Vector3 = Vector3.zero;
	eliminatedDir.x = vPoint.x <= 0 ? -1 : vPoint.x >= 1 ? 1 : 0;
	eliminatedDir.y = vPoint.y <= 0 ? -1 : vPoint.y >= 1 ? 1 : 0;
	return eliminatedDir;
}

Let me know if you have some questions, the code isn’t the easiest to understand :o

Scribe