In my unity app initially I have set the camera in a certain position. Later I change the camera position dynamically. After doing that I need to find the angle/rotation it rotated and another object needs to be rotated by the same angle but in the opposite direction.
I have two questions.
1.How do I find the angle the camera moved?
2.How do I rotate the game object by the same value but in the opposite direction.
I tried things like target.transform.Rotate( Camera.main.transform.position - cameraNewPos); and also googled a lot but couldn't find the answers.
You can always compare the current transform.rotation to its original value before you made the change to see the different. Then, apply the same change (in reverse) to your other object.
On camera:
var delta = transform.rotation - _originalRotation;
On that Object:
transform.rotation = transform.rotation - delta;
If your camera is at position P1, and orientation Q1 at start, and P2, Q2, after you moved it, you can find the translation T and rotation R that goes from 1 to 2 using (using transform.rotation and transform.position, which represent the world transform of you object, independent of its hierarchy) :
R = Q1.Inverse() * Q2
T = P2 - P1
Note that you can't substract quaternions.
Then you can simply move your other object accordingly.
Obj.position = initialCameraPosition - T
Obj.rotation = initialCameraRotation * R (or R.Inverse() if you want to mirror the rotation as well)
So:
If you want to get the amount of rotation applied from a time to a time, you could just save the data from the begin and then substract the end rotation - begin rotation.
Vector3 iRotation;
Vector3 amountRot;
void Start() { // for example
iRotation = obj.transform.rotation.eulerAngles;
}
void Update() { // at some point you want
if (sth) amountRot = obj.transform.rotation.eulerAngles - iRotation;
obj2.transform.rotation = Quaternion.Euler(-obj.transform.rotation.eulerAngles); // rotate opposite
Related
I have to make camera track a sphere object from behind it.
The camera should capture it in middle while face same direction of the object's velocity direction.
And the distance between the camera and the object should be always same.
I could make the camera face same direction of the object's velocity direction by this code.
Quaternion lookRotation = Quaternion.LookRotation(targetRb.velocity);
lookRotation.z = 0;
lookRotation.x = 0;
camera.transform.rotation = Quaternion.Lerp(camera.transform.rotation, lookRotation, 0.4f);
But I can't find how to calcurate the position where the camera should be.
Could you tell me how to do this?
You could add e.g.
var targetPosition = targetRb.position - targetRb.velocity.normalized * DESIRED_OFFSET;
camera.transform.position = Vector3.Lerp(camera.transform.position, targetPosition, 0.4f);
which always moves camera towards a position DESIRED_OFFSET units behind the target.
or alternatively you could use the camera's current direction if you really want the sphere to always be fix in the center
var targetPosition = targetRb.position - camera.transform.forward * DESIRED_OFFSET;
camera.transform.position = targetPosition;
Or you could also Lerp this one again. I guess you have to try a few options and see what fits your desired outcome best.
I have a main camera that rotates around an object (which I already move with AddForce). Using AddTorque, I would like the object to rotate its Y axis of rotation in the direction in which the camera's Y axis of rotation points so as to simulate the rotation of a person turning around. To do this I thought of using a force that gave me 0 when the Y axes of the two objects are the same, but I tried and the rigidbody covers only one part of the rotation of the camera while the other part is as if it not is detected.
var currentR = rb.rotation.y;
var targetR = Camera.main.transform.rotation.y;
rb.AddTorque(transform.up * 1000f * (targetR - currentR));
rotation my object
desired rotation
Vector3 camForward = Camera.main.transform.forward;
Vector3 rbForward = rb.transform.forward;
Vector3 torque = Vector3.Cross(camForward, rbForward);
rb.AddTorque(torque);
In the image above
the red vector is the spider's forward vector
the blue vector is the vector representing the direction between the spider and it's target
In the code below, orientation is a vector that's representing the normal of the terrain, so that the spider gets aligned to it:
Vector3 orientation = GetTerrainNormal();
Quaternion rotationNeeded = Quaternion.FromToRotation(Vector3.up, orientation);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
rotationNeeded,
RotationSpeed * Time.deltaTime
);
My issue is that I cannot manage to make the spider face its target... When I add any code that would make it rotate towards it, then it's not aligned with the terrain's normals anymore, it says straight...
So basically, how can I make the spider rotate on the Y world axis (I think), while still then being rotated to match the slope?
Full answer
In case it helps someone else, here's the full answer:
Vector3 orientation = GetTerrainNormal();
Vector3 directionToTarget = (target.position - transform.position).Y(0);
float d = Vector3.Dot(directionToTarget, orientation);
directionToTarget -= d * orientation;
if (directionToTarget.sqrMagnitude > 0.00001f) {
directionToTarget.Normalize();
Quaternion rotationNeeded = Quaternion.LookRotation(directionToTarget, orientation);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
rotationNeeded,
xRotationSpeed * Time.deltaTime
);
}
This answer on the unity forums was extremely helpful: https://forum.unity.com/threads/look-at-object-while-aligned-to-surface.515743/
Try this
Vector3 directionToTarget = target.transform.position - transform.position;
Quaternion rotationNeeded = Quaternion.LookRotation(directionToTarget, orientation);
First of all, I'm not sure why you need a code to orient the spider manually to the terrain. You can make the spider a Rigidbody and the Unity engine will take care of it for you.
Regardless, you want to rotate the spider around the local Y-Axis (this will keep the current orientation).
You can do this using transform.LookAt() (referring to the blue vector in the picture) (documented here) and passing the up vector as the 2nd argument.
I create a game and I need use inertia for object.
Example:
The image shows all what I need.
When I touch on screen, blueObject no longer uses the position of brownObject and rotation of redObject. And I add component Rigidbody. The object just falls down. I need him to fall further along his trajectory (inertia).
I tried to use addForce(transform.forward * float), this not work.
By setting the position of the transform, you don't use Unity Physics engine. Your cube must have a rigidbody from the begin of the simulation and what you need here is a spring joint (https://docs.unity3d.com/Manual/class-SpringJoint.html) or a fixed joint.
You need to calculate the current speed, when releasing the object.
Track the positions over the last frame & current frame, and use Time.deltaTime to compensate different frame-rates.
Then set this velocity to your objects rigidbody. (AddForce is just manipulating the velocity, but depending on the ForceMode it respects mass etc.)
public Vector3 lastPosition = Vector3.zero;
void Update()
{
// maybe do : if(lastPosition != Vector3.zero) to be sure
Vector3 obj_velocity = (lastPosition - transform.position) * Time.deltaTime;
lastPosition = transform.position;
// if you release the object, do your thing, add rigidbody, then:
rb.velocity = obj_velocity;
}
That should create the "inertia". the velocity contains the direction and the speed.
I have already this function from this question. I changed the sign of the rotation:
void rotateBotConnector()
{
Vector3 diff = (player.transform.position - botConnector.transform.position).normalized;
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
botConnector.transform.localRotation = Quaternion.Euler(0f, 0f, -(rot_z - 90f));
}
But the problem is, that now my object follows the player on the XZ plane but when the rotation reaches a certain degree, left or right, the object stops to rotate towards my player.
For better understanding: http://imgur.com/vWaqc31
Why not just use:
var target : Transform;
transform.LookAt(Vector3(target.transform.position.x, target.transform.position.y, transform.position.z);
It seems a lot easier than using euler. This way you look at target's x & y but transform your z.
Also I'm no expert with euler but it seems like it is limited to a 90 degree turn and I think this may be the reason why:
Quaternion.Euler(0f, 0f, -(rot_z - 90f));
Unless you have absolute necessity to rotate via angles maybe you'd rather go with manipulating the forward vector of the object, it's easier to understand the logic this way:
void rotateBotConnector()
{
Vector3 targetForwad = botConnector.transform.position - player.transform.position;
targetForward.y= 0f;
targetForward.Normalize(); // <-- this is very expensive function try avoid using it whenever possible
botConnector.forward = Vector3.Lerp(botConnector.forward, targetForward, Time.deltaTime));
}
once again, if you are short on cpu cycles you may want to go for trying to calculate angles instead of vectors. But in most cases this is ok. (the code needs a spell checking)