Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

TopDownCamera issue with object placement based on mouse position

Discussion in 'Navigation' started by Pdkkid188, Jun 17, 2016.

  1. Pdkkid188

    Pdkkid188

    Joined:
    Jan 2, 2015
    Posts:
    5
    Hello,
    I am currently attempting to write a script to place an object based on mouse location and to place it, click the mouse buttons. Using ScreenToWorldPoint with my camera setup causes the object, which is being moved from the result of object.transform = Camera.main.ScreenToWorldPoint(mousePosition) causes the object to remain in the center of the camera, without being moved based on where the mouse it, but rather where the camera is positions. Here is the current script i have for placement control.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlacementController : MonoBehaviour {
    5.  
    6.     public bool isPlacing;
    7.     public GameObject placingObject;
    8.  
    9.     Vector3 mousePos;
    10.  
    11.     void Update()
    12.     {
    13.         if(isPlacing)
    14.         {
    15.             if (Input.GetMouseButton(0))
    16.             {
    17.                 isPlacing = false;
    18.             }
    19.  
    20.             mousePos = Input.mousePosition;
    21.             Debug.Log("MouseBefore X: " + mousePos.x + "  MouseBefore Y: " + mousePos.y);
    22.             mousePos = Camera.main.ScreenToWorldPoint(mousePos);
    23.             Debug.Log("MouseAfter X: " + mousePos.x + "  MouseAfter Y: " + mousePos.y);
    24.             mousePos.y = .5f;
    25.             placingObject.transform.position = mousePos;
    26.         }
    27.  
    28.     }
    29.  
    30.     public void placeObject(GameObject obj)
    31.     {
    32.         isPlacing = true;
    33.  
    34.         placingObject = (GameObject)Instantiate(obj, obj.transform.position, obj.transform.rotation);
    35.  
    36.     }
    37.  
    38. }
    39.  
     
  2. Pdkkid188

    Pdkkid188

    Joined:
    Jan 2, 2015
    Posts:
    5
    Well.. I fixed the issue of the object only moving with the camera, i assigned mousepos.z = mousepos.y becuase my axis's are abit messed up. But now the issue is that when i move the mouse, the object moves, but it does not stay with the mouse, it acts like it is way to sensitive.
     
  3. calebc01

    calebc01

    Joined:
    Jul 21, 2015
    Posts:
    62
    The ScreenToWorldPoint(Vector3 position) function grabs the world point on a theoretical plane that sits the specified distance (position.z) from the camera. That plane lies normal to the camera, so the camera is looking "straight down" at that plane.

    position.x and position.y are in pixels, and position.z is in world units.

    You need to set mousepos.z to whatever the distance is between your camera and the plane that holds the point where you want to instantiate your new object. It is NOT the distance between the camera and the point. :) Note that unless you want to put your object on a surface that is also normal to the camera, the distance to that surface will be different based on which pixel is selected. See below for an example:


    The distance d is what you need to send to ScreenToWorldPoint() to get the world point shown in red, on the ground. This may seem a little weird, but if it were not the distance to the plane as shown in the image, it would be the distance to curved surface in front of the camera, and that surface shape would change based on the camera projection matrix (i.e. the field of view). That might be less than convenient in other circumstances.

    So, for your application, the ScreenToWorldPoint(.) function may not actually be the most convenient to use. Instead, you could use use Physics.Raycast to throw a ray into the world and grab the position of the collision:

    Code (csharp):
    1.  
    2.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    3.         RaycastHit hit;
    4.  
    5.         if (Physics.Raycast(ray, out hit))
    6.         {
    7.             Vector3 worldPoint = hit.point;
    8.        
    9.             // TODO: Make sure worldPoint is valid and do stuff with it.
    10.         }
    11.  
    Of course, the ground would need to have a collider attached so that the ray can run into it.

    I describe this process in more detail on my blog, here: http://www.yerawizard.com/unity-world-position-from-click/
     
    Last edited: Jun 21, 2016
  4. Pdkkid188

    Pdkkid188

    Joined:
    Jan 2, 2015
    Posts:
    5
    This worked perfectly! Thank you very much for your help!
     
  5. D12Duke1

    D12Duke1

    Joined:
    Feb 14, 2016
    Posts:
    103
    i woulda used pointereventdata :p but that is a pretty good way of doing it!