Round a Vector3 to a grid position?

I need to round a Vector3 so each value is rounded to place it on a point in a 2x2 grid.

I figure I can do it by Mathf.RoundToInt on x\y\z and then use %, but that seems bulky.

What grid size do you use? You talk about gird intersections but can you tell us the grid step size and min max values? Because there's always a problem if you want +- values. Around "0" the rounding direction will change. It's mirrored at the origin.

In most cases it's enough to devide your value be a grid unit, add 0.5 and truncate the value (just cast it to int). If it's rounded you have grid coordinates which you multiply again with the grid unit size.

examples(grid size 2.5):

start:   12.2   | 5.1    | 24.1
step1:    4.88  | 2.04   |  9.64   // devided by 2.5
step2:    5.38  | 2.54   | 10.14   // + 0.5
step3:    5     | 2      | 10      // truncated: x = (int)x; // C#
step4:   12.5   | 5      | 25      // multiplied by 2.5

In C# it could look like:

float GridSize = 2.5f;
float V = 12.2f;

V = (int)(V/GridSize + 0.5f);
V *= GridSize;

In JS it would be:

var GridSize = 2.5;
var V = 12.2;
V = parseInt(V/GridSize + 0.5f);
V *= GridSize;

ps. haven't tested those two snippets, they can contain syntax errors but they should be ok.


edit

Just tried it and that’s my little test class I end up with:

public class GridSnap : MonoBehaviour
{
    public float offset = 1.0f;
    public float gridSize = 4.0f;    
    private Plane plane;

    void Start ()
    {
        plane = new Plane(new Vector3(0,0,5),new Vector3(1,0,5),new Vector3(0,1,5));
    }

    void Update ()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float hit = 0.0f;
        if (plane.Raycast(ray, out hit))
        {
            Vector3 V = ray.GetPoint(hit);
            V -= Vector3.one * offset;
            V /= gridSize;
            V = new Vector3(Mathf.Round(V.x), Mathf.Round(V.y), Mathf.Round(V.z));
            V *= gridSize;
            V += Vector3.one * offset;
            transform.position = V;
        }
    }
}

In this example i use the same grid size and the same offset for each axis. With the current settings (grid 4 offset 1) i'll get values like: -3 | 1 | 5 | 9 | 13.

Mathf.Round works correct around 0 and it rounds exactly between two grid lines.

3.001 becomes 5

2.999 becomes 1

But if you have a working solution and you're happy with the result, keep it ;)

You shouldn't have to RoundToInt, % takes care of that (I'm told)