0

I'm trying to optimize accessing and changing data of a 3D environment, because some operations have to be done millions of times. Currently I have the following optimizations in place:

  • Using a flat array (1D)
  • The dimensions are in powers of 2
  • Bit-shifting, where possible, instead of multiplication/division

The indexing of the 3D vectors is as follows:

  • A change in the X vector would increase/decrease the index by 1
  • A change in the Y vector would increase/decrease the index by 3DEnvironmentSize.X
  • A change in the Z vector would increase/decrease the index by 3DEnvironmentSize.X * 3DEnvironmentSize.Y

Given the following pseudo-code:

mapSize.X = 4
mapSize.Y = 4
mapSize.Z = 2

Xdif = 1
Ydif = mapSize.X = 4
Zdif = mapSize.X * mapSize.Y = 16

Xexponent = log2(Xdif) = log2(1) = 0 (2^0 = 1 = Xdif)
Yexponent = log2(Ydif) = log2(4) = 2 (2^2 = 4 = Ydif)
Zexponent = log2(Zdif) = log2(16) = 4 (2^4 = 16 = Zdif)

One would go from 3D -> 1D given Vector(1,2,1) using the following:

location.X = 1
location.Y = 2
location.Z = 1

shiftIndex.X = location.X << Xexponent = 1 << 0 = 1
shiftIndex.Y = location.Y << YExponent = 2 << 2 = 8
shiftIndex.Z = location.Z << Zexponent = 1 << 4 = 16

index = shiftIndex.X + shiftIndex.Y + shiftIndex.Z = 1 + 8 + 16 = 25

As you can see, I'm making use of bit-shifting to increase the processing speed. Now I know how to convert 3D -> 1D using devisions and division remainders with given index 30 like so:

index = 30

location.X = index % mapSize.X
location.Y = (index / mapSize.X) % mapSize.Y
location.Z = ((index / mapSize.X) / mapSize.Y) % mapSize.Z

Is there any way to make use of bit-shifting (or anything else for that matter)here somehow that will make this faster as well? I've been trying to crunch this for some time but I'm unable to crack it, if its even possible in the first place.

Neijwiert
  • 985
  • 6
  • 19

2 Answers2

0

Are you just trying to pack 3 numbers in a bigger one ?

If so, why dont you just shift and mask ?

ThreeToOne(v3) -> v3.x | (v3.y << 8 ) | (v3.z << 16)

OneToThree(v) -> v3(v & 0xFF, v >> 8 & 0xFF, v >> 16 & 0xFF)
Nicolas Repiquet
  • 9,097
  • 2
  • 31
  • 53
  • Thanks for answering, but no I'm trying to gain access faster to elements in an array. However the disadvantage of having a 1D array is that you would need to calculate the coordinates from the index. I'm trying to optimize the way this is done (making it as fast as possible). – Neijwiert Oct 02 '15 at 11:10
0

I was given the answer elsewhere.

When you divide by a number that is of power of 2, you can then replace that division by a right shift operation that is the exponent of the power of 2. The modulus operation can be replaced (again if it is a power of 2) by a bit-wise and operator and n - 1. Where n is the number you were diving by. So to conclude the code:

mapSize.X = 4
mapSize.Y = 4
mapSize.Z = 2

Xdif = 1
Ydif = mapSize.X = 4
Zdif = mapSize.X * mapSize.Y = 16

XDifExponent = log2(Xdif) = log2(1) = 0 (2^0 = 1 = Xdif)
YDifExponent = log2(Ydif) = log2(4) = 2 (2^2 = 4 = Ydif)
ZDifExponent = log2(Zdif) = log2(16) = 4 (2^4 = 16 = Zdif)

XSizeExponent = log2(mapSize.X) = log2(4) = 2 (2^2 = 4 = mapSize.X)
YSizeExponent = log2(mapSize.Y) = log2(4) = 2 (2^2 = 4 = mapSize.Y)
ZSizeExponent = log2(mapSize.Z) = log2(2) = 1 (2^1 = 2 = mapSize.Z)

Vector3D -> Index example:
location.X = 1
location.Y = 2
location.Z = 1

shiftIndex.X = location.X << XDifExponent = 1 << 0 = 1
shiftIndex.Y = location.Y << YDifExponent = 2 << 2 = 8
shiftIndex.Z = location.Z << ZDifExponent = 1 << 4 = 16

index = shiftIndex.X + shiftIndex.Y + shiftIndex.Z = 1 + 8 + 16 = 25

Index -> Vector3D example:
index = 30

location.X = index & (mapSize.X - 1) = 2
location.Y = (index >> XSizeExponent) & (mapSize.Y - 1) = 3
location.Z = ((index >> XSizeExponent) >> YSizeExponent) & (mapSize.Z - 1) = 1
Neijwiert
  • 985
  • 6
  • 19