Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Cfirz · Mar 08, 2018 at 09:23 AM · mathgrid

How do I snap an object to a circular grid

This is how I generate the grid, I would like to know how to find nearest point on the grid to the mouse click position

 for (int layer = 1; layer < Layers; layer++)
   {
     for (int slice = 0; slice < Slices; slice++)
     {
      float angle = slice * Mathf.PI * 2 / Slices;
      Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * (gridRadius * layer);
 
      currentPos = transform.position;
      desiredPos = new Vector3(currentPos.x + pos.x, currentPos.y + pos.y, currentPos.z + pos.z);
 
      Gizmos.DrawSphere(desiredPos, 1.0f);
     }
 }

This is how my Grid looks like after I generate it: alt text

What I want is that where ever I click my mouse, lets say to place a simple cube object, I want it to find the nearest point on the grid and place the object there, something like that:

 private Grid grid;

     private void Awake()
     {
         grid = FindObjectOfType<Grid>();
     }
 
     private void Update()
     {
         if (Input.GetMouseButtonDown(0))
         {
             RaycastHit hitInfo;
             Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 
             if (Physics.Raycast(ray, out hitInfo))
             {
                 PlaceCubeNear(hitInfo.point);
             }
         }
     }
 
     private void PlaceCubeNear(Vector3 clickPoint)
     {
 //get closest point on grid and CreatePrimitive(PrimitiveType.Cube) at that location
     }

capture.png (231.6 kB)
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image RobAnthem · Mar 08, 2018 at 03:15 PM 0
Share

You could always do an overlapping sphere or box, find the grid pieces nearest, and snap the object to the nearest grid position.

avatar image Cfirz RobAnthem · Mar 08, 2018 at 05:03 PM 0
Share

@RobAnthem

find the grid pieces nearest, and snap the object to the nearest grid position

this is my problem, not sure how to do that...(or I didn't understand your answer)

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by ProtoTerminator · Mar 08, 2018 at 05:20 PM

First, fill a kd-tree (or similar) with all your points for a quicker lookup. Then, make a Plane and do a Plane.Raycast to find the place on the plane (the ground, or a wall) that you clicked, and pass that point into the kd-tree's find nearest function to get your result.

Alternatively (maybe faster and easier), using the same plane raycast, check how far the point is from the center and snap that distance to the nearest ring. Then find the nearest snap-angle from there and calculate where the point is on that angle. Or loop through all the points in that ring to find the nearest (slower).

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Cfirz · Mar 11, 2018 at 10:54 AM 0
Share

@ProtoTer$$anonymous$$ator Thanks for your comment, I've learned 2 new subjects from it, planes and kd trees.

I've tried to implement this solution but I think I have an issue on the plane as when I use plane.Raycast it seems that I never hit the plane and never get the hitPoint Here is what I did: Declaring the plane the following:

  DistanceFromCamera = new Vector3(Camera.main.transform.position.x, Camera.main.transform.position.y, Camera.main.transform.position.z - m_DistanceZ);
             plane = new Plane(Vector3.forward, DistanceFromCamera);

and here try to use it as following:

    if (Input.Get$$anonymous$$ouseButtonDown(0))
             {  
                 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                 float enter = 0.0f;
     
                 if (plane.Raycast(ray, out enter))
                 {
                     Vector3 hitPoint = ray.GetPoint(enter);
                     PlaceCubeNear(hitPoint);
                 }
             }



Any ideas what am I doing wrong ?

avatar image Bunny83 Cfirz · Mar 11, 2018 at 11:58 AM 0
Share

Well, first of all you use Vector3.forward (the worldspace z axis) as your plane normal vector. Since in your screenshot your desired plane seems to be the x-z-plane your normal vector should be Vector3.up.


Second you pass in the distance from the camera as the plane's "d" value which doesn't make too much sense here. You want the distance of the plane from the origin. It's generally easier to just use the plane constructor that takes a normal and a point on the plane.


The ray you get from "ScreenPointToRay" is a worldspace ray we want our plane to be defined in the world space coordinate system. So we use Vector3.up as normal and a worldspace position that is on the plane.


If you want the plane to "stick" to a gameobject just pass the gameobjects transform.up as normal and transform.position as point on the plane. Of course keep in $$anonymous$$d if the object moves or rotates you have to recreate the plane. Though the Plane is just a struct like a Vector4 so it's actually very cheap.

avatar image Cfirz · Mar 11, 2018 at 11:50 AM 0
Share

managed to fix the issue, I didn't initialized the tree list on the start method (just on the OnDrawGizmos) also I dropped the plane usage and did it like this :

 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
             RaycastHit hit;
 
             if (Physics.Raycast(ray, out hit))
             {
                 Debug.Log(hit.point);
                 if (hit.collider.gameObject.tag == "Terrain")
                 {
                     PlaceCubeNear(hit.point);
                 }
             }


Thanks a lot !

avatar image
0

Answer by Bunny83 · Mar 11, 2018 at 12:23 PM

If your desired gridpoints follow a simple formula you can simply convert your incoming point on the plane into polar coordinates (angle + distance), clamp both to your desired grid and just convert them back to cartesian coordinates.


The first thing you might want to do is reduce the 3d points to 2d points. The easiest way to do this is to convert them from worldspace into localspace coordinate of an empty gameobject. This gameobject should represent the center of your plane. Just use InverseTransformPoint to get a given worldspace point in local coordinates. Now we can just ignore the y component and only use x and z.


With Mathf.Atan2 you can calculate the angle (in radians) of the given local point in relation to the x axis. The magnitude of your local vector is your distance. Now just clamp those two values as you like. In your picture you splitted the 360° (2*PI) into 20 steps. So you would want to make the angle be a multiple of 360/20== 18 degree (2*PI / 20 == PI/10 radians). Your distance may be clamped to a multiple of 1 or whatever spacing you want.


When done you can use Sin and Cos to get back an actual local space vector and if you need the position in worldspace just use TransformPoint on it.

 public static Vector3 ClampCircle(Vector3 aLocalPoint, int aAngleSubDiv, float aDistance)
 {
     float segment = Mathf.PI*2f / aAngleSubDiv;
     float angle = Mathf.Atan2(aLocalPoint.z, aLocalPoint.x);
     float dist = aLocalPoint.magnitude;
     // clamp
     angle = Mathf.Round(angle / segment) * segment;
     dist = Mathf.Round(dist / aDistance) * aDistance;
 
     return new Vector3(Mathf.Cos(angle) * dist, 0, Mathf.Sin(angle) * dist);
 }

To get the closest point on a plane "attached" to the gameobject depending on where the user clicks, just do this:

 private void Update()
 {
     if (Input.GetMouseButtonDown(0))
     {
         Plane p = new Plane(transform.up, transform.position);
         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
         float dist;
         if (p.Raycast(ray, out dist))
         {
             var v = transform.InverseTransformPoint(ray.GetPoint(dist));
             v = ClampCircle(v, 20, 1f);
             v = transform.TransformPoint(v);
             // v is the clamped worldspace point
         }
     }
 }


Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

85 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

mouse position percentage problem 0 Answers

Hexagon-Grid Distance 2 Answers

Grid-based building system not working 1 Answer

Hexagon Grid 1 Answer

How can I calculate a list of points where a line intersects a grid? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges