Sep 17, 2021 17:06
P.S. for 3D array, that would 100x100x100 = 1M bytes just to store 100 points.
Sep 17, 2021 17:06
Just the size of that array makes the access time much slower.

Have a good one and hit me up here if you have further questions.
Sep 17, 2021 17:05
You're welcome. Couple of final things:

I would suggest... start with a new application.
Push 100 points into a 100x100 byte[] at random. That array will be something like 10000 bytes.

Play with the Morton-ordered basic `Dictionary` or `unordered_map`. You can store the same points as in the array, but for just over 100 (300 if you use ushort keys) bytes. So this already shows you why spatial hashes are preferable to arrays.
Sep 17, 2021 17:02
If you can find a "perfect spatial hash" (google) that will be best for you, I think.
Sep 17, 2021 17:01
https://cs.stackexchange.com/questions/249/when-is-hash-table-lookup-o1
https://stackoverflow.com/questions/16068151/c-stl-map-is-access-time-o1
https://stackoverflow.com/questions/2771368/can-hash-tables-really-be-o1

...there are countless discussions about this online.
Sep 17, 2021 17:00
O(1) amortised - that means almost always O(1) but there are cases where it can be much worse (rare cases usually).
Sep 17, 2021 16:59
And so this brings me to something else...

I recommend these approaches to you (whether manual Morton index + `Dictionary<int, Vertex>` OR a 3rd party spatial hash lib) but I cannot _guarantee_ the performance impacts that it will have.

You need to know that hashmaps (all, whether spatial or normal ones) have something like O(1) access times, but you MUST do your own research on the one you choose.

I am only advising you with how I would do this - I cannot guarantee the performance.
Sep 17, 2021 16:57
But the performance may be poor (I don't know how many thousands or millions of vertices in your octree)
Sep 17, 2021 16:57
You can start with the morton-ordered approach I give you above - if you like. It is quite easy to do.
Sep 17, 2021 16:57
Correct, yes, you should.
Sep 17, 2021 16:56
`var map = new SpatialHashMap<Vertex>();`
OR
`var map = new SpatialHashMap<SpatialKey, Vertex>();`

something like this.

And then your assignments and retrievals as usual. But all the difficult stuff, it SHOULD do inside that class.
Sep 17, 2021 16:55
So you will just say something like... and I will write this in C# style...
Sep 17, 2021 16:54
The spatial map should handle that side for you.
Sep 17, 2021 16:54
OK, not as such, no. You _may not need_ to do the morton ordering yourself.

Whatever spatial map implementation you choose, will have its own way of taking in the (x,y,z), e.g.

map(x,y,z)
OR
map(vector3)

etc.
Sep 17, 2021 16:48
Questions time :)
Sep 17, 2021 16:48
Now, you talk. Tell me how you see yourself doing this, or problems you may have with it. (assume we have already found the right spatial map from some GIS libary, and you are ready to start using it.)
Sep 17, 2021 16:47
So in other words, you know what the octree looks like, but now you need to push ALL its relevant vertices into the hash.

This is easy to do, because even if you (tried to) push a vertex in 2x, 4x or 8x at the same location, the spatial hash would only store one (the last one) that wash pushed in. You already know this is how `map`s work.
Sep 17, 2021 16:46
"before you begin" might simply mean "before you render, but after the game logic of the first frame of your game is run"
Sep 17, 2021 16:45
But what this approach implies is that you will need to pre-calculate ALL vertices of the entire octree before you begin - and store them, by (x,y,z) key - in that spatial hash.

OR, you can possibly also pre-allocate a large hash of a certain number of bytes / megabytes, and then you can change it as your game makes modifications to the terrain etc. Of course, this will have a cost compared to a smaller, statically-allocated spatial hash.
Sep 17, 2021 16:43
So for example, for 3 points / vertices

0,3,1
1,3,1
0,2,1

...will all be stored either in the same bucket, or buckets that are located very close together in RAM (and in L3 cache, and maybe in L2 cache, and possible in L1 cache).
Sep 17, 2021 16:42
What it will do is look at the spatial key (made from x,y,z) and IF that key is near to another key in the spatial sense, then it will put them in buckets that are stored CLOSE together.
Sep 17, 2021 16:41
A properly implemented spatial hash is implemented differently under the hood.
Sep 17, 2021 16:41
BUT...
Sep 17, 2021 16:41
If those are used as the KEY
Sep 17, 2021 16:41
It will do the same with j,k,l

or p,q,r

or x,y,z
Sep 17, 2021 16:40
a normal unordered_map like we use above, has an internal bucket system that will actively try to distribute a, b, c VERY far away from one another. It actually WANTS them distributed far apart, as this makes the map's performance better for most common tasks like, say, a phonebook.
Sep 17, 2021 16:39
So let me give you a simple example of this...
Sep 17, 2021 16:39
But in a spatial hash we are dealing with locations in space, and locality is very important to us (especially for collision detection), so our hash function will not change the distribution of the inputs."
Sep 17, 2021 16:39
"...for a normal hash table, a good hash function distributes keys as evenly as possible across the available buckets, in an effort to keep lookup time short. The result of this is that keys which are very close (lexicographically speaking) to each other, are likely to end up in distant buckets.
Sep 17, 2021 16:38
So let me just clarify that from the article which I linked in my answer...
Sep 17, 2021 16:38
This means the CPU cache has to keep refreshing during long sequential reads, AKA "cache miss"
Sep 17, 2021 16:37
Right. Access will be slow, because the buckets in which the vertices are stored, are not near to each other in memory.
Sep 17, 2021 16:36
Please - remain focused. Is this pattern familiar to you?
Sep 17, 2021 16:36
Is this pattern familiar to you so far?
Sep 17, 2021 16:35
`map[key] = vertex;`
...where those x,y,z used to create the key are `vertex.x` etc.
Sep 17, 2021 16:35
...or change the order as you see fit.
Sep 17, 2021 16:35
uint32 key = (z << 20) | (y << 10) | x;
Sep 17, 2021 16:34
We can create a key into a standard unordered_map like this (sorry, C++ is not my first language, I am more with C, C#, and JS these days).
Sep 17, 2021 16:34
This is something I sometimes do when I don't worry about memory use but NOT CPU cache performance.
Sep 17, 2021 16:33
OK let's start with a naive example of a spatial hash...
Sep 17, 2021 16:32
OK, let me know if / when you have further questions on the spatial hash structure.
Sep 17, 2021 16:30
So your choice:

1. Struggle to get that cache working with a totally new kind of data structure (octree)
2. Use what I suggest which can work with ANY spatial data structure (BSP tree, quadtree, octree, KD-tree, uniform grid...)

???
Sep 17, 2021 16:29
...unlikely that it will be, since I'm sure the Transvoxel guys knew what they were doing.
Sep 17, 2021 16:28
Even if you get the cache working, it may be sub-optimal in terms of your CPU cache - which is MUCH more important for performance.
Sep 17, 2021 16:27
OK - I don't - because I haven't worked with Transvoxel before. Maybe you can send me a screenshot - it would be interesting to see. But it's not important in terms of my answer that I wrote today.

Because this form of cache is not _necessary_. It is just one way to optimise the problem. Instead you can have a global spatial hash of all indices. This is how I do things in my projects.

Don't mistake me - the rolling cache is clever - but you are using a random-access octree now and it will be MUCH MUCH MUCH more difficult to make that rolling cache work with locales inside an octree.
Sep 17, 2021 16:25
Do you know how the cache looks if you were to highlight everything that it contains at a given time, and were to render that in 3D on your screen?
Sep 17, 2021 16:24
OK, do you know how that data access pattern looks, spatially speaking?
Sep 17, 2021 16:24
Right. So again - there is no global list or collection of ALL the vertices in the world / octree / uniform grid
Sep 17, 2021 16:22
Right?
Sep 17, 2021 16:22
The cache is having the values calculated into it, as we move forward during the algorithm. Next step, new values in the cache... etc. etc. etc.