- Home /
Return grid points within a cube selection
I'm working on a voxel based level editor for Unity and have run into a problem with building.
I need to define a cuboid selection with two Marker voxels and return the valid grid points within said cube.
Here's an example: Green is Marker 1, Red is Marker 2, I need to return the grid points that the black blocks are occupying.
While my example is a 2D rectangle, this should also work for cuboid selections.
For reference my grid spacing is 0.5. So the possible points would look something like (0,0,0), (0,0.5,0), (0,1,0) and so on...
Any help is greatly appreciated!
Possibly the easiest fix would be to make a small script named TileInfo (or something)
public class TileInfo : $$anonymous$$onoBehaviour
{
public Vector3 GridPosition;
}
And then in the script where you spawn your blocks:
void SpawnWorld()
{
// Do all your calculations for world coords and stuff
GameObject NewTile = (GameObject)Instantiate(BlockObject, BlockPosition, Quaternion.identity);
TileInfo CurrentInfo = NewTile.GetComponent<TileInfo>();
if(CurrentInfo != null)
CurrentInfo.GridPosition = BlockPosition;
}
After that you can just get it by using GetComponent. There are better ways to do this, as this is quite heavy, but this is (probably) the easiest/fastest way.
I can get the coordinates of blocks that are placed. The problem is getting a list or array of Vector3's within the bounds of a selection marked by two marker blocks. The idea is that I could mark one corner of a wall, then the opposite diagonal and have it filled in for me.
Here's an example showing roughly what I want: https://www.youtube.com/watch?v=mRltOZFo4aY#t=257 (Skip to 4:17 if it doesn't work).
You can see that he marks 2 blocks or world coordinates and then is able to fill everything in between. I need a function that does just that, gets two world positions, and lists out the possible grid points within the selection.
Answer by ThePersister · Sep 09, 2014 at 08:53 AM
Ok, this one is reasonably tough. If I understand correctly, you're trying to get the "GridPositions" of each block between Green Marker 1 and Red Marker 2.
So, for example, if you have:
Green Marker (0,0,0)
Red Marker (1,1,0)
That would lead to the Grid points:
(0,0,0)
(0,0.5f, 0)
(0, 1, 0)
(0.5f, 0, 0)
(1, 0, 0)
(0.5f, 0.5f, 0)
(0.5f, 1, 0)
(1, 0.5f, 0)
(1, 1, 0)
Correct? Also, I take it you're ignoring the Z axis for now.
So, we'll need a method that does this for us. Let's say it returns a list of Vector3, representing the GridPositions. And we'll define the GridSeperation as a public float, here you go:
public float gridSeperation = 0.5f;
public List<Vector3> GetOccupiedGridPoints(Vector3 greenMarkerPos, Vector3 redMarkerPos)
{
// Make a holder
List<Vector3> temp = new List<Vector3>();
// Get the difference Vector betwen the two markers
Vector3 deltaPos = (redMarkerPos - greenMarkerPos);
// Calculate how many blocks in Width and Height there are between the markers
int blocksInWidth = Mathf.RoundToInt(deltaPos.x / gridSeperation);
int blocksInHeight = Mathf.RoundToInt(deltaPos.y / gridSeperation);
// Use a double for loop to run through each block and add it's position
for (int x = 0; x < blocksInWidth; x++)
{
for (int y = 0; y < blocksInHeight; y++)
{
// Add the position to the list
temp.Add(new Vector3(greenMarkerPos.x + x * gridSeperation, greenMarkerPos.y + y * gridSeperation, greenMarkerPos.z));
}
}
// Return the list
return temp;
}
This was only a quick guess, but it could be right on the money. I hope it helps out, give it a shot! ;)
Oh and, if you haven't used Lists before, make sure to add: "using System.Collections.Generic;" At the top of your script to allow List variables :)
It worked almost perfectly :p. I even added in the Z axis and here's what it produced with a quick test:
The only problem is that it doesn't fill entirely up to the second marke,r while this isn't a huge problem it is somewhat annoying.
Here's the code I wrote based on your example:
//Return points within selection
public List<Vector3> GetSelectionPoints(Vector3 p1, Vector3 p2) {
List<Vector3> temp = new List<Vector3>();
Vector3 deltaPos = p2 - p1;
//Calculate blocks between positions
int blocksX = $$anonymous$$athf.RoundToInt(deltaPos.x / gridSpacing);
int blocksY = $$anonymous$$athf.RoundToInt(deltaPos.y / gridSpacing);
int blocksZ = $$anonymous$$athf.RoundToInt(deltaPos.z / gridSpacing);
for (int x = 0; x < blocksX; x++ ) {
for (int y = 0; y < blocksY; y++ ) {
for (int z = 0; z < blocksZ; z++ ) {
temp.Add(new Vector3(p1.x + x * gridSpacing, p1.y + y * gridSpacing, p1.z + z * gridSpacing));
}
}
}
Debug.Log("Selected: " + temp.Count.ToString() + " Voxels");
return temp;
}
By the way, I love Lists<>, been using them over arrays for awhile now xD
Never$$anonymous$$d on that little issue, it was solved by simply adding + 1 to the portion that calculates the number of points:
int blocksX = $$anonymous$$athf.RoundToInt(deltaPos.x / gridSpacing) + 1;
int blocksY = $$anonymous$$athf.RoundToInt(deltaPos.y / gridSpacing) + 1;
int blocksZ = $$anonymous$$athf.RoundToInt(deltaPos.z / gridSpacing) + 1;
There is one additional problem though, if the selection contains any negative coordinates, the function simply doesn't work. It acts like nothing was selected, any thoughts?
Haha exactly, it's a bit dirty but +1 does the trick. You can also change the "less than"'s in the for loops to "less than or equal to" to include the final index.
Also, great job on the Triple axis, I'm proud, and it looks awesome!
It took me a bit, but I realised why it doesn't work at all on negative selections, but it's easy to fix!
Say you have deltaPos (-2, -2, -2), you'll get -4, -4, -4 $$anonymous$$eaning when you run through the for loops, your x, y and z temp variables will never be smaller than the blockX,Y and Z, thus you'll run straight through it.
There are 2 issues with solving this: - $$anonymous$$ake the numbers positive - Get Positive numbers to go the other way (if you'd keep them positive, negative selections would show their inverted results)
Here's the full (speculated) code that should make your day:
public float gridSpacing = 0.5f;
//Return points within selection
public List<Vector3> GetSelectionPoints(Vector3 p1, Vector3 p2)
{
List<Vector3> temp = new List<Vector3>();
Vector3 deltaPos = p2 - p1;
//Calculate blocks between positions
int blocksX = $$anonymous$$athf.RoundToInt(deltaPos.x / gridSpacing);
int blocksY = $$anonymous$$athf.RoundToInt(deltaPos.y / gridSpacing);
int blocksZ = $$anonymous$$athf.RoundToInt(deltaPos.z / gridSpacing);
// $$anonymous$$ake positive no matter what with $$anonymous$$ath.Abs (Absolute)
int absBlocksX = $$anonymous$$athf.Abs(blocksX);
int absBlocksY = $$anonymous$$athf.Abs(blocksY);
int absBlocksZ = $$anonymous$$athf.Abs(blocksZ);
for (int x = 0; x <= absBlocksX; x++)
{
for (int y = 0; y <= absBlocksY; y++)
{
for (int z = 0; z <= absBlocksZ; z++)
{
temp.Add(new Vector3(p1.x + x * GetPosOrNegGridSpacing(blocksX), p1.y + y * GetPosOrNegGridSpacing(blocksY), p1.z + z * GetPosOrNegGridSpacing(blocksZ)));
}
}
}
Debug.Log("Selected: " + temp.Count.ToString() + " Voxels");
return temp;
}
/// <summary>
/// Get gridspacing or $$anonymous$$us gridspacing depending on blocksAmount being a Positive or a Negative Number
/// </summary>
private float GetPosOrNegGridSpacing(int blocksAmount)
{
if (blocksAmount >= 0)
return gridSpacing;
else
return -gridSpacing;
}
With this, your selection should work in all directions for 3 axis :) I hope that helps, if it doesn't let me know. Also, please accept my answer once it's all good ;3
Btw, thx for asking such a cool question, really like the look of your selection!
(Visited this question again, the reply only showed the first line of my comment, luckily when pressing edit I can still see it, but just for the idea and for others I'm trying to change the comment to see if it will fully show!)
Works perfectly now! I really appreciate the help. Seems I need to work on my math skills, I always get stuck when it comes to complex solutions like this.
Your answer
Follow this Question
Related Questions
Make something move away from click point. 2 Answers
Extending a vector? 4 Answers
Average of Vectors [Math] 1 Answer
Rotate 3d vector based on local forward 1 Answer
Calculate Bullet based on enemy speed and distance from player 0 Answers