How to set position of 3D model on center AR Camera? - unity3d

My application using Unity And Vuforia. I want set position of 3D model of tracked found target to center Screen and AR Camera after track lost. I mean that I want to show lost Image target on center position.

void centerGameObject(GameObject gameOBJToCenter, Camera cameraToCenterOBjectTo, float zOffset = 2.6f)
{
gameOBJToCenter.transform.position = cameraToCenterOBjectTo.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cameraToCenterOBjectTo.nearClipPlane + zOffset));
}
Then you can call it with
centerGameObject(gameOBJ, Camera.main);
The default zoffset(2.6f) should work but you can change it by supplying the third parameter.
centerGameObject(gameOBJ, Camera.main, 6f);

Related

Unity / Mirror - Is there a way to keep my camera independent from the player object's prefab after start?

I'm currently trying to create a multiplayer game using mirror!
So far I've been successful in creating a lobby and set up a simple character model with a player locomotion script I've taken and learnt inside out from Sebastian Graves on YouTube (you may know him as the dark souls III tutorial guy)
This player locomotion script uses unity's package 'Input System' and is also dependent on using the camera's .forward and .right directions to determine where the player moves and rotates instead of using forces on the rigidbody. This means you actually need the camera free in the scene and unparented from the player.
Here is my HandleRotation() function for rotating my character (not the camera's rotation function):
private void HandleRotation()
{
// target direction is the way we want our player to rotate and move // setting it to 0
Vector3 targetDirection = Vector3.zero;
targetDirection = cameraManager.cameraTransform.forward * inputHandler.verticalInput;
targetDirection += cameraManager.cameraTransform.right * inputHandler.horizontalInput;
targetDirection.Normalize();
targetDirection.y = 0;
if (targetDirection == Vector3.zero)
{
// keep our rotation facing the way we stopped
targetDirection = transform.forward;
}
// Quaternion's are used to calculate rotations
// Look towards our target direction
Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
// Slerp = rotation between current rotation and target rotation by the speed you want to rotate * constant time regardless of framerates
Quaternion playerRotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
transform.rotation = playerRotation;
}
It's also worth mentioning I'm not using cinemachine however I'm open to learning cinemachine as it may be beneficial in the future.
However, from what I've learnt and managed to find about mirror is that you have to parent the Main Camera under your player object's prefab so that when multiple people load in, multiple camera's are created. This has to happen on a Start() function or similar like OnStartLocalPlayer().
public override void OnStartLocalPlayer()
{
if (mainCam != null)
{
// configure and make camera a child of player
mainCam.orthographic = false;
mainCam.transform.SetParent(cameraPivotTransform);
mainCam.transform.localPosition = new Vector3(0f, 0f, -3f);
mainCam.transform.localEulerAngles = new Vector3(0f, 0f, 0f);
cameraTransform = GetComponentInChildren<Camera>().transform;
defaultPosition = cameraTransform.localPosition.z;
}
}
But of course, that means that the camera is no longer independent to the player and so what ends up happening is the camera rotates when the player rotates.
E.g. if I'm in game and looking to the right of my player model and then press 'w' to walk in the direction the camera is facing, my camera will spin with the player keeping the same rotation while my player spins in order to try and walk in the direction the camera is facing.
What my question here would be: Is there a way to create a system using mirror that doesn't require the camera to be parented to the player object prefab on start, and INSTEAD works by keeping it independent in the scene?
(I understand that using forces on a rigidbody is another method of creating a player locomotion script however I would like to avoid that if possible)
If anybody can help that would be greatly appreciated, Thank You! =]
With the constraint of your camera being attached to the player you will have to adapt the camera logic. What you can do is instantiate a proxy transform for the camera and copy that transforms properties to your camera, globally, every frame. The parent constraint component might do this for you. Then do all your transformations on that proxy.
Camera script with instantiation:
Transform proxy;
void Start(){
proxy = (new GameObject()).transform;
}
void Update(){
//transformations on proxy
transform.position = proxy.position;
transform.rotation = proxy.rotation;
}

Destroy Anchors in Unity ARCore

I have a project that places a game object on the position a user touches the screen. An anchor is made as such:
private Anchor anchor;
anchor = detectedPlane.CreateAnchor (new Pose (anchorPosition, Quaternion.identity));
transform.position = anchorPosition;
transform.SetParent (anchor.transform);
Right before creating an anchor when a user touches the screen the second time or any number of times after that, I make sure to destroy the anchor with the following code.
if (anchor != null) {
Destroy(anchor);
}
However, when I test my code on Instant Preview, all of the anchors remain after I touch the screen multiple times. Is this the right way of destroying anchors?
Android
If you want to remove an AnchorNode from a scene then parent.removeChild(child) or node.setParent(null) is the recommended wayin Android ARCore.
To get ARCore to stop tracking an Anchor, you can use yourAnchor.detach().
More details here - Android ARCore
https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.html#detach()
Unity
The Trackable class in unity has a method to create Anchors but not to destroy them. However, the approach that seems to be used is to destroy the Unity GameObject that represent the Anchor.
See an example from the Unity ARCore SDK here: https://github.com/google-ar/arcore-unity-sdk/blob/9448df3e371e7e04a3e99ed6745890021d8f3e32/Assets/GoogleARCore/Examples/ObjectManipulation/Scripts/Manipulators/TranslationManipulator.cs
An extract of the relevant code:
GameObject oldAnchor = transform.parent.gameObject;
Pose desiredPose = m_LastHit.Pose;
Vector3 desiredLocalPosition = transform.parent.InverseTransformPoint(desiredPose.position);
if (desiredLocalPosition.magnitude > MaxTranslationDistance)
{
desiredLocalPosition = desiredLocalPosition.normalized * MaxTranslationDistance;
}
desiredPose.position = transform.parent.TransformPoint(desiredLocalPosition);
Anchor newAnchor = m_LastHit.Trackable.CreateAnchor(desiredPose);
transform.parent = newAnchor.transform;
Destroy(oldAnchor);

How can I get the x,y coordinate location of a tile in the tilemap?

I have just started getting used to using Unity's new tilemap tool (UnityEngine.Tilemaps).
One issue I am having is that I don't know how to get the x,y coordinates of a placed tile via script. I am trying to move a scriptableObject on the tilemap in script to a new location that the player clicks, but I don't know how to get the coordinates of the clicked tile location. There doesn't seem to be any position property for the Tile class (the Tile knows nothing about its location), so the Tilemap must have the answer. I was not able to find anything in the Unity documentation for how to get the Vector3 coordinates for a selected tile in the Tilemap.
If you have access to the Tile instance you can use its transform (or the raycast hit from the click) to get its world position and than get the tile coordinates via the WorldToCell method of your Grid component (look at the documentation).
EDIT:
Unity seems to not instantiate the tiles but instead uses only one tile object to manage all tiles of that type, i wasn't aware of that.
To get the correct position you have to calculate it yourself. Here is an example of how to get the tile position at the mouse cursor if the grid is positioned at the xy-plane with z = 0
// get the grid by GetComponent or saving it as public field
Grid grid;
// save the camera as public field if you using not the main camera
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// get the collision point of the ray with the z = 0 plane
Vector3 worldPoint = ray.GetPoint(-ray.origin.z / ray.direction.z);
Vector3Int position = grid.WorldToCell(worldPoint);
I couldn't find a way to get the Grid's position from mouse click, so instead I used a Raycast to Vector3, and then converted that to coordinates via the WorldToCell method of the Grid component as per Shirotha's suggestion. This allows me to move the selected GameObject to a new position.
public class ClickableTile : MonoBehaviour
{
public NormalTile normalTile;
public Player selectedUnit;
private void OnMouseUp()
{
// left click - get info from selected tile
if (Input.GetMouseButtonUp(0))
{
// get mouse click's position in 2d plane
Vector3 pz = Camera.main.ScreenToWorldPoint(Input.mousePosition);
pz.z = 0;
// convert mouse click's position to Grid position
GridLayout gridLayout = transform.parent.GetComponentInParent<GridLayout>();
Vector3Int cellPosition = gridLayout.WorldToCell(pz);
// set selectedUnit to clicked location on grid
selectedUnit.setLocation(cellPosition);
Debug.Log(cellPosition);
}
}
}
On an aside, I know how to get the Grid location, but now how to query it. I need to get the GridSelection static object from Grid, and then get its position.

How to control oculus rotation and potition in unity 5.3.x

I want to control the rotation and position of the Oculus DK2 in Unity 5.3 over. It doesn't seems to be trivial, I've already tried all I could find on unity forum, but nothing seems to works. The CameraRig script doesn't look to do anything when i change it. I want to disable all rotation and position because I have a mocap system that more reliable for those things.
Need some help!
To be able to control the pose your camera must be represented by using a OVRCameraRig that is included with the OVRPlugin for Unity 5.
Once you have that you can use the UpdatedAnchors event from the camera to transform the mocap data on to the camera position, just overwrite the value of OVRCameraRig.trackerAnchor for the head and OVRCameraRig.leftHandAnchor and OVRCameraRig.rightEyeAnchorfor hand positions if your suit supports those.
public class MocapController : MonoBehavior
{
public OVRCameraRig camera; //Drag camera rig object on to the script in the editor.
void Awake()
{
camera.UpdatedAnchors += UpdateAnchors
}
void UpdatedAnchors(OVRCameraRig rigToUpdate)
{
Transform headTransform = GetHeadTransform(); //Write yourself
Transform lHandTransform = GetLHandTransform(); //Write yourself
Transform rHandTransform = GetRHandTransform(); //Write yourself
rigToUpdate.trackerAnchor = headTransform;
rigToUpdate.leftHandAnchor= lHandTransform;
rigToUpdate.rightHandAnchor= rHandTransform;
}
}

Unity 3D: draw line behind game object/record path taken by game object?

I am creating a VR app in Unity3d using Google cardboard and need to know how to record the path taken by the player (they are traversing a maze). Is there a way of drawing the path taken by the user (possibly in the console; not in the actual game and not visible to the user) and saving this path as an image?
I need to save an image or just a line of where the player went in the game so that I can then email this image/data to the player.. What is the best way to accomplish this?
You need to store the Player's path in List as Vector3. Then you can use LineRenderer to draw the line.change the vertext amount of the LineRenderer to List.Count with LineRenderer.SetVertexCount then loop over the List and change the position of the LineRenderer with LineRenderer.SetPosition(loopIndex,playersPo[loopIndex]).
List<Vector3> playerPos = new List<Vector3>();
//Store players positions somewhere
//playerPos.Add(pPos);
//playerPos.Add(pPos);
//playerPos.Add(pPos);
Color red = Color.red;
LineRenderer lineRenderer = gameObject.AddComponent<LineRenderer>();
lineRenderer.material = new Material(Shader.Find("Particles/Additive"));
lineRenderer.SetColors(red, red);
lineRenderer.SetWidth(0.2F, 0.2F);
//Change how mant points based on the mount of positions is the List
lineRenderer.SetVertexCount(playerPos.Count);
for (int i = 0; i < playerPos.Count; i++ )
{
//Change the postion of the lines
lineRenderer.SetPosition(i, playerPos[i]);
}