I'm trying to implement centripetal force in a programming language.
I saw some videos teaching the theory. But I dont know how to apply that in a programming language.
If I understand I have to apply centripetal force ac = v²/r to the velocity vector. But I dont know exactly how to proceed.
I have two game objects, one depicting Earth, other depicting Moon. What I wanted is to translate the moon around earth and using a button to "cut/cancel" the centripetal force in order to the moon get out to the earth's orbit.
I have no clue how to start that.
All I know is to rotate like this:
velocity.x = Mathf.Cos(Time.time) * earth_moon_radius;
velocity.z = Mathf.Sin(Time.time) * earth_moon_radius;
moon.transform.position = velocity;
But how to apply centripetal force as described above?
If you just want to have the moon rotating around earth and some trigger to release the moon, it's easier to use rotation around a center instead of forces. Given the following GameObject hierarchy:
Center (MoonRotator attached)
-- Moon
-- Earth
public class MoonRotator : MonoBehaviour
{
public bool cancelCentripetalForce = false;
public Vector3 angularVelocity = new Vector3 (0f, 0f, 100f);
public GameObject moon;
void Update () {
if (cancelCentripetalForce) {
Vector3 radius = moon.transform.position - transform.position;
Vector3 angularVelocityRadians = Mathf.Deg2Rad * angularVelocity;
moon.rigidbody.velocity = Vector3.Cross (angularVelocityRadians, radius);
moon.transform.parent = null;
Destroy (this);
} else {
Vector3 rot = transform.rotation.eulerAngles + angularVelocity * Time.deltaTime;
transform.rotation = Quaternion.Euler (rot);
}
}
}
If cancelCentripetalForce is set true Moon stops travelling around earth but proceeds with its current tangential velocity. This is given as:
v = ω × r
Earth has localPosition (0, 0, 0) and Moon is in this example located in the x-y plane rotating around the z axis.
If you want to cancel the force, add an opposing force vector that is based on your object's linear velocity and current direction.
So I have an object pointing straight along the Z axis. The object's 'forward' vector is 0, 0, 1. Do 1 - Math.abs(forward.x), same for y and z to get 1, 1, 0 when you're pointing forward along the Z axis. You want the direction you're pointing in to be 0'd so that the inertia from that direction is not damped in any way. Now you can apply a cancellation force in any direction that you are NOT pointed in.
This means that if your object is moving in any direction in world space that it's not facing in you can easily apply a cancellation force that is multiplied by the object's linear velocity to get circular motion that uses forces instead of directly setting velocity.
Another way you can do it is solve for V by manually setting it, then find radius using V=RW. You should know V and R or W. Now you can find the force necessary to keep the orbit stable around a point, rather than adding inertia from every frame.
Related
I am working on a VR project in Unity (2020.3.40f), and need to add the option to move an object on its axis based on the controller's (the user's hand) movement.
Currently I store the controller's position when it grabs the object, and continuously calculate the distance the controller has moved from the initial position.
But it is inaccurate, because the controller might have moved in a direction that shouldn't affect the object's position.
For example:
I have this blue lever that the user has to pull. I want to know how much the controller has moved along the green axis, so I can move the lever accordingly.
If the user moves their hand upwards, it shouldn't affect the lever (but in my current implementation, I use Vector3.Distance so the lever moves anyway).
My code:
private void OnTriggerEnter(Collider other)
{
controller = other.GetComponentInParent<IController>();
if (controller == null || controller.IsOccupied)
{
return;
}
controller.IsOccupied = true;
controllerStartPosition = controller.GetPosition();
}
private void Update()
{
if (controller == null) return;
Vector3 currentControllerPosition = controller.GetPosition();
float distance = Vector3.Distance(currentControllerPosition, controllerStartPosition);
transform.Translate(0, 0, distance * sensitivity); // The object always moves along its forward axis.
}
I assume that I need to project the controller's position on the object's forward axis and calculate the distance of that, but I have very basic knowledge in vectors maths so I am not sure about that.
So my question is, What are the calculations that I should do to get the correct distance?
As mentioned what you want to do is Vector3.Project your given hand movement onto the desired target axis direction and only move about this delta.
Something like
private void Update()
{
Vetcor3 currentControllerPosition = controller.GetPosition();
// the total vector in world space your hand has moved since start
Vector3 delta = currentControllerPosition - controllerStartPosition;
// the delta projected onto this objects forward vector in world space
// you can of course adjust the vector but from your usage this seems the desired one
Vector3 projectedDelta = Vector3.Project(delta, transform.forward);
// finally moving only about that projected vector in world space
transform.position += projectedDelta * sensitivity;
}
what you are currently doing is;
you are calculating the distance in every axis which the movment on every axis will change the outcome. What you need is when calculating the distance only pass in the parameters in the desired axis for example:
float distance = currentControllerPosition.x - controllerStartPosition.x;
this will give you the diffrence between the x axis of these points.
for example if it was at 5 and it moved to 8 this will return you 3 regardless the movement on the other axis.
I've gone through Unity's documentation for Quaternion.LookRotation, but I didn't get the full understanding of how it works.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
public Transform target;
void Update()
{
Vector3 relativePos = target.position - transform.position;
// the second argument, upwards, defaults to Vector3.up
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
}
}
A way to visualize a rotation is with three perpendicular axis-ex. A quaternion is a more compact representation, but you can still view it as having three axis-es.
LookRotation will align one of the rotation axes to the given direction, but with only one direction there is one degree of freedom left, the other two rotation axes.
That is what the 'up' vector is for, it locks in one of the other axes and forces it to be perpendicular to both the direction and up-vector. The third rotation axis is always perpendicular to both, so we have three perpendicular axes, i.e. a complete rotation.
You can do something similar yourself with a cross product, since that produces a perpendicular vector to two others. Pseudocode:
var xDir = direction;
var zDir= xDir.CrossProduct(upVector)
var yDir = zDir.CrossProduct(xDir)
var matrix = CreateARotationMatrixFromAxises(xDir, yDir, zDir)
var quaternion = CreateQuaternionFromRotationMatrix(matrix)
Note that the direction and up-vector cannot be parallel, or you will get some kind of error.
There is absolutely no reason for beginners and hobbyist programmers to touch Quaternions. Unity should remove it from the documentation.
What you want is simply the LookAt command. Fortunately, it's incredibly easy to use.
Say you have a tree that you want your character to look at, it's this simple:
transform.LookAt(tree);
I meanwhile found a solution, but I'd really like a code review. Perhaps there is an easier solution. I updated the script at the end of my question.
I have a camera in my scene with a specific position and rotation. I want to move the camera on the x- and z-axis so that it targets (0,0,0).
I have the position vector posVector of the camera object and the displacement vector dirVector, which is the viewing direction. Now at some point, posVector + dirVector will intersection the ground plane. This currently is (x,0,z) but I like to move the camera on the x- and z-axis so that this is (0,0,0). So I really need to know x and z.
I tried multiple things, but I still have trouble wrapping my head around vectors and intersections.
using UnityEngine;
[ExecuteInEditMode]
public class DebugHelper : MonoBehaviour {
public Camera mainCamera;
// This DebugHelper script runs in EditMode and will help me visualize vectors and also move the camera to where I want it to be.
private void Update()
{
Vector3 posVector = mainCamera.transform.position;
Vector3 dirVector = mainCamera.transform.rotation * Vector3.forward;
// Find scalar for dirVector that displaces posVector.y to 0
// posVector + dirVector * scalar = (x,0,z)
float scalar = Mathf.Abs(posVector.y / dirVector.y);
// Get the position vector of the current camera target at y=0.
Vector3 y0TargetVector = posVector + dirVector * scalar;
// Subtract the y0TargetVector from the posVector to move it back to zero. This works because y0TargetVector.y is 0 and therefore the height is the same.
mainCamera.transform.position -= y0TargetVector ;
Debug.DrawRay(posVector, dirVector * scalar, new Color(0, 1, 0));
}
}
I'm starting with Unity 3D and I want to make a simple game where you move a marble through a maze by tilting the device.
For that I need to know in what the direction the phone is tilted (where to move the ball) and how much (how fast to move it). This bubble level from iOS7 does something similar, the number rotates to show the direction you are tilting the device and the value represents how much the phone is tilted:
I've been experimenting with Input.gyro.attitude.eulerAngles but I'm not sure how to turn it into the values I need, also I'm not sure if gyro.attitude is the best solution to get responsive controls.
How can I get the direction and tilt of the device?
Unity3D documentation has a solution using Input.accelaration however I'm not sure whether it's as reliable as Input.gyro.
http://docs.unity3d.com/ScriptReference/Input-acceleration.html
This is what I'm trying now:
private Gyroscope gyro;
void Start () {
gyro = Input.gyro; // Store the reference for Gyroscope sensor
gyro.enabled = true; //Enable the Gyroscope sensor
}
void Update () {
// Gyroscope
Vector3 vec = gyro.attitude * Vector3.forward;
print (vec);
// Option 2
print(Input.accelaration);
}
You should be able to do it like this (in this case, taking the XZ plane projection of the quaternion = change the Vector3 in the second line to pick the plane you want);
// where q is the Quaternion from the gyro
Matrix4x4 quatMatrix = Matrix4x4.TRS(Vector3.zero, q, Vector3.one);
Matrix4x4 scaleMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1, 0, 1));
Matrix4x4 scaled_matrix = scaleMatrix * quatMatrix;
OutVector = scaled_matrix.MultiplyVector(Vector3.forward).normalized;
That should give you a 3-d vector that has only X and Z components, easy to turn into a 2-d vector.
I'm programming a game in C# using the XNA3.1 engine. However I'm having a small issue with my camera, basically my camera tends to "flip" when it rotates more than 180 degrees on its roll (when the camera reaches 180 degrees, it seems to flip back to 0 degrees). The code for obtaining the view matrix is as follows:
Globals.g_GameProcessingInfo.camera.viewMat = Matrix.CreateLookAt(Globals.g_GameProcessingInfo.camera.target.pos, Globals.g_GameProcessingInfo.camera.LookAt, up); //Calculate the view matrix
The Globals.g_GameProcessingInfo.camera.LookAt variable the position 1 unit directly in front of the camera, relative to the rotation of the camera, and the "up" variable is obtained with the following function:
static Vector3 GetUp() //Get the up Vector of the camera
{
Vector3 up = Vector3.Zero;
Quaternion quat = Quaternion.Identity;
Quaternion.CreateFromYawPitchRoll(Globals.g_GameProcessingInfo.camera.target.rot.Y, Globals.g_GameProcessingInfo.camera.target.rot.X, Globals.g_GameProcessingInfo.camera.target.rot.Z, out quat);
up.X = 2 * quat.X * quat.Y - 2 * quat.W * quat.Z; //Set the up x-value based on the orientation of the camera
up.Y = 1 - 2 * quat.X * quat.Z - 2 * quat.Z * quat.Z; //Set the up y-value based on the orientation of the camera
up.Z = 2 * quat.Z * quat.Y + 2 * quat.W * quat.X; //Set the up z-value based on the orientation of the camera
return up; //Return the up Vector3
}
I got same problems in OpenGL with gluLookAt. I fixed that problem with my own camera class:
void Camera::ComputeVectors()
{
Matrix4x4 rotX, rotZ;
Quaternion q_x, q_y, q_z;
Quaternion q_yx, q_yz;
q_x.FromAngleAxis(radians.x, startAxisX);
q_y.FromAngleAxis(radians.y, startAxisY);
q_z.FromAngleAxis(radians.z, startAxisZ);
q_yx = q_y * q_x;
q_yx.ToMatrix(rotZ);
q_yz = q_y * q_z;
q_yz.ToMatrix(rotX);
axisX = startAxisX;
axisZ = startAxisZ;
axisX.Transform(rotX);
axisZ.Transform(rotZ);
axisY = axisX.Cross(axisZ);
position = startPosition;
position -= center;
position.Transform(q_yx);
position += center;
}
It is maybe overcomplicated, but working. axisY is your up vector.
Full code listing is at:
http://github.com/filipkunc/opengl-editor-cocoa/blob/master/PureCpp/MathCore/Camera.cpp
Hope it helps.
This is probably slower but the only way I know to do with would be the with the rotation matrix for 3D. Wikipedia Link
Where
and U = (Camera.position - Camera.lookat).norm
... Now, I believe that would give you the rotation part of the view matrix. However, I'm not 100% on it. I'm still looking into this though.
meh was hoping to see a tan in there somewhere.
can you link to where you got your equation from please?
(am at work and really don;t want to sit down myself and derive it)
how are you setting your camera rotation? are you sure nothing is going on there?
I'm a bit unsure about the math in your GetUp method. Could you elaborate on the math behind it?
In my lookat camera I initialize my up-vector once and then rotate that vector using a quaternion. This removes the possibility of trying to do a cross-product on parallel vectors in order to calculate the up vector.
Some semicode to clarify perhaps:
var up = Vector3.Up;
var target = <some point in space>;
var rotation = <current rotation quaternion>;
var forward = target - position;
forward = Vector3.Transform(forward, rotation);
var updatedPosition = target - forward;
var updatedUp = Vector3.Transform(up, rotation);
var view = Matrix.CreateLookAt(updatedPosition, target, updatedUp);
Since I wasn't satisfied with the answers here already, I had to figure this out myself.
What I discovered is it's actually quite simple. Just do this:
Matrix ypr = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll);
Vector3 up = Vector3.Transform(Vector3.Up, ypr);
"up" is the direction you want.