Here’s my best shot at an explanation for what I think would be the process for this, sorry if I misunderstood anything or if it is poorly explained.
Imagine we’re doing this to pixels instead of voxels, to make the problem easier.
Here are two connected pixels which you call assemblies.
In the game world, these pixels would fit onto a grid, where the centre of the grid is the origin of the world. You can imagine this grid as a 2d array.
So the array of our game world may look something like this
world = {
{0 ,0 ,0}
{0, 0, 1}
{0, 0, 1}
}
Where the 1’s represent places where there are pixels and the 0s are places where there isnt any pixels.
Lets say we want to rotate the assembly at world[3][3] (the bottom right 1). 90 degrees counter-clockwise
The steps I would take:
- Given the pivot point world[3][3], find which pixels are connected to it, and add all of these to a list called assembly.
- Now, knowing the points of the assembly, convert these points in the 2d array world into coordinates, relative to the pivot point (so the pivot point is (0,0) and that say a pixel pixel to the right of it would be (0,1)
- Iterate throughout these points in the assembly and apply the appropriate matrix multiplication, if the “new point” of the point tries to overwrite a point in the world which is already 0, then we must be colliding with another pixel or assembly, so cancel the rotation. (One issue with this is that the 1 we are overwriting could be apart of the current assembly we are working on, you just need to check if this is the case)
Okay… so thats quite complex.
First we need the assembly - the group of connected pixels.
In the visualisation, these would just be the ones which are orthogonally adjacent. Meaning, what is the value of point which is “above” the pivot, as well as “right” “left” and “down”. So given the pivot point world[3][3], if we add 1 to the value of the second bracket, we would get the value which is “right” of the pivot point. -1 for the value to the left and apply these sums to the first bracket to find the “up” value and the “below” value.
We find all the points which are adjacent to the pivot, and check if they are 1, if they are 1, there is a pixel there, so it must be part of the assembly.
Here is a visualisation, where the pink pixel is the pivot:
We get the places you see there, and check if they are 1 or 0, the ones which are 1 will be added to an assembly list.
Cool, now we have a list storing the values which represent the grey part, the pink part and the other grey part. So the grey parts connected to the pink part. But you and I both know that that other grey part should belong to the assembly, as they’re connected in a chain along the other grey parts.
To do this, after finding the points around the pink part, we can imagine that the point world[2][4] becomes the pink part and we check all the values around it, then we do the same for the other grey part world[4][4], and we would find that world[4][3] is 1, so must be a part of this assembly. Once no more parts around the parts in the assembly are equal to 1, then we know we must have the full assembly.
With a list of all the points in the 2d array, we must now find there coordinates
If we imagine the top left to be the origin (world[1][1]) then we need to find the coordinates of the points in the assembly relative to it. HOWEVER, we’re getting these coordinates all in the hope that we can use matrix multiplication to rotate the entire assembly, but for that, if the origin was world[1][1], the entire assembly would rotate about the top left corner, not the pink pivot. So instead, we need to find the coordinates of the points in the assembly relative to the pink pivot.
This is quite simple (I imagine):
Given this part of the assembly, the point at world[2][4] has the first index which is 3-2 = +1. So it is 1 above the pink part, so the coordinate for the y component is 1. X would be 4-4 = 0, so the coordinate of world[2][4] relative to the pivot world[3][4] is (0,1), which, just by looking at it we know is true!
This same principle can be applied to all the points in the assembly, to work out how th point at world[4][3] is (-1,-1). Then we store all these coordinates in a list.
Phew…
Final step, apply the appropriate matrix multiplication to all the coordinates, then turn the new coordinate into a point in the 2d array, and check if that point is already occupied, if it is then we are intersecting some other pixel/assembly
So, iterate throughout the coordinates list. Apply the appropriate matrix multiplication, which in our case for “Lets say we want to rotate the assembly at world[3][3] (the bottom right 1). 90 degrees counter-clockwise” would be:
That one.
Then, given this new coordinate, turn that into a position in the world array by reversing the steps in step 2. And check if the world array already has a 1 at this point, if it does, we’re colliding with another assembly and the rotation should be cancelled, if not we can let that point be 1.
If we iterate through all the coordinates in the assembly without ever colliding, we can allow the assembly to rotate.
And we’re done.
So potential problems:
- Firstly, that bit in italics, is like that because I dont think that would actually work, or at least it requires some extra step. Too tired and late to really look into right now.
- Secondly, you need to actually visualise this in the roblox workspace, by using the 2d world array to generate those 4x4 parts you were on about, how you update this is up to you.
- And quite possibly the biggest complication, this was all about 2d arrays and pixels, but we actually want to do this with voxels, so 3d space. Obviously this means turning the world array into a 3d array, but then as for the matrix multiplication, I’m not sure. I’m slightly sure that when working with 3d space, the matrix multiplication for the same rotation ( say 90 counter clockwise) will also change in some way, not sure though, not learnt that in school yet
So yeah, thats my best shot at an explanation, hopefully you found it helpful and that I actually understood what you’re trying to achieve. Any questions just ask.
Oh yeah, and that @F0ZYAN guy is using ChatGPT to generate responses, someone called him out in some other post.