🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Required to use multiple octrees for Transvoxels

Started by
7 comments, last by Gnollrunner 3 years, 6 months ago

I am working on an implementation of Transvoxels and I am wondering if it is required to use multiple octrees for sections with different LODs and then use the transition parts to connect different octrees together. I believe this is what Eric’s paper talks about but I haven’t seen any implementation actually do this. Thank you a head of time for any and all help.

Advertisement

darrenc182 said:
…if it is required to use multiple octrees…

i'm not sure i understand your statement here, but afaik local voxel data is required at the "seams" of your high-res and lo-res boundaries. Then it is this local voxel that u triangulate to create a transition between the 2 res (and ultimately fill any elevation holes);

like the yellow [submarine] trail in this vid

hope this clears it a bit for u ?

I see no reason multiple octrees should be required. I don't use transvoxel but I do use something like it. It works both between voxels in the same octree and between different octrees. The key point is the level of the voxel itself. There shouldn't be more than 1 level difference.

Thank you both for your replies. @ddlox is that video just showing the transition from one lod to another along the z axis? I’ve seen that video before and thought that it was showing that. @gnollrunner what approach are you using for transitioning between lods in your voxel implementation? Are you using marching cubes or something else?

@darrenc182 I'm using marching prisms which is basically the same thing but with prisms instead of cubes. For transition I use my own algorithm. What it does is drop a point in the middle of the voxel and tessellate out to the edges to form pyramids and tetrahedrons which can be solved more easily. The tricky part is to determine what tessellation is necessary. For this I generate what I call "saturation codes". This is a bit odd. Basically each corner of the voxel has a bit, kind of like the value bit that you use for marching cubes but it has a different purpose. There are half byte counters for each corner vertex, at each possible level. The corner count is incremented if a voxel that uses that corner has data in it at a given level (i.e. a sign change). It is decremented when that same voxel is subdivided. If the count is zero that corner is said to be saturated and the saturation bit for that subdivision level (which is kind of virtual) is treated as 1. Combining all 6 (or 8 for cubes) saturation bits gives us a saturation code for the voxel. This determines how it it tessellated for a given level transition.

I guess the main advantage is there are only 64 cases for prisms and 256 for cubes and that covers all odd cases in the corners and edges of LOD chunks. It also means we can tesselate a voxel without looking at any neighboring voxels. The information is passed via the saturation codes in shared voxel corners so voxels are still fairly independent . The final advantage is when we approach a chunk transition boundary, the voxel becomes normally subdivided, irrespective of the voxel octree layout and data. So if you had a cliff running along the edge of a chunk it wouldn't change the geometry at all when both chunks are at max resolution. This is important for me, because I have a separate physics engine which only generates geometry around the player and that engine doesn't need or have chunking. I want the physics engine to generate the exact same geometry as the graphics engine so there aren't any mismatch anomalies just because we happen to be near a chunk boundary.

In any case the way the saturation codes are used is as follows ……. When considering a level transition we look at chunk border voxels one level up the tree. We check the saturation code for it at that level. If an edge of a voxel is between two saturated corners that edge needs to be split. If all four edges of a face are split the face is also split normally, i.e. there is a vertex in the middle of the face and we have four squares, which create four pyramids. If all four faces are split normally, the voxel is subdivided normally. In other cases we are subdividing faces into triangles which gives us tetrahedrons when combined with the center point. I think there are some optimizations I can do here where I can eliminate the center point for many cases but I haven't got that far yet. But again for cubes there are only 256 cases. I believe for transvoxel there are 512 and that doesn't included the cases at edges and corners of chunks where you have multiple transition cells in the same voxel.

Sorry if this seems a bit confusing. I didn't write a paper on it. I just kind of designed it over a few iterations until I got everything the way I wanted it. There is some logic behind all this, but it's hard to explain without a lot of pictures and text.

One final advantage of this system is it supports change in data fields at different levels of LOD. The idea is so you can add details to terrain as you zoom in. One problem with voxels is that you might have an underground cave relatively close to the surface. It might be such that one voxel corner is in the cave, and the next one up is above the ground at some lower level of resolution. This would create a terrain anomaly that won't be fixed until you zoom in.

My solution is to only add the cave function as you zoom in so it doesn't mess up your terrain when you are looking at it from a distance. The tricky part is again the LOD transitions. A voxel corner on the boundary of a chunk can be both in and out at the same time. We can define it as the lower resolution, but we need a way to solve the voxel transition properly when doing so. The “satuation code” system supports that also since it takes data and LOD level into account when doing the transition.

darrenc182 said:
is that video just showing the transition from one lod to another along the z axis?

there's no way to tell from that video how axis are used, but what is clear and based on the direction of the terrain motion is that if you had a game character walking from the blue half-res mesh to the white hi-res area that is what the player would see or experience;

the yellow transvoxels would be in front of him and would join both areas and fill holes as the player approaches the white hi-res mesh…

that's about it ?

@darrenc182 Hi – The Transvoxel algorithm does not require that you use multiple octrees, and I only use one octree in my implementation. I think in any sensible design, the sizes of individual blocks in each lower LOD would be an integer multiple of the block size in the next higher LOD. For example, I use 16x16x16-voxel blocks for the highest LOD, and the lower LODs cover volumes of 32x32x32 voxels and 64x64x64 voxels. This sets up a natural octree hierarchy all by itself, and each block for each LOD applies Marching Cubes to 17x17x17 data points (because you count by twos in the middle LOD and by fours in the lowest LOD).

Having the lower LODs cover more physical volume than the higher LODs they contain can be a little problematic for some engines, and I've been considering changing my implementation so that each LOD covers the same volume. GPUs can handle much larger triangle meshes now than they could when I first came up with Transvoxel. I'm going to try out something like 64x64x64 for the highest LOD (or maybe double that), and then use the 32x32x32 and 16x16x16 subsets of the same volume for the lower LODs. This has the nice property that the set of transition cells on one face of a lower-LOD block only interact with one higher-LOD block, where in my current implementation, it's four higher-LOD blocks.

Eric Lengyel said:

Having the lower LODs cover more physical volume than the higher LODs they contain can be a little problematic for some engines, and I've been considering changing my implementation so that each LOD covers the same volume.

In my experience that has negative effects for planetary scale stuff. The problem is if you zoom out, like say you are in orbit, you end up with a lot of tiny chunks with only a few triangles in them. The number of CPU calls to the GPU tends to kill your performance in that case. I think you need some sort of chunk resizing to keep things sane.

This topic is closed to new replies.

Advertisement