Hi, you're basically right about what's going on. I suggest we start with an example which does work and then go from there. Take a look at the BasicExample, and replace the CubicSurfaceExtractor with the Marching Cubes one:
Code:
//Create a surface extractor. Comment out one of the following two lines to decide which type gets created.
//CubicSurfaceExtractorWithNormals< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
MarchingCubesSurfaceExtractor< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
This will give you a jagged mesh as you have seen yourself, but but working with a simple 'uint8_t' voxel type. We can now use the LowPassFilter after we have generated the volume:
Code:
//Create an empty volume and then place a sphere in it
SimpleVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63)));
createSphereInVolume(volData, 30);
// Smooth
RawVolume<uint8_t> tempVolume(volData.getEnclosingRegion());
LowPassFilter< SimpleVolume<uint8_t>, RawVolume<uint8_t>, int16_t > pass1(&volData, PolyVox::Region(volData.getEnclosingRegion()), &tempVolume, PolyVox::Region(volData.getEnclosingRegion()), 3);
pass1.executeSAT();
LowPassFilter< RawVolume<uint8_t>, SimpleVolume<uint8_t>, int16_t > pass2(&tempVolume, PolyVox::Region(volData.getEnclosingRegion()), &volData, PolyVox::Region(volData.getEnclosingRegion()), 3);
pass2.executeSAT();
Note that you need a couple more headers:
Code:
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h"
#include "PolyVoxCore/LowPassFilter.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
#include "PolyVoxCore/RawVolume.h"
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/SimpleVolume.h"
I put the full code here for you:
http://pastebin.com/EShTTtBRThis should now give you a much smoother volume. It's important to note that another (probably better) approach is to generate smooth volume data in the first place, rather then generating jagged data and then smoothing it. In this example of generating a sphere you could set the voxel value to the inverse of it's distance from the center, rather than thresholding that distance and always writing 0 or 255. But sometimes the LowPassFilter is useful when you can't easily generate such smooth data.
Anyway, what goes wrong when we try to use MaterialDensityPair44? The basic problem is that there is no intuitive way to sum or average materials. If you have two materials identifiers such as 7 and 42, it does not make sense to compute the mathematical average. The resulting value may not be an integer, might not be a valid identifier, and will in no sense be the 'visual average' of the two input materials.
For this reason the MaterialDensityPair44 class does not define mathematical operators such as +, /, etc. You can see these are defined in the Density class (there may be more...):
Code:
// For densities we can supply mathematical operators which behave in an intuitive way.
// In particular the ability to add and subtract densities is important in order to
// apply an averaging filter. The ability to divide by an integer is also needed for
// this same purpose.
Density<Type>& operator+=(const Density<Type>& rhs)
{
m_uDensity += rhs.m_uDensity;
return *this;
}
Density<Type>& operator-=(const Density<Type>& rhs)
{
m_uDensity -= rhs.m_uDensity;
return *this;
}
Density<Type>& operator/=(uint32_t rhs)
{
m_uDensity /= rhs;
return *this;
}
You would need to implement these operators for the MaterialDensityPair44 class, and decide what they should do to material values (ignore them? take the max?). There might be others - my quick test indicated that the LowPassFilter assigns '0' at some point and expects an implicit conversion.
Anyway, I think overall you can see it's a conceptual problem rather than a PolyVox-specific one. But if you decide how it should behave then you should be able to implement the desired behaviour. Let me know if you have more questions about this.