ScreenToWorldPoint with perspective cameras - unity3d

So I am having an odd problem just now. I wrote a small script that, when atatched to an object will cause it to face the mouse pointer. However, since I switched from an orthographic camera to a perspective camera, the script has ceased to work. I have added in some debug and it looks like the ScreenToWorldPoint is just returning the same value no matter where the mouse is. I suspect this has something to do with the mouse being a fundamentally 2D entity, but I am not sure how to solve the problem.
Any help is much appreciated! :)
void Update () {
Vector3 difference = camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
//Debug.Log(Camera.main.ScreenToWorldPoint(Input.mousePosition));
difference.Normalize();
difference.Set (difference.x, difference.y, 0);
transform.up = difference;

This is addressed in unity answers.
Unity Answers say, and I quote:
ScreenToWorldPoint receives a Vector3 argument where x and y are the
screen coordinates, and z is the distance from the camera. Since
Input.mousePosition.z is always 0, what you're getting is the camera
position. The mouse position in the 2D screen corresponds to a line in
the 3D world passing through the camera center and the mouse pointer,
thus you must somehow select which point in this line you're
interested in - that's why you must pass the distance from the camera
in z. If you try something like this:
function Update() {
var mousePos = Input.mousePosition;
mousePos.z = 10; // select distance = 10 units from the camera
Debug.Log(camera.ScreenToWorldPoint(mousePos));
}
you will get the world point at 10 units from the camera.
Please use google before posting a question. There is a high change that you will find your answer before posting here.

Related

Which rotation is shown in the Inspector?

The chest bone of my player can be rotated while aiming.
Now I wanted to evaluate how much (minimum and maximum rotation) I should let the chest be rotatable.
To do that, I allowed all degrees of rotation and took a look at the Inspector.
For example, the minimum value that the chest should be rotatable to the left should be Y=-15.
At Y=-15 (seen in the Inspector), it still looked natural.
Now I wanted to code this.
To my surprise, chest.localRotation.Y was a completely different value than what the Inspector is showing.
I have then taken a look at the chest variable and extended the view.
I just can't see the rotation value that the Inspector is showing.
How should I go on in this case, please?
I'm using this to rotate the bone:
Chest.LookAt(ChestLookTarget.position);
Chest.rotation = Chest.rotation * Quaternion.Euler(Offset);
Thank you!
The reason why it doesn't work:
Quaternion is not a human readable value.
One Quaternion is allways unique but can have multiple (infinite?) different representations in Euler space! The other way round one Euler represents allways exactly one Quaternion value.
If you look at the docs it explicitly says
Don't modify this directly unless you know quaternions inside out.
Than as said what you see in the inspector is the localRotation in relation to the parent Transform.
Better said it is one of the many possible Euler inputs that result in the Quaternion. What you see in the debug at localEulerAngles is another possible Euler representation. Unity usually in localEulerAngles also gives you only values > 0.
It seems that the chest anyway will only rotate around the Y axis, right?
If this is the case you can simply get the Angle between the chest's original forward vector and the target. It is way easier to handle Vector3 values than Quaternions ;)
It seems to be the same use case as in this post
// get the target direction
Vector3 targetDir = ChestLookTarget.position - Chest.position;
// Reset any difference in the Y axis
// since it would change the angle as well if there was a difference I the height
// between the two objects
targetDir.y = 0;
// however you currently rotate
// instead rotate only the Vector3 variable without applying it to the transform yet
Vector3 newDir = Vector3.RotateTowards(Chest.forward, targetDir, RotationSpeed * Time.deltaTime, 0.0f);
// Compare the target direction to the parents forward vector
float newAngle = Vector3.Angle(Chest.parent.transform.forward, newDir);
if (newAngle > MaxRotationAngle)
{
// What should happen if angle gets bigger?
return;
}
// If angle still okey set the new direction
Chest.rotation = Quaternion.LookRotation(newDir);

Placing objects right in front of camera

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;

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.

Get the position behind an object (locally) ? - Unity3D

I ran into a problem while making my complex(ish) camera behaviour (using Javascript). The problem that i have run to is that i am not able to get the position behind my player. Please don't tell me to use Vector3.back etc.. , because i want the position locally, to support turning. It won't work if the camera is always set to that position, cos i have a cool movement system in place.
I tried a number of approaches, and confused myself with the math. I also tried complex addition and subtraction. None of them worked at all.
I guess i am probably missing something quite simple, like a way to get into local coordinates etc.. ( or maybe a few math functions )
thanks in advance
-Etaash
You can get the forward vector of any transform, and if you negate that it is the backward vector. So on a script attached to the player you would have:
Vector3 backward = -transform.forward;
So to get a position, you could do something like this:
Vector3 pos = transform.position + (backward * dist); // where dist is a float to scale how far away from the position you want it

unity3d: shoot where mouse clicks on sceen

Looking at various bulletin boards, this is a common problem, yet I could not find any good answers online.
My project has a first-person car that moves via the arrow keys. I want a gun mounted on the car to be able to shoot via crosshair that can aim anywhere on the current screen. Right now the bullets just shoot right through the middle all the time, except for the times when I click on the screen and nothing happens (which is about 50%). Here is the code which I got via various scripts on the web:
var speed = 20;
var bullet: GameObject;
function Update () {
var hit : RaycastHit;
if(Input.GetButtonDown("Fire1")){
var ray = Camera.main.ScreenPointToRay (Input.mousePosition); //ray from
// through the mousePosition.
if(Physics.Raycast(ray, hit, 1000)) { //does the ray collide with
// anything.
//add stuff here for finding type of object and such.
Debug.Log("Hit Something at mouse position");
Debug.DrawRay (ray.origin, ray.direction * 10, Color.yellow);
//Display the ray.
var projectile:GameObject = Instantiate(bullet,transform.position,transform.rotation);
projectile.rigidbody.velocity = transform.forward * speed;
}
}
}
If anyone could help, it would be very much appreciated.
Your ray is correct (pointing to middle of screen), but it has nothing to do with the way your making the bullet travel. The bullet travels based on a transform.forward * speed. What you need to do is get the hit point of your ray, then get a direction from your bullets origin to that point.
Vector3 direction = hit.point - projectile.transform.position;
projectile.rigidbody.velocity = direction * speed;
1000 is pretty low for a screenPointToRay, so you might want to up that by a lot if you want to avoid future problems.
Also rigidbody has been deprecated, im not sure if you should be doing a (GameObject).rigidbody directly like that
http://docs.unity3d.com/ScriptReference/GameObject-rigidbody.html
Without actually posting you any code, I can tell you that what you should probably be looking into is why your projectile is setting its rotation from the transform's rotation instead of the rotation of your ray if I understand your attempt.
The projectile is clearly gaining all of it's properties (including those which are supposed to be detached from the origination) from the vehicle and just following along accordingly.
Try setting your projectile's rotation to that of your ray.
Also, your ray is more than likely only ever hitting half of the time because of your amount of distance to test. Try upping that number, or creating walls for it to collide with at shorter range.