Angle information(degree) between AR camera and target object on a plane - unity3d

I have a question, please help and thanks!
I want to know how to show the Angle information(degree) between AR camera and target object on a plane. (Using Smartphone)
And I want to know how to "code" with Unity and AR Foundation.
I tried using some code(below), but it seems only work on Distance, not work on Angle...
Thank again!
void Start ()
{
//get the components
private ARRaycastManager RayManager;
private GameObject visual;
public Camera CameraStart;
public Text textField2;
public Text textField;
float distance;
float angle;
RayManager = FindObjectOfType<ARRaycastManager>();
visual = transform.GetChild(0).gameObject;
}
void Update ()
{
// shoot a raycast from the center of the screen
List<ARRaycastHit> hits = new List<ARRaycastHit>();
RayManager.Raycast(new Vector2(Screen.width / 2, Screen.height / 2), hits, TrackableType.Planes);
RaycastHit hit;
//Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// check if we hit an AR plane, update the position and rotation
if(hits.Count > 0)
{
transform.position = hits[0].pose.position;
transform.rotation = hits[0].pose.rotation;
distance = Vector3.Distance(CameraStart.transform.position, transform.position);
textField.text = distance.ToString("N2") + "meter";
Physics.Raycast(transform.position, out hit);
angle = Vector3.Angle(hit.normal, transform.forward);
textField2.text = angle.ToString("N2") + "degree";
if(!visual.activeInHierarchy)
visual.SetActive(true);
}
}
}

I would check that the ray hits:
if (Physics.Raycast(transform.position, out hit)) {
angle = Vector3.Angle(hit.normal, transform.forward);
textField2.text = angle.ToString("N2") + "degree";
} else {
Debug.LogError("Did not hit")
}
Also I would make sure that the target has a collider and that the layer mask is correct.

Related

Unity ortographic camera panning within boundaries issue

I have an ortographic camera and I need to create panning with mouse within boundaries. I currently have this code which works fine with one problem. When user drags camera out of bounds, mouse position still gets updated and user needs to first move the mouse back within the bounds before camera is panning again. E.g. let's say the max bounds of x axis is 140. If the user moves the mouse to 150, the camera's position is clamped to 140 which is fine. However, if the user pans the camera back without releasing button, the camera is stuck at 140 until the mouse position reaches 140 again. Any ideas how to implement this adjustment?
public class CameraDragMouse : MonoBehaviour
{
private Vector3 Origin;
private Vector3 Diference;
private bool Drag;
private float minPanningBoundaryX;
private float maxPanningBoundaryX;
private float minPanningBoundaryZ;
private float maxPanningBoundaryZ;
private Camera mainCamera;
private void Start()
{
mainCamera = this.GetComponentInChildren<Camera>();
CameraCenter.CenterCameraOnPosition(new Vector3(24, 0, 24));
minPanningBoundaryX = gameObject.transform.position.x - 40;
maxPanningBoundaryX = gameObject.transform.position.x + 40;
minPanningBoundaryZ = gameObject.transform.position.z - 40;
maxPanningBoundaryZ = gameObject.transform.position.z + 40;
}
void LateUpdate()
{
if (Input.GetMouseButton(0))
{
Ray rr = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(rr, out RaycastHit hit, Mathf.Infinity, Constants.LAYER_MASK_TERRAIN))
{
Diference = hit.point - gameObject.transform.position;
}
if (Drag == false)
{
Drag = true;
Origin = hit.point;
}
}
else
{
Drag = false;
}
if (Drag == true)
{
Vector3 newCameraPosition = Origin - Diference;
newCameraPosition.x = Mathf.Clamp(newCameraPosition.x, minPanningBoundaryX, maxPanningBoundaryX);
newCameraPosition.z = Mathf.Clamp(newCameraPosition.z, minPanningBoundaryZ, maxPanningBoundaryZ);
gameObject.transform.position = newCameraPosition;
}
}
}

Unity2D object rotation on Mobile device

I want to know if there is a way to rotate the object only when the user click and drag on the gameobject. If the user click and drag anywhere else, the gameobject should not rotate.
Object with this script on it is rotating no matter where the user clicks.
void Update()
{
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
Vector2 dir = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position) - Camera.main.ScreenToWorldPoint(transform.position);
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle - 90, Vector3.forward);
transform.rotation = rotation;
transform.rotation = rotationZ * transform.rotation;
}
}
Your current code indeed only checks for touches .. it doesn't matter whether these are "hitting" anything or not.
You could e.g. use a Physics.Raycast in order to check if your touch is above an object using
// store the direction from object to touch when the touch started
private Vector2 startDirection;
// store the objects orientation when the touch started
private Quaternion startRotation;
// only process touch moved if the touch actually started above this object
private bool isValidTouch;
// The collider of this object
[SerializeField] Collider _collider;
// The main camera
[SerializeField] Camera _mainCamera;
private void Awake()
{
if(!_collider) _collider = GetComponent<Collider>();
if(!_mainCamera) _mainCamera = Camera.main;
}
void Update()
{
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
var touchPosition = touch.position;
switch(touch.phase)
{
case TouchPhase.Began:
// Check if this touch actually is over this object
if(_collider.RayCast(_mainCamera.ScreenPointToRay(touchPosition), out var hit))
{
// Now store initial data
// You want to do ONLY ONE:
// - Either transform the touch into worldspace (more complicated)
// - OR transform the position into screenspace (easier)
// You definitely do not want to do both!
startDirection = (touchPosition - (Vector2)_mainCamera.WorldToScreenPoint(transform.position));
startRotation = transform.rotation;
isValidTouch = true;
}
break;
case TouchPhase.Moved
if(isValidTouch)
{
// Get the current touch direction
var direction = (touchPosition - (Vector2)_mainCamera.WorldToScreenPoint(transform.position));
// Get the angle between them
var differenceAngle = Vector3.SignedAngle(startDirection, direction, Vector3.forward);
// rotate the original rotation according to the current angle
Quaternion rotation = startRotation * Quaternion.AngleAxis(differenceAngle, Vector3.forward);
transform.rotation = rotation;
}
break;
case TouchPhase.Ended
isValidTouch = false;
break;
}
}
}

Rotate Camera vector to look at player Unity

I create a game, like minigolf/pool. I want to have a camera which follow player.
Position is normally ok, I get the ball direction and I lerp.
Rotation is almost ok. Currently, rotation by Y axis is ok, but camera look straigth forward, and don't look down to the player :
I already try many thing , quaternion angleToaxis, quarternion lookat ... but doesn't look good, the camera go look away ...
Here my code
namespace CameraManagerNameSpace
{
public class CameraManager : MonoBehaviour
{
public float cameraHeight=13f;
public PlayerNameSpace.Player playerToFollow;
public float followSpeed = 3f;
public float rotationSpeed = 1f;
float distance;
Vector3 position;
Vector3 newPos;
Quaternion rotation;
Quaternion newRot;
Vector3 playerPrevPos, playerMoveDir;
bool firstMoveDone=false;
void Start()
{
playerPrevPos = playerToFollow.player_transform.position;
distance = Vector3.Distance(transform.position,playerToFollow.player_transform.position);
}
void FixedUpdate()
{
if(Vector3.Distance(playerToFollow.player_transform.position ,playerPrevPos)>0.5f || firstMoveDone)
{
playerMoveDir = playerToFollow.player_transform.position - playerPrevPos;
firstMoveDone = true;
}
else
{
playerMoveDir = new Vector3(0,0,0);
}
if (playerMoveDir != Vector3.zero)
{
playerMoveDir.Normalize();
newPos = playerToFollow.player_transform.position - playerMoveDir * distance;
newRot =Quaternion.LookRotation(playerMoveDir,Vector3.up);
position = Vector3.Lerp(transform.position, new Vector3(newPos.x,newPos.y+cameraHeight,newPos.z), followSpeed * Time.deltaTime);
rotation = Quaternion.Lerp(transform.rotation, newRot, rotationSpeed * Time.deltaTime);
transform.position = position;
transform.rotation = rotation;
playerPrevPos = playerToFollow.player_transform.position;
}
}
}
}
Also, I don't know why, but after the balls stop the camera continue to do some movement very jerky, jolting, halting.
Well in
newRot = Quaternion.LookRotation(playerMoveDir,Vector3.up);
you are saying the camera to look in the same direction the player is moving ... not to look at the player. This would work if you wouldn't give the camera an extra position offset in the Y axis.
You might want to rather try
// vector pointing from the camera towards the player
var targetDirection = playerToFollow.player_transform.position - transform.position;
newRot = Quaternion.LookRotation(targetDirection, Vector3.up);
You should also rather use Update since FixedUpdate is only used for physics related stuff (also see Update & FixedUpdate)

Using RayCastAll instead of RayCast

I have two gameobjects roller and marker. When I use physics raycast it works, but with raycastall it doesn't. I need to use raycastall, because i need to iterate through colliders. When marker is on roller normal raycast doesn't work and I need to use raycastall.
This code works:
if (Input.touchCount > 0)
{
// get mouse position in screen space
// (if touch, gets average of all touches)
Vector3 screenPos = Input.mousePosition;
// set a distance from the camera
screenPos.z = 10.0f;
// convert mouse position to world space
Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
Physics.Raycast(cameraRay, out hit);
if (hit.collider.tag == "Floor")
{
transform.position = hit.point;
}
/*
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
// get current position of this GameObject
Vector3 newPos = transform.position;
// set x position to mouse world-space x position
newPos.x = worldPos.x;
newPos.z = worldPos.z-3f;
// apply new position
transform.position = newPos;
*/
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
Destroy(gameObject);
touchhandler = GameObject.Find("Roller").GetComponent<TouchHandler>();
touchhandler.markerexists = false;
}
}
And this doesn't:
if (Input.touchCount > 0)
{
// get mouse position in screen space
// (if touch, gets average of all touches)
Vector3 screenPos = Input.mousePosition;
// set a distance from the camera
screenPos.z = 10.0f;
// convert mouse position to world space
Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit[] hits;
hits = Physics.RaycastAll(Camera.main.ScreenPointToRay(Input.mousePosition), 100.0F);
while (i < hits.Length)
{
RaycastHit hit = hits[i];
if (hit.collider.tag == "Floor")
{
transform.position = hit.point;
}
i++;
}
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
Destroy(gameObject);
touchhandler = GameObject.Find("Roller").GetComponent<TouchHandler>();
touchhandler.markerexists = false;
}
}

Raycast rotate help need in unity

I have this code which lets an object rotate on Y axis. But I want to rotate the object on Z axis only. I tried to change the hPlane value, but no luck.
How can I do this?
Thanks
private Ray ray;
private Quaternion target;
private float speed = 1000.0f;
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0)) {
ray = Camera.main.ScreenPointToRay (Input.mousePosition);
Plane hPlane = new Plane(Vector3.up, Vector3.zero);
float distance = 0;
if(hPlane.Raycast(ray, out distance)){
Vector3 targetPoint = ray.GetPoint(distance);
targetPoint += transform.position;
Quaternion targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
float step = speed * Time.deltaTime;
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation,step);
}
}
}
Update:
My Goal is to rotate a bar (cube mesh) on Z axis smoothly using mouse click . The rotation will occur only when (this part I could not do) the mouse touch the corners of the bar.
I have already done the Z axis rotation with this code but the rotation very low (even for speed =1000.0f) and it rotates clockwise I suppose. But I want to move the bar in both direction and the movement will be smooth and faster like Quaternion.RotateTowards
Thanks
private Ray ray;
private RaycastHit hit;
private Quaternion target;
private float speed = 1000.0f;
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0)) {
ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if(Physics.Raycast(ray, out hit)){
//transform.position = new Vector3(hit.point.x, hit.point.y, 0);
target = Quaternion.Euler(0.0f,0.0f, hit.point.z * speed);
transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime);
}
}
}
http://i.stack.imgur.com/7qIcs.jpg
I suggest you to change the orientation of the object axis. For a better use of the Quaternion functions, edit your bar in order to have local Y has rotation axis and local Z as look direction.
Then use this code :
if (Input.GetMouseButton(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
Vector3 distance = hit.point - transform.position;
distance.y = 0;
Quaternion targetRotation = Quaternion.LookRotation(distance);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * speed);
}
}
Your bar will only rotate around Y axis.