Camera scripting references

I need some kind of tutorial, reference, or book to help me with in game camera movement. Based on the same camera movement that work in game (pan/zoom/orbit). But also incorporates click and drag functionality based on an objects position and not the position of the camera.

here is a sample of my scripting logic:

on left mouse click
   if (not hovering over dragable object)
     pan camera
   else
     drag object
spin mouse wheel (in/out)
   zoom (in/out)
on middle mouse click
   orbit(rotate) camera

I'm not looking for someone to write my script just point me in the right direction or tell me what functions involve moving the camera based on cameras local and if you want how to drag an object globally but not based on the cameras position.

This is the only thing that is halting my project right now.

If I take your meaning, you want to a. understand camera movement and b. implement dragging. There are many answered questions here which answer those two specific questions. Also, you could try referencing the standard asset camera scripts and understanding what they are doing.

Since this is simple enough, I'll provide the a summary of how to get what you want, but you really should try search the existing documentation whenever you have questions.

Mouse Input

GetAxis returns a floating point number indicating the amount of change since the last frame.

GetMouseButton... returns whether the condition is true.

Mouse Movement

h = Input.GetAxis("Mouse X"); //The horizontal movement - could use "Horizontal"
v = Input.GetAxis("Mouse Y"); //The vertical movement - could use "Vertical"

Mouse ScrollWheel

w = Input.GetAxis("Mouse ScrollWheel");

Mouse Buttons

if(Input.GetMouseButtonDown(0)){ //0 is left, 1 is right, 2 is middle mouse button
    //do something when the mouse button was just pressed down
}

if(Input.GetMouseButton(0)){ //0 is left, 1 is right, 2 is middle mouse button
    //do something when mouse button is held down
}

if(Input.GetMouseButtonUp(0)){ //0 is left, 1 is right, 2 is middle mouse button
    //do something when the mouse button was just released
}

Selection/Dragging

There are different ways to do this. Because this uses a raycast, it depends on selectable GameObjects having a Collider component if you were intending to select GameObjects.

Raycasting

Using raycasts, you would have to identify your selectable/drag-able gameObjects somehow. You could use their tags, their layers, their names or you could maintain a container of objects or references to the objects(names or whatever) and check if they are in the container (preferrably sorted in some intelligent way) to speed up indexing them. I like the container of names personally because it allows for changing what is and is not selectable fairly easily.

The more customizable approach is to perform your own raycast. You can pass a layer mask to limit the layers that are checked against and restrict the depth of the raycast, but this will not select GUI elements which would be checked against differently. This can be put anywhere.

var hitInfo : RaycastHit;
var ray : Ray = camera.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, hitInfo, camera.farClipPlane)
   && hitInfo.transform.tag = "selectable") {
    target = hitInfo.transform; //hitInfo.transform is what you hit, select it
}

To drag, you would do this if the mouse button was just pressed down so that you aren't raycasting every frame and you would clear your selection if the mouse button was just released.

private var distance : float = camera.nearClipPlane;
private var mouse : Vector2;
function Update() {
    if(Input.GetMouseButtonDown(0)) {
        var hitInfo : RaycastHit;
        var ray : Ray = camera.ScreenPointToRay(Input.mousePosition);
        //start drag
        if(Physics.Raycast(ray, hitInfo, camera.farClipPlane)
           && hitInfo.transform.tag = "drag-able") {
            target = hitInfo.transform;
            distance = hitInfo.distance;
        }
        //else do something when not starting dragging, maybe?
    }
    else if(Input.GetMouseButtonUp(0)) target = null;

    if(Input.GetMouseButton(0)) {
        if(target != null) { //drag
            mouse = Input.mousePosition;
            target.position = camera.ScreenToWorldPoint(mouse.x, mouse.y, distance)
            //Note that due to perspective camera projection, the world coordinates
            //will curve in depth relative to the camera
        }
        //else do something when not dragging, maybe?
    }

OnMouse... functions

The built-in approach is to override the provided OnMouse... functions. These functions are called on every GUIElement or collider with these functions overrided, meaning you would have to attach scripts with these functions to each selectable object. Also note that these events fire on their own and give no control over the checks that are being made. (It probably does something smart with the GUI elements (checking if the screen coordinates are over any GUI element) and then raycasts as above, calling the OnMouse... functions in every script attached to whatever it hit). OnMouseDown would select, OnMouseUp would deselect, and OnMouseDrag would drag.

function OnMouseDown() {
    //Do something when the mouse was just pressed down on this
}

function OnMouseDrag() {
    //If the mouse was first pressed down over this,
    //do something every frame the mouse is pressed down and has not been released
}

function OnMouseEnter() {
    //Do something when the mouse just came over this
}

function OnMouseEnter() {
    //Do something when the mouse just went off of this
}

function OnMouseOver() {
    //Do something every frame while the mouse is over this
}

function OnMouseUp() {
    //Do something when the mouse was pressed down over this and has just been released
}

Camera Movement

The terms are kind of misleading if you don't know the terminology.

The transformations here are given relative to the camera for generality and using simple functions whenever possible. Where applicable, target-relative transformations are provided.

transform.Translate takes a Vector3, therefore to combine Truck, Pedestal and Dolly, you could just do:

transform.Translate(Vector3(h * hSensitivity, v * vSensitivity, w * dSensitivity));

transform.Rotate takes a Vector3 indicating the angles to rotate, therefore to combine Pan, Tilt and Slant, you could just do:

transform.Rotate(Vector3(h * pSensitivity, v * tSensitivity, w * sSensitivity));
//Normally slant is a separate operation because it is uncommon and tends to confuse users

Camera Truck

What many think of as a pan.

transform.Translate(Vector3.right * h * hSensitivity); //truck = horizontal movement

Camera Pedestal

transform.Translate(Vector3.up * v * vSensitivity); //pedestal = vertical movement

Camera Dolly

What many think of as zoom.

transform.Translate(Vector3.forward * w * dSensitivity); //dolly = move forward/back

//To dolly relative to something, you would have to do it in a common coordinate system
//World space is common to both and therefore easier:
var forward : Vector3 = Vector3.Normalize(target.position - transform.position);
transform.Translate(forward * w * dSensitivity, Space.World);

Camera Tilt

transform.Rotate(Vector3.right * v * tSensitivity); //tilt = look up/down

Camera Pan

transform.Rotate(Vector3.up * h * pSensitivity); //pan = look left/right

Camera Slant or Spin

transform.Rotate(Vector3.forward * h * sSensitivity); //slant = tilt to the side

Camera Zoom

This involves a change of focal length and therefore field of view.

//This should probably be scaled on a curve
camera.fieldOfView -= w * zSensitivity; //zoom = change lens focal length

Camera Orbit

This is always target relative (relative to the orientation of the camera relative to the target).

This can be a bit more complicated when combined with other camera controls and becomes trickier as you must maintain more information. See the standard asset mouseOrbit. You can keep information about positions relative to the target or relative to the camera. If you do the latter, it becomes easier to reuse variables with other camera transforms.

The way the mouseOrbit script works is it rotates the camera to look in the direction and then moves it away from the target's origin. This can be kind of confusing if you want to force the orientation somehow. If you do some calculations with the camera's orientation, you can do this without being forced to look at the target;

The simple implementation is something like:

transform.RotateAround(target.position, upAxis, h * hoSensitivity); //orbit left/right
transform.RotateAround(target.position, rightAxis, v * voSensitivity); //orbit up/down
transform.RotateAround(target.position, forwardAxis, w * soSensitivity); //spin

but the problem comes from calculating the axes as they are transformation relative.

forwardAxis = Vector3.Normalize(target.position - transform.position);//The easy one

//Which way is up? camera's up? What if we aren't looking at the target?
//Besides, we need an axis perpendicular to the forward axis calculated.

upAxis = transform.up;
rightAxis = transform.right;

//Get normal and binormal
Vector3.OrthoNormalize(forwardAxis, upAxis, rightAxis);

//Orthonormalize may flip some signs - still need to test if this is a problem.
//If it is, use the 2 parameter version and get the rightAxis by
//rotating the upAxis 90 degrees about the forwardAxis