store imported geometry more compactly

metadata
Wenzel Jakob 2010-11-15 20:51:31 +01:00
parent 5452a0d30b
commit 02d6129df9
10 changed files with 177 additions and 67 deletions

View File

@ -31,36 +31,38 @@ class AbstractAnimationTrack {
public:
enum EType {
EInvalid = 0,
ELocationX, ELocationY, ELocationZ,
EScaleX, EScaleY, EScaleZ,
ELocationX, ELocationY, ELocationZ, ELocationXYZ,
EScaleX, EScaleY, EScaleZ, EScaleXYZ,
ERotationX, ERotationY, ERotationZ,
ERotationQuat
};
/// Return the type of this track
inline EType getType() const { return m_type; }
protected:
AbstractAnimationTrack(EType type) : m_type(type) { }
protected:
EType m_type;
};
/// Parameterizable animation track
template <typename T> class AnimationTrack : public AbstractAnimationTrack {
public:
AnimationTrack(EType type, size_t nKeyframes)
: AbstractAnimationTrack(type),
m_times(nKeyframes), m_values(nKeyframes) { }
/// Return the number of keyframes
inline size_t getSize() const { return m_times.size(); }
/// Set the time value of a certain keyframe
inline void setTime(size_t idx, Float time) { m_times[idx] = time; }
/// Return the time value of a certain keyframe
inline Float getTime(size_t idx) const { return m_times[idx]; }
/// Return the number of keyframes
inline size_t getSize() const { return m_times.size(); }
protected:
AbstractAnimationTrack(EType type, size_t nKeyframes)
: m_type(type), m_times(nKeyframes) { }
protected:
EType m_type;
std::vector<Float> m_times;
};
/// Parameterizable animation track
template <typename T> class AnimationTrack : public AbstractAnimationTrack {
public:
AnimationTrack(EType type, size_t nKeyframes)
: AbstractAnimationTrack(type, nKeyframes), m_values(nKeyframes) { }
/// Set the value of a certain keyframe
inline void setValue(size_t idx, const T &value) { m_values[idx] = value; }
@ -72,7 +74,6 @@ public:
inline T lookup(Float time) const {
}
private:
std::vector<Float> m_times;
std::vector<T> m_values;
};

View File

@ -62,9 +62,11 @@ public:
* Unserialize a triangle mesh - this is an alternative
* routine, which only loads triangle data (no BSDF,
* Sub-surface integrator, etc.) in a format that
* will remain stable as Mitsuba evolves.
* will remain stable as Mitsuba evolves. The files
* can optionally contain multiple meshes -- in that case,
* the specified index determines which one to load.
*/
TriMesh(Stream *stream);
TriMesh(Stream *stream, int idx = 0);
/// Return the name of this mesh
virtual std::string getName() const;

View File

@ -44,6 +44,8 @@
typedef AnimationTrack<Float> FloatTrack;
typedef AnimationTrack<Quaternion> QuatTrack;
typedef AnimationTrack<Vector> VectorTrack;
typedef AnimationTrack<Point> PointTrack;
typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, int> RefCountMap;
typedef std::multimap<std::string, AbstractAnimationTrack *> AnimationMap;
@ -456,11 +458,20 @@ void writeGeometry(ColladaContext &ctx, const std::string &prefixName, std::stri
}
id += formatString("_%i", geomIndex);
std::string filename = id + std::string(".serialized");
ref<FileStream> stream = new FileStream(ctx.meshesDirectory / filename, FileStream::ETruncReadWrite);
stream->setByteOrder(Stream::ELittleEndian);
mesh->serialize(stream);
stream->close();
std::string filename;
if (!ctx.cvt->m_geometryFile) {
filename = id + std::string(".serialized");
ref<FileStream> stream = new FileStream(ctx.meshesDirectory / filename, FileStream::ETruncReadWrite);
stream->setByteOrder(Stream::ELittleEndian);
mesh->serialize(stream);
stream->close();
filename = "meshes/" + filename;
} else {
ctx.cvt->m_geometryDict.push_back(ctx.cvt->m_geometryFile->getPos());
mesh->serialize(ctx.cvt->m_geometryFile);
filename = ctx.cvt->m_geometryFileName.filename();
}
std::ostringstream matrix;
for (int i=0; i<4; ++i)
@ -470,7 +481,9 @@ void writeGeometry(ColladaContext &ctx, const std::string &prefixName, std::stri
if (!exportShapeGroup) {
ctx.os << "\t<shape id=\"" << id << "\" type=\"serialized\">" << endl;
ctx.os << "\t\t<string name=\"filename\" value=\"meshes/" << filename << "\"/>" << endl;
ctx.os << "\t\t<string name=\"filename\" value=\"" << filename << "\"/>" << endl;
if (ctx.cvt->m_geometryFile)
ctx.os << "\t\t<integer name=\"shapeIndex\" value=\"" << (ctx.cvt->m_geometryDict.size() - 1) << "\"/>" << endl;
if (!transform.isIdentity()) {
ctx.os << "\t\t<transform name=\"toWorld\">" << endl;
ctx.os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
@ -481,7 +494,9 @@ void writeGeometry(ColladaContext &ctx, const std::string &prefixName, std::stri
ctx.os << "\t</shape>" << endl << endl;
} else {
ctx.os << "\t\t<shape type=\"serialized\">" << endl;
ctx.os << "\t\t\t<string name=\"filename\" value=\"meshes/" << filename << "\"/>" << endl;
ctx.os << "\t\t\t<string name=\"filename\" value=\"" << filename << "\"/>" << endl;
if (ctx.cvt->m_geometryFile)
ctx.os << "\t\t<integer name=\"shapeIndex\" value=\"" << (ctx.cvt->m_geometryDict.size() - 1)<< "\"/>" << endl;
if (matID != "")
ctx.os << "\t\t\t<ref name=\"bsdf\" id=\"" << matID << "\"/>" << endl;
ctx.os << "\t\t</shape>" << endl << endl;
@ -743,8 +758,7 @@ void loadMaterial(ColladaContext &ctx, domMaterial &mat) {
identifier = formatString("unnamedMat_%i", unnamedCtr++);
}
}
StringMap idToTexture = ctx.idToTexture;
daeURI &effRef = mat.getInstance_effect()->getUrl();
effRef.resolveElement();
domEffect *effect = daeSafeCast<domEffect>(effRef.getElement());
@ -773,16 +787,16 @@ void loadMaterial(ColladaContext &ctx, domMaterial &mat) {
= surface->getFx_surface_init_common()->getInit_from_array();
SAssert(initFromArray.getCount() == 1);
std::string id = initFromArray[0]->getValue().getID();
if (idToTexture.find(id) == idToTexture.end())
if (ctx.idToTexture.find(id) == ctx.idToTexture.end())
SLog(EError, "Referenced bitmap '%s' not found!", id.c_str());
idToTexture[newParam->getSid()] = idToTexture[id];
ctx.idToTexture[newParam->getSid()] = ctx.idToTexture[id];
}
if (sampler2D) {
std::string id = sampler2D->getSource()->getValue();
if (idToTexture.find(id) == idToTexture.end())
if (ctx.idToTexture.find(id) == ctx.idToTexture.end())
SLog(EError, "Referenced surface '%s' not found!", id.c_str());
idToTexture[newParam->getSid()] = idToTexture[id];
ctx.idToTexture[newParam->getSid()] = ctx.idToTexture[id];
}
}
@ -1314,7 +1328,7 @@ void loadAnimation(ColladaContext &ctx, domAnimation &anim) {
for (size_t i=0; i<channels.getCount(); ++i) {
domChannel *channel = channels[i];
std::vector<std::string> target = tokenize(channel->getTarget(), "./");
SAssertEx(target.size() == 3, "Encountered an unknown animation channel identifier!");
SAssert(target.size() >= 2);
daeURI &sourceRef = channel->getSource();
sourceRef.resolveElement();
@ -1322,12 +1336,15 @@ void loadAnimation(ColladaContext &ctx, domAnimation &anim) {
if (!sampler)
SLog(EError, "Referenced animation sampler not found!");
const domInputLocal_Array &inputs = sampler->getInput_array();
FloatTrack *track = NULL;
FloatTrack::EType trackType = FloatTrack::EInvalid;
AbstractAnimationTrack *track = NULL;
AbstractAnimationTrack::EType trackType = AbstractAnimationTrack::EInvalid;
boost::to_lower(target[1]);
boost::to_lower(target[2]);
if (target[1] == "location") {
if (target[2] == "x") {
if (target.size() > 2)
boost::to_lower(target[2]);
if (target[1] == "location" || target[1] == "translate") {
if (target.size() == 2) {
trackType = PointTrack::ELocationXYZ;
} else if (target[2] == "x") {
trackType = FloatTrack::ELocationX;
} else if (target[2] == "y") {
trackType = FloatTrack::ELocationY;
@ -1335,24 +1352,26 @@ void loadAnimation(ColladaContext &ctx, domAnimation &anim) {
trackType = FloatTrack::ELocationZ;
}
} else if (target[1] == "scale") {
if (target[2] == "x") {
if (target.size() == 2) {
trackType = VectorTrack::EScaleXYZ;
} else if (target[2] == "x") {
trackType = FloatTrack::EScaleX;
} else if (target[2] == "y") {
trackType = FloatTrack::EScaleY;
} else if (target[3] == "z") {
trackType = FloatTrack::EScaleZ;
}
} else if (target[1] == "rotationx" && target[2] == "angle") {
} else if ((target[1] == "rotationx" || target[1] == "rotatex") && target.size() == 3 && target[2] == "angle") {
trackType = FloatTrack::ERotationX;
} else if (target[1] == "rotationy" && target[2] == "angle") {
} else if ((target[1] == "rotationy" || target[1] == "rotatey") && target.size() == 3 && target[2] == "angle") {
trackType = FloatTrack::ERotationY;
} else if (target[1] == "rotationz" && target[2] == "angle") {
} else if ((target[1] == "rotationz" || target[1] == "rotatez") && target.size() == 3 && target[2] == "angle") {
trackType = FloatTrack::ERotationZ;
}
if (trackType == FloatTrack::EInvalid) {
SLog(EWarn, "Skipping unsupported animation track of type %s.%s",
target[1].c_str(), target[2].c_str());
target[1].c_str(), target.size() > 2 ? target[2].c_str() : "");
continue;
}
@ -1369,27 +1388,44 @@ void loadAnimation(ColladaContext &ctx, domAnimation &anim) {
domAccessor *accessor = techniqueCommon->getAccessor();
if (!accessor)
SLog(EError, "Data source does not have a <accessor> tag!");
unsigned int nParams = (unsigned int) accessor->getParam_array().getCount(),
stride = (unsigned int) accessor->getStride();
unsigned int stride = (unsigned int) accessor->getStride();
size_t size = (size_t) accessor->getCount();
if (stride != 1 || nParams != 1) {
/// Only single-valued tracks are supported for now
SLog(EError, "Encountered a multi-valued animation track.");
}
if (!track)
track = new FloatTrack(trackType, size);
else
if (!track) {
if (trackType == VectorTrack::EScaleXYZ)
track = new VectorTrack(trackType, size);
else if (trackType == PointTrack::ELocationXYZ)
track = new PointTrack(trackType, size);
else
track = new FloatTrack(trackType, size);
} else {
SAssert(track->getSize() == size);
}
if (semantic == "INPUT") {
domListOfFloats &floatArray = source->getFloat_array()->getValue();
for (size_t i=0; i<size; ++i)
SAssert(stride == 1);
for (size_t i=0; i<size; ++i)
track->setTime(i, floatArray[i]);
} else if (semantic == "OUTPUT") {
domListOfFloats &floatArray = source->getFloat_array()->getValue();
for (size_t i=0; i<size; ++i)
track->setValue(i, floatArray[i]);
if (trackType == PointTrack::ELocationXYZ) {
SAssert(stride == 3);
for (size_t i=0; i<size; ++i)
((PointTrack *) track)->setValue(i,
Point(floatArray[i*3+0], floatArray[i*3+1],
floatArray[i*3+2]));
} else if (trackType == PointTrack::EScaleXYZ) {
SAssert(stride == 3);
for (size_t i=0; i<size; ++i)
((VectorTrack *) track)->setValue(i,
Vector(floatArray[i*3+0], floatArray[i*3+1],
floatArray[i*3+2]));
} else {
SAssert(stride == 1);
for (size_t i=0; i<size; ++i)
((FloatTrack *) track)->setValue(i, floatArray[i]);
}
} else if (semantic == "INTERPOLATION") {
/// Ignored for now
} else {

View File

@ -30,6 +30,7 @@
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <mitsuba/core/fresolver.h>
#include <mitsuba/core/fstream.h>
#include <boost/algorithm/string.hpp>
#include <sys/stat.h>
#include <sys/types.h>
@ -139,6 +140,13 @@ void GeometryConverter::convert(const fs::path &inputFile,
outputFile = outputDirectory / sceneName;
}
if (m_packGeometry) {
m_geometryFileName = outputDirectory / sceneName;
m_geometryFileName.replace_extension(".serialized");
m_geometryFile = new FileStream(m_geometryFileName, FileStream::ETruncReadWrite);
m_geometryFile->setByteOrder(Stream::ELittleEndian);
}
if (!fs::exists(textureDirectory)) {
SLog(EInfo, "Creating directory \"%s\" ..", textureDirectory.file_string().c_str());
fs::create_directory(textureDirectory);
@ -237,6 +245,13 @@ void GeometryConverter::convert(const fs::path &inputFile,
ofile << os.str();
ofile.close();
}
if (m_geometryFile) {
for (size_t i=0; i<m_geometryDict.size(); ++i)
m_geometryFile->writeUInt(m_geometryDict[i]);
m_geometryFile->writeUInt((uint32_t) m_geometryDict.size());
m_geometryFile->close();
}
m_filename = outputFile;
}

View File

@ -29,6 +29,7 @@ public:
m_samplesPerPixel = 8;
m_fov = -1;
m_filmType = "exrfilm";
m_packGeometry = true;
}
void convert(const fs::path &inputFile,
@ -42,6 +43,7 @@ public:
inline void setMapSmallerSide(bool mapSmallerSide) { m_mapSmallerSide = mapSmallerSide; }
inline void setResolution(int xres, int yres) { m_xres = xres; m_yres = yres; }
inline void setSamplesPerPixel(int samplesPerPixel) { m_samplesPerPixel = samplesPerPixel; }
inline void setPackGeometry(bool packGeometry) { m_packGeometry = packGeometry; }
inline void setFov(Float fov) { m_fov = fov; }
inline void setFilmType(const std::string &filmType) { m_filmType = filmType; }
inline const fs::path &getFilename() const { return m_filename; }
@ -58,4 +60,8 @@ public:
Float m_fov;
fs::path m_filename;
std::string m_filmType;
ref<FileStream> m_geometryFile;
fs::path m_geometryFileName;
std::vector<uint32_t> m_geometryDict;
bool m_packGeometry;
};

View File

@ -57,6 +57,7 @@ void help() {
<< " -p <num> Use the specified number of samples per pixel." << endl << endl
<< " -s Assume that colors are in sRGB space." << endl << endl
<< " -m Map the larger image side to the full field of view" << endl << endl
<< " -y Don't pack all geometry data into a single file" << endl << endl
<< " -l <type> Override the type of film (e.g. 'exrfilm', 'pngfilm', ..)" << endl << endl
<< " -r <w>x<h> Override the image resolution to e.g. 1920x1080" << endl << endl
<< " -f <fov> Override the field of view to the given value in degrees." << endl << endl
@ -72,10 +73,11 @@ int colladaMain(int argc, char **argv) {
Float fov = -1;
FileResolver *fileResolver = Thread::getThread()->getFileResolver();
ELogLevel logLevel = EInfo;
bool packGeometry = true;
optind = 1;
while ((optchar = getopt(argc, argv, "svhmr:a:p:f:l:")) != -1) {
while ((optchar = getopt(argc, argv, "svyhmr:a:p:f:l:")) != -1) {
switch (optchar) {
case 'a': {
std::vector<std::string> paths = tokenize(optarg, ";");
@ -100,6 +102,9 @@ int colladaMain(int argc, char **argv) {
case 'l':
filmType = optarg;
break;
case 'y':
packGeometry = false;
break;
case 'f':
fov = (Float) strtod(optarg, &end_ptr);
if (*end_ptr != '\0')
@ -138,6 +143,7 @@ int colladaMain(int argc, char **argv) {
converter.setMapSmallerSide(mapSmallerSide);
converter.setSamplesPerPixel(samplesPerPixel);
converter.setFov(fov);
converter.setPackGeometry(packGeometry);
converter.setFilmType(filmType);
const Logger *logger = Thread::getThread()->getLogger();

View File

@ -182,14 +182,24 @@ void GeometryConverter::convertOBJ(const fs::path &inputFile,
TriMesh *mesh = static_cast<TriMesh *>(rootShape->getElement(ctr++));
if (!mesh)
break;
std::string filename = mesh->getName() + std::string(".serialized");
SLog(EInfo, "Saving \"%s\"", filename.c_str());
ref<FileStream> stream = new FileStream(meshesDirectory / filename, FileStream::ETruncReadWrite);
stream->setByteOrder(Stream::ELittleEndian);
mesh->serialize(stream);
stream->close();
os << "\t<shape id=\"" << mesh->getName() << "\" type=\"serialized\">" << endl;
os << "\t\t<string name=\"filename\" value=\"meshes/" << filename.c_str() << "\"/>" << endl;
if (!m_geometryFile) {
std::string filename = mesh->getName() + std::string(".serialized");
SLog(EInfo, "Saving \"%s\"", filename.c_str());
ref<FileStream> stream = new FileStream(meshesDirectory / filename, FileStream::ETruncReadWrite);
stream->setByteOrder(Stream::ELittleEndian);
mesh->serialize(stream);
stream->close();
os << "\t\t<string name=\"filename\" value=\"meshes/" << filename.c_str() << "\"/>" << endl;
} else {
m_geometryDict.push_back(m_geometryFile->getPos());
SLog(EInfo, "Saving mesh \"%s\"", mesh->getName().c_str());
mesh->serialize(m_geometryFile);
os << "\t\t<string name=\"filename\" value=\"" << m_geometryFileName.filename() << "\"/>" << endl;
os << "\t\t<integername=\"shapeIndex\" value=\"" << (m_geometryDict.size()-1) << "\"/>" << endl;
}
if (mesh->getBSDF() != NULL &&
mtlList.find(mesh->getBSDF()->getName()) != mtlList.end()) {
const std::string &matID = mesh->getBSDF()->getName();

View File

@ -151,9 +151,25 @@ static void readHelper(Stream *stream, bool fileDoublePrecision,
}
}
TriMesh::TriMesh(Stream *_stream) : Shape(Properties()), m_tangents(NULL) {
TriMesh::TriMesh(Stream *_stream, int index)
: Shape(Properties()), m_tangents(NULL) {
ref<Stream> stream = _stream;
if (index != 0) {
/* Determine the position of the requested substream. This
is stored at the end of the file */
stream->setPos(stream->getSize() - sizeof(uint32_t));
uint32_t count = stream->readUInt();
if (index < 0 || index > (int) count) {
Log(EError, "Unable to unserialize mesh, "
"shape index is out of range! (requested %i out of 0..%i)",
index, count-1);
}
stream->setPos(stream->getSize() - sizeof(uint32_t) * (1+count-index));
// Seek to the correct position
stream->setPos(stream->readUInt());
}
if (stream->getByteOrder() != Stream::ELittleEndian)
Log(EError, "Tried to unserialize a shape from a stream, "
"which was not previously set to little endian byte order!");

View File

@ -35,13 +35,16 @@ public:
/* Object-space -> World-space transformation */
Transform objectToWorld = props.getTransform("toWorld", Transform());
/// When the file contains multiple meshes, this index specifies which one to load
int shapeIndex = props.getInteger("shapeIndex", 0);
m_name = filePath.stem();
/* Load the geometry */
Log(EInfo, "Loading geometry from \"%s\" ..", filePath.leaf().c_str());
ref<FileStream> stream = new FileStream(filePath, FileStream::EReadOnly);
stream->setByteOrder(Stream::ELittleEndian);
ref<TriMesh> mesh = new TriMesh(stream);
ref<TriMesh> mesh = new TriMesh(stream, shapeIndex);
m_triangleCount = mesh->getTriangleCount();
m_vertexCount = mesh->getVertexCount();

View File

@ -184,6 +184,21 @@ public:
*flData++ = 1.0f;
}
}
} else if (bitmap->getBitsPerPixel() == 1) {
int pos = 0;
for (int y=0; y<bitmap->getHeight(); ++y) {
for (int x=0; x<bitmap->getWidth(); ++x) {
int entry = pos / 8;
int bit = pos % 8;
int value = (data[entry] & (1 << bit)) ? 255 : 0;
float col = tbl[value];
*flData++ = col;
*flData++ = col;
*flData++ = col;
*flData++ = 1.0f;
pos++;
}
}
} else {
Log(EError, "%i bpp images are currently not supported!", bitmap->getBitsPerPixel());
}