Placing objects right in front of camera - unity3d

I am trying to figure out how to modify HelloARController.cs from the example ARCore scene to place objects directly in front of the camera. My thinking is that we are raycasting from the camera to a Vector3 on an anchor or tracked plane, so can't we get the Vector3 of the start of that ray and place an object at or near that point?
I have tried lots, and although I am somewhat a beginner, I have come up with this
From my understanding, ScreenToWorldPoint should output a vector3 of the screen position corresponding to the world, but it is not working correctly. I have tried other options instead of ScreenToWorldPoint, but nothing has presented the desired effect. Does anyone have any tips?

To place the object right at the middle of the camera's view, you would have to change the target gameObject's transform.position (as AlmightyR has said).
The ready code would look something like this:
GameObject camera;
GameObject object;
float distance = 1;
object.transform.position = camera.transform.position + camera.transform.forward * distance;
Since camera's forward component (Z axis) is always poiting at the direction where Camera is looking to, you take that vector's direction and multiply it by a distance you want your object to be placed on. If you want your object to always stay at that position no matter how camera moves, you can make it a child of camera's transform.
object.transform.SetParent(camera.transform);
object.transform.localPosition = Vector3.forward * distance;

Arman's suggestion works. Also giving credit to AlmightyR since they got me started in the right direction. Here's what I have now:
// Set a position in front of the camera
float distance = 1;
Vector3 cameraPoint = m_firstPersonCamera.transform.position + m_firstPersonCamera.transform.forward * distance;
// Intanstiate an Andy Android object as a child of the anchor; it's transform will now benefit
// from the anchor's tracking.
var andyObject = Instantiate(m_andyAndroidPrefab, cameraPoint, Quaternion.identity,anchor.transform);
The only problem with this is that because of the existing HelloAR example code, an object is only placed if you click on a point in the point cloud in my case (or a point on a plane by default). I would like it to behave so that you click anywhere on screen, and it places an object anchored to a nearby point in the point cloud, not necessarily one that you clicked. Any thoughts for how to do that?
Side tip for those who don't know: If you want to place something anchored to a point in the cloud, instead of on a plane, change
TrackableHitFlag raycastFilter = TrackableHitFlag.PlaneWithinBounds | TrackableHitFlag.PlaneWithinPolygon;
to
TrackableHitFlag raycastFilter = TrackableHitFlag.PointCloud;

Related

apply a rotation relative to any reference space - Unity

is there a way to apply a rotation for any arbitrarily orientation (Object A's rotation relative to Object B's local orientation)
I know I can simply get desired result if i do setParent thing, but i want to get without it
In my situation, my character holds water bottle and moves around the room holding it so I set its rotation like this
transform.rotation = mainCamera.transform.rotation;
but As bottle top pointing to the sky seems more natural, I want it to rotate 90 degree by its own X-axis
I tried below codes but it dosent work as i intended
`originalRotation = transform.rotation;
Quaternion rotationDelta = Quaternion.FromToRotation(Vector3.forward, mainCamera.transform.forward);
transform.rotation = rotationDelta * originalRotation;`
Yes, Like i said above if i make my character parent to the bottle will solve the issue, but i want to
do it without it.
Thank you
Try this one:
transform.forward = mainCamera.transform.up;

(Unity + 2D) Change UI Button position issue

The last few days I've been stuck with a headache of a problem in Unity.
Okay, I won't go into details with my game, but I've made a super-simple example which represents my issue.
I have a 2D scene these components:
When the scene loads, and I tap the button this script executes:
Vector3 pos = transform.position;
pos.x -= 10;
transform.position = pos;
I have also tried this code:
transform.position = Camera.main.WorldToScreenPoint(new Vector3(0, 0, 0));
The problem is, that when I click the button, the x-pos of the object sets to -1536 which is not as expected. Picture shows the scene after the button has been clicked. Notice the Rect Transform values:
So I did a little Googling and found out about ScreenToWorldPoint, WorldToScreenPoint etc but no of these conversions solves my problem.
I'm pretty sure I'm missing someting here, which probably is right in front of my, but I simply can't figure out what.
I hope someone can point me in the right direction.
Best regards.
The issue is that you are using transform.position instead of rectTransform.anchoredPosition.
While it's true that UI elements are still GameObjects and do have the normal Transform component accessible in script, what you see in the editor is a representation of the RectTransform that is built on top. This is a special inspector window for UI elements, which use the anchored positioning system so you can specify how the edges line up with their parent elements.
When you set a GameObject's transform.position, you are providing a world space position specified in 3D scene units (meters by default). This is different from a local position relative to the canvas or parent UI element, specified in reference pixels (the reference pixel size is determined by the canvas "Reference Resolution" field).
A potential issue with your use of Camera.WorldToScreenPoint is that that function returns a position specified in pixels. Whereas, as mentioned before, setting the transform.position is specified in scene units (i.e. meters by default) and not relative to the parent UI element. The inspector, though, knows it's a UI element so instead of showing you that value, it is showing you the world position translated to the UI's local coordinates.
In other words, when you set the position to zero, you are getting the indices of whatever pixels happen to be over the scene's zero point in your main camera's view, and converting those pixel numbers to meters, and moving the element there. The editor is showing you a position in reference pixels (which are not necessarily screen pixels, check your canvas setting) relative to the object's parent UI element. To verify, try tilting your camera a bit and note that the value displayed will be different.
So again you would need to use rectTransform.anchoredPosition, and you would further need to ensure that the canvas resolution is the same as your screen resolution (or do the math to account for the difference). The way the object is anchored will also matter for what the rectTransform values refer to.
Try using transform.localposition = new Vector3(0,0,0); as your button is a child of multiple game objects. You could also try using transform.TransformPoint, which should just convert localpos to worldpos.
The issue is that your button is inside of another object. You want to be changing the local position. transform.localPosition -= new Vector3(10, 0, 0)
As #Joseph has clearly explained, you have to make changes on your RectTransform for your UI components, instead of change Transform.
To achieve what you want, do it like this:
RectTransform rectTransform = this.GetComponent<RectTransform>();
Vector2 anchoredPos = rectTransform.anchoredPosition;
anchoredPos.x -= 10;
rectTransform.anchoredPosition = anchoredPos;
Just keep in mind that this 10 are not your 3D world space units (like meters or centimeters).
Try these things because I did not understand what you were trying to do
Try using transform.deltaposition
Go to the canvas and go then scale with screen size then! You can use transform.position = new Vector3(transform.position.x -10,transform.position.y, transform.positon.z)
And if this doesn't work
transform.Translate(new Vector3(transform.deltaposition.x - 10,transform.deltaposition.y, transform.deltaposition.z);
I have a better idea. Instead of changing the positions of the buttons, why not change the values that the buttons represent?
Moving Buttons
Remember that the buttons are GameObjects, and every gameobject has a position vector in its transform. So if your button is named ButtonA, then in your code you want to get a reference to that.
GameObject buttonA = GameObject.Find("ButtonA");
//or you can assign the game object from the inspector
Once you have a reference to the button, you can proceed in moving it. So let's imagine that we want to move ButtonA 10 units left.
Vector3 pos = buttonA.transform.position;
pos.X -= 10f;
buttonA.transform.position = pos;

How to make a 3D compass in Unity? similar to the transform compass in scene mode

I'm trying to make a 3D compass in unity, like the one in scene mode.
But its not looking to bright.
At the moment
end goal How do I better emulate the scene mode transform compass? and keep the GamObject "3DCompass" always in view? (without putting it under the Main Camera)
//Compass3D
public class Compass3D : MonoBehaviour
{
public Vector3 NorthDir;
public Transform Player; // Camera
public GameObject NorthLayer;
// Update is called once per frame
void Update()
{
ChangeNorthDir();
}
public void ChangeNorthDir()
{
NorthDir.z = Player.eulerAngles.y; //May need to change
NorthLayer.transform.eulerAngles = NorthDir;
}
}
Hm...
Well, firstly, you need to realize that the compass' orientation never changes. That's kind of the point of it. The compass always points the same way, meaning it doesn't rotate.
Meaning there's no need for you to do anything in update, you just set where the north is supposed to point to, and leave it at that. The illusion of it rotating comes from person rotating, while the compass keeps pointing the same (global) direction.
The second thing is a big, lazy, awesome secret I'm going to tell you about:
Quaternion.LookRotation
So what you need to do is just rotate the compass correctly on Start, meaning rotate it so that its "Forward direction" is Vector3.forwards (that's a global Z+), and its upward is Vector3.up (global y+). And then never touch the rotation again.
But you want it to stay in view (without being childed to the camera), so what you'll do in update is that:
public class Compass3D : MonoBehaviour
{
public Vector3 NorthDir;
public Transform Player; // Camera
public Vector3 offsetFromPlayer; //needed to keep position from camera. this basically determines where on screen the compass will be positioned. 0,0,0 would be at the same position as the camera, experiment with other values to find one which positions compass relative to camera in such way that it displays on screen where you want it
public GameObject NorthLayer;
void Start()
{
//northDir can be whatever you want, I'm going to assume you want it to point along Unity's forward axis
NorthDir = Vector3.forward;
//set the compass to point to north (assuming its "N" needle points in the direction of model's forward axis (z+). if not, change the model, or nest it into a gameobject within which you'll rotate the model so that the N points along the parent gameobject's z+ axis
NorthLayer.transform.rotation = Quaternion.LookRotation(NorthDir, Vector3.up);
//nothing else needed, the rotation will be fine forever now. if you want to change it later, just do the above line again, and supply it the new NorthDir
}
// Update is called once per frame
void Update()
{
//only thing you need to do in update, is keep the relative position to camera. tbh, easiest way would be to parent the compass, but you said you don't want that, so...
transform.position = Player.position + (Player.rotation * offsetFromPlayer);
//you need to make sure that the compass' offset from camera rotates with the direction of the camera itself, otherwise when camera rotates, the compass will get out of view. that's what multiplying by Player.rotation is there for. you rotate Vectors by multiplying them with quaternions (which is how we express rotations).
}
}
What this code does: first it sets the compass so it points towards north. And then it never touches that again, because once the compass points towards north, if it's not parented to anything (which I assume it's not), it will keep pointing north. IF it is parented to anything else, just copypaste that line from start to Update too, so that when the orientation of compass' parent changes, the compass fixes its pointing back to global north.
Then, in update, it only updates its position, to keep at the same place relative to camera. The important thing to note is that the position needs to take the camera's direction into account, so that when camera rotates, the compass moves similarly to if you had your hand outstretched in front of you, and you rotated your whole body. If the compass is not parented to anything, that motion the tip of your hand does is still just a position change, but it is position relative to your whole body and its direction, so that position change needs to take that into account.
In this code, if you put the offsetFromPlayer as Vector3(0,0,1), that would mean "one unit along the way the camera is looking". If you put it as Vector3(1,0,1), that would mean "one unit along the way the camera is looking, and one unit to the right". So you'll need to experiment with that value to find one that makes the compass display where you actually want it to be on the screen.

Which side of my cube is hitting the plane below the cube

Im working in Unity and I have a simple scene. It consists of a cube which has a box collider on it. Below this cube is a plane
I want to know which side of the cube is hitting the plane at any given instant
One way to do this is to cast a ray from each side of the cube and determine which ray is colliding with the plane
But i fear that it may be performance heavy. Is there a way to do this in an efficient manner?
I used for same need:
1) Place plane for each side of cude;
2) Set clear color for planes;
3) Write script that check plane position (in your option need loop that search plane with lower position.
If you're just looking for a way other than just ray casting then you could create a method that takes in your cube's position and your plane's position and then do some calculations.
Vector3 heading = plane.transform.position - cube.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance;
From here you would just have to check what that direction is.

Check if camera if facing a specific direction

I'm working to let a character push objects around. The problem is that as soon as he touches an object he starts moving it, even when the touch was accidental and the character isn't facing the direction of the object.
What I want to do is get the direction the object when a collision happens, and if the camara is really facing that direction allow the player to move it.
Right now I only managed to get the direction of the object, but I don't know how to compare that with the direction of the camera.
This is what I'm trying now:
void OnCollisionEnter(Collision col) {
float maxOffset = 1f;
if (col.gameObject.name == "Sol") {
// Calculate object direction
Vector3 direction = (col.transform.position - transform.position).normalized;
// Check the offset with the camera rotation (this doesn't work)
Vector3 offset = direccion - Camera.main.transform.rotation.eulerAngles.normalized;
if(offset.x + offset.y + offset.z < maxOffset) {
// Move the object
}
}
You can try to achieve this in several different ways. And it is a bit dependent on how precise you mean facing the box.
You can get events when an object is visible within a certain camera, and when it enters or leaves using the following functions. With these commands from the moment the box gets rendered with that camera (so even if just a edge is visible) your collision will trigger.
OnWillRenderObject, Renderer.isVisible Renderer.OnBecameVisible, OnBecameInvisible
Or you could attempt to calculate whether and objects bounding box falls within the camera's view frustum, there for you could use the following geometry commands
GeometryUtility.CalculateFrustumPlanes, GeometryUtility.TestPlanesAABB
Or if you rather have a very precise facing you could also go for a Physics.Raycast So then you will only trigger the event when the ray is hitting the object.
Hope this helps ya out.
Take a compass obj and align it to ur device sorry object than when you move it you can always know where it points to.
theoretically it should work but maybe your object just moves around because of a bug in your simulator motion engine.