Rotate object around world origin - matrix

I am currently trying to rotate a positionVector (0,0,1) around the world's x-axis and then rotate it back to its original position (just trying to get it to work). I read into rotation matrixes and got it working (sorta) but i am pretty stuck now.
As the image and code shows i create a cube at the starting point (0,0,1) and rotate it down in this case 30 degrees. But it seems to rotate more than 30 degrees when rotating clockwise. However when i rotate it back counterclockwise (30 degrees) it does rotate the proper amount. Which results in it not ending up at its starting point as it should (0,0,1).
I was wondering if any of you could shed some light on why this is happening and how to fix it. Thank you guys in advance!
public float RotAngle = 330f;
public GameObject cube;
public GameObject original;
public GameObject relocator;
public GameObject initialTurn;
void Start ()
{
Vector3 pixelPos = new Vector3(0f, 0f, 1f);
original = GameObject.Instantiate(cube,pixelPos,Quaternion.identity) as GameObject;
original.name = "Original";
initialTurn = GameObject.Instantiate(cube, pixelPos, Quaternion.identity) as GameObject;
initialTurn.name = "InitialTurn";
relocator = GameObject.Instantiate(cube, pixelPos, Quaternion.identity) as GameObject;
relocator.name = "Relocator";
}
void Update()
{
initialTurn.transform.position = RotateAroundOrigin(original.transform.position, RotAngle*Mathf.Deg2Rad);
relocator.transform.position = RotateAroundOrigin(initialTurn.transform.position, (RotAngle * -1f) * Mathf.Deg2Rad);
}
Vector3 RotateAroundOrigin(Vector3 startPos,float angle)
{
startPos.Normalize();
startPos.y = (startPos.y * Mathf.Cos(angle)) - (startPos.z * Mathf.Sin(angle));
startPos.z = (startPos.y * Mathf.Sin(angle)) + (startPos.z * Mathf.Cos(angle));
return startPos.normalized;
}

You can rotate a direction vector pretty easily with a Quaternion.
Try this:
Vector3 RotateAroundOrigin(Vector3 startPos,float angle)
{
startPos.Normalize();
Quaternion rot = Quaternion.Euler(angle, 0.0f, 0.0f); // Rotate [angle] degrees about the x axis.
startPos = rot * startPos;
return startPos;
}

Related

Aligning animation with direction Unity

So the problem is when I move the character(he is not humanoid) his walk animation is not aligned with the direction of his movement, for example, if I press W then he moves forward but his walk animation turns 90 degrees left, I have no idea where the problem might be. Here's the code I have:
public class PlayerControler : MonoBehaviour
{
public float MovSpeed = 3;
public float SmoothTime = 0.1f;
float TurnSmoothVelocity;
public float SpeedSmoothTime = 0.1f;
float SmoothVelocity;
float CurrentSpeed;
Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
Vector2 Input = new Vector2(UnityEngine.Input.GetAxisRaw("Horizontal"), UnityEngine.Input.GetAxisRaw("Vertical"));
Vector2 InputDirection = Input.normalized;
if (InputDirection != Vector2.zero)
{
float TargetRotation = Mathf.Atan2(InputDirection.x, InputDirection.y) * Mathf.Rad2Deg;
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y , TargetRotation, ref TurnSmoothVelocity, SmoothTime);
}
float targetSpeed = MovSpeed * InputDirection.magnitude;
CurrentSpeed = Mathf.SmoothDamp(CurrentSpeed, targetSpeed, ref SmoothVelocity, SmoothTime);
transform.Translate(transform.forward * CurrentSpeed * Time.deltaTime, Space.World);
float animationSpeedPercent = .5f * InputDirection.magnitude;
animator.SetFloat("SpeedPercent", animationSpeedPercent, SpeedSmoothTime, Time.deltaTime);
}
}
The Animated Object should be the Child of the Controller that has this Script assigned.
Just make an EmptyGameObject, add this script and parent your Animated Character under that Object.
If it's still not working correctly there might be something wrong with the Animation. The Script looks right to me.

Horizontal axis not working after animation

So, I have built a simple car game, and have attached a script that allows it to move on both axes. I have created an animation, so that if the car turns upside down, there is an option to press the 'f' button and flip the car back to normal. Unfortunately, once the animation plays and the car flips back onto it's wheels, the car moves forwards and backwards, but doesn't rotate.
What could be the issue?
Here is the script:
var speed : float = 10.0;
var rotationSpeed : float = 100.0;
var CarFlip : Animator;
function Start () {
CarFlip.enabled = false;
}
function Update () {
var translation : float = Input.GetAxis ("Vertical") * speed;
var rotation : float = Input.GetAxis ("Horizontal") * rotationSpeed;
translation *= Time.deltaTime;
rotation *= Time.deltaTime;
transform.Translate (0, 0, translation);
transform.Rotate (0, rotation, 0);
if(Input.GetKeyUp(KeyCode.F)){
CarFlip.enabled = true;
}
if(Input.GetKeyDown(KeyCode.B)){
speed = 30;
}
if(Input.GetKeyUp(KeyCode.B)){
speed = 15;
}
}
The Animator updates the transforms every frame so your change in Update() is being over-written.
If you want to override what it has done you need to apply your changes during LateUpdate().
I think the animator is still enabled making the rotation stuck. Maybe try something like this as a test to see if setting animator to false will get the car rotating again:
if(Input.GetKeyDown(KeyCode.F))
{
CarFlip.enabled = true;
}
if(Input.GetKeyUp(KeyCode.F))
{
CarFlip.enabled = false;
}

Google IO Tango Unity example not working

I'm having alot of trouble with the Google IO codelab for Tango https://io2015codelabs.appspot.com/codelabs/project-tango#1
After I finished it, it runs but it only turns, it doesnt move forward and backwars like the other tango apps in the play store.
I started on this yesterday but even after two days of debugging, I cannot get it to work right. Today I got so frustrated that I deleted everything and started over from scratch and it is still broken. I can get the permissions so I think tango is up and running, but not moving. I have enabled motion tracking and disabled/removed the scripts and code as specified in the tutorial. My PoseController looks like this:
using UnityEngine;
using System.Collections;
using Tango;
using System;
public class PoseController : MonoBehaviour , ITangoPose {
private TangoApplication m_tangoApplication; // Instance for Tango Client
private Vector3 m_tangoPosition; // Position from Pose Callback
private Quaternion m_tangoRotation; // Rotation from Pose Callback
private Vector3 m_startPosition; // Start Position of the camera
private Vector3 m_lastPosition; // last position returned in Unity coordinates.
// Controls movement scale, use 1.0f to be metric accurate
// For the codelab, we adjust the scale so movement results in larger movements in the
// virtual world.
private float m_movementScale = 10.0f;
// Use this for initialization
void Start ()
{
// Initialize some variables
m_tangoRotation = Quaternion.identity;
m_tangoPosition = Vector3.zero;
m_lastPosition = Vector3.zero;
m_startPosition = transform.position;
m_tangoApplication = FindObjectOfType<TangoApplication>();
if(m_tangoApplication != null)
{
RequestPermissions();
}
else
{
Debug.Log("No Tango Manager found in scene.");
}
}
// Permissions callback
private void PermissionsCallback(bool success)
{
if(success)
{
m_tangoApplication.InitApplication(); // Initialize Tango Client
m_tangoApplication.InitProviders(string.Empty); // Initialize listeners
m_tangoApplication.ConnectToService(); // Connect to Tango Service
}
else
{
AndroidHelper.ShowAndroidToastMessage("Motion Tracking Permissions Needed", true);
}
}
private void RequestPermissions()
{
// Request Tango permissions
m_tangoApplication.RegisterPermissionsCallback(PermissionsCallback);
m_tangoApplication.RequestNecessaryPermissionsAndConnect();
m_tangoApplication.Register(this);
}
// Pose callbacks from Project Tango
public void OnTangoPoseAvailable(Tango.TangoPoseData pose)
{
// Do nothing if we don't get a pose
if (pose == null) {
Debug.Log("TangoPoseData is null.");
return;
}
// The callback pose is for device with respect to start of service pose.
if (pose.framePair.baseFrame == TangoEnums.TangoCoordinateFrameType.TANGO_COORDINATE_FRAME_START_OF_SERVICE &&
pose.framePair.targetFrame == TangoEnums.TangoCoordinateFrameType.TANGO_COORDINATE_FRAME_DEVICE)
{
if (pose.status_code == TangoEnums.TangoPoseStatusType.TANGO_POSE_VALID)
{
// Cache the position and rotation to be set in the update function.
m_tangoPosition = new Vector3((float)pose.translation [0],
(float)pose.translation [1],
(float)pose.translation [2]);
m_tangoRotation = new Quaternion((float)pose.orientation [0],
(float)pose.orientation [1],
(float)pose.orientation [2],
(float)pose.orientation [3]);
}
else // if the current pose is not valid we set the pose to identity
{
m_tangoPosition = Vector3.zero;
m_tangoRotation = Quaternion.identity;
}
}
}
/// <summary>
/// Transforms the Tango pose which is in Start of Service to Device frame to Unity coordinate system.
/// </summary>
/// <returns>The Tango Pose in unity coordinate system.</returns>
/// <param name="translation">Translation.</param>
/// <param name="rotation">Rotation.</param>
/// <param name="scale">Scale.</param>
Matrix4x4 TransformTangoPoseToUnityCoordinateSystem(Vector3 translation,
Quaternion rotation, Vector3 scale)
{
// Matrix for Tango coordinate frame to Unity coordinate frame conversion.
// Start of service frame with respect to Unity world frame.
Matrix4x4 m_uwTss;
// Unity camera frame with respect to device frame.
Matrix4x4 m_dTuc;
m_uwTss = new Matrix4x4();
m_uwTss.SetColumn (0, new Vector4 (1.0f, 0.0f, 0.0f, 0.0f));
m_uwTss.SetColumn (1, new Vector4 (0.0f, 0.0f, 1.0f, 0.0f));
m_uwTss.SetColumn (2, new Vector4 (0.0f, 1.0f, 0.0f, 0.0f));
m_uwTss.SetColumn (3, new Vector4 (0.0f, 0.0f, 0.0f, 1.0f));
m_dTuc = new Matrix4x4();
m_dTuc.SetColumn (0, new Vector4 (1.0f, 0.0f, 0.0f, 0.0f));
m_dTuc.SetColumn (1, new Vector4 (0.0f, 1.0f, 0.0f, 0.0f));
m_dTuc.SetColumn (2, new Vector4 (0.0f, 0.0f, -1.0f, 0.0f));
m_dTuc.SetColumn (3, new Vector4 (0.0f, 0.0f, 0.0f, 1.0f));
Matrix4x4 ssTd = Matrix4x4.TRS(translation, rotation, scale);
return m_uwTss * ssTd * m_dTuc;
}
// FixedUpdate is called at a fixed rate
void FixedUpdate()
{
// Convert position and rotation from Tango's coordinate system to Unity's.
Matrix4x4 uwTuc = TransformTangoPoseToUnityCoordinateSystem(m_tangoPosition,
m_tangoRotation, Vector3.one);
Vector3 newPosition = (uwTuc.GetColumn(3))* m_movementScale;
Quaternion newRotation = Quaternion.LookRotation(uwTuc.GetColumn(2),
uwTuc.GetColumn(1));
// Calculate the difference in the poses received. This allows us
// to recover when we hit something in the virtual world.
Vector3 delta = newPosition - m_lastPosition;
m_lastPosition = newPosition;
Vector3 destination = rigidbody.position + delta;
Vector3 vectorToTargetPosition = destination - transform.position;
// If there is motion, move the player around the scene.
if(vectorToTargetPosition.magnitude > 0.1f)
{
vectorToTargetPosition.Normalize();
// Set the movement vector based on the axis input.
Vector3 movement = vectorToTargetPosition;
// Normalise the movement vector and make it proportional to the speed per second.
movement = movement.normalized * 5f * Time.deltaTime;
// Move the player to it's current position plus the movement.
rigidbody.MovePosition (transform.position + movement);
}
else {
rigidbody.velocity = Vector3.zero;
}
// always rotate, even if we don't move.
rigidbody.MoveRotation (newRotation);
// finally, let the game manager know the position of the player.
GameManager.Instance.PlayerPosition = transform.position;
}
}
That was just a copy and paste of what was in the codelab, so at this point there is none of my own code and still I cannot run this correctly. What am I doing wrong????
I've done some android development before tango but I'm fairly new to unity. However, I've double and triple checked everything and also my device says everything is up to date.
Thanks in advance!
It looks like the codelab has been updated and the last line in FixedUpdate was commented out "//GameManager.Instance.PlayerPosition = transform.position;".
https://io2015codelabs.appspot.com/codelabs/project-tango#7
Hope that helps.

Unity: Changing direction character faces when using InputManager(side scroller)

I'm creating a simple side scroller with a couple people using Unity and am definitely a beginner. The character being used is 3D and runs forward well, but when running backwards he still faces forward. I have the controls setup in the InputManager so pressing A moves backwards and D moves forward but I'm not sure what to do so he faces his respective movement.
Any help would be greatly appreciated and if you need more information besides the following code I have for the movement let me know, it's based off another post I found.
var speed : float = 6.0;
var jumpSpeed : float = 6.0;
var gravity : float = 12.0;
//This variable is now inheriting the Vector3 info (X,Y,Z) and setting them to 0.
private var moveDirection : Vector3 = Vector3.zero;
function MoveAndJump() {
var controller : CharacterController = GetComponent(CharacterController);
if(controller.isGrounded) {
//moveDirection is inheriting Vector3 info. This now sets the X and Z coords to receive the input set to "Horizontal" and "Vertical"
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); //Allows player Input
moveDirection = transform.TransformDirection(moveDirection); //How to move
moveDirection *= speed; //How fast to move
if(Input.GetButtonDown("Jump")) {
animation.Play("Jump");
moveDirection.y = jumpSpeed;
}
}
//Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
//This moves the controller
controller.Move(moveDirection * Time.deltaTime);
if(Input.GetButton("Fire1")){
animation.Play("Attack");
}
if(Input.GetButton("Vertical")){
animation.Play("Run");
}
}
function Update() {
MoveAndJump();
}
For what it's worth another problem I'm having involves having two different animations being able to work at the same time, like run and attack. I figured I should mention while I'm here if anybody knew how to go about that. Thank you again for your time!
I ended up solving this based off a different code I stumbled upon, then called the function inside of Update():
var speed : float;
var jumpSpeed : float;
var gravity : float;
private var moveDirection : Vector3 = Vector3.zero;
function MoveJumpAttack() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0, 0);
moveDirection *= speed;
if (moveDirection.sqrMagnitude > 0.01)
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (moveDirection), 90);
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}

XNA 2d rotation around centre

I'm trying to include support for zooming and rotating my camera class, around the centre of the viewport.
In my application, I've already positioned sprites manually before entering the SpriteBatch.Begin code, according to where the camera is positioned (to make culling easier to implement). Although each sprite is positioned manually, I would rather not rotate and scale each sprite individually.
I therefore am trying to use the matrixTransform argument on the SpriteBatch.Begin method.
Below is a hard-coded application I've made to illustrate the problem (using a Car.png content image). The rotation isn't as fast as I'd expect (10 degrees rotation every frame?), and it rotates/zooms about the top left. I would like it to rotate around the centre of the screen, which would always keep the middle car in the centre, and also scale from that point.
I have tried several combinations of creating matrix translations, reordering/adding/multiplying/translating by the halfway distance of viewport, but I don't really understand how matrices work. I've also tried the solutions on several websites which I haven't managed to make work for me.
Can someone tell me the matrix translations I have to create, or point me in the direction of a website you think will work for my setup?
Windows XNA application to demonstrate the problem:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace RenderTest
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D _carTexture;
float _zoom = 1.0f;
float _rotationInDegrees = 0.0f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
_carTexture = Content.Load<Texture2D>("Car");
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up)) // Zoom in key
_zoom *= 1.1f;
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Down)) // Zoom out key
_zoom /= 1.1f;
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left)) // Rotate anticlockwise key
_rotationInDegrees -= 10;
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right)) // Rotate clockwise key
_rotationInDegrees += 10;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullNone, null, GetMatrix(GraphicsDevice));
spriteBatch.Draw(_carTexture, new Rectangle(0, 0, 50, 50), Color.White);//Square car placed top left
spriteBatch.Draw(_carTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 - 25, GraphicsDevice.Viewport.Height / 2 - 50, 50, 100), Color.Green);//Car placed centre
spriteBatch.Draw(_carTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 + 100, GraphicsDevice.Viewport.Height / 2 + 100, 50, 50), Color.Black);//Off centre but always within screen
spriteBatch.End();
base.Draw(gameTime);
}
Matrix GetMatrix(GraphicsDevice graphicsDevice)
{
Matrix translationMatrix = Matrix.CreateTranslation(0, 0, 0);
Matrix rotationMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(MathHelper.ToRadians(_rotationInDegrees)));
Matrix zoomMatrix = Matrix.CreateScale(_zoom);
Matrix compositeMatrix = translationMatrix * rotationMatrix * zoomMatrix;
return compositeMatrix;
}
}
}
Thanks,
Lee
Solution
Matrix GetMatrix(GraphicsDevice graphicsDevice)
{
Matrix translateToOrigin = Matrix.CreateTranslation(-graphicsDevice.Viewport.Width / 2, -graphicsDevice.Viewport.Height / 2, 0);
Matrix rotationMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(_rotationInDegrees));
Matrix zoomMatrix = Matrix.CreateScale(_zoom);
Matrix translateBackToPosition = Matrix.CreateTranslation(graphicsDevice.Viewport.Width / 2, graphicsDevice.Viewport.Height / 2, 0);
Matrix compositeMatrix = translateToOrigin * rotationMatrix * zoomMatrix * translateBackToPosition;
return compositeMatrix;
}
You should use the same Rectangle each time, and do the positioning in the matrix.
The reason for this is that the matrix is applied to your sprites after they are positioned using rectangle. All subseqent matrix operations will treat (0,0) as the origin, instead of the center of the texture as you expected.

Resources