Phuein

3D Spaceship Camera

Recommended Posts

I'm working on a camera that behaves as if tracking a spaceship. The Z axis rotation shouldn't affect looking up/down and right/left, as if I'm the pilot in the cockpit of the ship in space, up is always my local up.

I tried the FollowCamera, but it only lets me rotate the target mesh so the camera yaws, but doesn't roll or pitch. I tried the Free/Universal cameras, but rotating the camera to roll skews the yaw and pitch, as if they're in global dimensions - instead of local. I couldn't find a local/global rotation option, or figure out using quaternions/matrices with it, no matter how much I read about those and tweaked the code.

I know I could make this spaceship camera from scratch, using an empty/mesh as a pivot, but I don't want to miss on using the quality code that comes with the engine already. Any suggestions?

Image result for roll pitch yaw

Share this post


Link to post
Share on other sites

Hi Phuein,

I also believe BJS should have a "flying" camera. Here is a thread that led to my solution:

I used it in ZOOM my "flying through space" game.

 

 

And here I added flight simulator functionality:

)))))))))))))))))))))))))))))))))))))))                                                      Best luck to ya!  ☘️ 

Share this post


Link to post
Share on other sites
1 hour ago, coolroar said:

Hi Phuein,

I also believe BJS should have a "flying" camera. Here is a thread that led to my solution:

I like the colors in your flight demo :D. Can you show a PG with your addYawPitchRollFunction function with roll upside down and around to make sure right stays right, left stays left, up is up, and so on? The flight example doesn't let me move that much around, so it's hard to tell.

Share this post


Link to post
Share on other sites

Hi Phuein, 

Before I made addYawPitchRollFunction  I did it like this: https://www.babylonjs-playground.com/index.html#2UFUC3

Otherwise to keep left left, right right, & up up, you will need a manual roll control for your space craft.

Imagine heading North, then applying up pitch. As you pass straight up, down & up will reverse.

But remember, in real space there is no UNIVERSAL up, left, etc. 

Try my zoom game to as an example where you can move around a lot! https://jounce.space/zoom?deep=5

Share this post


Link to post
Share on other sites

Neither example has roll, to freely test all directions. It would be awesome if you link a PG example with free movement in all directions including yaw.

To clarify, in real space, when you're the pilot, yaw and pitch are ALWAYS local to you. You never fly to your right and it's not your right.

Share this post


Link to post
Share on other sites

Ok, try this: https://www.babylonjs-playground.com/index.html#Q1RH6C

Edit: add playground instructions:

///// Mouse point to desired yaw pitch
///// Left-right arrow keys for roll.
/////

                            ✈️                    :lol:

Edited by coolroar
add playground instructions

Share this post


Link to post
Share on other sites

Cool, seems to work fine in this trippy example. :P Instructions definitely needed!

So, in your experience that function works fine? Test plenty? If so, it looks like a solution. I'd say this should be applied to the Universal camera, so it can move in 3D freely out-of-the-box. Have you considered pulling this into the engine? Say at https://github.com/BabylonJS/Babylon.js/blob/master/src/Cameras/Inputs/babylon.freeCameraMouseInput.ts#L122

Share this post


Link to post
Share on other sites

Tested only in examples referred to in this topic and at ZOOM.

Agree "this should be applied to the Universal camera, so it can move in 3D freely out-of-the-box".

I don't know how to merge to the code-base, and I don't care to learn it at this time.

But I'd be happy if someone else were to do that.

Here it is with both  yawPitchRoll() and autoBank(), plus clearYawPitchRoll().

function addYawPitchRollFunction(ob, gravity) {
    ob.rotationQuaternion  = new BABYLON.Quaternion();
    ob.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(ob.rotation.y, ob.rotation.x, ob.rotation.z);
    ob.myGrav = gravity;

    ob.yawPitchRoll = function(yaw, pitch, roll) {
        var axis = new BABYLON.Vector3(0, 0, -1);
        var partRotQuat  = new BABYLON.Quaternion();

        BABYLON.Quaternion.RotationAxisToRef(axis, roll, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat);

        BABYLON.Quaternion.RotationAxisToRef(axis.set(-1, 0, 0), pitch, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat);

        BABYLON.Quaternion.RotationAxisToRef(axis.set(0, 1, 0), yaw, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat);

        this.rotationQuaternion.toEulerAnglesToRef(this.rotation);
    }

    ob.autoBank = function(yaw, pitch, speed) {
        var axis = new BABYLON.Vector3(0, 0, -1);
        var partRotQuat  = new BABYLON.Quaternion();

        var roll = Math.atan2(-yaw*222*speed, this.myGrav);
        this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, roll);

        BABYLON.Quaternion.RotationAxisToRef(axis.set(-1, 0, 0), pitch, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat);

        BABYLON.Quaternion.RotationAxisToRef(axis.set(0, 1, 0), yaw, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat);

        this.rotationQuaternion.toEulerAnglesToRef(this.rotation);
    }

    ob.clearYawPitchRoll = function() {
        this.rotationQuaternion.set(0, 0, 0, 1);
        this.rotation.set(0,0,0);
    }
}

Cheers -- 👀  !

Share this post


Link to post
Share on other sites

I saw the demo, but I'm still not clear on what it does. The 222 multiplier, and why RotationAxisToRef twice? Also, how does the yawPitchRoll function work, in regards to calling RotationAxisToRef three times? Seems mysterious without some explanation.

Share this post


Link to post
Share on other sites

Ok. fine. sheesh.

function addYawPitchRollFunction(ob, gravity) {
    ob.rotationQuaternion  = new BABYLON.Quaternion();
    ob.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(ob.rotation.y, ob.rotation.x, ob.rotation.z);// Initialize to current rotation.
    ob.myGrav = gravity; // Set some gravity for autoBank() function.

    ob.yawPitchRoll = function(yaw, pitch, roll) {
        var axis = new BABYLON.Vector3(0, 0, -1); // Set an axis to 'z' (roll).
        var partRotQuat  = new BABYLON.Quaternion(); // A var to hold partial rotation.

        BABYLON.Quaternion.RotationAxisToRef(axis, roll, partRotQuat); // put roll in partRotQuat
        this.rotationQuaternion.multiplyInPlace(partRotQuat); // Apply roll to rotationQuaternion.

        //  Set axis to '-x' (pitch) and put pitch in partRotQuat.
        BABYLON.Quaternion.RotationAxisToRef(axis.set(-1, 0, 0), pitch, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat); // Apply pitch to rotationQuaternion.

        //  Set axis to 'y' (yaw) and put yaw in partRotQuat.
        BABYLON.Quaternion.RotationAxisToRef(axis.set(0, 1, 0), yaw, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat); // Apply yaw to rotationQuaternion.

        this.rotationQuaternion.toEulerAnglesToRef(this.rotation); // Apply rotationQuaternion to  (camera.rotation)
    }

    ob.autoBank = function(yaw, pitch, speed) {
        var axis = new BABYLON.Vector3(0, 0, -1); // Set an axis to 'z' (roll).
        var partRotQuat  = new BABYLON.Quaternion(); // A var to hold partial rotation.

        var fudge = 222; // Whatever, change to make bank angle seem appropriate.
        var roll = Math.atan2(-yaw*fudge*speed, this.myGrav);// Roll (bank) based on speed, turn rate, & gravity.

        // get current camera.rotation, substitute roll for camera.rotation.z.
        this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, roll);


        //  Set axis to '-x' (pitch) and put pitch in partRotQuat.
        BABYLON.Quaternion.RotationAxisToRef(axis.set(-1, 0, 0), pitch, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat); // Apply pitch to rotationQuaternion.

        //  Set axis to 'y' (yaw) and put yaw in partRotQuat.
        BABYLON.Quaternion.RotationAxisToRef(axis.set(0, 1, 0), yaw, partRotQuat);
        this.rotationQuaternion.multiplyInPlace(partRotQuat); // Apply yaw to rotationQuaternion.

        this.rotationQuaternion.toEulerAnglesToRef(this.rotation);// Apply rotationQuaternion to  (camera.rotation)
    }

    ob.clearYawPitchRoll = function() {
        this.rotationQuaternion.set(0, 0, 0, 1);
        this.rotation.set(0,0,0);
    }
}

 

🙄

Share this post


Link to post
Share on other sites

In case it help, I did some camera for flying spaceship for this demo

Here is the script about the flying camera following the spaceship : https://github.com/SvenFrankson/space-scout/blob/master/scripts/SpaceShipCamera.ts

Line 55, there's an update loop for the camera.

Main idea is that I keep an empty mesh at a fixed position relatively to the spaceship (it's the vector named _targetPosition), and lerp to it each frame with a smoothness factor.

It makes the camera go to a point with some delay, so when spaceship accelerates you feel it a little more because it goes further.

A Slerp make the camera rotationQuaternion go to the spaceship rotationQuaternion, so barrel rolls are smoothed too.

For the most part it's inspired from the Galactic StarFighter mode of Star Wars The Old Republic.

Hope it helps, good luck !

Share this post


Link to post
Share on other sites

Thanks! Now the code makes full sense. :D I'm sure others will enjoy it, too.

 

Cool space example, Sven. Thanks for sharing. Could you add comments to the code? I'm not entirely sure how you chose your logic there. What's focalLength() about? And focalPlane? Why _checkInputs() checks on the ship's worldMatrix? I do generally get that you basically used a rotationQuaternion like coolroar's example, which seems like what's missing from the FreeCamera/UniversalCamera.

Share this post


Link to post
Share on other sites

Say coolroar, did you notice that your rotation method loses the straight angle when it goes over a certain degree?

When implementing your method, I noticed that I get an issue with the camera slowly rolling, when I rotate the camera on X and Y. It doesn't happen in your example - but that's not a free rolling camera either - but it does show when changing the angle enough.

image.thumb.png.b11ab7084b23ac4a762b0b3493b90ab5.png

Share this post


Link to post
Share on other sites

 

Does "...loses the straight angle..." mean "...the screen point for zero attitude change..."?

I think I noticed that once. If true, I don't know why.

Work-a-round: periodic re-center:  https://www.babylonjs-playground.com/index.html#Q1RH6C#1

 

"...camera slowly rolling..." I'm not sure what you mean. You know of course that you will get roll as you yaw when pitch != 0.

☘️ 😏

Share this post


Link to post
Share on other sites

Clarification of my previous post:

"... you will get roll as you yaw when pitch != 0"  should be:

" the horizon will tilt (relative to your craft) as you yaw when pitch != 0".

The tilted horizon makes you think your craft rolled.  (Since at computer we lack the physical sensations of yaw, pitch, & roll).

Imagine:

  1. You are heading North, straight and level.
  2. Then you pitch to straight up.
  3. Then you yaw PI/2 to the left.

What is your heading? Describe the horizon as seen looking straight ahead.

You are headed West, the horizon appears vertical with the ground out the left window. With no craft roll!

Pitch(PI/2), Yaw(PI/2) = Roll(PI/2), Pitch(PI/2) = Yaw(PI/2), Roll(PI/2)

A series of yaws and pitches can equal a roll: Roll(PI/2) =  Pitch(PI/2),  Yaw(PI/2),  Pitch(-PI/2).

(Check my work? 🙄)

I hope I'm not blathering stuff you already know.  😏

For the benefit of others, I'll also post this to 

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.