How to make a plane to rotate only on one axis? - c#

How to make a plane to "look" at the camera by rotating on only on one axis?
For example, I have a plane with a texture of smoke coming from the pipe. If I walk around the pipe the plane should always be facing the camera, rotating along the y axis. But the direction of the smoke should not change, therefore, along with the x and z axes, the plane should not rotate.
Here is a code example which helps to rotate the plane on all axes:
void Update()
{
transform.LookAt(Camera.main.transform.position, -Vector3.up);
}
How to make it rotate only on one axis?

One approach to this is to store the object's original rotation in a Vector3 using transform.eulerAngles. You can then create another Vector3 to store the object's rotation after the LookAt function has completed. You can then set the object's rotation to a new Vector3 using only the y value from the second variable and using the original x and y values. It would look something like this:
void Update()
{
Vector3 originalRotation = transform.eulerAngles;
transform.LookAt(Camera.main.transform.position, -Vector3.up);
Vector3 newRotation = transform.eulerAngles;
transform.eulerAngles = new Vector3(originalRotation.x, newRotation.y, originalRotation.z);
}

Related

Unity point game object to another only on the Local Y Axis

I would like to have a Gameobject point to another only on the Local Y-axis.
void FixedUpdate()
{
if(started){
Quaternion lookRot = Quaternion.LookRotation(target.position - transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation,Quaternion.Euler(transform.eulerAngles.x, lookRot.eulerAngles.y, transform.eulerAngles.z),1);
}
}
If I understand you correctly what you want to achieve is make this object "point at" the target but only allow it to rotate around its local Y axis.
What I would do for this is map the targets actual position onto a mathematical Plane that goes throw this object's position and uses the local Y axis as normal.
Then make your object face towards this mapped position additionally also passing in the local Y axis as the target UP vector which means it rotates only around its local Y axis.
something like e.g.
void FixedUpdate()
{
if(started)
{
var targetPosition = target.position;
var plane = new Plane(transform.up, transform.position);
var mappedTargetPosition = plane.ClosestPointOnPlane(targetPosition);
Quaternion lookRot = Quaternion.LookRotation(mappedTargetPosition - transform.position, transform.up);
}
}

how to rotate object according to the rotation of the camera?

i want to rotate player body according to the rotation of the camera. like FPS game.
STEPS >>
When the camera is facing down, i can see my body under the camera.
My body has to follow the location of the camera.
My body has to also follow the rotation of the camera.
So i can see my body anywhere when i facing down camera.
here is my code. It is attached to body(the object i have to rotate).
private void Update()
{
transform.position = arCamera.transform.position;
transform.rotation = arCamera.transform.rotation;
}
I want to see my body when the camera facing down but body rotates according with camera so i never see the body. How can i see it? ;(
Please help!
Sounds like you want your body only copy the rotation around the Y axis.
It is way easier to calculate with vectors than with quaternion rotations ;)
private void Update()
{
transform.position = arCamera.transform.position;
// Take your camera forward vector
var camForward = arCamera.transform.forward;
// erase the Y component
camForward.y = 0;
// and now make your body look into this flattened direction
transform.rotation = Quaternion.LookDirection(camForward, Vector3.up);
}
See also Quaternion.LookDirection.
This has of course one little flaw: The moment the camera looks up or down more than 90° the body is flipping to the opposite direction. So you either want to limit the camera rotation or come up with a different approach.
E.g. assuming that it is way harder for a human being to rotate (tilt) the head more then 90° on the Z axis, you could instead also do
private void Update()
{
transform.position = arCamera.transform.position;
// Take your camera forward vector
var camRight = arCamera.transform.right;
// erase the Y component
camRight.y = 0;
// and now align the body's right axis with this flattened direction
// Since we never touch the object's up vector this works without problems
transform.right = camRight;
}

unity fix orientation in an axis

I have a first person rigidbody capsule that rotates so that he will always be upright against the gravity direction. I want to rotate my player to the side so that the player camera will not rotate vertically.
My code is,
void Update() {
FixOrientation();
}
void FixOrientation()
{
if (trans.up != -GetGravityDirection())
{
Quaternion targetRotation = Quaternion.FromToRotation(trans.up, -GetGravityDirection()) * trans.localRotation;
trans.localRotation = Quaternion.RotateTowards(trans.localRotation, targetRotation, 5f);
}
}
The result is,
In the image above, I changed the gravity direction to point to the ceiling.
This code only rotates the player at the global x-axis no matter where he is facing which means when i'm facing global forward or backward, the player will rotate vertically the camera. What I want is for it to rotate on the side(local z axis).
Unity already has a method for exactly that: Transform.Rotate has an overload taking an angle and a rotation axis.
It might look like
// rotation speed in degrees per second
public float RotationSpeed;
void Update()
{
FixOrientation();
}
void FixOrientation()
{
if (transform.up != -GetGravityDirection())
{
// Get the current angle between the up axis and your negative gravity vector
var difference = Vector3.Angle(transform.up, -GetGravityDirection());
// This simply assures you don't overshoot and rotate more than required
// to avoid a back-forward loop
// also use Time.deltaTime for a frame-independent rotation speed
var maxStep = Mathf.Min(difference, RotationSpeed * Time.deltaTime);
// you only want ot rotate around local Z axis
// Space.Self makes sure you use the local axis
transform.Rotate(0, 0, maxStep, Space.Self);
}
}
A Sidenote:
Just in general be careful with the direct comparison of two Vectors
trans.up != -GetGravityDirection()
uses an approximation of 0.00001. In your case that should be fine anyway but for comparing you should rather use
Vector3.Angle(vector1, vector2) > threshold
to define a wider or stronger threshold

how to make world space UI crosshair line up with screen space crosshair?

So I'm trying to make the gun on the turret of my tank point towards the center of the screen just like in World of tanks where you have a crosshair for where the gun is pointing and the crosshair for the center of the screen.
The problem is that the gun crosshair which is a UI image in world space parented to the gun, doesn't exactly line up with the center of the screen which is the big crosshair in the image [enter image description here][1].
edit: so this works but how can I change it to the x axis?
public class CenterCursor : MonoBehaviour
{
// speed is the rate at which the object will rotate
public float speed;
void FixedUpdate()
{
// Generate a plane that intersects the transform's position with an upwards normal.
Plane playerPlane = new Plane(Vector3.up, transform.position);
// Generate a ray from the cursor position
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Determine the point where the cursor ray intersects the plane.
// This will be the point that the object must look towards to be looking at the mouse.
// Raycasting to a Plane object only gives us a distance, so we'll have to take the distance,
// then find the point along that ray that meets that distance. This will be the point
// to look at.
float hitdist = 0.0f;
// If the ray is parallel to the plane, Raycast will return false.
if (playerPlane.Raycast(ray, out hitdist))
{
// Get the point along the ray that hits the calculated distance.
Vector3 targetPoint = ray.GetPoint(hitdist);
// Determine the target rotation. This is the rotation if the transform looks at the target point.
Quaternion targetRotation = Quaternion.LookRotation( targetPoint - transform.position);
// Smoothly rotate towards the target point.
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
}
You can also try putting your turret object as a child of camera object...

Set player's boundary within sphere

I want to restrict player movement in the sphere, the schematic diagram show as below. If player movement is out of range, then restrict player to sphere max radius range.
How can I write C# code to implement it, like this?
These are my current steps:
Create 3D sphere
Create C# code append to sphere object
My code so far:
public Transform player;
void update(){
Vector3 pos = player.position;
}
I don't know how you calculate your player`s position but before assigning the new position to the player you should check and see if the move is eligible by
checking the new position distance form the center of the sphere
//so calculate your player`s position
//before moving it then assign it to a variable named NewPosition
//then we check and see if we can make this move then we make it
//this way you don't have to make your player suddenly stop or move it
//back to the bounds manually
if( Vector3.Distance(sphereGameObject.transform.position, NewPosition)< radius)
{
//player is in bounds and clear to move
SetThePlayerNewPosition();
}
What #Milad suggested is right but also include the fact you won't be able to "slide" on the sphere border if your movement vector even slightly goes outside the sphere :
(sorry for the crappy graphic skills...)
What you can do if you want to be able to "slide" on the sphere interior surface is get the angle formed between the player position and the X vector and then apply this angle with the :
public Transform player;
public float sphereRadius;
void LateUpdate()
{
Vector3 pos = player.position;
float angle = Mathf.Atan2(pos.y, pos.x);
float distance = Mathf.Clamp(pos.magnitude, 0.0f, sphereRadius);
pos.x = Mathf.Cos(angle) * distance;
pos.y = Mathf.Sin(angle) * distance;
player.position = pos;
}
Just make sure using this won't counter effect your player movement script (that's why I put it in LateUpdate() in my example).

Categories