Keep camera from rotating around relative z-axis - unity3d

I'm trying to create camera movement that mimics the behavior of the unity scene editor where you can perform a spherical rotation around the scene with 2d mouse movement. So far the camera is rotating correctly given x or y movement, but dragging diagonally causes the camera to rotate around its relative z-axis until it gets locked. I cannot force the camera to look at the origin relative to world up because then it cannot rotate upside-down
Here is the script that I've attached to the camera
using UnityEngine;
public class MainCamera : MonoBehaviour
{
Vector2 startingPosition;
Vector2 mousePosition;
Vector3 orthogonalCameraVector;
float degreesPerUnitWidth = 180f / Screen.width;
float degreesPerUnitHeight = 180f / Screen.height;
float cameraRadius = 10;
void Start()
{
transform.position = new Vector3(0, 0, -cameraRadius);
transform.LookAt(Vector3.zero);
orthogonalCameraVector = -Vector3.left;
}
void LateUpdate()
{
if (Input.GetMouseButtonDown(0))
{
mousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0))
{
var input = new Vector2(Input.mousePosition.x ,Input.mousePosition.y);
startingPosition = mousePosition;
var mouseDelta = startingPosition - input;
var xzDegrees = -mouseDelta.y * degreesPerUnitHeight;
var xzRotation = Quaternion.AngleAxis(xzDegrees, orthogonalCameraVector); // rotate about the relative x-z plane
var yRotation = Quaternion.AngleAxis(-mouseDelta.x * degreesPerUnitWidth, Vector3.up); // rotate about the world y-axis
var rotation = xzRotation * yRotation;
orthogonalCameraVector = rotation * orthogonalCameraVector;
transform.position = rotation * transform.position;
transform.rotation = rotation * transform.rotation;
mousePosition = Input.mousePosition;
}
}
}

I realized the orthogonalCamerVector only needed to be rotated about the y-axis because I wanted to keep it parallel with the xz-plane. I then applied this rotation to the orthogonalCamerVector before rotating the transform so it would always be rotating about a fixed plane so it looks something like this:
var xzDegrees = -mouseDelta.y * degreesPerUnitHeight;
var yRotation = Quaternion.AngleAxis(-mouseDelta.x * degreesPerUnitWidth, Vector3.up); // rotate about the world y-axis
orthogonalCameraVector = yRotation * orthogonalCameraVector;
var xzRotation = Quaternion.AngleAxis(xzDegrees, orthogonalCameraVector); // rotate about the relative x-z plane
var rotation = xzRotation * yRotation;
transform.position = rotation * transform.position;
transform.rotation = rotation * transform.rotation;

Related

Unity 3d main camera LookAt is not rotating on x axis

Am developing a follow target camera, it's working fine but when the vehicle(Target) is on slope, the camera is not rotating to show the full vehicle.
void LateUpdate()
{
if (car1.controlled && Camera.main != null)
{
float speedFactor = Mathf.Clamp01(target.root.GetComponent<Rigidbody>().velocity.magnitude / 20.0f);
if (speedFactor < 0.01f)
speedFactor = 0.01f;
Camera.main.fieldOfView = Mathf.Lerp(40, 65, speedFactor);
float currentDistance = Mathf.Lerp(13.5f, 8.5f, speedFactor);
currentVelocity = currentVelocity.normalized;
Vector3 newTargetPosition = target.position + Vector3.up * height;
Vector3 newPosition = newTargetPosition - ((currentVelocity * currentDistance));
newPosition.y = newTargetPosition.y;
Vector3 targetDirection = newPosition - newTargetPosition;
if (Physics.Raycast(newTargetPosition, targetDirection, out hit, currentDistance, raycastLayers))
newPosition = hit.point;
Camera.main.transform.position = newPosition;
Camera.main.transform.LookAt(newTargetPosition);
}
LookAt is going to set the camera rotation to be looking straight at the newTargetPosition. It doesn't actually moves the camera up, it simply rotates it to look at the vehicule. You should modify your code so the camera moves up when the vehicule goes down a slope and then make it look at the vehicule.

camera always rotate to 90 degrees

so i was writing some codes to make camera follows player, i already set camera rotation to 30 degrees, but when i test it, it always rotate to 90 degrees.
this is my code
public GameObject target;
public float damping = 1;
Vector3 offset;
// Start is called before the first frame update
void Start()
{
offset = target.transform.position - transform.position;
}
// Update is called once per frame
void LateUpdate()
{
float currentAngle = transform.eulerAngles.y;
float desiredAngle = target.transform.eulerAngles.y;
float angle = Mathf.LerpAngle(currentAngle, desiredAngle, Time.deltaTime * damping);
Quaternion rotation = Quaternion.Euler(0, angle, 0);
transform.position = target.transform.position - (rotation * offset);
transform.LookAt(target.transform);
}
how to make camera rotates to 30 degrees instead of 90 degrees?

Rotate Camera vector to look at player Unity

I create a game, like minigolf/pool. I want to have a camera which follow player.
Position is normally ok, I get the ball direction and I lerp.
Rotation is almost ok. Currently, rotation by Y axis is ok, but camera look straigth forward, and don't look down to the player :
I already try many thing , quaternion angleToaxis, quarternion lookat ... but doesn't look good, the camera go look away ...
Here my code
namespace CameraManagerNameSpace
{
public class CameraManager : MonoBehaviour
{
public float cameraHeight=13f;
public PlayerNameSpace.Player playerToFollow;
public float followSpeed = 3f;
public float rotationSpeed = 1f;
float distance;
Vector3 position;
Vector3 newPos;
Quaternion rotation;
Quaternion newRot;
Vector3 playerPrevPos, playerMoveDir;
bool firstMoveDone=false;
void Start()
{
playerPrevPos = playerToFollow.player_transform.position;
distance = Vector3.Distance(transform.position,playerToFollow.player_transform.position);
}
void FixedUpdate()
{
if(Vector3.Distance(playerToFollow.player_transform.position ,playerPrevPos)>0.5f || firstMoveDone)
{
playerMoveDir = playerToFollow.player_transform.position - playerPrevPos;
firstMoveDone = true;
}
else
{
playerMoveDir = new Vector3(0,0,0);
}
if (playerMoveDir != Vector3.zero)
{
playerMoveDir.Normalize();
newPos = playerToFollow.player_transform.position - playerMoveDir * distance;
newRot =Quaternion.LookRotation(playerMoveDir,Vector3.up);
position = Vector3.Lerp(transform.position, new Vector3(newPos.x,newPos.y+cameraHeight,newPos.z), followSpeed * Time.deltaTime);
rotation = Quaternion.Lerp(transform.rotation, newRot, rotationSpeed * Time.deltaTime);
transform.position = position;
transform.rotation = rotation;
playerPrevPos = playerToFollow.player_transform.position;
}
}
}
}
Also, I don't know why, but after the balls stop the camera continue to do some movement very jerky, jolting, halting.
Well in
newRot = Quaternion.LookRotation(playerMoveDir,Vector3.up);
you are saying the camera to look in the same direction the player is moving ... not to look at the player. This would work if you wouldn't give the camera an extra position offset in the Y axis.
You might want to rather try
// vector pointing from the camera towards the player
var targetDirection = playerToFollow.player_transform.position - transform.position;
newRot = Quaternion.LookRotation(targetDirection, Vector3.up);
You should also rather use Update since FixedUpdate is only used for physics related stuff (also see Update & FixedUpdate)

unity camera follow rolling box

i have a cube that rolls with the arrow keys or control pad
up goes up, left turns left, and right turns right, so only the up makes it roll
im trying to get a camera to follow but not really getting anywhere
i found this script cant rember where that im trying to alter
but as i roll the cube forward the camera spins
simple video showing movment
https://imgur.com/a/BfoR1VF
any pointers in the right direction sorry about the pun would be good
simple lookat script
public Transform player;
void Start()
{
}
void Update()
{
Vector3 targetPostion = new Vector3(player.transform.position.x, transform.position.y,player.transform.position.z);
transform.LookAt(targetPostion);
}
and the follow script
// The target we are following
public Transform target;
// The distance in the x-z plane to the target
//So this would be your offset
public float distance = 10.0f;
// the height we want the camera to be above the target
public float height = 5.0f;
// How much we
public float heightDamping = 2.0f;
public float rotationDamping = 3.0f;
void LateUpdate()
{
// Early out if we don't have a target
if (!target) return;
// Calculate the current rotation angles
float wantedRotationAngle = target.eulerAngles.y;
float wantedHeight = target.position.y + height;
float currentRotationAngle = transform.eulerAngles.y;
float currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position = new Vector3(transform.position.x, currentHeight, transform.position.z);
// Always look at the target
Vector3 thetargetPostition = new Vector3(0, target.position.y,0);
transform.LookAt(target.position);
//transform.LookAt(thetargetPostition);

MouseOrbit Customization: Place camera on spot orbit

I have a MouseOrbit script based on the Standard Assets Script that I need to customize to place the camera in a specific spot in the orbit.
Heres the basics of the standard script that ships with Unity3d:
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 onUpdate(){
x += Input.GetAxis("Mouse X") * xSpeed;
y -= Input.GetAxis("Mouse Y") * ySpeed;
var rotation = Quaternion.Euler(y, x,0);
var position = rotation * Vector3(0.0, 0.0, cameraDelta);
transform.rotation = rotation;
transform.position = position;
}
What I need to do is place the camera in a few spots around the target object at 0,0.
The first is directly behind the object. x:7,:y0,z:0.
Here's what I thought would work:
function TransformCamera(x,y,z){
//set position of camera
transform.position = new Vector3(x, y, z);
var angles = transform.eulerAngles;
y = angles.y;
x = angles.x;
z = angles.z;
var rotation = Quaternion.Euler(y, x, z);
var position = rotation * Vector3(0.0, 0.0, cameraDelta);
//adjusted_target;
transform.rotation = rotation;
transform.position = position;
}
This script is close... it transforms the camera and rotates it to look at the object, but it doesn't place the camera in the correct location 7,0,0.
Thanks!
Try this modified script. i hope this will solve your problem.
using UnityEngine;
using System.Collections;
public class OrbitCamera : MonoBehaviour
{
//The target of the camera. The camera will always point to this object.
public Transform _target;
//The default distance of the camera from the target.
private float _distance ;
//Control the speed of zooming and dezooming.
public float _zoomStep = 1.0f;
//The speed of the camera. Control how fast the camera will rotate.
public float _xSpeed = 1f;
public float _ySpeed = 1f;
//The position of the cursor on the screen. Used to rotate the camera.
private float _x = 0.0f;
private float _y = 0.0f;
//Distance vector.
private Vector3 _distanceVector;
/**
* Move the camera to its initial position.
*/
void Start ()
{
_distanceVector = new Vector3(0.0f,0.0f,-this.transform.position.z);
_distance = this.transform.position.z;
Vector2 angles = this.transform.localEulerAngles;
_x = angles.x;
_y = angles.y;
this.Rotate(_x, _y);
}
/**
* Rotate the camera or zoom depending on the input of the player.
*/
void LateUpdate()
{
if ( _target )
{
this.RotateControls();
this.Zoom();
}
}
/**
* Rotate the camera when the first button of the mouse is pressed.
*
*/
void RotateControls()
{
if ( Input.GetButton("Fire1") )
{
_x += Input.GetAxis("Mouse X") * _xSpeed;
_y += -Input.GetAxis("Mouse Y")* _ySpeed;
this.Rotate(_x,_y);
}
}
/**
* Transform the cursor mouvement in rotation and in a new position
* for the camera.
*/
void Rotate( float x, float y )
{
//Transform angle in degree in quaternion form used by Unity for rotation.
Quaternion rotation = Quaternion.Euler(y,x,0.0f);
//The new position is the target position + the distance vector of the camera
//rotated at the specified angle.
Vector3 position = rotation * _distanceVector + _target.position;
//Update the rotation and position of the camera.
transform.rotation = rotation;
transform.position = position;
}
/**
* Zoom or dezoom depending on the input of the mouse wheel.
*/
void Zoom()
{
if ( Input.GetAxis("Mouse ScrollWheel") < 0.0f )
{
this.ZoomOut();
}
else if ( Input.GetAxis("Mouse ScrollWheel") > 0.0f )
{
this.ZoomIn();
}
}
/**
* Reduce the distance from the camera to the target and
* update the position of the camera (with the Rotate function).
*/
void ZoomIn()
{
_distance -= _zoomStep;
_distanceVector = new Vector3(0.0f,0.0f,-_distance);
this.Rotate(_x,_y);
}
/**
* Increase the distance from the camera to the target and
* update the position of the camera (with the Rotate function).
*/
void ZoomOut()
{
_distance += _zoomStep;
_distanceVector = new Vector3(0.0f,0.0f,-_distance);
this.Rotate(_x,_y);
}
} //End class