From 0953ceaba3630a8e4bf0c5f8666e140e2a1ea20d Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 12 Aug 2010 20:01:08 +0200 Subject: [PATCH] better COLLADA import from Blender, improvements to the import dialog --- SConstruct | 3 +- src/collada/converter.cpp | 904 ++++++++++++++++++ src/collada/converter.h | 15 + src/collada/main.cpp | 858 +---------------- src/integrators/photonmapper/photonmapper.cpp | 2 +- src/qtgui/importdlg.cpp | 77 +- src/qtgui/importdlg.h | 7 + src/qtgui/importdlg.ui | 53 +- src/qtgui/resources/docs.xml | 2 +- 9 files changed, 1035 insertions(+), 886 deletions(-) create mode 100644 src/collada/converter.cpp create mode 100644 src/collada/converter.h diff --git a/SConstruct b/SConstruct index 0f3d821e..df1051eb 100644 --- a/SConstruct +++ b/SConstruct @@ -408,7 +408,8 @@ if hasCollada: colladaEnv.Append(LIBPATH=env['COLLADALIBDIR']) if env.has_key('COLLADALIB'): colladaEnv.Append(LIBS=env['COLLADALIB']) - colladaEnv.Program('mtsimport', darwinStub + ['src/collada/main.cpp']) + colladaConverter = colladaEnv.StaticObject('src/collada/converter.cpp') + colladaEnv.Program('mtsimport', darwinStub + ['src/collada/main.cpp', colladaConverter]) if hasQt: qtEnv = mainEnv.Clone() diff --git a/src/collada/converter.cpp b/src/collada/converter.cpp new file mode 100644 index 00000000..79cbf993 --- /dev/null +++ b/src/collada/converter.cpp @@ -0,0 +1,904 @@ +#define BOOST_FILESYSTEM_NO_LIB +#define BOOST_SYSTEM_NO_LIB + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__OSX__) +#include +#else +#include +#endif + +#include "converter.h" + +typedef std::map StringMap; + +enum ESourceType { + EPosition = 0, + ENormal = 1, + EUV = 2, + EVertexColors = 3, + ELast +}; + +struct Vec4 { + Float x, y, z, w; + + inline Vec4(Float x=0, Float y=0, Float z=0, Float w=0) + : x(x), y(y), z(z), w(w) { + } + + inline Float operator[](int i) const { + return (&x)[i]; + } + + inline Float &operator[](int i) { + return (&x)[i]; + } + + inline Point toPoint() const { + return Point(x, y, z); + } + + inline Normal toNormal() const { + return Normal(x, y, z); + } + + inline Point2 toPoint2() const { + return Point2(x, y); + } +}; + +struct VertexData { + size_t nSources; + bool hasNormals; + bool hasUVs; + GLdouble *glPos; + std::vector data; + std::vector offsetToType; + std::vector typeToOffset; + + VertexData() : glPos(NULL) { + } + + virtual ~VertexData() { + for (size_t i=0; i tess_data; +size_t tess_nSources; + +VertexData *fetchVertexData(Transform transform, std::ostream &os, + const domInputLocal_Array &vertInputs, + const domInputLocalOffset_Array &inputs) { + VertexData *result = new VertexData(); + + result->hasNormals = false; + result->hasUVs = false; + result->nSources = inputs.getCount(); + result->data.resize(inputs.getCount()); + for (size_t i=0; idata[i] = NULL; + result->offsetToType.resize(inputs.getCount()); + result->typeToOffset.resize(ELast); + for (int i=0; itypeToOffset[i] = -1; + + for (size_t i=0; igetOffset(); + daeURI &sourceRef = inputs[i]->getSource(); + sourceRef.resolveElement(); + domSource *source = daeSafeCast(sourceRef.getElement()); + + if (!strcmp(inputs[i]->getSemantic(), "VERTEX")) { + SAssert(vertInputs.getCount() == 1); + sourceRef = vertInputs[0]->getSource(); + sourceRef.resolveElement(); + source = daeSafeCast(sourceRef.getElement()); + } + + domListOfFloats &floatArray = source->getFloat_array()->getValue(); + domSource::domTechnique_common *techniqueCommon = source->getTechnique_common(); + if (!techniqueCommon) + SLog(EError, "Data source does not have a tag!"); + domAccessor *accessor = techniqueCommon->getAccessor(); + if (!accessor) + SLog(EError, "Data source does not have a tag!"); + int nParams = (int) accessor->getParam_array().getCount(), + stride = (int) accessor->getStride(), + size = (int) accessor->getCount(); + SAssert(nParams <= 4); + + Vec4 *target = new Vec4[size]; + for (int j=0; jdata[offset] = target; + + if (!strcmp(inputs[i]->getSemantic(), "VERTEX")) { + SAssert(accessor->getStride() == 3); + SAssert(result->typeToOffset[EPosition] == -1); + result->offsetToType[offset] = EPosition; + result->typeToOffset[EPosition] = offset; + result->glPos = new GLdouble[3*size]; + for (int k=0; k<3*size; ++k) + result->glPos[k] = floatArray[k]; + } else if (!strcmp(inputs[i]->getSemantic(), "NORMAL")) { + SAssert(accessor->getStride() == 3); + SAssert(result->typeToOffset[ENormal] == -1); + result->hasNormals = true; + result->offsetToType[offset] = ENormal; + result->typeToOffset[ENormal] = offset; + } else if (!strcmp(inputs[i]->getSemantic(), "TEXCOORD")) { + SAssert(accessor->getStride() == 2 || accessor->getStride() == 3); + if (result->typeToOffset[EUV] == -1) { + result->hasUVs = true; + result->offsetToType[offset] = EUV; + result->typeToOffset[EUV] = offset; + } else { + SLog(EWarn, "Found multiple texture coordinate records - ignoring!"); + } + } else if (!strcmp(inputs[i]->getSemantic(), "COLOR")) { + SLog(EWarn, "Found per-vertex colors - ignoring. Please bake into a texture (Lighting/shading -> Batch Bake in Maya)"); + result->offsetToType[offset] = EVertexColors; + result->typeToOffset[EVertexColors] = offset; + } else { + SLog(EError, "Encountered an unknown source semantic: %s", + inputs[i]->getSemantic()); + } + } + SAssert(result->typeToOffset[EPosition] != -1); + + return result; +} + +/// For using vertices as keys in an associative structure +struct vertex_key_order : public + std::binary_function { +public: + bool operator()(const Vertex &v1, const Vertex &v2) const { + if (v1.v.x < v2.v.x) return true; + else if (v1.v.x > v2.v.x) return false; + if (v1.v.y < v2.v.y) return true; + else if (v1.v.y > v2.v.y) return false; + if (v1.v.z < v2.v.z) return true; + else if (v1.v.z > v2.v.z) return false; + if (v1.n.x < v2.n.x) return true; + else if (v1.n.x > v2.n.x) return false; + if (v1.n.y < v2.n.y) return true; + else if (v1.n.y > v2.n.y) return false; + if (v1.n.z < v2.n.z) return true; + else if (v1.n.z > v2.n.z) return false; + if (v1.uv.x < v2.uv.x) return true; + else if (v1.uv.x > v2.uv.x) return false; + if (v1.uv.y < v2.uv.y) return true; + else if (v1.uv.y > v2.uv.y) return false; + return false; + } +}; + +void writeGeometry(std::string id, int geomIndex, std::string matID, Transform transform, std::ostream &os, VertexData *vData) { + std::vector vertexBuffer; + std::vector triangles; + std::map vertexMap; + size_t numMerged = 0, triangleIdx = 0; + Triangle triangle; + + id += formatString("_%i", geomIndex); + + for (size_t i=0; itypeToOffset[EPosition]]; + vertex.v = vData->data[vData->typeToOffset[EPosition]][posRef].toPoint(); + + if (vData->typeToOffset[ENormal] != -1) { + domUint normalRef = tess_data[i+vData->typeToOffset[ENormal]]; + vertex.n = vData->data[vData->typeToOffset[ENormal]][normalRef].toNormal(); + } + + if (vData->typeToOffset[EUV] != -1) { + domUint uvRef = tess_data[i+vData->typeToOffset[EUV]]; + vertex.uv = vData->data[vData->typeToOffset[EUV]][uvRef].toPoint2(); + } + + int key = -1; + if (vertexMap.find(vertex) != vertexMap.end()) { + key = vertexMap[vertex]; + numMerged++; + } else { + key = (int) vertexBuffer.size(); + vertexMap[vertex] = (int) key; + vertexBuffer.push_back(vertex); + } + triangle.idx[triangleIdx++] = key; + if (triangleIdx == 3) { + triangles.push_back(triangle); + triangleIdx = 0; + } + } + + SAssert(triangleIdx == 0); + SLog(EInfo, "%s: Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT + " vertices (merged " SIZE_T_FMT " vertices).", id.c_str(), + triangles.size(), vertexBuffer.size(), numMerged); + + ref mesh = new TriMesh(triangles.size(), vertexBuffer.size()); + std::copy(triangles.begin(), triangles.end(), mesh->getTriangles()); + std::copy(vertexBuffer.begin(), vertexBuffer.end(), mesh->getVertexBuffer()); + mesh->calculateTangentSpaceBasis(vData->typeToOffset[ENormal]!=-1, vData->typeToOffset[EUV]!=-1); + + std::string filename = formatString("meshes/%s.serialized", id.c_str()); + ref stream = new FileStream(filename, FileStream::ETruncReadWrite); + stream->setByteOrder(Stream::ENetworkByteOrder); + mesh->serialize(stream); + stream->close(); + + std::ostringstream matrix; + for (int i=0; i<4; ++i) + for (int j=0; j<4; ++j) + matrix << transform.getMatrix()->m[i][j] << " "; + std::string matrixValues = matrix.str(); + + os << "\t" << endl; + os << "\t\t" << endl; + if (!transform.isIdentity()) { + os << "\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t" << endl; + } + if (matID != "") + os << "\t\t" << endl; + os << "\t" << endl << endl; +} + +void loadGeometry(std::string nodeName, Transform transform, std::ostream &os, domGeometry &geom, + StringMap &matLookupTable) { + SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", geom.getName(), nodeName.c_str()); + + domMesh *mesh = geom.getMesh().cast(); + if (!mesh) + SLog(EError, "Invalid geometry type encountered (must be a )!"); + + const domInputLocal_Array &vertInputs = mesh->getVertices()->getInput_array(); + + std::string xmlName = nodeName + std::string("_") + geom.getId(); + int geomIndex = 0; + + domTriangles_Array &trianglesArray = mesh->getTriangles_array(); + for (size_t i=0; igetInput_array(); + VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); + domListOfUInts &indices = triangles->getP()->getValue(); + tess_data.clear(); + tess_nSources = data->nSources; + for (size_t j=0; jgetMaterial() == NULL || matLookupTable.find(triangles->getMaterial()) == matLookupTable.end()) + SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); + else + matID = matLookupTable[triangles->getMaterial()]; + writeGeometry(xmlName, geomIndex, matID, transform, os, data); + delete data; + ++geomIndex; + } + + domPolygons_Array &polygonsArray = mesh->getPolygons_array(); + for (size_t i=0; igetInput_array(); + VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); + domP_Array &indexArray = polygons->getP_array(); + int posOffset = data->typeToOffset[EPosition]; + + tess_data.clear(); + tess_nSources = data->nSources; + for (size_t j=0; jgetValue(); + domUint *temp = new domUint[indices.getCount()]; + for (size_t l = 0; lnSources) + gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp)); + + gluTessEndContour(tess); + gluTessEndPolygon(tess); + delete[] temp; + } + + std::string matID; + if (polygons->getMaterial() == NULL || matLookupTable.find(polygons->getMaterial()) == matLookupTable.end()) + SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); + else + matID = matLookupTable[polygons->getMaterial()]; + + writeGeometry(xmlName, geomIndex, matID, transform, os, data); + delete data; + ++geomIndex; + } + + domPolylist_Array &polylistArray = mesh->getPolylist_array(); + for (size_t i=0; igetInput_array(); + VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); + domListOfUInts &vcount = polylist->getVcount()->getValue(); + domListOfUInts &indexArray = polylist->getP()->getValue(); + int posOffset = data->typeToOffset[EPosition], indexOffset = 0; + tess_data.clear(); + tess_nSources = data->nSources; + + for (size_t j=0; jnSources]; + for (size_t l = 0; lnSources; ++l) + temp[l] = indexArray.get(indexOffset++); + + gluTessBeginPolygon(tess, NULL); + gluTessBeginContour(tess); + + for (size_t k=0; knSources; k+=data->nSources) + gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp)); + + gluTessEndContour(tess); + gluTessEndPolygon(tess); + delete[] temp; + } + + std::string matID; + if (polylist->getMaterial() == NULL || matLookupTable.find(polylist->getMaterial()) == matLookupTable.end()) + SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); + else + matID = polylist->getMaterial(); + + writeGeometry(xmlName, geomIndex, matID, transform, os, data); + delete data; + ++geomIndex; + } +} + +void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &idToTexture, + domCommon_color_or_texture_type *value, bool handleRefs) { + if (!value) + return; + domCommon_color_or_texture_type_complexType::domColor* color = + value->getColor().cast(); + domCommon_color_or_texture_type_complexType::domTexture* texture = + value->getTexture().cast(); + if (color && !handleRefs) { + domFloat4 &colValue = color->getValue(); + os << "\t\t" << endl; + } else if (texture && handleRefs) { + if (idToTexture.find(texture->getTexture()) == idToTexture.end()) { + SLog(EError, "Could not find referenced texture \"%s\"", texture->getTexture()); + } else { + os << "\t\tgetTexture()] << "\"/>" << endl; + } + } +} + +void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &, + domCommon_float_or_param_type *value, bool handleRef) { + if (!value) + return; + domCommon_float_or_param_type::domFloat *floatValue = value->getFloat(); + if (!handleRef && floatValue) { + os << "\t\tgetValue() << "\"/>" << endl; + } +} + +void loadMaterial(std::ostream &os, domMaterial &mat, StringMap &_idToTexture) { + SLog(EInfo, "Converting material \"%s\" ..", mat.getName()); + StringMap idToTexture = _idToTexture; + + daeURI &effRef = mat.getInstance_effect()->getUrl(); + effRef.resolveElement(); + domEffect *effect = daeSafeCast(effRef.getElement()); + + if (!effect) + SLog(EError, "Referenced effect not found!"); + + domProfile_COMMON *commonProfile = daeSafeCast + (effect->getDescendant("profile_COMMON")); + + if (!commonProfile) + SLog(EError, "Common effect profile not found!"); + + /* The following supports a subset of the curious ColladaFX output + produced by the Blender COLLADA exporter */ + daeTArray > &newParamArray = commonProfile->getNewparam_array(); + for (size_t i=0; igetSurface(); + domFx_sampler2D_common *sampler2D = newParam->getSampler2D(); + + + if (surface) { + SAssert(surface->getType() == FX_SURFACE_TYPE_ENUM_2D); + daeTArray > &initFromArray + = 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()) + SLog(EError, "Referenced bitmap '%s' not found!", id.c_str()); + idToTexture[newParam->getSid()] = idToTexture[id]; + } + + if (sampler2D) { + std::string id = sampler2D->getSource()->getValue(); + if (idToTexture.find(id) == idToTexture.end()) + SLog(EError, "Referenced surface '%s' not found!", id.c_str()); + idToTexture[newParam->getSid()] = idToTexture[id]; + } + } + + domProfile_COMMON::domTechnique *technique = commonProfile->getTechnique(); + + if (!technique) + SLog(EError, "The technique element is missing!"); + + domProfile_COMMON::domTechnique::domPhong* phong = technique->getPhong(); + domProfile_COMMON::domTechnique::domLambert* lambert = technique->getLambert(); + + if (phong) { + domCommon_color_or_texture_type* diffuse = phong->getDiffuse(); + domCommon_color_or_texture_type* specular = phong->getSpecular(); + domCommon_float_or_param_type* shininess = phong->getShininess(); + bool isDiffuse = false; + + if (specular->getColor().cast()) { + domFloat4 &colValue = specular->getColor()->getValue(); + if (colValue.get(0) == colValue.get(1) && + colValue.get(1) == colValue.get(2) && + colValue.get(2) == 0) + isDiffuse = true; + } + if (isDiffuse) { + os << "\t" << endl; + loadMaterialParam(os, "reflectance", idToTexture, diffuse, false); + loadMaterialParam(os, "reflectance", idToTexture, diffuse, true); + os << "\t" << endl << endl; + } else { + os << "\t" << endl; + loadMaterialParam(os, "diffuseReflectance", idToTexture, diffuse, false); + loadMaterialParam(os, "specularReflectance", idToTexture, specular, false); + loadMaterialParam(os, "exponent", idToTexture, shininess, false); + loadMaterialParam(os, "diffuseReflectance", idToTexture, diffuse, true); + loadMaterialParam(os, "specularReflectance", idToTexture, specular, true); + loadMaterialParam(os, "exponent", idToTexture, shininess, true); + os << "\t" << endl << endl; + } + } else if (lambert) { + domCommon_color_or_texture_type* diffuse = lambert->getDiffuse(); + os << "\t" << endl; + loadMaterialParam(os, "reflectance", idToTexture, diffuse, false); + loadMaterialParam(os, "reflectance", idToTexture, diffuse, true); + os << "\t" << endl << endl; + } else { + SLog(EError, "Material type not supported! (must be Lambertian/Phong)"); + } +} + +void loadLight(Transform transform, std::ostream &os, domLight &light) { + SLog(EInfo, "Converting light \"%s\" ..", light.getName()); + char *end_ptr = NULL; + + // Lights in Mitsuba point along the positive Z axis (COLLADA: neg. Z) + transform = transform * Transform::scale(Vector(1, 1, -1)); + + Point pos = transform(Point(0, 0, 0)); + Vector target = transform(Point(0, 0, 1)); + + Float intensity = 1; + const domTechnique_Array &techniques = light.getTechnique_array(); + for (size_t i=0; igetChild("intensity"); + if (intensityElement && intensityElement->hasCharData()) { + std::string charData = intensityElement->getCharData(); + intensity = (Float) strtod(charData.c_str(), &end_ptr); + if (*end_ptr != '\0') + SLog(EError, "Could not parse the light intensity!"); + } + } + + domLight::domTechnique_common::domPoint *point = light.getTechnique_common()->getPoint().cast(); + if (point) { + domFloat3 &color = point->getColor()->getValue(); + os << "\t" << endl; + os << "\t\t" << endl << endl; + os << "\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t" << endl; + os << "\t" << endl << endl; + } + domLight::domTechnique_common::domSpot *spot = light.getTechnique_common()->getSpot().cast(); + if (spot) { + domFloat3 &color = spot->getColor()->getValue(); + Float falloffAngle = 180.0f; + if (spot->getFalloff_angle()) + falloffAngle = (Float) spot->getFalloff_angle()->getValue(); + os << "\t" << endl; + os << "\t\t" << endl; + os << "\t\t" << endl << endl; + os << "\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t" << endl; + os << "\t" << endl << endl; + } + domLight::domTechnique_common::domAmbient *ambient = light.getTechnique_common()->getAmbient().cast(); + if (ambient) { + domFloat3 &color = ambient->getColor()->getValue(); + os << "\t" << endl; + os << "\t\t" << endl; + os << "\t" << endl << endl; + } + if (!point && !spot && !ambient) + SLog(EWarn, "Encountered an unknown light type!"); +} + +void loadImage(ColladaConverter *cvt, std::ostream &os, domImage &image, StringMap &idToTexture, StringMap &fileToId) { + SLog(EInfo, "Converting texture \"%s\" ..", image.getName()); + + std::string filename = cdom::uriToFilePath(image.getInit_from()->getValue().str()); + if (fileToId.find(filename) != fileToId.end()) { + idToTexture[image.getId()] = fileToId[filename]; + return; + } + + idToTexture[image.getId()] = image.getId(); + fileToId[filename] = image.getId(); + + boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native); + std::string leaf = path.leaf(); + + if (endsWith(leaf, ".rgb")) + SLog(EWarn, "Maya RGB images must be converted to PNG, EXR or JPEG! The 'imgcvt' " + "utility found in the Maya binary directory can be used to do this."); + + if (!FileStream::exists(filename)) { + if (!FileStream::exists(leaf)) { + SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), leaf.c_str()); + filename = cvt->locateResource(filename); + if (filename == "") + SLog(EError, "Unable to locate a resource -- aborting conversion."); + } else { + filename = leaf; + } + } + + ref input = new FileStream(filename, FileStream::EReadOnly); + ref output = new FileStream(formatString("textures/%s", leaf.c_str()), FileStream::ETruncReadWrite); + input->copyTo(output); + + os << "\t" << endl; + os << "\t\t" << endl; + os << "\t" << endl << endl; +} + +void loadCamera(Transform transform, std::ostream &os, domCamera &camera) { + SLog(EInfo, "Converting camera \"%s\" ..", camera.getName()); + Float aspect = 1.0f; + int xres=768; + + // Cameras in Mitsuba point along the positive Z axis (COLLADA: neg. Z) + transform = transform * Transform::scale(Vector(1,1,-1)); + + std::ostringstream matrix; + for (int i=0; i<4; ++i) + for (int j=0; j<4; ++j) + matrix << transform.getMatrix()->m[i][j] << " "; + std::string matrixValues = matrix.str(); + + domCamera::domOptics::domTechnique_common::domOrthographic* ortho = camera.getOptics()-> + getTechnique_common()->getOrthographic().cast(); + if (ortho) { + if (ortho->getAspect_ratio().cast() != 0) + aspect = (Float) ortho->getAspect_ratio()->getValue(); + os << "\t" << endl; + } + + domCamera::domOptics::domTechnique_common::domPerspective* persp = camera.getOptics()-> + getTechnique_common()->getPerspective().cast(); + if (persp) { + if (persp->getAspect_ratio().cast() != 0) + aspect = (Float) persp->getAspect_ratio()->getValue(); + os << "\t" << endl; + if (persp->getXfov().cast()) { + Float yFov = radToDeg(2 * std::atan(std::tan(degToRad((Float) persp->getXfov()->getValue())/2) / aspect)); + if (aspect <= 1.0f) + os << "\t\tgetXfov()->getValue() << "\"/>" << endl; + else + os << "\t\t" << endl; + os << "\t\tgetZnear()->getValue() << "\"/>" << endl; + os << "\t\tgetZfar()->getValue() << "\"/>" << endl; + } else if (persp->getYfov().cast()) { + Float xFov = radToDeg(2 * std::atan(std::tan(degToRad((Float) persp->getYfov()->getValue())/2) * aspect)); + if (aspect > 1.0f) + os << "\t\tgetYfov()->getValue() << "\"/>" << endl; + else + os << "\t\t" << endl; + os << "\t\tgetZnear()->getValue() << "\"/>" << endl; + os << "\t\tgetZfar()->getValue() << "\"/>" << endl; + } + } + + os << endl; + os << "\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t" << endl << endl; + + os << "\t\t" << endl << endl; + os << "\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t\t" << endl; + os << "\t\t" << endl; + os << "\t" << endl << endl; +} + +void loadNode(Transform transform, std::ostream &os, domNode &node) { + SLog(EInfo, "Converting node \"%s\" ..", node.getName()); + + daeTArray > children = node.getChildren(); + /* Parse transformations */ + for (size_t i=0; itypeID() == domRotate::ID()) { + /* Skip rotations labeled as "post-rotationY". Maya exports these with some cameras, + which introduces an incorrect 90 degree rotation unless ignored */ + if (element->hasAttribute("sid") && element->getAttribute("sid") == "post-rotationY") + continue; + daeTArray value = daeSafeCast(element)->getValue(); + transform = transform * + Transform::rotate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), (Float) value.get(3)); + } else if (element->typeID() == domTranslate::ID()) { + daeTArray value = daeSafeCast(element)->getValue(); + transform = transform * + Transform::translate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2))); + } else if (element->typeID() == domScale::ID()) { + daeTArray value = daeSafeCast(element)->getValue(); + transform = transform * + Transform::scale(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2))); + } else if (element->typeID() == domLookat::ID()) { + daeTArray value = daeSafeCast(element)->getValue(); + transform = transform * + Transform::lookAt( + Point((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), + Point((Float) value.get(3), (Float) value.get(4), (Float) value.get(5)), + Vector((Float) value.get(6), (Float) value.get(7), (Float) value.get(8)) + ); + } + } + + /* Iterate over all geometry references */ + domInstance_geometry_Array &instanceGeometries = node.getInstance_geometry_array(); + for (size_t i=0; i(inst->getUrl().getElement()); + domBind_material *bmat = inst->getBind_material(); + StringMap matLookupTable; + if (bmat) { + domBind_material::domTechnique_common *technique = bmat->getTechnique_common(); + if (!technique) + SLog(EError, "bind_material does not contain a element!"); + domInstance_material_Array &instMaterials = technique->getInstance_material_array(); + + for (size_t i=0; igetTarget(); + matRef.resolveElement(); + domMaterial *material = daeSafeCast(matRef.getElement()); + matLookupTable[instMat->getSymbol()] = material->getId(); + } + } else { + SLog(EWarn, "instance_geometry does not contain a element!"); + } + + if (!geom) + SLog(EError, "Could not find a referenced geometry object!"); + loadGeometry(node.getName(), transform, os, *geom, matLookupTable); + } + + /* Iterate over all light references */ + domInstance_light_Array &instanceLights = node.getInstance_light_array(); + for (size_t i=0; i(inst->getUrl().getElement()); + if (!light) + SLog(EError, "Could not find a referenced light!"); + loadLight(transform, os, *light); + } + + /* Iterate over all camera references */ + domInstance_camera_Array &instanceCameras = node.getInstance_camera_array(); + for (size_t i=0; i(inst->getUrl().getElement()); + if (camera == NULL) + SLog(EError, "Could not find a referenced camera!"); + loadCamera(transform, os, *camera); + } + + /* Recursively iterate through sub-nodes */ + domNode_Array &nodes = node.getNode_array(); + for (size_t i=0; i elements */ + domInstance_node_Array &instanceNodes = node.getInstance_node_array(); + for (size_t i=0; i(instanceNodes[i]->getUrl().getElement()); + if (!node) + SLog(EError, "Could not find a referenced node!"); + loadNode(transform, os, *node); + } +} + +#ifndef WIN32 +#define __stdcall +#endif + +GLvoid __stdcall tessBegin(GLenum type) { + SAssert(type == GL_TRIANGLES); +} + +GLvoid __stdcall tessVertex(void *data) { + const domUint *raw = (domUint *) data; + for (size_t i=0; iresolveAbsolute(inputFile); +#else + std::string path = inputFile; +#endif + + DAE *dae = new DAE(); + SLog(EInfo, "Loading \"%s\" ..", path.c_str()); + if (dae->load(path.c_str()) != DAE_OK) + SLog(EError, "Could not load \"%s\"!", path.c_str()); + + std::ostringstream os; + + domCOLLADA *document = dae->getDom(path.c_str()); + domVisual_scene *visualScene = daeSafeCast + (document->getDescendant("visual_scene")); + if (!visualScene) + SLog(EError, "Could not find a visual_scene!"); + + /* Configure the GLU tesselator */ + tess = gluNewTess(); + if (!tess) + SLog(EError, "Could not allocate a GLU tesselator!"); + + std::string textureDirectory = "textures"; + std::string meshesDirectory = "meshes"; + std::string outputFile = sceneName; +#ifndef WIN32 + if (outputDirectory != "") { + textureDirectory = outputDirectory + "/textures"; + meshesDirectory = outputDirectory + "/meshes"; + outputFile = outputDirectory + std::string("/") + sceneName; + } + + int status = mkdir(textureDirectory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (status != 0 && errno != EEXIST) + SLog(EError, "Could not create the directory \"textures\""); + status = mkdir(meshesDirectory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (status != 0 && errno != EEXIST) + SLog(EError, "Could not create the directory \"meshes\""); +#else + if (outputDirectory != "") { + textureDirectory = textureDirectory + "\\textures"; + meshesDirectory = meshesDirectory + "\\meshes"; + outputFile = outputDirectory + std::string("\\") + sceneName; + } + + int status = CreateDirectory(textureDirectory.c_str(), NULL); + if (status == 0 && GetLastError() != ERROR_ALREADY_EXISTS) + SLog(EError, "Could not create the directory \"textures\""); + status = CreateDirectory(meshesDirectory.c_str(), NULL); + if (status == 0 && GetLastError() != ERROR_ALREADY_EXISTS) + SLog(EError, "Could not create the directory \"meshes\""); +#endif + + gluTessCallback(tess, GLU_TESS_VERTEX, reinterpret_cast(&tessVertex)); + gluTessCallback(tess, GLU_TESS_BEGIN, reinterpret_cast(&tessBegin)); + gluTessCallback(tess, GLU_TESS_END, reinterpret_cast(&tessEnd)); + gluTessCallback(tess, GLU_TESS_ERROR, reinterpret_cast(&tessError)); + gluTessCallback(tess, GLU_TESS_COMBINE, reinterpret_cast(&tessCombine)); + gluTessCallback(tess, GLU_TESS_EDGE_FLAG, reinterpret_cast(&tessEdgeFlag)); + + domNode_Array &nodes = visualScene->getNode_array(); + os << "" << endl << endl; + os << "" << endl << endl; + os << "" << endl; + os << "\t" << endl << endl; + + SLog(EInfo, "Converting to \"%s\" ..", outputFile.c_str()); + + StringMap idToTexture, fileToId; + domLibrary_images_Array &libraryImages = document->getLibrary_images_array(); + for (size_t i=0; igetImage_array(); + for (size_t j=0; jgetLibrary_materials_array(); + for (size_t i=0; igetMaterial_array(); + for (size_t j=0; j" << endl; + + gluDeleteTess(tess); + delete dae; + + std::ofstream ofile(outputFile.c_str()); + if (ofile.fail()) + SLog(EError, "Could not write to \"%s\"!", outputFile.c_str()); + ofile << os.str(); + ofile.close(); +} + diff --git a/src/collada/converter.h b/src/collada/converter.h new file mode 100644 index 00000000..c53db038 --- /dev/null +++ b/src/collada/converter.h @@ -0,0 +1,15 @@ +#include + +using namespace mitsuba; + +class ColladaConverter { +public: + inline ColladaConverter() { } + + void convert(const std::string &inputFile, + const std::string &outputDirectory, + const std::string &sceneName, + const std::string &adjustmentFile); + + virtual std::string locateResource(const std::string &resource) = 0; +}; diff --git a/src/collada/main.cpp b/src/collada/main.cpp index e5c4f8cc..bd3ea3e0 100644 --- a/src/collada/main.cpp +++ b/src/collada/main.cpp @@ -29,855 +29,30 @@ * (e.g. using Lighting/shading -> Batch bake in Maya). */ -#define BOOST_FILESYSTEM_NO_LIB -#define BOOST_SYSTEM_NO_LIB - -#include -#include +#include "converter.h" #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__OSX__) -#include -#else -#include -#endif - -using namespace mitsuba; - -typedef std::map StringMap; - -enum ESourceType { - EPosition = 0, - ENormal = 1, - EUV = 2, - EVertexColors = 3, - ELast -}; - -struct Vec4 { - Float x, y, z, w; - - inline Vec4(Float x=0, Float y=0, Float z=0, Float w=0) - : x(x), y(y), z(z), w(w) { - } - - inline Float operator[](int i) const { - return (&x)[i]; - } - - inline Float &operator[](int i) { - return (&x)[i]; - } - - inline Point toPoint() const { - return Point(x, y, z); - } - - inline Normal toNormal() const { - return Normal(x, y, z); - } - - inline Point2 toPoint2() const { - return Point2(x, y); - } -}; - - -struct VertexData { - size_t nSources; - bool hasNormals; - bool hasUVs; - GLdouble *glPos; - std::vector data; - std::vector offsetToType; - std::vector typeToOffset; - - VertexData() : glPos(NULL) { - } - - virtual ~VertexData() { - for (size_t i=0; i tess_data; -size_t tess_nSources; - -VertexData *fetchVertexData(Transform transform, std::ostream &os, - const domInputLocal_Array &vertInputs, - const domInputLocalOffset_Array &inputs) { - VertexData *result = new VertexData(); - - result->hasNormals = false; - result->hasUVs = false; - result->nSources = inputs.getCount(); - result->data.resize(inputs.getCount()); - for (size_t i=0; idata[i] = NULL; - result->offsetToType.resize(inputs.getCount()); - result->typeToOffset.resize(ELast); - for (int i=0; itypeToOffset[i] = -1; - - for (size_t i=0; igetOffset(); - daeURI &sourceRef = inputs[i]->getSource(); - sourceRef.resolveElement(); - domSource *source = daeSafeCast(sourceRef.getElement()); - - if (!strcmp(inputs[i]->getSemantic(), "VERTEX")) { - SAssert(vertInputs.getCount() == 1); - sourceRef = vertInputs[0]->getSource(); - sourceRef.resolveElement(); - source = daeSafeCast(sourceRef.getElement()); - } - - domListOfFloats &floatArray = source->getFloat_array()->getValue(); - domSource::domTechnique_common *techniqueCommon = source->getTechnique_common(); - if (!techniqueCommon) - SLog(EError, "Data source does not have a tag!"); - domAccessor *accessor = techniqueCommon->getAccessor(); - if (!accessor) - SLog(EError, "Data source does not have a tag!"); - int nParams = (int) accessor->getParam_array().getCount(), - stride = (int) accessor->getStride(), - size = (int) accessor->getCount(); - SAssert(nParams <= 4); - - Vec4 *target = new Vec4[size]; - for (int j=0; jdata[offset] = target; - - if (!strcmp(inputs[i]->getSemantic(), "VERTEX")) { - SAssert(accessor->getStride() == 3); - SAssert(result->typeToOffset[EPosition] == -1); - result->offsetToType[offset] = EPosition; - result->typeToOffset[EPosition] = offset; - result->glPos = new GLdouble[3*size]; - for (int k=0; k<3*size; ++k) - result->glPos[k] = floatArray[k]; - } else if (!strcmp(inputs[i]->getSemantic(), "NORMAL")) { - SAssert(accessor->getStride() == 3); - SAssert(result->typeToOffset[ENormal] == -1); - result->hasNormals = true; - result->offsetToType[offset] = ENormal; - result->typeToOffset[ENormal] = offset; - } else if (!strcmp(inputs[i]->getSemantic(), "TEXCOORD")) { - SAssert(accessor->getStride() == 2 || accessor->getStride() == 3); - if (result->typeToOffset[EUV] == -1) { - result->hasUVs = true; - result->offsetToType[offset] = EUV; - result->typeToOffset[EUV] = offset; - } else { - SLog(EWarn, "Found multiple texture coordinate records - ignoring!"); - } - } else if (!strcmp(inputs[i]->getSemantic(), "COLOR")) { - SLog(EWarn, "Found per-vertex colors - ignoring. Please bake into a texture (Lighting/shading -> Batch Bake in Maya)"); - result->offsetToType[offset] = EVertexColors; - result->typeToOffset[EVertexColors] = offset; - } else { - SLog(EError, "Encountered an unknown source semantic: %s", - inputs[i]->getSemantic()); - } - } - SAssert(result->typeToOffset[EPosition] != -1); - - return result; -} - -/// For using vertices as keys in an associative structure -struct vertex_key_order : public - std::binary_function { +class ConsoleColladaConverter : public ColladaConverter { public: - bool operator()(const Vertex &v1, const Vertex &v2) const { - if (v1.v.x < v2.v.x) return true; - else if (v1.v.x > v2.v.x) return false; - if (v1.v.y < v2.v.y) return true; - else if (v1.v.y > v2.v.y) return false; - if (v1.v.z < v2.v.z) return true; - else if (v1.v.z > v2.v.z) return false; - if (v1.n.x < v2.n.x) return true; - else if (v1.n.x > v2.n.x) return false; - if (v1.n.y < v2.n.y) return true; - else if (v1.n.y > v2.n.y) return false; - if (v1.n.z < v2.n.z) return true; - else if (v1.n.z > v2.n.z) return false; - if (v1.uv.x < v2.uv.x) return true; - else if (v1.uv.x > v2.uv.x) return false; - if (v1.uv.y < v2.uv.y) return true; - else if (v1.uv.y > v2.uv.y) return false; - return false; + inline ConsoleColladaConverter() { + } + + std::string locateResource(const std::string &resource) { + return ""; } }; -void writeGeometry(std::string id, int geomIndex, std::string matID, Transform transform, std::ostream &os, VertexData *vData) { - std::vector vertexBuffer; - std::vector triangles; - std::map vertexMap; - size_t numMerged = 0, triangleIdx = 0; - Triangle triangle; - - id += formatString("_%i", geomIndex); - - for (size_t i=0; itypeToOffset[EPosition]]; - vertex.v = vData->data[vData->typeToOffset[EPosition]][posRef].toPoint(); - - if (vData->typeToOffset[ENormal] != -1) { - domUint normalRef = tess_data[i+vData->typeToOffset[ENormal]]; - vertex.n = vData->data[vData->typeToOffset[ENormal]][normalRef].toNormal(); - } - - if (vData->typeToOffset[EUV] != -1) { - domUint uvRef = tess_data[i+vData->typeToOffset[EUV]]; - vertex.uv = vData->data[vData->typeToOffset[EUV]][uvRef].toPoint2(); - } - - int key = -1; - if (vertexMap.find(vertex) != vertexMap.end()) { - key = vertexMap[vertex]; - numMerged++; - } else { - key = (int) vertexBuffer.size(); - vertexMap[vertex] = (int) key; - vertexBuffer.push_back(vertex); - } - triangle.idx[triangleIdx++] = key; - if (triangleIdx == 3) { - triangles.push_back(triangle); - triangleIdx = 0; - } - } - - SAssert(triangleIdx == 0); - SLog(EInfo, "%s: Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT - " vertices (merged " SIZE_T_FMT " vertices).", id.c_str(), - triangles.size(), vertexBuffer.size(), numMerged); - - ref mesh = new TriMesh(triangles.size(), vertexBuffer.size()); - std::copy(triangles.begin(), triangles.end(), mesh->getTriangles()); - std::copy(vertexBuffer.begin(), vertexBuffer.end(), mesh->getVertexBuffer()); - mesh->calculateTangentSpaceBasis(vData->typeToOffset[ENormal]!=-1, vData->typeToOffset[EUV]!=-1); - - std::string filename = formatString("meshes/%s.serialized", id.c_str()); - ref stream = new FileStream(filename, FileStream::ETruncReadWrite); - stream->setByteOrder(Stream::ENetworkByteOrder); - mesh->serialize(stream); - stream->close(); - - std::ostringstream matrix; - for (int i=0; i<4; ++i) - for (int j=0; j<4; ++j) - matrix << transform.getMatrix()->m[i][j] << " "; - std::string matrixValues = matrix.str(); - - os << "\t" << endl; - os << "\t\t" << endl; - if (!transform.isIdentity()) { - os << "\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t" << endl; - } - if (matID != "") - os << "\t\t" << endl; - os << "\t" << endl << endl; -} - -void loadGeometry(std::string nodeName, Transform transform, std::ostream &os, domGeometry &geom, - StringMap &matLookupTable) { - SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", geom.getName(), nodeName.c_str()); - - domMesh *mesh = geom.getMesh().cast(); - if (!mesh) - SLog(EError, "Invalid geometry type encountered (must be a )!"); - - const domInputLocal_Array &vertInputs = mesh->getVertices()->getInput_array(); - - std::string xmlName = nodeName + std::string("_") + geom.getId(); - int geomIndex = 0; - - domTriangles_Array &trianglesArray = mesh->getTriangles_array(); - for (size_t i=0; igetInput_array(); - VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); - domListOfUInts &indices = triangles->getP()->getValue(); - tess_data.clear(); - tess_nSources = data->nSources; - for (size_t j=0; jgetMaterial() == NULL || matLookupTable.find(triangles->getMaterial()) == matLookupTable.end()) - SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); - else - matID = matLookupTable[triangles->getMaterial()]; - writeGeometry(xmlName, geomIndex, matID, transform, os, data); - delete data; - ++geomIndex; - } - - domPolygons_Array &polygonsArray = mesh->getPolygons_array(); - for (size_t i=0; igetInput_array(); - VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); - domP_Array &indexArray = polygons->getP_array(); - int posOffset = data->typeToOffset[EPosition]; - - tess_data.clear(); - tess_nSources = data->nSources; - for (size_t j=0; jgetValue(); - domUint *temp = new domUint[indices.getCount()]; - for (size_t l = 0; lnSources) - gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp)); - - gluTessEndContour(tess); - gluTessEndPolygon(tess); - delete[] temp; - } - - std::string matID; - if (polygons->getMaterial() == NULL || matLookupTable.find(polygons->getMaterial()) == matLookupTable.end()) - SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); - else - matID = matLookupTable[polygons->getMaterial()]; - - writeGeometry(xmlName, geomIndex, matID, transform, os, data); - delete data; - ++geomIndex; - } - - domPolylist_Array &polylistArray = mesh->getPolylist_array(); - for (size_t i=0; igetInput_array(); - VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); - domListOfUInts &vcount = polylist->getVcount()->getValue(); - domListOfUInts &indexArray = polylist->getP()->getValue(); - int posOffset = data->typeToOffset[EPosition], indexOffset = 0; - tess_data.clear(); - tess_nSources = data->nSources; - - for (size_t j=0; jnSources]; - for (size_t l = 0; lnSources; ++l) - temp[l] = indexArray.get(indexOffset++); - - gluTessBeginPolygon(tess, NULL); - gluTessBeginContour(tess); - - for (size_t k=0; knSources; k+=data->nSources) - gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp)); - - gluTessEndContour(tess); - gluTessEndPolygon(tess); - delete[] temp; - } - - std::string matID; - if (polylist->getMaterial() == NULL || matLookupTable.find(polylist->getMaterial()) == matLookupTable.end()) - SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); - else - matID = polylist->getMaterial(); - - writeGeometry(xmlName, geomIndex, matID, transform, os, data); - delete data; - ++geomIndex; - } -} - -void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &idToTexture, - domCommon_color_or_texture_type *value, bool handleRefs) { - if (!value) - return; - domCommon_color_or_texture_type_complexType::domColor* color = - value->getColor().cast(); - domCommon_color_or_texture_type_complexType::domTexture* texture = - value->getTexture().cast(); - if (color && !handleRefs) { - domFloat4 &colValue = color->getValue(); - os << "\t\t" << endl; - } else if (texture && handleRefs) { - os << "\t\tgetTexture()] << "\"/>" << endl; - } -} - -void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &, - domCommon_float_or_param_type *value, bool handleRef) { - if (!value) - return; - domCommon_float_or_param_type::domFloat *floatValue = value->getFloat(); - if (!handleRef && floatValue) { - os << "\t\tgetValue() << "\"/>" << endl; - } -} - -void loadMaterial(std::ostream &os, domMaterial &mat, StringMap &idToTexture) { - SLog(EInfo, "Converting material \"%s\" ..", mat.getName()); - - daeURI &effRef = mat.getInstance_effect()->getUrl(); - effRef.resolveElement(); - domEffect *effect = daeSafeCast(effRef.getElement()); - - if (!effect) - SLog(EError, "Referenced effect not found!"); - - domProfile_COMMON *commonProfile = daeSafeCast - (effect->getDescendant("profile_COMMON")); - - if (!commonProfile) - SLog(EError, "Common effect profile not found!"); - - domProfile_COMMON::domTechnique *technique = commonProfile->getTechnique(); - - if (!technique) - SLog(EError, "The technique element is missing!"); - - domProfile_COMMON::domTechnique::domPhong* phong = technique->getPhong(); - domProfile_COMMON::domTechnique::domLambert* lambert = technique->getLambert(); - - if (phong) { - domCommon_color_or_texture_type* diffuse = phong->getDiffuse(); - domCommon_color_or_texture_type* specular = phong->getSpecular(); - domCommon_float_or_param_type* shininess = phong->getShininess(); - bool isDiffuse = false; - - if (specular->getColor().cast()) { - domFloat4 &colValue = specular->getColor()->getValue(); - if (colValue.get(0) == colValue.get(1) && - colValue.get(1) == colValue.get(2) && - colValue.get(2) == 0) - isDiffuse = true; - } - if (isDiffuse) { - os << "\t" << endl; - loadMaterialParam(os, "reflectance", idToTexture, diffuse, false); - loadMaterialParam(os, "reflectance", idToTexture, diffuse, true); - os << "\t" << endl << endl; - } else { - os << "\t" << endl; - loadMaterialParam(os, "diffuseReflectance", idToTexture, diffuse, false); - loadMaterialParam(os, "specularReflectance", idToTexture, specular, false); - loadMaterialParam(os, "exponent", idToTexture, shininess, false); - loadMaterialParam(os, "diffuseReflectance", idToTexture, diffuse, true); - loadMaterialParam(os, "specularReflectance", idToTexture, specular, true); - loadMaterialParam(os, "exponent", idToTexture, shininess, true); - os << "\t" << endl << endl; - } - } else if (lambert) { - domCommon_color_or_texture_type* diffuse = lambert->getDiffuse(); - os << "\t" << endl; - loadMaterialParam(os, "reflectance", idToTexture, diffuse, false); - loadMaterialParam(os, "reflectance", idToTexture, diffuse, true); - os << "\t" << endl << endl; - } else { - SLog(EError, "Material type not supported! (must be Lambertian/Phong)"); - } -} - -void loadLight(Transform transform, std::ostream &os, domLight &light) { - SLog(EInfo, "Converting light \"%s\" ..", light.getName()); - char *end_ptr = NULL; - - // Lights in Mitsuba point along the positive Z axis (COLLADA: neg. Z) - transform = transform * Transform::scale(Vector(1, 1, -1)); - - Point pos = transform(Point(0, 0, 0)); - Vector target = transform(Point(0, 0, 1)); - - Float intensity = 1; - const domTechnique_Array &techniques = light.getTechnique_array(); - for (size_t i=0; igetChild("intensity"); - if (intensityElement && intensityElement->hasCharData()) { - std::string charData = intensityElement->getCharData(); - intensity = (Float) strtod(charData.c_str(), &end_ptr); - if (*end_ptr != '\0') - SLog(EError, "Could not parse the light intensity!"); - } - } - - domLight::domTechnique_common::domPoint *point = light.getTechnique_common()->getPoint().cast(); - if (point) { - domFloat3 &color = point->getColor()->getValue(); - os << "\t" << endl; - os << "\t\t" << endl << endl; - os << "\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t" << endl; - os << "\t" << endl << endl; - } - domLight::domTechnique_common::domSpot *spot = light.getTechnique_common()->getSpot().cast(); - if (spot) { - domFloat3 &color = spot->getColor()->getValue(); - Float falloffAngle = 180.0f; - if (spot->getFalloff_angle()) - falloffAngle = (Float) spot->getFalloff_angle()->getValue(); - os << "\t" << endl; - os << "\t\t" << endl; - os << "\t\t" << endl << endl; - os << "\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t" << endl; - os << "\t" << endl << endl; - } - domLight::domTechnique_common::domAmbient *ambient = light.getTechnique_common()->getAmbient().cast(); - if (ambient) { - domFloat3 &color = ambient->getColor()->getValue(); - os << "\t" << endl; - os << "\t\t" << endl; - os << "\t" << endl << endl; - } - if (!point && !spot && !ambient) - SLog(EWarn, "Encountered an unknown light type!"); -} - -void loadImage(std::ostream &os, domImage &image, StringMap &idToTexture, StringMap &fileToId) { - SLog(EInfo, "Converting texture \"%s\" ..", image.getName()); - - std::string filename = cdom::uriToFilePath(image.getInit_from()->getValue().str()); - if (fileToId.find(filename) != fileToId.end()) { - idToTexture[image.getId()] = fileToId[filename]; - return; - } - - idToTexture[image.getId()] = image.getId(); - fileToId[filename] = image.getId(); - - boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native); - std::string leaf = path.leaf(); - - if (endsWith(leaf, ".rgb")) - SLog(EWarn, "Maya RGB images must be converted to PNG, EXR or JPEG! The 'imgcvt' " - "utility found in the Maya binary directory can be used to do this."); - - if (!FileStream::exists(filename)) { - if (!FileStream::exists(leaf)) - SLog(EError, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), leaf.c_str()); - filename = leaf; - } - - ref input = new FileStream(filename, FileStream::EReadOnly); - ref output = new FileStream(formatString("textures/%s", leaf.c_str()), FileStream::ETruncReadWrite); - input->copyTo(output); - - os << "\t" << endl; - os << "\t\t" << endl; - os << "\t" << endl << endl; -} - -void loadCamera(Transform transform, std::ostream &os, domCamera &camera) { - SLog(EInfo, "Converting camera \"%s\" ..", camera.getName()); - Float aspect = 1.0f; - int xres=768; - - // Cameras in Mitsuba point along the positive Z axis (COLLADA: neg. Z) - transform = transform * Transform::scale(Vector(1,1,-1)); - - std::ostringstream matrix; - for (int i=0; i<4; ++i) - for (int j=0; j<4; ++j) - matrix << transform.getMatrix()->m[i][j] << " "; - std::string matrixValues = matrix.str(); - - domCamera::domOptics::domTechnique_common::domOrthographic* ortho = camera.getOptics()-> - getTechnique_common()->getOrthographic().cast(); - if (ortho) { - if (ortho->getAspect_ratio().cast() != 0) - aspect = (Float) ortho->getAspect_ratio()->getValue(); - os << "\t" << endl; - } - - domCamera::domOptics::domTechnique_common::domPerspective* persp = camera.getOptics()-> - getTechnique_common()->getPerspective().cast(); - if (persp) { - if (persp->getAspect_ratio().cast() != 0) - aspect = (Float) persp->getAspect_ratio()->getValue(); - os << "\t" << endl; - if (persp->getXfov().cast()) { - Float yFov = radToDeg(2 * std::atan(std::tan(degToRad((Float) persp->getXfov()->getValue())/2) / aspect)); - if (aspect <= 1.0f) - os << "\t\tgetXfov()->getValue() << "\"/>" << endl; - else - os << "\t\t" << endl; - os << "\t\tgetZnear()->getValue() << "\"/>" << endl; - os << "\t\tgetZfar()->getValue() << "\"/>" << endl; - } else if (persp->getYfov().cast()) { - Float xFov = radToDeg(2 * std::atan(std::tan(degToRad((Float) persp->getYfov()->getValue())/2) * aspect)); - if (aspect > 1.0f) - os << "\t\tgetYfov()->getValue() << "\"/>" << endl; - else - os << "\t\t" << endl; - os << "\t\tgetZnear()->getValue() << "\"/>" << endl; - os << "\t\tgetZfar()->getValue() << "\"/>" << endl; - } - } - - os << endl; - os << "\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t" << endl << endl; - - os << "\t\t" << endl << endl; - os << "\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t\t" << endl; - os << "\t\t" << endl; - os << "\t" << endl << endl; -} - -void loadNode(Transform transform, std::ostream &os, domNode &node) { - SLog(EInfo, "Converting node \"%s\" ..", node.getName()); - - daeTArray > children = node.getChildren(); - /* Parse transformations */ - for (size_t i=0; itypeID() == domRotate::ID()) { - /* Skip rotations labeled as "post-rotationY". Maya exports these with some cameras, - which introduces an incorrect 90 degree rotation unless ignored */ - if (element->hasAttribute("sid") && element->getAttribute("sid") == "post-rotationY") - continue; - daeTArray value = daeSafeCast(element)->getValue(); - transform = transform * - Transform::rotate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), (Float) value.get(3)); - } else if (element->typeID() == domTranslate::ID()) { - daeTArray value = daeSafeCast(element)->getValue(); - transform = transform * - Transform::translate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2))); - } else if (element->typeID() == domScale::ID()) { - daeTArray value = daeSafeCast(element)->getValue(); - transform = transform * - Transform::scale(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2))); - } else if (element->typeID() == domLookat::ID()) { - daeTArray value = daeSafeCast(element)->getValue(); - transform = transform * - Transform::lookAt( - Point((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), - Point((Float) value.get(3), (Float) value.get(4), (Float) value.get(5)), - Vector((Float) value.get(6), (Float) value.get(7), (Float) value.get(8)) - ); - } - } - - /* Iterate over all geometry references */ - domInstance_geometry_Array &instanceGeometries = node.getInstance_geometry_array(); - for (size_t i=0; i(inst->getUrl().getElement()); - domBind_material *bmat = inst->getBind_material(); - StringMap matLookupTable; - if (bmat) { - domBind_material::domTechnique_common *technique = bmat->getTechnique_common(); - if (!technique) - SLog(EError, "bind_material does not contain a element!"); - domInstance_material_Array &instMaterials = technique->getInstance_material_array(); - - for (size_t i=0; igetTarget(); - matRef.resolveElement(); - domMaterial *material = daeSafeCast(matRef.getElement()); - matLookupTable[instMat->getSymbol()] = material->getId(); - } - } else { - SLog(EWarn, "instance_geometry does not contain a element!"); - } - - if (!geom) - SLog(EError, "Could not find a referenced geometry object!"); - loadGeometry(node.getName(), transform, os, *geom, matLookupTable); - } - - /* Iterate over all light references */ - domInstance_light_Array &instanceLights = node.getInstance_light_array(); - for (size_t i=0; i(inst->getUrl().getElement()); - if (!light) - SLog(EError, "Could not find a referenced light!"); - loadLight(transform, os, *light); - } - - /* Iterate over all camera references */ - domInstance_camera_Array &instanceCameras = node.getInstance_camera_array(); - for (size_t i=0; i(inst->getUrl().getElement()); - if (camera == NULL) - SLog(EError, "Could not find a referenced camera!"); - loadCamera(transform, os, *camera); - } - - /* Recursively iterate through sub-nodes */ - domNode_Array &nodes = node.getNode_array(); - for (size_t i=0; i elements */ - domInstance_node_Array &instanceNodes = node.getInstance_node_array(); - for (size_t i=0; i(instanceNodes[i]->getUrl().getElement()); - if (!node) - SLog(EError, "Could not find a referenced node!"); - loadNode(transform, os, *node); - } -} - -#ifndef WIN32 -#define __stdcall -#endif - -GLvoid __stdcall tessBegin(GLenum type) { - SAssert(type == GL_TRIANGLES); -} - -GLvoid __stdcall tessVertex(void *data) { - const domUint *raw = (domUint *) data; - for (size_t i=0; i " << endl; + cout << "Syntax: mtsimport [Adjustment file]" << endl + << "Please see the documentation for more information." << endl; return -1; } -#if defined(__LINUX__) - std::string path = std::string("file://") + - FileResolver::getInstance()->resolveAbsolute(argv[1]); -#else - std::string path = argv[1]; -#endif + ConsoleColladaConverter converter; + converter.convert(argv[1], "", argv[2], argc > 3 ? argv[3] : ""); - DAE *dae = new DAE(); - SLog(EInfo, "Loading \"%s\" ..", path.c_str()); - if (dae->load(path.c_str()) != DAE_OK) - SLog(EError, "Could not load \"%s\"!", argv[1]); - - std::ofstream os(argv[2]); - if (os.fail()) - SLog(EError, "Could not write to \"%s\"!", argv[2]); - - domCOLLADA *document = dae->getDom(path.c_str()); - domVisual_scene *visualScene = daeSafeCast - (document->getDescendant("visual_scene")); - if (!visualScene) - SLog(EError, "Could not find a visual_scene!"); - - /* Configure the GLU tesselator */ - tess = gluNewTess(); - if (!tess) - SLog(EError, "Could not allocate a GLU tesselator!"); - -#ifndef WIN32 - int status = mkdir("textures", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if (status != 0 && errno != EEXIST) - SLog(EError, "Could not create the directory \"textures\""); - status = mkdir("meshes", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if (status != 0 && errno != EEXIST) - SLog(EError, "Could not create the directory \"meshes\""); -#else - int status = CreateDirectory("textures", NULL); - if (status == 0 && GetLastError() != ERROR_ALREADY_EXISTS) - SLog(EError, "Could not create the directory \"textures\""); - status = CreateDirectory("meshes", NULL); - if (status == 0 && GetLastError() != ERROR_ALREADY_EXISTS) - SLog(EError, "Could not create the directory \"meshes\""); -#endif - - gluTessCallback(tess, GLU_TESS_VERTEX, reinterpret_cast(&tessVertex)); - gluTessCallback(tess, GLU_TESS_BEGIN, reinterpret_cast(&tessBegin)); - gluTessCallback(tess, GLU_TESS_END, reinterpret_cast(&tessEnd)); - gluTessCallback(tess, GLU_TESS_ERROR, reinterpret_cast(&tessError)); - gluTessCallback(tess, GLU_TESS_COMBINE, reinterpret_cast(&tessCombine)); - gluTessCallback(tess, GLU_TESS_EDGE_FLAG, reinterpret_cast(&tessEdgeFlag)); - - domNode_Array &nodes = visualScene->getNode_array(); - os << "" << endl << endl; - os << "" << endl << endl; - os << "" << endl; - os << "\t" << endl << endl; - - SLog(EInfo, "Converting to \"%s\" ..", argv[2]); - - StringMap idToTexture, fileToId; - domLibrary_images_Array &libraryImages = document->getLibrary_images_array(); - for (size_t i=0; igetImage_array(); - for (size_t j=0; jgetLibrary_materials_array(); - for (size_t i=0; igetMaterial_array(); - for (size_t j=0; j" << endl; - - gluDeleteTess(tess); - delete dae; return 0; } @@ -892,23 +67,26 @@ int ubi_main(int argc, char **argv) { Thread::getThread()->getLogger()->setLogLevel(EInfo); -#ifdef WIN32 + FileResolver *resolver = FileResolver::getInstance(); +#if defined(WIN32) char lpFilename[1024]; if (GetModuleFileNameA(NULL, lpFilename, sizeof(lpFilename))) { - FileResolver *resolver = FileResolver::getInstance(); resolver->addPathFromFile(lpFilename); } else { SLog(EWarn, "Could not determine the executable path"); } -#else +#elif defined(__LINUX__) char exePath[PATH_MAX]; if (getcwd(exePath, PATH_MAX)) { - FileResolver *resolver = FileResolver::getInstance(); resolver->addPathFromFile(exePath); } else { SLog(EWarn, "Could not determine the executable path"); } +#else + MTS_AUTORELEASE_BEGIN() + resolver->addPath(__ubi_bundlepath()); + MTS_AUTORELEASE_END() #endif try { diff --git a/src/integrators/photonmapper/photonmapper.cpp b/src/integrators/photonmapper/photonmapper.cpp index c5b2486d..5cb42b06 100644 --- a/src/integrators/photonmapper/photonmapper.cpp +++ b/src/integrators/photonmapper/photonmapper.cpp @@ -14,7 +14,7 @@ public: /* Number of luminaire samples for direct illumination */ m_directSamples = props.getInteger("directSamples", 1); /* Number of BSDF samples when intersecting a glossy material */ - m_glossySamples = props.getInteger("glossySamples", 1); + m_glossySamples = props.getInteger("glossySamples", 32); /* Depth to start using russian roulette when tracing photons */ m_rrDepth = props.getInteger("rrDepth", 10); /* Depth cutoff when tracing photons */ diff --git a/src/qtgui/importdlg.cpp b/src/qtgui/importdlg.cpp index 5399ca3f..cd00635d 100644 --- a/src/qtgui/importdlg.cpp +++ b/src/qtgui/importdlg.cpp @@ -6,6 +6,8 @@ ImportDialog::ImportDialog(QWidget *parent) : QDialog(parent, Qt::Sheet), ui(new Ui::ImportDialog) { ui->setupUi(this); + connect(ui->sceneEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(refresh())); } ImportDialog::~ImportDialog() { @@ -13,12 +15,73 @@ ImportDialog::~ImportDialog() { } void ImportDialog::changeEvent(QEvent *e) { - QDialog::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: ui->retranslateUi(this); - break; - default: - break; - } + break; + default: + break; + } +} + +void ImportDialog::on_inputBrowse_clicked(bool checked) { + QFileDialog dialog(this); + dialog.setNameFilter(tr("COLLADA scenes (*.dae)")); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setViewMode(QFileDialog::Detail); + dialog.setWindowModality(Qt::ApplicationModal); + if (dialog.exec()) { + QString fname = dialog.selectedFiles()[0]; + ui->inputEdit->setText(fname); + QFileInfo info(fname); + ui->directoryEdit->setText(info.absoluteDir().absolutePath()); + ui->sceneEdit->setText(info.completeBaseName() + ".xml"); + refresh(); + } +} + +void ImportDialog::on_directoryBrowse_clicked(bool checked) { + QFileDialog dialog(this); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setFileMode(QFileDialog::DirectoryOnly); + dialog.setWindowModality(Qt::ApplicationModal); + if (dialog.exec()) { + QString fname = dialog.selectedFiles()[0]; + ui->directoryEdit->setText(fname); + refresh(); + } +} + +void ImportDialog::on_adjustmentBrowse_clicked(bool checked) { + QFileDialog dialog(this); + dialog.setNameFilter(tr("Import adjustment files (*.xml)")); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setViewMode(QFileDialog::Detail); + dialog.setWindowModality(Qt::ApplicationModal); + if (dialog.exec()) { + QString fname = dialog.selectedFiles()[0]; + ui->adjustmentEdit->setText(fname); + refresh(); + } +} + +void ImportDialog::refresh() { + bool hasInput = ui->inputEdit->text() != ""; + bool hasOutput = ui->sceneEdit->text().endsWith(".xml"); + + ui->directoryBrowse->setEnabled(hasInput); + ui->directoryEdit->setEnabled(hasInput); + ui->adjustmentBrowse->setEnabled(hasInput); + ui->adjustmentEdit->setEnabled(hasInput); + ui->sceneEdit->setEnabled(hasInput); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(hasInput && hasOutput); +} + +void ImportDialog::accept() { + QDialog::accept(); + + QString sourceFile = ui->inputEdit->text(); + QString targetScene = ui->sceneEdit->text(); + QString directory = ui->directoryEdit->text(); } diff --git a/src/qtgui/importdlg.h b/src/qtgui/importdlg.h index af04241d..19efb8db 100644 --- a/src/qtgui/importdlg.h +++ b/src/qtgui/importdlg.h @@ -12,6 +12,13 @@ class ImportDialog : public QDialog { public: ImportDialog(QWidget *parent); ~ImportDialog(); +public slots: + void accept(); +protected slots: + void on_inputBrowse_clicked(bool checked); + void on_directoryBrowse_clicked(bool checked); + void on_adjustmentBrowse_clicked(bool checked); + void refresh(); protected: void changeEvent(QEvent *e); private: diff --git a/src/qtgui/importdlg.ui b/src/qtgui/importdlg.ui index 2649b7b7..a1d4a268 100644 --- a/src/qtgui/importdlg.ui +++ b/src/qtgui/importdlg.ui @@ -6,7 +6,7 @@ 0 0 - 358 + 357 250 @@ -67,14 +67,14 @@ - + true - + 30 @@ -94,9 +94,9 @@ - + - true + false true @@ -104,9 +104,9 @@ - + - true + false @@ -128,42 +128,20 @@ - Target scene : + Target scene file : - + - true + false false - - - - true - - - - 0 - 0 - - - - - 30 - 16777215 - - - - ... - - - @@ -179,15 +157,18 @@ + + true + Adjustment file : - + - true + false true @@ -195,9 +176,9 @@ - + - true + false diff --git a/src/qtgui/resources/docs.xml b/src/qtgui/resources/docs.xml index 7b03017c..a76a167d 100644 --- a/src/qtgui/resources/docs.xml +++ b/src/qtgui/resources/docs.xml @@ -326,7 +326,7 @@ encoding to reduce the storage footprint of photons. Number of luminaire samples for direct illumination - Number of glossy samples for direct illumination + Number of glossy samples for direct illumination Depth cutoff when tracing photons Depth cutoff when recursively tracing specular materials Granularity of photon tracing work units (in shot particles)