1 #include <IO/VolumesLoader/VolumeLoader.hpp>
3 #include <IO/VolumesLoader/pvmutils.hpp>
5 #include <Core/Asset/FileData.hpp>
6 #include <Core/Geometry/Volume.hpp>
7 #include <Core/Utils/Log.hpp>
16 using namespace Ra::Core;
17 using namespace Ra::Core::Utils;
19 static const std::string volFileExtension {
"vol" };
20 static const std::string pvmFileExtension {
"pvm" };
22 VolumeLoader::VolumeLoader() =
default;
23 VolumeLoader::~VolumeLoader() =
default;
25 std::vector<std::string> VolumeLoader::getFileExtensions()
const {
26 return { {
"*." + volFileExtension }, {
"*." + pvmFileExtension } };
29 bool VolumeLoader::handleFileExtension(
const std::string& extension )
const {
30 return ( extension.compare( volFileExtension ) == 0 ) ||
31 ( extension.compare( pvmFileExtension ) == 0 );
37 input >> name >> beg >> r >> g >> b >> end;
42 bool checkExpected(
const std::string& expected,
const std::string& found ) {
43 if ( expected != found ) {
44 LOG( logWARNING ) <<
"\tVolumeLoader : unexpected volume attribute " << found <<
" : "
45 << expected <<
" was expected";
51 Ra::Core::Asset::FileData* VolumeLoader::loadVolFile(
const std::string& filename ) {
52 LOG( logINFO ) <<
"VolumeLoader : loading vol (pbrt based) file " << filename;
53 std::ifstream input( filename );
54 if ( input.is_open() ) {
55 auto fileData =
new Ra::Core::Asset::FileData( filename );
56 std::string attribname;
57 auto sigma_a = readColor( input, attribname );
58 if ( !checkExpected(
"sigma_a", attribname ) ) {
return nullptr; }
59 auto sigma_s = readColor( input, attribname );
60 if ( !checkExpected(
"sigma_s", attribname ) ) {
return nullptr; }
65 input >> attribname >> beg >> sx >> sy >> sz >> end;
66 if ( !checkExpected(
"size", attribname ) ) {
return nullptr; }
68 input >> attribname >> beg;
69 if ( !checkExpected(
"density", attribname ) ) {
return nullptr; }
71 LOG( logWARNING ) <<
"\tVolumeLoader : unexpected start of density gri delimiter "
75 LOG( logINFO ) <<
"\tVolumeLoader : reading a volume of size " << sx <<
"x" << sy <<
"x"
78 Ra::Core::Vector3 voxelSize { 1_ra, 1_ra, 1_ra };
80 density->setSize( Vector3i( sx, sy, sz ) );
81 density->setBinSize( voxelSize );
82 std::generate( density->data().begin(), density->data().end(), [&input]() {
90 LOG( logWARNING ) <<
"\tVolumeLoader : unexpected end of density grid delimiter "
94 LOG( logINFO ) <<
"\tVolumeLoader : done reading";
96 auto volume =
new Asset::VolumeData( filename.substr( filename.find_last_of(
'/' ) + 1 ) );
97 volume->volume = density;
98 volume->sigma_a = sigma_a;
99 volume->sigma_s = sigma_s;
100 Scalar maxDim = std::max( std::max( sx, sy ), sz );
101 Ra::Core::Vector3 p0( 0, 0, 0 );
102 Ra::Core::Vector3 p1( sx, sy, sz );
103 volume->boundingBox = Aabb( p0, p1 );
104 volume->densityToModel = Transform::Identity();
105 volume->modelToWorld = Eigen::Scaling( 1_ra / maxDim );
106 fileData->m_volumeData.push_back( std::unique_ptr<Ra::Core::Asset::VolumeData>( volume ) );
109 LOG( logWARNING ) <<
"VolumeLoader : unable to open file " << filename;
113 Ra::Core::Asset::FileData* VolumeLoader::loadPvmFile(
const std::string& filename ) {
114 using namespace PVMVolume;
116 unsigned int width, height, depth, bytePerVoxel;
117 float scalex, scaley, scalez;
118 unsigned char *description, *courtesy, *parameter, *comment;
120 auto volumeData = readPVMvolume( filename.c_str(),
134 unsigned char empty[1] {
'\0' };
135 LOG( logINFO ) <<
"VolumeLoader : \n\tpvm (The Volume Library) file " << filename
136 <<
" \n\twidth = " << width <<
" \n\theight = " << height
137 <<
" \n\tdepth = " << depth <<
" \n\tbyte per voxel = " << bytePerVoxel
138 <<
" \n\tscalex = " << scalex <<
" \n\tscaley = " << scaley
139 <<
" \n\tscalez = " << scalez
140 <<
" \n\tdescription = " << ( description ? description : empty )
141 <<
" \n\tcourtesy = " << ( courtesy ? courtesy : empty )
142 <<
" \n\tparameter = " << ( parameter ? parameter : empty )
143 <<
" \n\tcomment = " << ( comment ? comment : empty ) <<
'\n';
145 auto fillRadiumVolume = [](
auto container,
auto densityData ) {
146 std::generate( container->data().begin(), container->data().end(), [&densityData]() {
147 auto d = *densityData++;
148 return Scalar( d ) / Scalar( std::numeric_limits<decltype( d )>::max() );
151 Ra::Core::Vector3 binSize { Scalar( scalex ), Scalar( scaley ), Scalar( scalez ) };
152 Ra::Core::Vector3i gridSize { int( width ), int( height ), int( depth ) };
154 density->setSize( gridSize );
155 density->setBinSize( binSize );
157 switch ( bytePerVoxel ) {
159 fillRadiumVolume( density, volumeData );
163 fillRadiumVolume( density, (uint16_t*)( volumeData ) );
167 fillRadiumVolume( density, (uint*)( volumeData ) );
171 LOG( logERROR ) <<
"VolumeLoader : unsupported number of componenets : "
176 LOG( logINFO ) <<
"\tVolumeLoader : done reading";
178 auto volume =
new Asset::VolumeData( filename.substr( filename.find_last_of(
'/' ) + 1 ) );
179 volume->volume = density;
180 Scalar maxDim = std::max( std::max( width, height ), depth );
181 Ra::Core::Vector3 p0 = Vector3::Zero();
182 Ra::Core::Vector3 p1 = gridSize.cast<Scalar>().cwiseProduct( binSize );
183 volume->boundingBox = Aabb( p0, p1 );
184 volume->densityToModel = Eigen::Scaling( binSize );
185 volume->modelToWorld = Eigen::Scaling( 1_ra / maxDim ) * Translation( p1 * -0.5 );
187 auto fileData =
new Ra::Core::Asset::FileData( filename );
188 fileData->m_volumeData.push_back( std::unique_ptr<Ra::Core::Asset::VolumeData>( volume ) );
191 LOG( logWARNING ) <<
"VolumeLoader : unable to open file " << filename;
195 Ra::Core::Asset::FileData* VolumeLoader::loadFile(
const std::string& filename ) {
196 std::string extension = filename.substr( filename.find_last_of(
'.' ) + 1 );
197 if ( extension.compare( volFileExtension ) == 0 ) {
return loadVolFile( filename ); }
198 else if ( extension.compare( pvmFileExtension ) == 0 ) {
return loadPvmFile( filename ); }
199 LOG( logWARNING ) <<
"VolumeLoader : unsupported file format : " << filename;
203 std::string VolumeLoader::name()
const {
204 return "VolumeLoader (pbrt experimental, pvm)";
Discrete volume data storing values in a regular grid.