We finally started porting the core of the voxel viewer to the GPU using OpenCL. This is our first debug build after a few hours playing around with it. We don’t fully rasterize the mesh yet nor do we have any textures like we do in the CPU version. And yes there is noise but hey, we’ve just started ;)
Here’s a more interactive video, it shows the model being scaled through voxelspace.
Together with a friend of mine ( Quinten Lansu ) I started a new project which will also be part of an assignment in our GPU programming course. Our idea is to create modelviewer which doesn’t show meshes the normal way but convert it to voxels on the GPU or CPU ( depending on the settings ) in realtime.
The idea of it being realtime is that voxels do not have an orientation that changes. They are always unit cubes which are aligned on the axis. When you rotate your model you do not want to rotate your voxels but rather rotate your model through the voxels ‘space’ and generate new ones on the fly. Of course if you just fly around with a camera this isn’t an issue, you can generate the voxels once. This is also a way of doing it, we are implementing a dynamic and static rendering routine. The dynamic one rasterizes the loaded mesh in realtime to a pointcloud which are turned into voxels. The static one generates the pointcloud once and keeps this rendering, you can fly around with the camera but not move the model in any way because its static.
Our first problem was actually getting some voxels on the screen. Because they were cubes we would need to send 8 points the the GPU which was not exactly fast for 1 million voxels. We went for a different approach, we generate a pointcloud which are always a unit space apart ( In our case 1 unit, this is the size of 1 voxel ). We then send the pointcloud to the GPU and generate cubes with them using a geometry shader. What the shader does it receive the point and wrap a triangle strip around the point and creating a cube this way.This is what our first tries looked like:
Really simpel pointcloud and a standard red color which we forced in the fragment shader. Our next step was to actually generate a pointcloud from a sphere.
To do this we had to rasterize the triangle in 3D rather than 2D which is the normal routine enforced by GPU’s. In 3D it is still the normal approach like in 2D, you create spanlines for your triangles by walking over the Y between vertices, every step you save the start and the end of the line creating a span of the triangle. Just simple interpolation. In 3D it has a bit of a twist, you will have to do it per axis. Named the “Dominant Axis” and the “Submissive Axis” by Quinten. Basically you rasterize per axis and in the end merge these together. With a little fiddling we got to this:
We were pretty happy but one big problem was overlapping voxels. We had a lot of them unfortunately. We decided to tackle this problem at a later time because right now performance wasn’t our big concern, getting it to actually work was the main concern.
We went onto coloring the voxels. What we had to do when rasterizing just like with a triangle was to interpolate the U and V of the triangle and put this into the Voxel and implement it in the shader to make it use the color. This is what our first attempts looked like:
The UV’s were a bit off but we were getting there. After we worked out the interpolation a bit better we got to this:
We added some extra features like scaling the model which would give the whole thing more detail ( and more Voxels which in turn caused it to have more detail. )
The thing is that when you have a small model and a set unit size for the voxels it will mean that if your model is small and the voxels, in comparison, really big it will look like a low resolution version of the ship. Hard to explain in words so here’s a screenshot:
So as you can see there’s more detail every step, this shows scale 1 2 4 8 and 10. As you can see it really improves on the overall detail of the model.
Our next and old problem was performance, this was all done on the CPU on a single core and we want to port it to the GPU when we were done and be able to switch between it in runtime so the difference in performance on the CPU and GPU would be noticeable. We were still dealing with the problem of having voxels at the same position when rasterizing the different axis. We decided to build a Octree to see if this would fix the issue. Our first tries weren’t so good:
It did fix our issue but it wasn’t optimal, the working version (props to Quinten for coding this in an hour or so ) would take up one gigabyte of RAM when building a tree for the ship model. Not good! It didn’t help our performance for the dynamic one at all, the performance went down. The static version did gain performance because the tree was only needed one tick, one rendertick was done for the static version so this was quite fast and we didn’t have voxels existing at the same spot. Right now it looks like this with the voxels using the Octree, we also added some extra features like drag and drop of models when loading and some rendering options. I’ll might post a build of it next week, if we feel like its worthy of a public build.
We have decided to ditch the Octree because of the RAM usage plus it wasn’t really giving us the performance we wanted. We are working on a perfect spacial hashing algorithm which will tackle the same problem but do it in a less RAM costly way and not have such a bad performance at runtime. I’ll write a new entry when we’ve improved on the current version, I was a bit behind on this project thats why the post is so long. I’ll explain the 3D rasterization in detail in my next entry.
Untill next time!
Here’s the latest version of the NDP, still a POC and far from finished. Project has been put aside until we have more time. Read the readme.txt to see how to get it up and running.