How do I get the vector indicating the direction to travel if I have a starting position vector3 and rotation vector3? I get a normalized vector to indicate how it's rotated but of course that only indicated how it's rotated not the direction of travel. i.e. if I rotate on the y that should affect the direction of travel on the x and the z rather than what normailzing a vector rotated on the y would do which would indicate just indicate it has been rotated on the y.
At some point you will probably take that 'rotation Vector3' and make a Matrix from it. That Matrix has a Vector3 property (Matrix.Forward) that is the direction in that corresponds to the 'rotation Vector3'. If you don't want to mess with a matrix you already have, this method should do the job.
Vector3 DirectionToTravel(bool rotationVecIsInRadians, Vector3 rotationVec)//rotation vec must not be normalized at this point
{
Vector3 result;
if (!rotationVecIsInRadians)
{
rotationVec *= MathHelper.Pi / 180f;
}
float angle = rotationVec.Length();
rotationVec /= angle; //normalizes rotation vec
result = Matrix.CreateFromAxisAngle(rotationVec, angle).Forward;
return result;
}
In addition to Steve H's answer, you may find you need to use Quarternions to do rotation in an 3D space more effectively. I've provided some links that might help you out if you decide to use Quarternions.
Quarternion Structure (MSDN)
Quarternion Tutorial (MSDN Social)
Quarternion Rotation in XNA (Stackoverflow Question)
Related
I did something to get the depth distance using XRCpuImage in AROcciusionManager.
But I want to get the coordinates of the end using this distance.
The starting point is (0, 0, 0), and I want to get the coordinates in the direction away from it by this distance.
How do I get the coordinates of the end using distance and vector in unity?
Also, I tried to convert the rotation information of Unity into an angle and get it in the spherical coordinate system, but I don't know how.
If you have the Vector3 of the direction, To find a point along that vector distance away from the origin, you can use:
Vector3 PointAlongDirection(Vector3 origin, Vector3 direction,
float distance) {
return origin + direction.normalized * distance;
}
A good reference is Understanding Vector Arithmetic.
I have a 2.5d platformer game. The character is using rigidbody movement on a spline (using the curvy splines asset) which curves into 3d space in all sorts of ways, while the camera stays fixed to the side so that you see the path and background turning, but maintain a 2d side scrolling perspective.
I'm essentially creating a look rotation based on the spline, then moving the player using that forward vector, and making sure to remove any velocity perpendicular to the path so that the player stays centered on the path even when curving. I'm removing the velocity on that vector instead of projecting all the velocity in the direction of the path so that the player can still jump and fall like normal.
void SetLookRotation()
{
// get nearest TF and point on spline
Vector3 p;
mTF = Spline.GetNearestPointTF(transform.localPosition, out p);
// Get forward and up vectors of point on spline
_localHorizontal = Spline.GetTangentFast(mTF);
_localVertical = Spline.GetOrientationUpFast(mTF);
// Set look rotation to path
transform.rotation = Quaternion.LookRotation(Vector3.Cross(_localHorizontal, _localVertical), _localVertical);
}
void Movement()
{
Vector3 m = transform.right * groundAcceleration * moveInput;
rb.AddForce(RemoveCrossVelocity(m));
rb.velocity = RemoveCrossVelocity(rb.velocity);
Vector3 localVelocity = transform.InverseTransformDirection(rb.velocity);
localVelocity.z = 0;
rb.velocity = transform.TransformDirection(localVelocity);
}
Vector3 RemoveCrossVelocity(Vector3 v)
{
// get magnitude going in the cross product / perpindicular of localHorizontal and localVertical vector
// (essentially the magnitude on "local Z" or to the sides of the player)
Vector3 crossVelocity = Vector3.Project(v, Vector3.Cross(transform.right, transform.up));
// and remove it from the vector
return v -= crossVelocity;
}
The first 2 functions are happening in FixedUpdate() in the order shown.
The problem is, when hitting sharp corners at high speeds, some inertia causes the player to deviate off the center of the path still just ever so slightly, and a lot of that momentum turns into upward momentum, launching the player upwards. Eventually the player can fall off the path completely (I do have a custom gravity acting towards the spline though). It works perfectly at lower speeds though, even when dealing with sharp corners. At least as far as I can tell.
I tried a bit of code from https://answers.unity.com/questions/205406/constraining-rigidbody-to-spline.html too but no luck.
Is there a way I could constrain the player rigidbody on a vector that is not one of the global x/y/z axes? I've tried a host of other solutions like setting the transform of the player towards at the center of the spline but I can't seem to get it without feeling very jerky. Using forces makes the player "rubber band" towards and past the center back and forth. Maybe there is something in my math wrong. In any case, I'm hoping someone could help me make sure that the player will always stay on the center of the spline but only on the vector to the sides of the player's face direction, so that it doesn't mess with jumping. Thank you very much in advance!
For potential future visitors, I have figured this out. There are a few components (and a lot more if you're trying to do full spline based physics, but just to start with movement...)
First we must orient our character, so that our local coordinate system can be referenced with transform.right etc. Luckily this package provides these functions which return useful vectors. I'm sure there is math beyond me to do this otherwise if you are building your own spline system.
void SetLookRotation()
{
// get nearest TF and point on spline
Vector3 p;
playerTF = currentSpline.GetNearestPointTF(transform.localPosition, out p);
// Get forward and up vectors of point on spline
_localHorizontal = currentSpline.GetTangentFast(playerTF);
_localVertical = currentSpline.GetOrientationUpFast(playerTF);
// Set look rotation to path
transform.rotation = Quaternion.LookRotation(Vector3.Cross(_localHorizontal, _localVertical), _localVertical);
}
Here I am setting a velocity directly but if you're using forces it's the same principle.
if (Mathf.Abs(localVelocityAs_X) <= maxDashSpeed * Mathf.Abs(moveInput))
{
Vector3 m = transform.right * maxDashSpeed * moveInput;
rb.velocity = RemoveCrossVelocity(m);
}
localVelocityAs_X is defined as (ran in fixedUpdate/ physics step):
float currLocalVelocityX = (playerTF - prevPositionX) / Time.deltaTime;
localVelocityAs_X = Mathf.Lerp(localVelocityAs_X, currLocalVelocityX, 0.5f);
prevPositionX = playerTF;
Where playerTF is your position on a spline (in this case, using the curvy spline package from the unity asset store. Those spline positions return very small floats so in my case I multiplied playerTF by around 10,000 to make it a more easily readable metric). This is essentially just manually calculating velocity of the player each frame by comparing current position on the spline to last frame's.
RemoveCrossVelocity is the same as above. Comment explanations should suffice.
Vector3 RemoveCrossVelocity(Vector3 v)
{
// get magnitude going in the cross product / perpendicular of local horizontal and local vertical vectors
// (essentially the magnitude on "local Z" of the player)
Vector3 crossVelocity = Vector3.Project(v, Vector3.Cross(transform.right, transform.up));
// and remove it from the vector
return v -= crossVelocity;
}
Finally the solution to the drift. My crude fix was essentially to just adjust the player to the center of the spline every frame. Horizontally, there is no change because it grabs the closest spline point which is calculated by this package to be sort of a float clamped between the start and end of the spline. Vertically, we are being set to the distance the player is from the spline in the local up direction - a fancy way of saying we're not moving vertically at all. The reason this must be done is to avoid the spline vertical position overwriting the players, and we obviously can't set this vector back to playerPos.y in our local coordinate space, so we must resort to using a direction vector * the distance from our everchanging floor. This isn't absolutely ideal at the end of the day, but it works, and there isn't any extra jitter from it (interpolate on your player's rigidbody and some camera dampening helps). All in all these together combine to make a player able to accelerate quickly around sharp corners of a spline with physics and intertia will never cause the player to fly off or drift from the center. Take that, rocket physics!
void ResetPlayerToSpline()
{
Vector3 P; //closest spline point to player
float pTf = currentSpline.GetNearestPointTF(transform.position, out P);
playerHeight = Vector3.Distance(transform.position, P);
transform.position = P + (transform.up * Vector3.Distance(transform.position, P));
}
Ultimately for those possibly looking to do some kind of implementation in the future, the biggest thing you'll run into is a lack of cardinal direction, global oriented axis-based functions and properties normally provided by a game engine. For a primer, here are a few I would use (not including gravity, which is simply opposite your up vector times whatever magnitude):
This one allows you to create a vector using x and y like normal (and z in theory) and run this function to convert it when you actually use the vector in a local space. That way, you don't have to try and think in directions without names. You can still think of things in terms of x and y:
Vector3 ConvertWorldToLocalVector(Vector3 v)
{
Vector3 c;
c = transform.right * v.x + transform.up * v.y;
return c;
}
This is basically the same as what is happening in RemoveCrossVelocity(), but it's important to reiterate this is how you set velocity in a direction to 0. The second part shows how to get velocity in a certain vector.
void Velocity_ZeroY()
{
rb.velocity -= GetLocalVerticalVelocity();
}
public Vector3 GetLocalVerticalVelocity()
{
return Vector3.Project(rb.velocity, _localVertical);
}
Getting height, since you cannot just compare y positions:
height = Vector3.Distance(transform.position, P);
I think that's all the good stuff I can think of. I noticed a severe lack of resources for created spline based physics movement in games, and I'm guessing now it's based on the fact that this was quite an undertaking. It has since been brought to my attention that the game "Pandemonium"(1996) is a curvy 3d spline based sidescrolling platformer - just like mine! The main difference seems to be that it isn't at all based on physics, and I'm not sure from what I can tell if it has pitch changes and gravity to compliment. Hope this helps someone someday, and thank you to those who contributed to the discussion.
I'm writing a script which rotates a Rigidbody using a Configurable Joint. I've got the targetRotation figured out, but now I'm struggling with targetAngularVelocity, which should help me avoid wobbliness if set correctly.
targetAngularVelocity is defined like this in the documantation: "This is a Vector3. It defines the desired angular velocity that the joint should rotate into". The problem is that I don't know how to get this Vector3 based on two Quaternions - current rotation of the object and the target rotation.
Am I not understanding it correctly? Is there a function that returns a rotation vector based on two Quaternions?
So mathematically a Quaternion represents the orientation of a rigid body. Consider the forward problem first, and see how the orientation q_1 transforms to another orientation q_2 after a rotational velocity ω is applied for t time.
Mathematically the rotation vector has a magnitude ω and a direction k such that ω = ω* k
This is done with quaternion multiplication as
q_2 = q_ω * q_1
Where q_ω represents a rotation about the axis of k of an angle θ=ω*t.
In reverse, you need to find q_ω with
var q_ω = q_2 * Quaternion.Inverse(q_1);
and extract the rotation axis and angle
q_ω.ToAngleAxis(out float angle, out Vector3 axis);
and compose the rotational velocity vector, that corresponds to this transformation in time seconds.
var ω = (angle/time)*axis;
I've been struggling with what I think should be a very simple problem:
.
I know the current heading angle (say 15 deg), and given a target gameObject's transform, I want to calculate the angle that I should rotate towards to face the target. In the above example I want to calculate say 335ish deg.
Note that I need to calculate the target angle, I have another class that, given an angle, takes care of rotating the heading to the desired angle. I'm aware of the Transform.LookAt() and other similar functions, they don't apply in this situation because reasons (in the other class I basically calculate a Euler Quaternion and Lerp until I reach the target angle, due to project constraints, Transform.LookAt() doesn't work).
In the first approach, I tried calculating angle theta with the Dot product of Vector3.forward and the direction vector, didn't quite work right (either rotated forever or in the wrong direction)
targetAngle = Vector3.Angle(Vector3.forward, (target pos - current pos).normalized);
I thought maybe if I could calculate the current heading direction vector, I could take the Dot product of that and the target direction vector to get angle theta, then use theta and the current angle to figure out the target angle (360 - theta or something?) to get the angle I want to rotate to. Thing is, I only have the current angle and current pos, I don't understand how to calculate the current heading direction vector from that info. Do I just add some arbitrary constant to the current position's Z value and subtract from that the current position, to get a dir vector? Seems hacky and like it shouldn't work.
Any ideas are welcome.
Edit: Additional Info
The orientation code /u/Asad asked about:
// Calculate the target Quat to rotate all children by
Quaternion targ = Quaternion.Euler(0, 0, targetAngleHeading);
// Calculate the Linear interpolation to apply to all children
Quaternion lerp = Quaternion.Lerp(children[0].transform.localRotation, targ, Time.deltaTime * speedHeading_dps);
foreach (GameObject c in children)
{
// Apply lerp calcualted above to all children
c.transform.localRotation = lerp;
}
// Update the current heading angle 1st child's local z angle
currentAngleHeading = turrets[0].transform.localEulerAngles.z;
Then in FixedUpdate() I have:
if (currentAngleHeading != targetAngleHeading)
{
DesiredHeading();
}
You can take your transform's forward, and the vector to your target, and get an angle or rotation from those:
Vector3 vectorToTarget = target.transform.position - transform.position;
Vector3 facingDirection = transform.forward; // just for clarity!
float angleInDegrees = Vector3.Angle(facingDirection, vectorToTarget);
Quaternion rotation = Quaternion.FromToRotation(facingDirection, vectorToTarget);
Note that the rotation is relative; i.e., it's the rotation you need to apply from the current position to be facing the target.
try this instead
you can directly take the vector distance vector from transform.position and then
vector3.normalize (target.position - object.position)
this is the angle object'll want to move
I've been hanging my head around this issue for some time now and I'm at the top of my head not figuring this out.
The issue:
Currently trying to do a fake "swing" moment. Where I have the player object becoming a child to an object you can latch onto during a keypush.
With this in mind, I need to get the correct rotation on the grappleobject, making the velocity of the player becoming the correct rotation on the grappleobject.
This is not meant to be 2D, but 3D. Which causes this headache.
http://img843.imageshack.us/img843/7434/rotations.jpg
I figured that if I could get the vector of position, and the vector of the direction where the player is going towards, as in velocity of the character motor, to get an unique Vector, and this vector info should be able to rotate the grappleobject correctly.
However, that's what I thought was easy, but I've been hacking at this for hours to get that vector difference to do the rotation as it was thought out to be.
tl:dr
2 Vectors, the difference of these two to one vector, this vector controls the rotation of grappleobject to "fake" a swing motion with the proper velocity.
Thank you in advance if there'll be an answer.
Added Info:
Current testings has been these.
///
Parent Orb is the grappleobjects which updates its transform depending on trigger events.
CurDirection is where the player is heading within the vector in world.
CurPos is where the player is at that point in time within the world.
CurDirection = (transform.position-ParentOrb.position);
CurDirection.Normalize();
motor.movement.velocity = (CurDirection);
CurPos = transform.position;
////
Also tried out to get the angle from the grappleobject to the player.
///
otherDirection = The direction of velocity in space.
OtherDirectionPre = Current position in space.
Vector3 targetDir = otherDirection;
Vector3 forward = otherDirectionPre;
angle = Vector3.Angle(targetDir, forward);
///
I assume these may not be helpful, but better to show where I have gotten so far.
I think you know the radius between the hit point and the center, let's call it r. With the velocity v of the player and the angular velocity ω (=omega) of the axis the player should be connected to you have the vector equation:
v = ω × r
Assuming all 3 vectors are perpendicular to each other you have ω = v / r.
EDIT: You get the radius r from the position of the center and the point of contact of your collision:
Vector3 r = collision.contacts[0].point - center;
float radius = r.magnitude;
float angularSpeed = rigidbody.veloctiy.magnitude / radius;