Hi all, with the first release of Cubiquity finally out of the door I'm now going to get back to PolyVox for a few weeks. Cubiquity is providing a great use-case to see what needs to change in PolyVox, and it's time to apply what we've learned. Many of these changes will break backwards compatibility so I'll use this thread to discuss what is changing and why.
Also, please note that there will be quite some disruption with class/function names changing, etc. You might want to hold off updating if you don't want to endure this instability. But we'll try and keep the examples compiling so you have something to work from.
The list below is just an initial taster - I'll keep posting here as other things change. Better volume and multi-threading is still planned but the refactoring below will happen first.
CubicSurfaceExtractorWithNormals is goneThis class was always a temporary measure as it generally makes more sense to compute the 'cubic' mesh normals in the fragment shader rather than having them stored per-vertex. This lets you perform flat-shading without storing any normals at all, which also avoids duplicating vertices on cube corners. The only reason we hadn't done this previously is that our examples didn't use shaders, but Matt has recently fixed that (at least for the example which matters).
CubicSurfaceExtractor does still exist though it is now a free-function (see next point). You should use this instead of CubicSurfaceExtractorWithNormals and compute the normals in the fragment shader.
Unclassing surface extractors.Previously all PolyVox surface extractors were classes, e.g. MarchingCubesSurfaceExtractor and CubicSurfaceExtractor, but these have been replaced by free functions called 'extractCubicMesh()' and 'extractMarchingCubesMesh()'. There was no need for them to be classes, and having free functions makes the code much simpler especially when combined with C+11 'auto' keyword. The example code used to look like this:
Code:
SurfaceMesh<PositionMaterial> mesh;
CubicSurfaceExtractor< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
surfaceExtractor.execute();
But now it is:
Code:
auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion());
Note that the code is shorter, and more importantly you don't need to specify any types. The voxel type can be inferred from the function parameters (in C++ this is not possible with classes) and the complex return type is obtained through auto.
Currently the free functions are actually just wrappers around the classes, but that will probably change in the future.
Vertex types are now templatised on VoxelTypePolyVox used to represent it's vertices with the awkwardly-named 'PositionMaterial' and 'PositionMaterialNormal' classes. These are now gone and replaced with new 'CubicVertex' and 'MarchingCubesVertex' classes. More importantly, the new classes are templatised on the voxel type, though the new use of the 'auto' keyword (as mentioned above) should limit the complexity which comes from this.
Users can store essentially any data they wish with a voxel, and so previously it was not clear how the 'material' should be represented, or even if it was present at all. Many users use an integer ID to represent a material, but at east on older GPU hardware it's only possible to pass floats as vertex attributes. Also, how should such material IDs be interpolated? It was all a bit messy.
The new system templatises the vertex types on the voxel type. So if you have a volume of floats then the MarchingCubesVertex will contain a position, normal, and a float. If you have a more complex voxel type then the MarchingCubesVertex will contain a position, a normal, and your more complex type. Note that you still need to define how you types will be interpolated because Marching Cubes vertices will always end up between particular voxel positions.
What you actually do with the voxel type in your vertex is entirely up to you. You can pass all or part of it to your shader, or cast the type to something different as you wish. PolyVox just takes care of pulling the voxel values out of the volume, interpolating them, and putting them in the mesh.