Story
so I'm working on making a procedural terrain generator script to spawn rocks on the ground all the big rocks don't care what rotation they are but I have some small rocks that have to be parallel to the terrain or they look weird, part of them floating off the ground other part stuck in the ground the quaternions I don't seem to understand
Problem
i am getting the terrainData.GetInterpolatedNormal and putting it into a vector3 called normals then when i am spawning my rock i rotate it towards ground
Instantiate(SmallRock, new Vector3(point.x, Heights, point.y) transform.rotation = new Quaternion(normals.x,normals.y, normals.z, 90));
my problem lies in the Quaternion(normals.x,normals.y, normals.z, 90)
I don't know what to put where like should I only put the normals.x/z there or should I put the normals.y in there too and I don't even know what 90 at the end does, and yes I know that the interpolatednormals returns a 0 to 1 so I tried multiplying it to make it rotate more than 1 but it seems to just not rotate the right way if you can't tell by now I really have no clue how quaternions work but everywhere i search I can't find anything that helps and I didn't really feel like learning about how quaternions work so thanks for saving me time
Quaternions use compound(Imaginary) numbers to represent a sequence of rotations in 3d space.
When you instantiate a new Quaternion using it's constructor you are providing it with what you think the Quaternion's real and imaginary numbers should be.
Despite the seemingly familiar x, y, and z names you should not manually modify or provided them, they are not euler angles, cartesian coordinates, or traditional vector components.
What you're currently passing it is portions of a direction instead of the real and imaginary parts of a Quaternion.
A normal is an "outwards direction" from a given position. So to get a rotation we need some other direction to compare it to in order to get a rotation.
Compare your direction with the up direction and you'll get a rotation that you can use.
Quaternion rotation = Quaternion.FromToRotation(Vector3.up, normalDirection);
Related
In unity documentation, under Transform.rotation, there is written:
Do not attempt to edit/modify rotation.
But few lines after, in the example, the assignment is used transform.rotation = ...
And setting transform.rotation directly seems to be everyday practice.
But can it be recommended? What about other properties, like localRotation, is the setter of the rotation property implemented so that the localRotation is changed too?
I feel like the wording on this in the docs used to be more clear, but this is what it implies:
It is highly discouraged to edit the transform.rotation of an object directly. that is to say doing something like transform.rotation = new Quaternion(0, 100, 15, 1); unless you really know the ins and outs of working with Quaternions, which are a great deal harder than working with EulerAngles which is more user friendly and easier to understand.
What you should be using instead (and this is also reflected in the code samples of the docs) are the methods made available by Unity to alter the rotation. These methods will deal with the complexity that comes with changing Quaternion values for you.
If we take a closer look at the code samples Unity provides:
Quaternion target = Quaternion.Euler(tiltAroundX, 0, tiltAroundZ);
transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
The two key factors here being target = Quaternion.Euler() which takes in three euler angles (angles on a 360 degree scale) and transforms them to Quaternions for you. And the other being rotation = Quaternion.Slerp() which takes in the current rotation as a quaternion, and a target rotation as quaternion and interpolates between the two.
Notice that neither of these two functions alters the transform.rotation "directly" from your side, but both pass through Unity's internal logic for converting to proper quaternions.
the same goes for methods like transform.Rotate.
transform.localRotation is basically the same as transform.rotation. The only difference being that the former indicates the rotation relative to the parent, and the latter its rotation relative to the world.
If you want to edit the rotation of an object directly it is easiest to edit the EulerAngles of the object. An example being:
transform.localEulerAngles = new Vector3(10, 150, 0);
Which will rotate your object 10 degrees around the X axis and 150 degrees along the Y axis, relative to its parent. Using transform.eulerAngles would rotate it relative to the world.
Note that, despite this being the easiest way to go around it. Unity does encourage using the Quaternions class and its functions to apply rotations, as using Euler angles can cause weird effects to happen.
There is also this doc talking about rotation and orientation in Unity which also states (emphasis mine):
Quaternions can be used to represent the orientation or rotation of a GameObject. This representation internally consists of four numbers (referenced in Unity as x, y, z & w) however these numbers don’t represent angles or axes and you never normally need to access them directly. Unless you are particularly interested in delving into the mathematics of Quaternions, you only really need to know that a Quaternion represents a rotation in 3D space and you never normally need to know or modify the x, y & z properties.
The reason for Unity using quaternions is, among others, that quaternions do not suffer from gimbal lock, which eulerAngles does. I quote from the article:
Unity stores all GameObject rotations internally as Quaternions, because the benefits outweigh the limitations.
The components of transform.rotation are not angles and are not able to be handled as angles.
As robertbu mentions in this article:
Many rotations (and likely the one you were attempting) can be
accomplished through other (simpler) methods, including
'Transform.Roate()' and directly accessing 'Transform.eulerAngles'-..
Transform.Rotate() - Rotate() does a relative rotation, and by
default, a local rotation-..
What they mean by not editing/modifying rotation is that rotation is a built in class by unity that handles rotations for objects.
So feel free to set the rotation of an object
like so:
Transform.rotation = object.transform.rotation;
But modifying the built in rotation class isn't recommended.
I'm recreating the movement system from the DS game Dragon Quest Heroes Rocket Slime in Unity. Currently I've got pretty desirable results but it's not 100%.
One of the things that are different is that my player bounces back from walls further on long distance slings than he does in the original game. (left is my recreation, right is original game). Obviously, I can't find out how the game was made and the exact maths/values they use for slinging but one of the things I got from the game is that:
The player moves at constant velocity while slinging in a direction (no slow down, they just stop at a certain point)
Which led me to believe the game doesn't use traditional velocity mechanics so I made it so:
While stretching, the players 'pVelocity' (potentialVelocity) goes up. When they let go a point create at curPlayerPosition + pVelocity is created. I then move the player at a constant velocity to that point. My idea to fix my issue of bouncing too far is by getting the distance from the position where I slung from to the end point and making the player bounce less the larger the distance and further the smaller the distance.
Problem is, I'm not really sure how to do that last part.
Here's my code:
Vector2 reflectedVelocity = Vector2.Reflect(pVelNormalized, foundHit.normal);
playerAnimator.SetFloat("VelocityX", reflectedVelocity.x);
playerAnimator.SetFloat("VelocityY", reflectedVelocity.y);
float DistanceFromOrigin = Vector3.Distance(slingOrigin, transform.position);
print(DistanceFromOrigin);
//ToDo: reflectedVelocity is lower the higher DistanceFromOrigin is.
The other solution I thought of is that maybe my idea of how the 'velocity' works in the original game is completely wrong and if so, please tell me how it actually is/looks to be actually done
reflectedVelocity is lower the higher DistanceFromOrigin is.
So reflectedVelocity should have an inverse relationship with DistanceFromOrigin
Vector2 reflectedVelocity = Vector2.Reflect(pVelNormalized, foundHit.normal);
float DistanceFromOrigin = Vector3.Distance(slingOrigin, transform.position);
if(DistanceFromOrigin == 0) DistanceFromOrigin = 0.00001f;//to avoid division by zero
reflectedVelocity *= (SomeConstant / DistanceFromOrigin);
playerAnimator.SetFloat("VelocityX", reflectedVelocity.x);
playerAnimator.SetFloat("VelocityY", reflectedVelocity.y);
You may use a linear relationship instead of non-linear:
reflectedVelocity *= (SomeConstant - DistanceFromOrigin);
title pretty much says it all.. say I have a ship, its worldVelocity is a Vector3 with these values:
X: 0
Y: 0
Z: 1
(assuming +Z is Forward, +Y is Up, and +X is Right)
this Vector3 is added to the ships worldTranslations Matrix which stores translation and rotation.
worldTranslations.Translation += worldVelocity
and my ship goes forward, and it stops accelerating at speed 1 (correctly) as this is its target velocity, but what if the ship has been rotated Right 180 degrees, so its now flying backwards. Automatically the ships target velocity should detect this and begin trying to fly forward again.
The problem is I don't know how to get the local velocity out of my ships velocity and localTransforms, and I cant find an answer anywhere..
so at the moment my ship uses the world velocity for checking if its reached its target speed, so long as the ship doesnt rotate, it flies properly. My target speed will be one, so my ship compares its current velocity (0,0,0) to target velocity (0,0,1) and properly accelerates till it reaches its target (0,0,1) and stops accelerating to maintain a constant speed, but if i turn (say just 90 degrees right), current velocity is now (-1,0,0) because the ship is drifting left now, so it should use that relative velocity to determine that it needs to accelerate (1,0,1) to get back to (0,0,1) but I have no idea how to get relative velocity so it currently uses world velocity which is still (0,0,1) even though its flying left and so it thinks its all good but its still drifting left..
Thanks.. again everyone :)
The answer was to transform the velocity vector by the inverse rotation matrix.
This post was made as my friend realised the desired result was achieved in Unity3D using one of its built in functions, but ultimately is the same question:
XNA equivalency of unity function Transform.InverseTransformDirection
More detailed explanation can be found on that page.
However if this does not work for you, as it didn't immediately fix my problem, try examining one component of the vector at a time. I had to multiply only the Z component of the vector by -1 to make it work. Most likely interference by other maths so I recommend you examine the result vectors components results individually.
-Aaron
The ship's world matrix has a 'Forward' property which is a unit length vector that always points in the ship's forward direction. This vector is updated anytime the ship's rotation is changed and the world matrix updated to store the change.
So you can key the velocity off that vector and it will always go forward relative to the rotation of the ship.
Velocity = shipMatrix.Forward * speed;
ShipMatrix.Translation += velocity;
I'm developing a 3D spaceshooter in XNA as a school project (basically Asteroids in 3D with power-ups), and have been working to implement roll, pitch, and yaw with respect to the ship's local axes. (I should emphasize: the rotation is not with respect to the absolute/world x, y, and z axes.) Sadly, I've been struggling with this for the last few weeks. Google and my neolithic monkey brain have failed me; maybe you folks can help!
Here's my setup:
Via keyboard input, I have the following variables ready to go:
yawRadians, which stores the desired yaw away from the ship's initial
position
pitchRadians, which stores the desired pitch away from the
ship's initial position
rollRadians, which stores the desired roll
away from the ship's initial position
The ship also maintains its own Front, Back, Right, Left, Top and Bottom unit vectors, which are used both for the rotations and also for propulsion. (Different keys will propel the ship toward the Front, Back, etc. This part is working great.)
Ultimately, I generate the rotation matrix mShipRotation, representing all of the ship's rotations, which is passed to the ship's draw method.
The problem I have is with the rotations themselves. Different solutions I've tried have had differing results. Here's what I've gone with so far:
Method 1 – Yaw, Pitch, and Roll relative to the absolute/world x, y, and z axes
At first, I naively tried using the following in my ship's Update method:
qYawPitchRoll = Quaternion.CreateFromYawPitchRoll(yawRadians, pitchRadians, rollRadians);
vFront = Vector3.Transform(vOriginalFront, qYawPitchRoll);
vBack = -1 * vFront;
vRight = Vector3.Transform(vOriginalRight, qYawPitchRoll);
vLeft = -1 * vRight;
vTop = Vector3.Transform(vOriginalTop, qYawPitchRoll);
vBottom = -1 * vTop;
mShipRotation = Matrix.CreateFromQuaternion(qYawPitchRoll);
(vOriginalFront, vOriginalRight, and vOriginalTop just store the ship's initial orientation.)
The above actually works without any errors, except that the rotations are always with respect to the x, y, and z axes, and not with respect to the ship's Front/Back/Right/Left/Top/Bottom vectors. This results in the ship not always yawing and pitching as expected. (Specifically, yawing degenerates to rolling if you have pitched up so the ship is pointing to the top. This makes sense, as yawing in this solution is just rotating about the world up axis.)
I heard about the Quarternion.CreateFromAxisAngle method, which sounded perfect. I could just combine three Quaternion rotations, one around each of the ship's local axis. What could go wrong?
Method 2 – Quaternion.CreateFromAxisAngle
Here's the second code snippet I used in my ship's Update method:
qPitch = Quaternion.CreateFromAxisAngle(vRight, pitchRadians);
qYaw = Quaternion.CreateFromAxisAngle(vTop, yawRadians);
qRoll = Quaternion.CreateFromAxisAngle(vFront, rollRadians);
qPitchYawAndRoll = Quaternion.Concatenate(Quaternion.Concatenate(qPitch, qYaw), qRoll);
vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, qPitchYawAndRoll));
vBack = -1 * vFront;
vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, qPitchYawAndRoll));
vLeft = -1 * vRight;
vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, qPitchYawAndRoll));
vBottom = -1 * vTop;
mShipRotation = Matrix.CreateFromQuaternion(qPitchYawAndRoll);
The above works perfectly if I only do one rotation at a time (yaw, pitch, or roll), but if I combine more than one rotation simultaneously, the ship begins to wildly spin and point in many different directions, getting more and more warped until it disappears entirely.
I've tried variants of the above where I first apply the Pitch to all the vectors, then the Yaw, then the Roll, but no luck.
I also tried it using Matrices directly, despite concerns of Gimbal Lock:
Method 3: Matrices
mShipRotation = Matrix.Identity;
mShipRotation *= Matrix.CreateFromAxisAngle(vRight, pitchRadians);
mShipRotation *= Matrix.CreateFromAxisAngle(vFront, rollRadians);
mShipRotation *= Matrix.CreateFromAxisAngle(vTop, yawRadians);
vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, mShipRotation));
vBack = -1 * vFront;
vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, mShipRotation));
vLeft = -1 * vRight;
vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, mShipRotation));
vBottom = -1 * vTop;
No luck; I got the same behavior. One rotation at a time is okay, but rotating about multiple axes resulted in the same bizarre spinning behavior.
After some brilliant debugging (read as: blindly outputting variables to the console), I noticed that the Front/Right/Top vectors were slowly, over time, becoming less orthogonal to one another. I added Normalization to vectors basically every step of the way, and also tried computing new vectors based on cross products, to try to ensure that they always remained perpendicular to one another, but even then they were not perfectly orthogonal. I'm guessing this is due to floating point math not being perfectly precise.
Note that I regenerate the mShipRotation matrix every Update method, so it cannot be accumulating drift or inaccuracies directly. I think that applying multiple Quarternion rotations may be accumulating error (as I can do one rotation just fine), but my attempts to fix it have not worked.
In short:
I can pitch/roll/yaw relative to the world axes x, y, and z just
fine. It's just not what the player would expect to happen as the
rolling/pitching/yawing is not relative to the ship, but to the
world.
I can roll, pitch, or yaw around the ship's local axes (Front/Back/Top/Bottom/Left/Right) just fine, but only one at a time. Any combination of them will cause the ship to spiral and deform rapidly.
I've tried Quaternions and Matrices. I've tried suggestions I've found in various forums, but ultimately do not wind up with a working solution. Often people recommend using Quaternion.CreateFromYawPitchRoll, not really realizing that the intent is to have a ship rotate about its own (constantly changing) axes, and not the (fixed) world axes.
Any ideas? Given a situation where you are given the roll, pitch, and yaw about a ship's front, right, and top vectors, how would you go about creating the rotation matrix?
You seem to be applying your overall angles (yawRadians, pitchRadians, rollRadians) to your local axis in your methods 2 & 3. These values are married to the world axis and have no meaning in local space. The root of your problem is wanting to hang onto the 3 angles.
In local space, use an angular amount that is the amount you want to rotate between frames. If you only pitched up 0.002f radians since the last frame, that would be what you would use when you rotate around the vRight axis.
This will screw with your overall angle values (yawRadians, pitchRadians, & rollRadians) and render them useless but most folks who stick with 3d programming quickly drop the angle approach to storing the orientation anyway.
Simply rotate your matrix or quaternion little by little each frame around your local axis and store the orientation in that structure (the quat or matrix) instead of the 3 angles.
There is no worries about gimbal lock when you are rotating a matrix about local axis like this. You would have to have 90 degree rotations between frames to bring that into the picture.
If you want to avoid error accumulation use a quat to store the orientation and normalize it each frame. Then the matrix you send to the effect will be made each frame from the quat and will be ortho-normal. Even if you didn't use a quat and stored your orientation in a matrix it would take hours or days to accumulate enough error to be visually noticeable.
This blog might help: http://stevehazen.wordpress.com/2010/02/15/matrix-basics-how-to-step-away-from-storing-an-orientation-as-3-angles/
I think this might be what you're looking for:
http://forums.create.msdn.com/forums/t/33807.aspx
I'm pretty sure that CreateFromAxisAngle is the way to go.
I have a question regarding using primitive shapes and simulating a circle to be free falling. How would I go about this? Do I use the formula for gravity?
It depends how detailed you want to be. Newtonian gravity laws dictate an force which has inverse square relationship between two bodies and their distance.
F is the magnitude of the gravitational force between the two point masses,
G is the gravitational constant,
m1 is the mass of the first point mass,
m2 is the mass of the second point mass, and
r is the distance between the two point masses.
So if you are simulating large bodies (say a planetary system) you need to apply gravity between each pair of objects.
Obviously, once you know the force you can apply Newton's second law (force=mass*acceleration) to calculate the acceleration you should apply to each body.
On the other end of the simplicity scale, if you have a fixed reference frame with respect to a single very large body (the ground) and multiple small objects, all you really need to do is apply a constant acceleration towards the ground. In this case, (in a vacuum) gravity on earth applies a constant acceleration of 9.81m/s2 to all objects. CodeInChaos gives a good code example of this.
(Of course we now know that Newtonian gravity isn't quite right and it breaks down at very large and very small scales. But that's a bit beyond this answer)
Gravity is just constant acceleration downwards.
Pseudocode:
const Vector3D Gravity=(0, 0, -9.8 m/s^2);
Vector3D Acceleration=Gravity;//insert other forces here
Vector3D Position+=Speed*DeltaT+0.5*Acceleration*DeltaT*DeltaT.
Vector3D Speed+=Acceleration*DeltaT;
You can use a physics engine, like Farseer:
http://roy-t.nl/index.php/2010/09/10/xna-farseer-platformer-physics-tutorial/
Simple version: if your circle has direction and speed then gravity is just a additional direction and speed pointing at the direction you want your gravity to pull.
Even simpler: just move the location of the circle downwards.
After this just fine tune it to fit your purpose with acceleration and setting the speed.