Unity - Quaternion.Lerp - Wheel rotation - unity3d

I have one problem in script(Unity) that I made for car controller. When I want to rotate front wheels of car, example I'm pressing 'A' or 'D' wheels will turn on left or right(0,45 or -45,0) and immediately it will turn on starting rotation(0,0,0), I didn't have this problem when I didn't use Quaternion.Lerp, without Quaternion.Lerp it works fine. Any kind of help will be welcome.
//Rotation - WHEELS
CurrentRotation = Horizontal * RotationSpeed * Time.deltaTime;
if (CurrentRotation <= MaximumRotation || CurrentRotation >= -MaximumRotation)
{
Vector3 from_v = new Vector3(Wheels[0].transform.localRotation.x, Wheels[0].transform.localRotation.y, Wheels[0].transform.localRotation.z);
Vector3 to_v = new Vector3(Wheels[1].transform.localRotation.x, CurrentRotation, Wheels[1].transform.localRotation.z);
Quaternion from = Quaternion.Euler(from_v);
Quaternion to = Quaternion.Euler(to_v);
float lerp = 0.5F * (1.0F + Mathf.Sin(Mathf.PI * Time.realtimeSinceStartup * 3f));
Wheels[0].transform.localRotation = Quaternion.Lerp(from, to, lerp);
Wheels[1].transform.localRotation = Quaternion.Lerp(from, to, lerp);
}

I don't fully understand what you want to achieve. Is it the rolling of the wheel plus steering?
Quaternions are great, but here you don't need them. You can get and set the Euler (main axis) rotation directly. Untested code:
Vector3 rot = Wheels[0].localRotation;
rot.x += speed * Time.deltaTime;
rot.y = (current smoothed steering angle)
Wheels[0].localRotation = rot;
Wheels[1].localRotation = rot;
You should orient all your wheel game objects to point x-Axis to the right and Y-Axis to the top. The smoothing / max angles can depend on the input type / device, the game settings and the car speed.
It would be nice if you upvote my answer so I finally can write comments here.
Kind Regards,
Chris

Related

Unity - rotated objects flips in a strange way when using Quaternions

I'm trying to create a system in VR in which an object rotation follows the rotation of the player's hand. Unfortunately, when the hand rotates at a high angle, the rotated object flips in a strange way as if it had a problem with the rotation change from 360 degrees to 0. I tried many ways to solve this problem, but each one that worked did not allow me to change "sensitivity" on the basis of:
1 - target is rotating 1: 1 ratio with hand
2 - target is rotating twice as much as hand
etc.
// In FixedUpdate
Quaternion deltaRotation = Quaternion.Inverse(target.rotation) * hand.rotation;
deltaRotation.ToAngleAxis(out float angle, out Vector3 axis);
target.rotation *= Quaternion.AngleAxis(angle * sensitivity, axis);
Any help would be appreciated!
So the problem is in
Quaternion deltaRotation = Quaternion.Inverse(target.rotation) * hand.rotation;
if the sensitivity is != 1 these objects rotations get desynchronized so the deltaRotation will not give you the value you expect. You probably wanted to check how much hand rotated since last frame, like that:
Quaternion _lastFrameRotation;
void Awake()
{
_lastFrameRotation = transform.rotation;
}
private void FixedUpdate()
{
Quaternion deltaRotation = Quaternion.Inverse(_lastFrameRotation) * transform.rotation;
deltaRotation.ToAngleAxis( out float angle, out Vector3 axis );
target.rotation *= Quaternion.AngleAxis( angle * sensitivity, axis );
_lastFrameRotation = transform.rotation;
}

1st person space ship pitch and yaw isue

I've been trying for some time now with different tutorials to get a nice firstperson (cockpit view) spaceship controll system. I tried using mouse only, keyboard only and combinations but I keep encountering the same problem with all tutorials. even this simple line of code does it:
transform.position += transform.forward * Time.deltaTime * 90f;
transform.Rotate( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
The problem I keep getting is that if I pitch its ok. it I yaw its ok. But If I do both (so I go diagonaly) it also rotates my ship on the Z axis and messes up my orientation. I tried locking the z rotation in the rigidbody but that does'nt help either. I tried making code myself alternating with apply torque and simply rotating, followed some tutorials including this one: Tutorial but keep getting the rotation problem.
What I want to make is a game that controlls like the old game Helbender
Does anyone of you know of a way that I can get spaceship controlls to work?
----EDIT-----
Got a bit further now. It doenst turn on my z axis anymore becouse I keep setting it to 0. Only problem now is that if I try to make a looping the ship flips around instead of nicely looping.
if (Input.GetKey("up"))
{
transform.Rotate(transform.right * -ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("down"))
{
transform.Rotate(transform.right * ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("left"))
{
transform.Rotate(transform.up * -ShipPanSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey("right"))
{
transform.Rotate(transform.up * ShipPanSpeed * Time.deltaTime,Space.World);
}
float z = transform.eulerAngles.z;
transform.Rotate(0, 0, -z);
You could always try to make one parent object for the Controls and then a child object (the spaceshit) that you can rotate for the pivot but not attach any movement beside rotation.
What i mean is that you can rotate the parent on the Y axis to make it rotate and move the transform forward or backward at the same time. If you want to pivot up or down you can transform forward at the sametime you transform up/down multiplied with the axis you want to pivot with
Example:
private void Update(){
//PARENT--------------------------------------------
// MOVING FORWARD AND BACKWARD
transform.position += transform.forward * Input.GetAxis("Vertical") * speed * Time.deltaTime();
// MOVING RIGHT AND LEFT
transform.position += transform.right * Input.GetAxis("Horizontal") * speed * Time.deltaTime();
//PIVOT UP AND DOWN
transform.position += transform.up * -Input.GetAxis("Mouse Y") * speed * Time.deltaTime();
//ROTATE AROUND THE Y AXIS
tranform.Rotate(0f, Input.GetAxis("Horizontal") * rotationspeed, 0f);
}
For the spaceship (child) for the pivot i would recommend you to make a emptyobject and set the chip to lookAt that object based on the input axis you use to move up/down and forward/backward.
Hope this helped or at least gave you a idea of how to make it :)

Lossless movement in hinge joints - Unity

I've created a simple pendulum in Unity - GameObject with Rigidbody and Hinge Joint components. I've set both drag ang angular drag to 0. With starting position at 90 degrees I'd expect the pendulum to swing back and forth from 90 to -90 degrees. However, that's not the case - the amplitude decays very quickly, but for small angles the pendulum looks like it's never going to stop.
My question is: How should I configure hinge joints in order to achieve full control over physics and forces that resist motion? My goal is to have physics simulation as precise as it's possible, even at the cost of performance.
I've already tried to reduce time intervals for fixed step and increased solver iterations - none of these worked out.
Why do I need it? I'm planning to design a control system for multiple inverted pendulum on a cart. I have a mathematical model of my pendulum implemented in Matlab and I wanted to verify it using a simple model in Unity (because in that case I adjust all parameters, initial conditions etc. and the physics engine is calculating everything for me). If it turns out the physics engine that is backing Unity isn't reliable enough, what other software would you recommend me?
My understanding is that due to the way Unity's physics operates, there can be a loss of kinetic energy over time in this sort of pendulum motion if you only use a hinge joint. Basically, if you want an accurate pendulum simulation, you have to bypass the physics engine and implement it directly.
There is a very good post on the gamedev stackexchange originally posted by MLM about how to implement a more accurate pendulum simulation in Unity, which I have pasted below.
I thought this would be a relatively simple problem to solve but I spent a couple days trying to figure out how the heck to simulate pendulum movement. I didn't want to cheat and just change the x,y position based on sin(theta) and cos(theta) curves. Instead I wanted to deal with the two forces that are applied in real life, Gravity and Tension. The main piece I was missing was centripetal force.
The Pendulum (mathematics) wikipedia page has a great animation(below, on left) explaining the pendulum motion. You can see my result(on right) strikingly similar to that diagram
The "bob" is the swinging object and the "pivot" is the origin/root.
I also found this article and diagram(below) pretty helpful:
Theta equals the angle between the rope and the direction of gravity.
When the bob is on the left or right the tension equals:
The reason the tension force is greater as the bob approaches equilibrium point(middle) is because of centripetal force:
So the overrall tension formula looks like as the bob swings is:
There are two forces in the pendulum system:
Gravity
GravityForce = mass * gravity.magnitude
GravityDirection = gravity.normalized
Tension
TensionForce = (mass * gravity * Cos(theta)) + ((mass * velocityTangent^2)/ropeLength)
TensionDirection = ropeDirection = bob to pivot
Just apply gravity to your object like you would for a normal object and then apply the tension. When you apply the forces, just multiply the force by the direction and deltaTime.
Below is the Pendulum.cs script(also as a GitHub Gist). It works quite well but there is some rounding error drift if you leave it for a while (doesn't return to exactly same position).
The script works in 3D but of course a pendulum only swings in a 2D plane. It also works with gravity in any direction. So for example, if you invert the gravity the pendulum works upside down. Edit->Project Settings->Physics->Gravity
It is very important to have a consistent relatively small deltaTime when updating the pendulum so that you do not bounce around the curve. I am using the technique found in this article, FIX YOUR TIMESTEP! by Glenn Fiedler to accomplish this. Check the Update() function below to see how I implemented it.
Also as a GitHub Gist
using UnityEngine;
using System.Collections;
// Author: Eric Eastwood (ericeastwood.com)
//
// Description:
// Written for this gd.se question: http://gamedev.stackexchange.com/a/75748/16587
// Simulates/Emulates pendulum motion in code
// Works in any 3D direction and with any force/direciton of gravity
//
// Demonstration: https://i.imgur.com/vOQgFMe.gif
//
// Usage: https://i.imgur.com/BM52dbT.png
public class Pendulum : MonoBehaviour {
public GameObject Pivot;
public GameObject Bob;
public float mass = 1f;
float ropeLength = 2f;
Vector3 bobStartingPosition;
bool bobStartingPositionSet = false;
// You could define these in the `PendulumUpdate()` loop
// But we want them in the class scope so we can draw gizmos `OnDrawGizmos()`
private Vector3 gravityDirection;
private Vector3 tensionDirection;
private Vector3 tangentDirection;
private Vector3 pendulumSideDirection;
private float tensionForce = 0f;
private float gravityForce = 0f;
// Keep track of the current velocity
Vector3 currentVelocity = new Vector3();
// We use these to smooth between values in certain framerate situations in the `Update()` loop
Vector3 currentStatePosition;
Vector3 previousStatePosition;
// Use this for initialization
void Start () {
// Set the starting position for later use in the context menu reset methods
this.bobStartingPosition = this.Bob.transform.position;
this.bobStartingPositionSet = true;
this.PendulumInit();
}
float t = 0f;
float dt = 0.01f;
float currentTime = 0f;
float accumulator = 0f;
void Update()
{
/* */
// Fixed deltaTime rendering at any speed with smoothing
// Technique: http://gafferongames.com/game-physics/fix-your-timestep/
float frameTime = Time.time - currentTime;
this.currentTime = Time.time;
this.accumulator += frameTime;
while (this.accumulator >= this.dt)
{
this.previousStatePosition = this.currentStatePosition;
this.currentStatePosition = this.PendulumUpdate(this.currentStatePosition, this.dt);
//integrate(state, this.t, this.dt);
accumulator -= this.dt;
this.t += this.dt;
}
float alpha = this.accumulator/this.dt;
Vector3 newPosition = this.currentStatePosition*alpha + this.previousStatePosition*(1f-alpha);
this.Bob.transform.position = newPosition; //this.currentStatePosition;
/* */
//this.Bob.transform.position = this.PendulumUpdate(this.Bob.transform.position, Time.deltaTime);
}
// Use this to reset forces and go back to the starting position
[ContextMenu("Reset Pendulum Position")]
void ResetPendulumPosition()
{
if(this.bobStartingPositionSet)
this.MoveBob(this.bobStartingPosition);
else
this.PendulumInit();
}
// Use this to reset any built up forces
[ContextMenu("Reset Pendulum Forces")]
void ResetPendulumForces()
{
this.currentVelocity = Vector3.zero;
// Set the transition state
this.currentStatePosition = this.Bob.transform.position;
}
void PendulumInit()
{
// Get the initial rope length from how far away the bob is now
this.ropeLength = Vector3.Distance(Pivot.transform.position, Bob.transform.position);
this.ResetPendulumForces();
}
void MoveBob(Vector3 resetBobPosition)
{
// Put the bob back in the place we first saw it at in `Start()`
this.Bob.transform.position = resetBobPosition;
// Set the transition state
this.currentStatePosition = resetBobPosition;
}
Vector3 PendulumUpdate(Vector3 currentStatePosition, float deltaTime)
{
// Add gravity free fall
this.gravityForce = this.mass * Physics.gravity.magnitude;
this.gravityDirection = Physics.gravity.normalized;
this.currentVelocity += this.gravityDirection * this.gravityForce * deltaTime;
Vector3 pivot_p = this.Pivot.transform.position;
Vector3 bob_p = this.currentStatePosition;
Vector3 auxiliaryMovementDelta = this.currentVelocity * deltaTime;
float distanceAfterGravity = Vector3.Distance(pivot_p, bob_p + auxiliaryMovementDelta);
// If at the end of the rope
if(distanceAfterGravity > this.ropeLength || Mathf.Approximately(distanceAfterGravity, this.ropeLength))
{
this.tensionDirection = (pivot_p - bob_p).normalized;
this.pendulumSideDirection = (Quaternion.Euler(0f, 90f, 0f) * this.tensionDirection);
this.pendulumSideDirection.Scale(new Vector3(1f, 0f, 1f));
this.pendulumSideDirection.Normalize();
this.tangentDirection = (-1f * Vector3.Cross(this.tensionDirection, this.pendulumSideDirection)).normalized;
float inclinationAngle = Vector3.Angle(bob_p-pivot_p, this.gravityDirection);
this.tensionForce = this.mass * Physics.gravity.magnitude * Mathf.Cos(Mathf.Deg2Rad * inclinationAngle);
float centripetalForce = ((this.mass * Mathf.Pow(this.currentVelocity.magnitude, 2))/this.ropeLength);
this.tensionForce += centripetalForce;
this.currentVelocity += this.tensionDirection * this.tensionForce * deltaTime;
}
// Get the movement delta
Vector3 movementDelta = Vector3.zero;
movementDelta += this.currentVelocity * deltaTime;
//return currentStatePosition + movementDelta;
float distance = Vector3.Distance(pivot_p, currentStatePosition + movementDelta);
return this.GetPointOnLine(pivot_p, currentStatePosition + movementDelta, distance <= this.ropeLength ? distance : this.ropeLength);
}
Vector3 GetPointOnLine(Vector3 start, Vector3 end, float distanceFromStart)
{
return start + (distanceFromStart * Vector3.Normalize(end - start));
}
void OnDrawGizmos()
{
// purple
Gizmos.color = new Color(.5f, 0f, .5f);
Gizmos.DrawWireSphere(this.Pivot.transform.position, this.ropeLength);
Gizmos.DrawWireCube(this.bobStartingPosition, new Vector3(.5f, .5f, .5f));
// Blue: Auxilary
Gizmos.color = new Color(.3f, .3f, 1f); // blue
Vector3 auxVel = .3f * this.currentVelocity;
Gizmos.DrawRay(this.Bob.transform.position, auxVel);
Gizmos.DrawSphere(this.Bob.transform.position + auxVel, .2f);
// Yellow: Gravity
Gizmos.color = new Color(1f, 1f, .2f);
Vector3 gravity = .3f * this.gravityForce*this.gravityDirection;
Gizmos.DrawRay(this.Bob.transform.position, gravity);
Gizmos.DrawSphere(this.Bob.transform.position + gravity, .2f);
// Orange: Tension
Gizmos.color = new Color(1f, .5f, .2f); // Orange
Vector3 tension = .3f * this.tensionForce*this.tensionDirection;
Gizmos.DrawRay(this.Bob.transform.position, tension);
Gizmos.DrawSphere(this.Bob.transform.position + tension, .2f);
// Red: Resultant
Gizmos.color = new Color(1f, .3f, .3f); // red
Vector3 resultant = gravity + tension;
Gizmos.DrawRay(this.Bob.transform.position, resultant);
Gizmos.DrawSphere(this.Bob.transform.position + resultant, .2f);
/* * /
// Green: Pendulum side direction
Gizmos.color = new Color(.3f, 1f, .3f);
Gizmos.DrawRay(this.Bob.transform.position, 3f*this.pendulumSideDirection);
Gizmos.DrawSphere(this.Bob.transform.position + 3f*this.pendulumSideDirection, .2f);
/* */
/* * /
// Cyan: tangent direction
Gizmos.color = new Color(.2f, 1f, 1f); // cyan
Gizmos.DrawRay(this.Bob.transform.position, 3f*this.tangentDirection);
Gizmos.DrawSphere(this.Bob.transform.position + 3f*this.tangentDirection, .2f);
/* */
}
}
More glamour shots:
Set the maxAngularVelocity on your Rigidbody to Mathf.Infinity.
I know this topic is 9 months old, but I have been banging my head against a wall recently because of this issue. For some reason the Unity developers thought it was a good idea to limit the maximum rotational velocity of rigidbodies to 7 radians per second! That's just a little over one revolution per second, which is way too low for any application that requires physcal accuracy. And on top of that, the property isn't visible in the inspector, or the physics settings!
I hope this will help you (if you haven't figured it out on your own yet) and anyone else who might be fighting with this problem in the future, cheers!

Topdown camera focus with angle

I'm making a topdown game with the camera at 40 degree angle. What I want to do is when i click an gameobject, It will move the camera and position the object at the left side from the center of the camera view regardless of its rotation. So that I can place a menu at the right side. How do I get the offset of the angled camera so that the object is in the middle left side of the camera view?
Right now i use lerp but it overshoots the target because of the cameras angle. Sorry for the noob question I'm new to unity3d.
transform.position = Vector3.Lerp(transform.position, new Vector3(target.transform.position.x, transform.position.y, target.transform.position.z), 0.1f);
First of all you should start by finding point that your camera will move/lerp to.
In your case in can be simplified to 2D-Space:
It shouldnt be tough to find that one.
Use transform.forward of camera to get vector (Vector3 cameraDir) of direction your camera is looking at
Rotate by horizontal fov / 4 around y axis:
Vector3 cameraDirRotated = Quaternion.AngleAxis(hFov/4f, Vector3.up) * cameraDir;
-cameraDirRotated will be vector from Cube To point P you're looking for, u can also scale it:
Vector3 PtoMoveTo = cube.transform.position - cameraDirRotated.normalized * 5f;
Full:
Vector3 FindCameraTarget(Transform targetObj, float hFov)
{
Vector3 cameraDir = transform.forward;
Vector3 cameraDirRotated = Quaternion.AngleAxis(hFov / 4f, Vector3.up) * cameraDir;
Vector3 target = targetObj.transform.position - cameraDirRotated.normalized * 5f;
return target;
}
Then:
transform.position = Vector3.Lerp(transform.position, FindCameraTarget(target, 90f) , 2f * Time.deltaTime);
For performance u can save that target vector once if Cube is not moving. Search web how to precisely count horizontal fov. Multiply speed by Time.timeDelta if u lerp in Update().

How to Calculate Target Destination

I'm having a bit of trouble figuring this one out. What I'm trying to achieve is a sort of tackling motion. The player lunges at the target from a distance.
The diagram shows the set up. The blue diamond is the player and the red thing is the target. The purple box is the renderer bounds of the targets SkinnedMeshRenderer. I'm using renderer bounds because some target's mesh are much larger than other. Currently, the player is shooting to the orange star...which is unrealistic. I want him to, no matter what way the target is facing, always target the closest point of the target relative to his position...in the diagram's case that would be the brown star. Here's the code I've been using...
public IEnumerator Blitz()
{
rigidbody.velocity = Vector3.zero; //ZERO OUT THE RIGIDBODY VELOCITY TO GET READY FOR THE BLITZ
SkinnedMeshRenderer image = target.GetComponentInChildren<SkinnedMeshRenderer>();
Vector3 position = image.renderer.bounds.center + image.renderer.bounds.extents;
position.y = target.transform.position.y;
while(Vector3.Distance(transform.position, position) > 0.5f)
{
transform.position = Vector3.Lerp(transform.position, position, Time.deltaTime * 10);
yield return null;
}
Results(); //IRRELEVANT TO THIS PROBLEM. THIS CALCULATES DAMAGE.
Blitz.Stop(); //THE PARTICLE EFFECT ASSOCIATED WITH THE BLITZ.
GetComponent<Animator>().SetBool(moveName, false); //TRANSITIONS OUT OF THE BLITZ ANIMATION
GetComponent<Input>().NotAttacking(); //LET'S THE INPUT SCRIPT KNOW THE PLAYER CAN HAVE CONTROL BACK.
}
//Get the derection to tarvel in and normalize it to length of 1
Vector3 Direction = (Target - transform.position).normalized
With Direction, you can do many things. For example, you can multiply the direction by your speed and add that to your position.
transform.position += Direction * MoveSpeed;
If you want to get to the closest point, you can use the handy Collider.ClosestPointOnBounds method.
Target = TargetObject.GetComponent<Collider>().ClosestPointOnBounds(transform.position)
and plug the Target into the code used to get the direction.
Alternatively, you can use Vector3.Lerp without getting a direction since it's just interpolating.
transform.position = Vector3.Lerp(Target,transform.position,time.DeltaTime);
For stopping at the target point, you can use the arrival behavior.
//Declare the distance to start slowing down
float ClosingDistance = Speed * 2;
//Get the distance to the target
float Distance = (Target - transform.position).magnitude;
//Check if the player needs to slow down
if (Distance < ClosingDistance)
{
//If you're closer than the ClosingDistance, move slower
transform.position += Direction * (MoveSpeed * Distance / ClosingDistance);
}
else{
//If not, move at normal speed
transform.position += Directino * MoveSpeed;
}