How to copy camera rotation, plus custom setup for parallax scrolling?

Hi,

I'm a new user and I really enjoy discovering Unity3D. I'm more an artist than a programmer, so I have some difficulties to "translate" my thoughts into code.

Would you help me with javascript scripting?

  1. I would like the camera 2 to copy the camera 1 rotation. It should work for case B also. alt text

  2. I would like to try a setup where the camera 2 rotates on the left when the camera 1 moves to the right. I want to use it for a sidescroller. The more Camera 1 goes to the right, the more Camera 2 rotates to the left. If Camera 1 goest to the left, Camera 2 rotates to the right. alt text

The best would be to have a variable that allows me to make the rotation faster/slower per axis.

  1. I would like to mix 1) and 2) : see image below. alt text

Here is what I have so far, but it doesn't work the way that is described in the images above :

var rot_speed : Vector3;
var myTransform : Transform;

function Update () {
   var target_rot = myTransform.eulerAngles;
    for (i=0;i<3;i++){
        target_rot <em>= target_rot<em>*rot_speed*;*</em></em>
 <em><em>*transform.eulerAngles = target_rot;*</em></em>
<em>_*}*_</em>
<em>_*```*_</em>
<em>_*<p>Can you help me on that?</p>*_</em>

Your script seems to be on the right track. You should describe what your script is not doing when you post a script so that it is clearer what problem to solve.

What you describe is rather simple. Your code seems to be a bit confused about what eulerAngles are and you've left out some rather important details about your implementation.

In order to mirror the rotation about the right axis, you would apply this to your first camera

//this is the other camera.
var other : Transform;

function Update() {
    if(other) other.eulerAngles.x = transform.eulerAngles.x;
}

eulerAngles.x is your rotation about the right (x) axis and will make your camera look up or down. All you need to mirror the rotation is to set the rotation of your mimic camera to be the same as your lead camera.

To mirror all rotation, you would simply need:

other.eulerAngles = transform.eulerAngles;

You've left out the part where you are translating one of your cameras. I don't really know how you mean to move your camera so it's challenging to assume a given movement system.

Wherever you move your camera, you would need to do something like:

var rotateScale : float = -15.0; //rotate left 15 degrees per unit moved right
var movementAmount : float = something; //Where you get your movement from
camera1.position.x += movementAmount;
camera2.eulerAngles.y += movementAmount * rotateScale;

Here's a script to attach to your main camera that will move based on input axes;

Master.js

var other : Transform; //the slave
var moveSpeedX : float = 2.0; //units to move per unit of input
var rotateSpeedX : float = 5.0; //degrees per unit of input
var rotateSpeedY : float = -15.0; //degrees per unit of input

function Update() {
    //Get input
    var v : float = Input.GetAxis("Vertical") * time.deltaTime * rotateSpeedX;
    var h : float = Input.GetAxis("Horizontal") * time.deltaTime;

    //Move this
    transform.position.x += h * moveSpeedX;
    transform.eulerAngles.x += v;

    //Move the slave
    if(other) {
        other.eulerAngles.y += h * rotateSpeedY;
        other.eulerAngles.x += v;
    }
}

EDIT 10/04/10

From the slave perspective

Master.js

var moveSpeedX : float = 1.0; //units to move per unit of input
var h : float = 0.0; //The horizontal input

function Update () {
    h = Input.GetAxis("Horizontal") * Time.deltaTime;    
    transform.position.x += h * moveSpeedX;
}

Slave.js

var master : Master;
var moveSpeedX : float = 1.0; //units to move per unit of input

function LateUpdate () {
    if(master) {
        var script : Master = master.GetComponent(Master);
        if(script && script.h) transform.position.x += script.h * moveSpeedX;
    }
}

Copying rotation is the same as copying position above, but replacing transform.position with transform.eulerAngles.

Considering things from the slave perspective is really spreading your code out. I assume this may be because you want the script to just work with a prefab and require little-to-no setup. You can achieve this from the master perspective by having the slaves add themselves to their master, changing the first scripting to something like:

Master.js

var slaves : Transform[] = new Array(); //the slaves
var moveSpeedX : float = 2.0; //units to move per unit of input
var rotateSpeedX : float = 5.0; //degrees per unit of input
var rotateSpeedY : float = -15.0; //degrees per unit of input

function Update() {
    //Get input
    var v : float = Input.GetAxis("Vertical") * time.deltaTime;
    var h : float = Input.GetAxis("Horizontal") * time.deltaTime;

    //Move this
    transform.position.x += h * moveSpeedX;
    transform.eulerAngles.x += v * rotateSpeedX;

    //Move the slaves
    for(var slave : Transform in slaves) {
        //If you wanted to use slave-specific values
        //var script : Slave = slave.GetComponent(Slave);
        //if(script) {
        //    slave.eulerAngles.y += h * script.rotateSpeedY;
        //    slave.eulerAngles.x += v * script.rotateSpeedX;
        //}
        slave.eulerAngles.y += h * rotateSpeedY;
        slave.eulerAngles.x += v * rotateSpeedX;
    }
}

Slave.js

var master : Transform;

function Start() {
    //add yourself as a slave
    var script : Master = master.GetComponent(Master);
    if(script) script.slaves.push(transform);  
}

EDIT 10/07/10

If you cannot get your deltas directly or use input or some such (as in the case where using physics), you will have to calculate them manually.

Master.js

var slaves : Transform[] = new Array(); //the slaves
private var oldPosition : Vector3; //the position we had last frame
private var oldRotation : Quaternion; //the rotation we had last frame

function Start() {
    oldPosition = transform.position;
    oldRotation = transform.rotation;
}

function Update() {
    //We may have been moved. Get deltas
    var deltaPosition : Vector3 = transform.position - oldPosition;
    var deltaRotation : Vector3 = Quaternion.FromToRotation(oldRotation,
        transform.rotation).eulerAngles;
    oldPosition = transform.position;
    oldRotation = transform.rotation;

    //Move the slaves
    for(var slave : Transform in slaves) {
        var script : Slave = slave.GetComponent(Slave);
        if(script) {
            slave.eulerAngles.y += deltaPosition.x * script.rotateSpeedY;
            slave.eulerAngles.x += deltaRotation.x * script.rotateSpeedX;
        }
    }
}

Slave.js

var master : Transform;
var rotateSpeedX : float = 1.0; //degrees per unit of input
var rotateSpeedY : float = -5.0; //degrees per unit of input

function Start() {
    //add yourself as a slave
    var script : Master = master.GetComponent(Master);
    if(script) script.slaves.push(transform);  
}

Note that from the master's perspective, we only calculate their delta's once per frame, whereas from the slave perspective, every slave would have to re-calculate.

I have decided to break my setup into 2 distinct scripts :

Setup 1 : Camera 2 movement Camera 2 copies Camera 1 movements on X axis. moveSpeedX variable is used to control the scrolling speed.

Camera 1 movements script *Simplified for testing purposes*

var moveSpeedX : float = 1.0; //units to move per unit of input

function Update () {

    var h : float = Input.GetAxis("Horizontal") * Time.deltaTime;    
    //Move this
    transform.position.x += h * moveSpeedX;

}

Camera 2 copy Camera 1 movements script

var master_obj : Transform; // Camera 1
var moveSpeedX : float = 1.0; //degrees per unit of input
var moveSpeedY : float = 1.0; //degrees per unit of input
var moveSpeedZ : float = 1.0; //degrees per unit of input

function Start () {
    // Here I want to save initial Camera 2 position : InitPosX, InitPosY, InitPosZ

}

function Update () {

    if (master_obj){
        //Move this
        transform.position.x = master_obj.position.x * moveSpeedX + InitPosX;
        transform.position.y = master_obj.position.y * moveSpeedY + InitPosY;
        transform.position.z = master_obj.position.z * moveSpeedZ + InitPosZ;
    }
}

Problem

I don't know how to save the initial transform.position in a Start() function and use it in Update() function. Or maybe something like transform.Globalposition.x = master_obj.Localposition.x * moveSpeedX exists in some way, and would do the trick?

More explanations

With the help of the first answer I got, here is the setup I actually have : alt text

On layer 1, Camera 1 is parented to the main character. On layer 2, Camera 2 is put in front of a background (image, or 3D scene in that case). Camera 2 copies Camera 1 orientation.

The main character is moving with the following script (simplified for testing)

Camera 1 is parented to the main character.

Camera 2 is the "slave" of Camera 1.

Being able to save the Camera 2 initial position would help me to change its position at startup and get something like the following image :

alt text


Setup 2 : Camera 2 orientation Simplified for testing purposes

Camera 2 copies Camera 1 orientation on its local axis. See images above.

var master_obj : Transform; //the master Camera 1
var rotateSpeedX : float = 1.0; //degrees per unit of input

function Start () {
    // Here I want to save initial Camera 2 orientation : InitOrX, InitOrY, InitOrZ

}
function Update() {

   if (master_obj){
       transform.eulerAngles.x = InitOrX + master_obj.eulerAngles.x * rotateSpeedX;
   }

}

Problem

I don't know how to save the initial transform.eulerAngles in a Start() function and use it in Update() function. Or maybe something like transform.Globalorientation.x = master_obj.Localorientation.x * moveSpeedX exists in some way, and would do the trick?

I don't know how to get the expected result. I am a bit confused about the way I can get it. I don't want my camera 2 to copy Camera 1 position but more like "ADD" it to its current position. I don't want my camera 2 to copy Camera 1 orientation but more like "ADD" it to its current orientation.

After that, I will try to implement the Camera 1 translation on x / Camera 2 rotation on Y axis.

I've tried to describe my question precisely.

Thank you again for your help.