Chase Camera

Discuss your feature requests for the next release of Ardor3D here.
Forum rules
Discuss your feature requests for the next release of Ardor3D here. Please make a ticket and reference it in your first post.

Chase Camera

Postby Gentleman Hal » Thu Jul 08, 2010 2:32 pm

Anyone started work on a chase camera?

If not I'll look into it :)
Quite!
User avatar
Gentleman Hal
regular
 
Posts: 79
Joined: Tue Jan 06, 2009 2:59 am
Location: Kent, UK

Re: Chase Camera

Postby renanse » Thu Jul 08, 2010 3:32 pm

No, I did the one in jME and my biggest regret was using the spring ideas from one of the Gems books (turned out to be too unstable in low fps).

Related... I just added a orbit camera controller that could work (or be extended) in a pinch as a chase camera since I allow the target to be a spatial.
Gratitude is a mark of a noble soul and a refined character.
User avatar
renanse
Site Admin
 
Posts: 2958
Joined: Tue Oct 28, 2008 6:49 pm
Location: Austin, TX

Re: Chase Camera

Postby paranoidray » Sun Aug 08, 2010 1:09 am

paranoidray
Officer
 
Posts: 174
Joined: Sat May 01, 2010 8:29 pm

Re: Chase Camera

Postby MrCoder » Sun Aug 08, 2010 2:53 pm

I might be able to port over an old WoW-style third person controller. Also know the spaced guys has something like that they might share with us? Guys? :)
Destroy, Erase, Improve
User avatar
MrCoder
Site Admin
 
Posts: 755
Joined: Mon Nov 03, 2008 8:56 am
Location: Stockholm, Sweden

Re: Chase Camera

Postby oskar » Sun Aug 08, 2010 4:21 pm

We got a bunch of wierd "mmo cameras" for various situations like walking, swimming, flying and god mode, They are all in need of many iterations of usability work but they could be useful for random purposes too. I doubt this stuff is of any use to any of you as it seems rather dependant on other parts of the system but take a peek at this stuff which is our "follow camera".

Code: Select all
package se.spaced.client.model.control;

import com.ardor3d.math.Quaternion;
import com.ardor3d.math.Vector3;
import com.ardor3d.renderer.Camera;
import com.google.inject.Inject;
import se.spaced.client.model.UserCharacter;
import se.spaced.client.physics.PhysicsWorld;

public class FollowCamera {
   private double desiredPlayerDistance = 14;
   private double playerDistance = 14;

   Vector3 store = new Vector3();
   Vector3 cameraToPlayer = new Vector3(Vector3.ZERO);
   Vector3 focusPosition = new Vector3(Vector3.ZERO);
   Vector3 focusOffset = new Vector3(0, 1.7, 0);
   Vector3 cameraDesiredPosition = new Vector3();

   Quaternion cameraSteerRot = new Quaternion(Quaternion.IDENTITY);
   Quaternion cameraRot = new Quaternion(Quaternion.IDENTITY);

   double dx;
   double dy;
   boolean directSteering;
   private final double sensitivity = 0.1;
   double cameraToPlayerY = 0;

   private final CameraCollisionHandler collHandler;

   @Inject
   public FollowCamera(CameraCollisionHandler collHandler) {
      this.collHandler = collHandler;
   }

   public void update(double dt, Camera camera, UserCharacter userCharacter, PhysicsWorld physicsWorld) {
      playerDistance = 0.9 * playerDistance + 0.1 * desiredPlayerDistance;

      focusPosition.set(userCharacter.getPosition());
      focusPosition.addLocal(userCharacter.getRotation().apply(focusOffset, store));

      // Refresh c2p to match current camera position
      if (cameraToPlayer.equals(Vector3.ZERO)) {
         cameraToPlayer.set(camera.getLocation());
         cameraToPlayer.subtractLocal(focusPosition);
         cameraToPlayerY = cameraToPlayer.getY();
      }

      if (directSteering) {
         // apply steering
         cameraSteerRot.fromAngleAxis(dx * dt, Vector3.UNIT_Y);
         cameraSteerRot.apply(cameraToPlayer, cameraToPlayer);
         dx = 0;

         cameraSteerRot.fromAngleAxis(dy * dt, camera.getLeft());
         cameraSteerRot.apply(cameraToPlayer, cameraToPlayer);
         dy = 0;
      } else {
         // apply follow
         cameraToPlayer.set(camera.getLocation());
         cameraToPlayer.subtractLocal(focusPosition);

         cameraToPlayerY *= 0.9;
         cameraToPlayer.setY(cameraToPlayerY);
      }

      cameraToPlayer.normalizeLocal().multiplyLocal(playerDistance);
      cameraDesiredPosition.set(focusPosition.add(cameraToPlayer, store));

      collHandler.handleIt(camera, focusPosition, cameraDesiredPosition, Vector3.UNIT_Y);
   }
User avatar
oskar
regular
 
Posts: 118
Joined: Thu May 14, 2009 12:38 pm

Re: Chase Camera

Postby Gentleman Hal » Mon Aug 09, 2010 2:26 am

I'm attempting to make a racing game so I wanted a simple camera that would follow the vehicle.

Even if it's not exactly what I need anything added to Ardor that I can edit slightly will be awesome.

Thanks guys!
Quite!
User avatar
Gentleman Hal
regular
 
Posts: 79
Joined: Tue Jan 06, 2009 2:59 am
Location: Kent, UK

Re: Chase Camera

Postby obi » Mon Aug 09, 2010 6:52 am

Gentleman Hal wrote:I'm attempting to make a racing game so I wanted a simple camera that would follow the vehicle.

Even if it's not exactly what I need anything added to Ardor that I can edit slightly will be awesome.

Thanks guys!


Well I might not have exactly what you want but in my Free Flight showcase I just made a slightly altered CameraNode that just copy the translations and not the orientation. Depending on what Chase Camera I wanted I would implement some way to perform the orientation based on the parent spatial.

Like only turn when the angle between the camera direction and the parent direction goes over some limit. If it is a chase camera for a car I could have the orientation tracking just rotate around the worlds up direction and maybe add some springy or slightly delayed reaction motion for the translation along the up axis. Well I could think of 100 ways to implement a ChaseCamera ;)

This one follows the parent and just have a zoom feature that translates the camera along the camera direction axis, which is the z-axis. This is not a generic solution and if you start changing the orientation you will have to change the code and translate along another axis for the zoom.

Code: Select all
import java.io.IOException;

import com.ardor3d.math.Matrix3;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.Camera;
import com.ardor3d.scenegraph.Node;
import com.ardor3d.util.export.InputCapsule;
import com.ardor3d.util.export.OutputCapsule;

public class ExtendedCameraNode extends Node
{
    private static final long serialVersionUID = 1L;

    private Camera _camera;
    protected Matrix3 _mat = new Matrix3( 1,0,0,0,1,0,0,0,1 );
   
    protected float _zoomLevel = -10;

    public ExtendedCameraNode() {}

    /**
     * Constructor instantiates a new <code>CameraNode</code> object setting the camera to use for the frame reference.
     *
     * @param name
     *            the name of the scene element. This is required for identification and comparision purposes.
     * @param camera
     *            the camera this node controls.
     */
    public ExtendedCameraNode(final String name, final Camera camera) {
        super(name);
        _camera = camera;
        setTranslation(0,0,_zoomLevel);
    }

    /**
     * Forces rotation and translation of this node to be sync'd with the attached camera. (Assumes the node is in world
     * space.)
     */
    public void updateFromCamera() {
        final ReadOnlyVector3 camLeft = _camera.getLeft();
        final ReadOnlyVector3 camUp = _camera.getUp();
        final ReadOnlyVector3 camDir = _camera.getDirection();
        final ReadOnlyVector3 camLoc = _camera.getLocation();

        final Matrix3 rotation = Matrix3.fetchTempInstance();
        rotation.fromAxes(camLeft, camUp, camDir);

        setRotation(rotation);
        setTranslation(camLoc);

        Matrix3.releaseTempInstance(rotation);
    }

    /**
     * <code>setCamera</code> sets the camera that this node controls.
     *
     * @param camera
     *            the camera that this node controls.
     */
    public void setCamera(final Camera camera) {
        _camera = camera;
    }

    /**
     * <code>getCamera</code> retrieves the camera object that this node controls.
     *
     * @return the camera this node controls.
     */
    public Camera getCamera() {
        return _camera;
    }

    /**
     * <code>updateWorldTransform</code> updates the rotation and translation of this node, and sets the camera's frame
     * buffer to reflect the current view.
     */
    @Override
    public void updateWorldTransform(final boolean recurse) {
        _worldTransform.setTranslation( _parent.getWorldTranslation().getX() + getTranslation().getX(),
                                        _parent.getWorldTranslation().getY() + getTranslation().getY(),
                                        _parent.getWorldTranslation().getZ() + getTranslation().getZ() );
        _worldTransform.setRotation( _mat );
        if (_camera != null)
        {
            _camera.setAxes( _mat );
            _camera.setLocation( getWorldTranslation() );
            _camera.onFrameChange();
        }
    }

    @Override
    public void write(final OutputCapsule capsule) throws IOException {
        super.write(capsule);
        capsule.write(_camera, "camera", null);

    }

    @Override
    public void read(final InputCapsule capsule) throws IOException {
        super.read(capsule);
        _camera = (Camera) capsule.readSavable("camera", null);

    }

    public void increaseZoom()
    {
        _zoomLevel += 0.1*_zoomLevel;
        setTranslation( 0, 0,_zoomLevel );
    }

    public void decreaseZoom()
    {
        _zoomLevel -= 0.1*_zoomLevel;
        setTranslation( 0, 0,_zoomLevel );
    }
}


For those new to Ardor3D reading this:
To get it to work you just initialize something like this
Code: Select all
_cameraNode = new ExtendedCameraNode("CameraNode", _canvas.getCanvasRenderer().getCamera() );
myCar.attachChild( _cameraNode );
obi
regular
 
Posts: 317
Joined: Thu Sep 24, 2009 8:06 pm

Re: Chase Camera

Postby obi » Thu Aug 12, 2010 11:16 am

Did you implement any ChaseCam's?

I was playing around with some road building and implemented a simple ChaseCam that actually can be used as one ;)
You can see it in action here:

http://www.youtube.com/watch?v=YLTnOdEvioo

Here's the code:

You can set any translation relative the object your chasing. The camera will keep that but adjust it to track the direction of the target.
So you could easily implement a InputController that translate a point in space relative the car so you could implement a free look. This way you can rotate around the car at any angles during the chase.

Code: Select all
import java.io.IOException;

import com.ardor3d.math.Matrix3;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.type.ReadOnlyMatrix3;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.Camera;
import com.ardor3d.scenegraph.Node;
import com.ardor3d.scenegraph.event.DirtyType;
import com.ardor3d.util.export.InputCapsule;
import com.ardor3d.util.export.OutputCapsule;

public class ChaseCameraNode extends Node
{
    private static final long serialVersionUID = 1L;

    public enum ChaseMode
    {
        Hard, Soft;
    }
   
    private ChaseMode _chaseMode = ChaseMode.Soft;
   
    private Camera _camera;
//    protected Matrix3 _mat = new Matrix3( 1,0,0,0,1,0,0,0,1 );
   
    protected Vector3 _baseTranslation = new Vector3();
    protected Vector3 _newTranslation = new Vector3();
    protected Vector3 _previousTranslation = new Vector3();
   
    protected double _targetZoomLevel = 1;
    protected double _currentZoomLevel = 1;
    protected double _softnessFactor = 0.02;
    protected ReadOnlyVector3 _worldUp = Vector3.UNIT_Z;
   
    protected ChaseCameraNode() {}

    /**
     * Constructor instantiates a new <code>ChaseCameraNode</code> object setting the camera to use for the frame reference.
     *
     * @param name
     *            the name of the scene element. This is required for identification and comparision purposes.
     * @param camera
     *            the camera this node controls.
     */
    public ChaseCameraNode(final String name, final Camera camera) {
        super(name);
        _camera = camera;
    }

    public void setChaseMode( ChaseMode chaseMode )
    {
        _chaseMode = chaseMode;
    }
   
    public void setSoftnessFactor( double factor )
    {
        _softnessFactor = factor;
    }
   
    /**
     * Forces rotation and translation of this node to be sync'd with the attached camera. (Assumes the node is in world
     * space.)
     */
    public void updateFromCamera() {
        final ReadOnlyVector3 camLeft = _camera.getLeft();
        final ReadOnlyVector3 camUp = _camera.getUp();
        final ReadOnlyVector3 camDir = _camera.getDirection();
        final ReadOnlyVector3 camLoc = _camera.getLocation();

        final Matrix3 rotation = Matrix3.fetchTempInstance();
        rotation.fromAxes(camLeft, camUp, camDir);

        setRotation(rotation);
        setTranslation(camLoc);

        Matrix3.releaseTempInstance(rotation);
    }

    /**
     * <code>setCamera</code> sets the camera that this node controls.
     *
     * @param camera
     *            the camera that this node controls.
     */
    public void setCamera(final Camera camera) {
        _camera = camera;
    }

    /**
     * <code>getCamera</code> retrieves the camera object that this node controls.
     *
     * @return the camera this node controls.
     */
    public Camera getCamera() {
        return _camera;
    }

    /**
     * <code>updateWorldTransform</code> updates the rotation and translation of this node, and sets the camera's frame
     * buffer to reflect the current view.
     */
    @Override
    public void updateWorldTransform(final boolean recurse)
    {
        updateLocalTransform();
        _worldTransform.setTranslation( _parent.getWorldTranslation().getX() + getTranslation().getX(),
                                        _parent.getWorldTranslation().getY() + getTranslation().getY(),
                                        _parent.getWorldTranslation().getZ() + getTranslation().getZ() );
//        _worldTransform.setRotation( _mat );
        if (_camera != null)
        {
            _camera.setLocation( getWorldTranslation() );
            _camera.lookAt( _parent.getWorldTranslation(), _worldUp );
            _camera.onFrameChange();
        }
    }

    private void updateLocalTransform()
    {
        ReadOnlyMatrix3 _pMat;
        _pMat = _parent.getWorldRotation();
        _newTranslation.set( _baseTranslation );
        _pMat.applyPost( _newTranslation, _newTranslation );
        switch( _chaseMode )
        {
            case Hard:
                break;
            case Soft:
                Vector3.lerp( _previousTranslation, _newTranslation, _softnessFactor, _previousTranslation );
                _previousTranslation.normalizeLocal();
                _newTranslation.set( _previousTranslation );
                break;               
        }
        _currentZoomLevel = _currentZoomLevel + 0.05*(_targetZoomLevel-_currentZoomLevel);       
        _localTransform.setTranslation( _newTranslation.multiplyLocal( _currentZoomLevel ) );
        markDirty(DirtyType.Transform);
    }
   
    @Override
    public void write(final OutputCapsule capsule) throws IOException {
        super.write(capsule);
        capsule.write(_camera, "camera", null);

    }

    @Override
    public void read(final InputCapsule capsule) throws IOException {
        super.read(capsule);
        _camera = (Camera) capsule.readSavable("camera", null);

    }

    public void increaseZoom()
    {
        _targetZoomLevel += 0.1*_targetZoomLevel;
    }

    public void decreaseZoom()
    {
        _targetZoomLevel -= 0.1*_targetZoomLevel;
    }

    @Override
    public void setTranslation( double x, double y, double z )
    {
        _baseTranslation.set( x, y, z );
        _targetZoomLevel = (float)_baseTranslation.length();
        _currentZoomLevel = _targetZoomLevel;
        _localTransform.setTranslation(_baseTranslation);
        _baseTranslation.normalizeLocal();
        markDirty(DirtyType.Transform);
    }

    @Override
    public void setTranslation( ReadOnlyVector3 translation )
    {
        setTranslation( translation.getX(), translation.getY(), translation.getZ() );
    }

   
}
obi
regular
 
Posts: 317
Joined: Thu Sep 24, 2009 8:06 pm


Return to Wishlist

Who is online

Users browsing this forum: No registered users and 0 guests

cron