Snapping to grid with grid size of <= 1

I’m creating a basic voxel editor that uses several different sizes of cubes.

The user has a slider the use to control the current cube size their editing with, then when adjusted changes the scale of the cube to-be-placed and the guide grid.

Now all I have left to do it to snap the placement cursor’s position to the grid (just trying to get it to work right now, worrying about face direction calculations later). The grid sizes are <= 1 (0.2, 0.25, 0.33, 0.5, 1).

I can calculate the grid position using:

Vector3 currentPos = hit.point; /* where hit.point is the position in space of the cursor on the model*/
Vector3 GridLock = new Vector3(Mathf.Round(currentPos.x / gridScale), Mathf.Round(currentPos.y / gridScale), Mathf.Round(currentPos.z / gridScale)) * gridScale;

Which works fine for some grid positions (1, 0.33, 0.2) but for the other sizes (0.25, 0.5) the position when snapped to the grid is offset by half a unit.

I’m sure this is just a basic math problem, but I’m having a tricky time figuring it out :frowning:

Any help is appreciated!

Example at size 1: (yellow cube is the cursor clamped to the grid)

alt text

Example at size 0.5: (cursor (yellow cube) is offset to (I believe) the top and right)

alt text
The white grid lines are a tiling texture on the voxels.

P.S. The slider goes from 1 to 5 with whole numbers, which is used for the tiling value. The Grid interval is calculated with (1/sliderval)

Well, first of all what you have here are not “voxels”:

A voxel represents a value on a
regular grid in three-dimensional

Since you vary the grid size it’s not a regular grid. Also how are you actually storing your data? Voxel systems don’t store the position of each voxel, just the data. You could, in theory, use a way smaller grid as basis. You can create the next “larger” cube by having 8 voxels next to each other in a cube pattern (a 2x2x2 cube). If you want to change the snap grid, you might only use power of two sizes:

1, 2, 4, 8, 16, 32, ...

Anything else will not fit together. Of course instead of power of 2 you could also use power of 3:

1, 3, 9, 27, 81, 243

But that’s very uncommon and grows much faster than power of two.

To calculate the power of two gridsize you have to calculate the appropriate “power of 2”. This could be done with Mathf.Pow, but a left shift is way easier ^^:


Also it’s important to define a voxel position at one of the corners of the cubes and not the center. Otherwise they won’t fit together.

Some might look like they fit together but that’s just an arbitrary interference between the two spacings. Look at this:

|              |              |              |              |
|              |              |              |              |
|              |              |              |              |
|              |              |              |              |
|              |              |              |              |
|              |              |              |              |
|     |     |     |     |     |     |     |     |     |     |
|     |     |     |     |     |     |     |     |     |     |

This is a ratio of 2 to 5 (or 1 to 2.5)

Any ratio could be reduced to a 1 to X ratio

so 3 to 4 would be 1 to 1.3333 → 1/3 off
and 3 to 5 would be 1 to 1.6666 → 2/3 off
4 to 5 would be 1 to 1.25 → 1/4 off
2 to 3 would be 1 to 1.5 → 1/2 off
and the case above: 2 to 5 would be 1 to 2.5 → 3/2 off

That means all those cases don’t fit together because every X cubes there would be some cubes off

So the problem why it doesn’t work in your case is the combination of using the center as well as odd ratios. If you have ratios that fit together they will always be off by half a cube, But some which are off every X cubes might fit nicely to the next larger grid every now and then. This is generally called interference since you have two different frequencies which overlap.