better COLLADA import from Blender, improvements to the import dialog
parent
845ca566ec
commit
0953ceaba3
|
@ -408,7 +408,8 @@ if hasCollada:
|
||||||
colladaEnv.Append(LIBPATH=env['COLLADALIBDIR'])
|
colladaEnv.Append(LIBPATH=env['COLLADALIBDIR'])
|
||||||
if env.has_key('COLLADALIB'):
|
if env.has_key('COLLADALIB'):
|
||||||
colladaEnv.Append(LIBS=env['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:
|
if hasQt:
|
||||||
qtEnv = mainEnv.Clone()
|
qtEnv = mainEnv.Clone()
|
||||||
|
|
|
@ -0,0 +1,904 @@
|
||||||
|
#define BOOST_FILESYSTEM_NO_LIB
|
||||||
|
#define BOOST_SYSTEM_NO_LIB
|
||||||
|
|
||||||
|
#include <mitsuba/mitsuba.h>
|
||||||
|
#include <mitsuba/render/trimesh.h>
|
||||||
|
#include <mitsuba/core/fresolver.h>
|
||||||
|
#include <dae.h>
|
||||||
|
#include <dom/domCOLLADA.h>
|
||||||
|
#include <dom/domProfile_COMMON.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#if defined(__OSX__)
|
||||||
|
#include <OpenGL/glu.h>
|
||||||
|
#else
|
||||||
|
#include <GL/glu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "converter.h"
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::string> 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<Vec4 *> data;
|
||||||
|
std::vector<ESourceType> offsetToType;
|
||||||
|
std::vector<int> typeToOffset;
|
||||||
|
|
||||||
|
VertexData() : glPos(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~VertexData() {
|
||||||
|
for (size_t i=0; i<data.size(); ++i) {
|
||||||
|
if (data[i])
|
||||||
|
delete[] data[i];
|
||||||
|
}
|
||||||
|
if (glPos)
|
||||||
|
delete[] glPos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This code is not thread-safe for now */
|
||||||
|
GLUtesselator *tess = NULL;
|
||||||
|
std::vector<domUint> 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; i<inputs.getCount(); ++i)
|
||||||
|
result->data[i] = NULL;
|
||||||
|
result->offsetToType.resize(inputs.getCount());
|
||||||
|
result->typeToOffset.resize(ELast);
|
||||||
|
for (int i=0; i<ELast; ++i)
|
||||||
|
result->typeToOffset[i] = -1;
|
||||||
|
|
||||||
|
for (size_t i=0; i<inputs.getCount(); ++i) {
|
||||||
|
int offset = (int) inputs[i]->getOffset();
|
||||||
|
daeURI &sourceRef = inputs[i]->getSource();
|
||||||
|
sourceRef.resolveElement();
|
||||||
|
domSource *source = daeSafeCast<domSource>(sourceRef.getElement());
|
||||||
|
|
||||||
|
if (!strcmp(inputs[i]->getSemantic(), "VERTEX")) {
|
||||||
|
SAssert(vertInputs.getCount() == 1);
|
||||||
|
sourceRef = vertInputs[0]->getSource();
|
||||||
|
sourceRef.resolveElement();
|
||||||
|
source = daeSafeCast<domSource>(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 <technique_common> tag!");
|
||||||
|
domAccessor *accessor = techniqueCommon->getAccessor();
|
||||||
|
if (!accessor)
|
||||||
|
SLog(EError, "Data source does not have a <accessor> 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; j<size; ++j) {
|
||||||
|
for (int k=0; k<nParams; ++k)
|
||||||
|
target[j][k] = (Float) floatArray[j*stride+k];
|
||||||
|
}
|
||||||
|
|
||||||
|
result->data[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<Vertex, Vertex, bool> {
|
||||||
|
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<Vertex> vertexBuffer;
|
||||||
|
std::vector<Triangle> triangles;
|
||||||
|
std::map<Vertex, int, vertex_key_order> vertexMap;
|
||||||
|
size_t numMerged = 0, triangleIdx = 0;
|
||||||
|
Triangle triangle;
|
||||||
|
|
||||||
|
id += formatString("_%i", geomIndex);
|
||||||
|
|
||||||
|
for (size_t i=0; i<tess_data.size(); i+=tess_nSources) {
|
||||||
|
Vertex vertex;
|
||||||
|
domUint posRef = tess_data[i+vData->typeToOffset[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<TriMesh> 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<FileStream> 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<shape id=\"" << id << "\" type=\"serialized\">" << endl;
|
||||||
|
os << "\t\t<string name=\"filename\" value=\"" << filename.c_str() << "\"/>" << endl;
|
||||||
|
if (!transform.isIdentity()) {
|
||||||
|
os << "\t\t<transform name=\"toWorld\">" << endl;
|
||||||
|
os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
|
||||||
|
os << "\t\t</transform>" << endl;
|
||||||
|
}
|
||||||
|
if (matID != "")
|
||||||
|
os << "\t\t<ref name=\"bsdf\" id=\"" << matID << "\"/>" << endl;
|
||||||
|
os << "\t</shape>" << 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 <mesh>)!");
|
||||||
|
|
||||||
|
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; i<trianglesArray.getCount(); ++i) {
|
||||||
|
domTriangles *triangles = trianglesArray[i];
|
||||||
|
domInputLocalOffset_Array &inputs = triangles->getInput_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; j<indices.getCount(); ++j)
|
||||||
|
tess_data.push_back(indices[j]);
|
||||||
|
std::string matID;
|
||||||
|
if (triangles->getMaterial() == 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; i<polygonsArray.getCount(); ++i) {
|
||||||
|
domPolygons *polygons = polygonsArray[i];
|
||||||
|
domInputLocalOffset_Array &inputs = polygons->getInput_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; j<indexArray.getCount(); ++j) {
|
||||||
|
domListOfUInts &indices = indexArray[j]->getValue();
|
||||||
|
domUint *temp = new domUint[indices.getCount()];
|
||||||
|
for (size_t l = 0; l<indices.getCount(); ++l)
|
||||||
|
temp[l] = indices.get(l);
|
||||||
|
|
||||||
|
gluTessBeginPolygon(tess, NULL);
|
||||||
|
gluTessBeginContour(tess);
|
||||||
|
|
||||||
|
for (size_t k=0; k<indices.getCount(); k+=data->nSources)
|
||||||
|
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; i<polylistArray.getCount(); ++i) {
|
||||||
|
domPolylist *polylist = polylistArray[i];
|
||||||
|
domInputLocalOffset_Array &inputs = polylist->getInput_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; j<vcount.getCount(); ++j) {
|
||||||
|
size_t vertexCount = vcount.get(i);
|
||||||
|
|
||||||
|
domUint *temp = new domUint[vertexCount * data->nSources];
|
||||||
|
for (size_t l = 0; l<vertexCount * data->nSources; ++l)
|
||||||
|
temp[l] = indexArray.get(indexOffset++);
|
||||||
|
|
||||||
|
gluTessBeginPolygon(tess, NULL);
|
||||||
|
gluTessBeginContour(tess);
|
||||||
|
|
||||||
|
for (size_t k=0; k<vertexCount*data->nSources; 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<rgb name=\"" << name << "\" value=\""
|
||||||
|
<< colValue.get(0) << " " << colValue.get(1) << " "
|
||||||
|
<< colValue.get(2) << "\"/>" << 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\t<ref name=\"" << name << "\" id=\""
|
||||||
|
<< idToTexture[texture->getTexture()] << "\"/>" << 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\t<float name=\"" << name << "\" value=\""
|
||||||
|
<< floatValue->getValue() << "\"/>" << 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<domEffect>(effRef.getElement());
|
||||||
|
|
||||||
|
if (!effect)
|
||||||
|
SLog(EError, "Referenced effect not found!");
|
||||||
|
|
||||||
|
domProfile_COMMON *commonProfile = daeSafeCast<domProfile_COMMON>
|
||||||
|
(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<daeSmartRef<domCommon_newparam_type> > &newParamArray = commonProfile->getNewparam_array();
|
||||||
|
for (size_t i=0; i<newParamArray.getCount(); ++i) {
|
||||||
|
domCommon_newparam_type_complexType *newParam = newParamArray[i];
|
||||||
|
domFx_surface_common *surface = newParam->getSurface();
|
||||||
|
domFx_sampler2D_common *sampler2D = newParam->getSampler2D();
|
||||||
|
|
||||||
|
|
||||||
|
if (surface) {
|
||||||
|
SAssert(surface->getType() == FX_SURFACE_TYPE_ENUM_2D);
|
||||||
|
daeTArray<daeSmartRef<domFx_surface_init_from_common> > &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<bsdf id=\"" << mat.getId() << "\" type=\"lambertian\">" << endl;
|
||||||
|
loadMaterialParam(os, "reflectance", idToTexture, diffuse, false);
|
||||||
|
loadMaterialParam(os, "reflectance", idToTexture, diffuse, true);
|
||||||
|
os << "\t</bsdf>" << endl << endl;
|
||||||
|
} else {
|
||||||
|
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"phong\">" << 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</bsdf>" << endl << endl;
|
||||||
|
}
|
||||||
|
} else if (lambert) {
|
||||||
|
domCommon_color_or_texture_type* diffuse = lambert->getDiffuse();
|
||||||
|
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"lambertian\">" << endl;
|
||||||
|
loadMaterialParam(os, "reflectance", idToTexture, diffuse, false);
|
||||||
|
loadMaterialParam(os, "reflectance", idToTexture, diffuse, true);
|
||||||
|
os << "\t</bsdf>" << 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; i<techniques.getCount(); ++i) {
|
||||||
|
domTechnique *tech = techniques.get(i);
|
||||||
|
|
||||||
|
daeElement *intensityElement = tech->getChild("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<luminaire id=\"" << light.getId() << "\" type=\"point\">" << endl;
|
||||||
|
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl << endl;
|
||||||
|
os << "\t\t<transform name=\"toWorld\">" << endl;
|
||||||
|
os << "\t\t\t<translate x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\"/>" << endl;
|
||||||
|
os << "\t\t</transform>" << endl;
|
||||||
|
os << "\t</luminaire>" << 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<luminaire id=\"" << light.getId() << "\" type=\"spot\">" << endl;
|
||||||
|
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl;
|
||||||
|
os << "\t\t<float name=\"cutoffAngle\" value=\"" << falloffAngle/2 << "\"/>" << endl << endl;
|
||||||
|
os << "\t\t<transform name=\"toWorld\">" << endl;
|
||||||
|
os << "\t\t\t<lookAt ox=\"" << pos.x << "\" oy=\"" << pos.y << "\" oz=\"" << pos.z << "\" tx=\"" << target.x << "\" ty=\"" << target.y << "\" tz=\"" << target.z << "\"/>" << endl;
|
||||||
|
os << "\t\t</transform>" << endl;
|
||||||
|
os << "\t</luminaire>" << endl << endl;
|
||||||
|
}
|
||||||
|
domLight::domTechnique_common::domAmbient *ambient = light.getTechnique_common()->getAmbient().cast();
|
||||||
|
if (ambient) {
|
||||||
|
domFloat3 &color = ambient->getColor()->getValue();
|
||||||
|
os << "\t<luminaire id=\"" << light.getId() << "\" type=\"constant\">" << endl;
|
||||||
|
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl;
|
||||||
|
os << "\t</luminaire>" << 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<FileStream> input = new FileStream(filename, FileStream::EReadOnly);
|
||||||
|
ref<FileStream> output = new FileStream(formatString("textures/%s", leaf.c_str()), FileStream::ETruncReadWrite);
|
||||||
|
input->copyTo(output);
|
||||||
|
|
||||||
|
os << "\t<texture id=\"" << image.getId() << "\" type=\"ldrtexture\">" << endl;
|
||||||
|
os << "\t\t<string name=\"filename\" value=\"textures/" << leaf << "\"/>" << endl;
|
||||||
|
os << "\t</texture>" << 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<camera id=\"" << camera.getId() << "\" type=\"orthographic\">" << 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<camera id=\"" << camera.getId() << "\" type=\"perspective\">" << 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\t<float name=\"fov\" value=\"" << persp->getXfov()->getValue() << "\"/>" << endl;
|
||||||
|
else
|
||||||
|
os << "\t\t<float name=\"fov\" value=\"" << yFov << "\"/>" << endl;
|
||||||
|
os << "\t\t<float name=\"nearClip\" value=\"" << persp->getZnear()->getValue() << "\"/>" << endl;
|
||||||
|
os << "\t\t<float name=\"farClip\" value=\"" << persp->getZfar()->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\t<float name=\"fov\" value=\"" << persp->getYfov()->getValue() << "\"/>" << endl;
|
||||||
|
else
|
||||||
|
os << "\t\t<float name=\"fov\" value=\"" << xFov << "\"/>" << endl;
|
||||||
|
os << "\t\t<float name=\"nearClip\" value=\"" << persp->getZnear()->getValue() << "\"/>" << endl;
|
||||||
|
os << "\t\t<float name=\"farClip\" value=\"" << persp->getZfar()->getValue() << "\"/>" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os << endl;
|
||||||
|
os << "\t\t<transform name=\"toWorld\">" << endl;
|
||||||
|
os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
|
||||||
|
os << "\t\t</transform>" << endl << endl;
|
||||||
|
|
||||||
|
os << "\t\t<sampler type=\"stratified\"/>" << endl << endl;
|
||||||
|
os << "\t\t<film type=\"exrfilm\">" << endl;
|
||||||
|
os << "\t\t\t<integer name=\"width\" value=\"" << xres << "\"/>" << endl;
|
||||||
|
os << "\t\t\t<integer name=\"height\" value=\"" << (int) (xres/aspect) << "\"/>" << endl;
|
||||||
|
os << "\t\t\t<rfilter type=\"gaussian\"/>" << endl;
|
||||||
|
os << "\t\t</film>" << endl;
|
||||||
|
os << "\t</camera>" << endl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadNode(Transform transform, std::ostream &os, domNode &node) {
|
||||||
|
SLog(EInfo, "Converting node \"%s\" ..", node.getName());
|
||||||
|
|
||||||
|
daeTArray<daeSmartRef<daeElement> > children = node.getChildren();
|
||||||
|
/* Parse transformations */
|
||||||
|
for (size_t i=0; i<children.getCount(); ++i) {
|
||||||
|
daeElement *element = children.get(i);
|
||||||
|
if (element->typeID() == 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<double> value = daeSafeCast<domRotate>(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<double> value = daeSafeCast<domTranslate>(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<double> value = daeSafeCast<domScale>(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<double> value = daeSafeCast<domLookat>(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<instanceGeometries.getCount(); ++i) {
|
||||||
|
domInstance_geometry *inst = instanceGeometries[i];
|
||||||
|
domGeometry *geom = daeSafeCast<domGeometry>(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 <technique_common> element!");
|
||||||
|
domInstance_material_Array &instMaterials = technique->getInstance_material_array();
|
||||||
|
|
||||||
|
for (size_t i=0; i<instMaterials.getCount(); ++i) {
|
||||||
|
domInstance_material *instMat = instMaterials[i];
|
||||||
|
daeURI &matRef = instMat->getTarget();
|
||||||
|
matRef.resolveElement();
|
||||||
|
domMaterial *material = daeSafeCast<domMaterial>(matRef.getElement());
|
||||||
|
matLookupTable[instMat->getSymbol()] = material->getId();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SLog(EWarn, "instance_geometry does not contain a <bind_material> 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<instanceLights.getCount(); ++i) {
|
||||||
|
domInstance_light *inst = instanceLights[i];
|
||||||
|
domLight *light = daeSafeCast<domLight>(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<instanceCameras.getCount(); ++i) {
|
||||||
|
domInstance_camera *inst = instanceCameras[i];
|
||||||
|
domCamera *camera = daeSafeCast<domCamera>(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<nodes.getCount(); ++i)
|
||||||
|
loadNode(transform, os, *nodes[i]);
|
||||||
|
|
||||||
|
/* Recursively iterate through <instance_node> elements */
|
||||||
|
domInstance_node_Array &instanceNodes = node.getInstance_node_array();
|
||||||
|
for (size_t i=0; i<instanceNodes.getCount(); ++i) {
|
||||||
|
domNode *node = daeSafeCast<domNode>(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<tess_nSources; ++i)
|
||||||
|
tess_data.push_back(raw[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLvoid __stdcall tessCombine(GLdouble coords[3], void *vertex_data[4],
|
||||||
|
GLfloat weight[4], void **outData) {
|
||||||
|
SLog(EWarn, "Detected a self-intersecting polygon!");
|
||||||
|
}
|
||||||
|
|
||||||
|
GLvoid __stdcall tessEnd() {
|
||||||
|
}
|
||||||
|
|
||||||
|
GLvoid __stdcall tessError(GLenum error) {
|
||||||
|
SLog(EError, "The GLU tesselator generated an error: %s!", gluErrorString(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLvoid __stdcall tessEdgeFlag(GLboolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColladaConverter::convert(const std::string &inputFile,
|
||||||
|
const std::string &outputDirectory,
|
||||||
|
const std::string &sceneName,
|
||||||
|
const std::string &adjustmentFile) {
|
||||||
|
#if defined(__LINUX__)
|
||||||
|
std::string path = std::string("file://") +
|
||||||
|
FileResolver::getInstance()->resolveAbsolute(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<domVisual_scene>
|
||||||
|
(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<GLvoid (__stdcall *)()>(&tessVertex));
|
||||||
|
gluTessCallback(tess, GLU_TESS_BEGIN, reinterpret_cast<GLvoid (__stdcall *)()>(&tessBegin));
|
||||||
|
gluTessCallback(tess, GLU_TESS_END, reinterpret_cast<GLvoid (__stdcall *)()>(&tessEnd));
|
||||||
|
gluTessCallback(tess, GLU_TESS_ERROR, reinterpret_cast<GLvoid (__stdcall *)()>(&tessError));
|
||||||
|
gluTessCallback(tess, GLU_TESS_COMBINE, reinterpret_cast<GLvoid (__stdcall *)()>(&tessCombine));
|
||||||
|
gluTessCallback(tess, GLU_TESS_EDGE_FLAG, reinterpret_cast<GLvoid (__stdcall *)()>(&tessEdgeFlag));
|
||||||
|
|
||||||
|
domNode_Array &nodes = visualScene->getNode_array();
|
||||||
|
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << endl;
|
||||||
|
os << "<!--" << endl;
|
||||||
|
os << "\tAutomatically converted from COLLADA" << endl;
|
||||||
|
os << "-->" << endl << endl;
|
||||||
|
os << "<scene>" << endl;
|
||||||
|
os << "\t<integrator type=\"direct\"/>" << 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; i<libraryImages.getCount(); ++i) {
|
||||||
|
domImage_Array &images = libraryImages[i]->getImage_array();
|
||||||
|
for (size_t j=0; j<images.getCount(); ++j)
|
||||||
|
loadImage(this, os, *images.get(j), idToTexture, fileToId);
|
||||||
|
}
|
||||||
|
|
||||||
|
domLibrary_materials_Array &libraryMaterials = document->getLibrary_materials_array();
|
||||||
|
for (size_t i=0; i<libraryMaterials.getCount(); ++i) {
|
||||||
|
domMaterial_Array &materials = libraryMaterials[i]->getMaterial_array();
|
||||||
|
for (size_t j=0; j<materials.getCount(); ++j)
|
||||||
|
loadMaterial(os, *materials.get(j), idToTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i<nodes.getCount(); ++i)
|
||||||
|
loadNode(Transform(), os, *nodes[i]);
|
||||||
|
|
||||||
|
os << "</scene>" << 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();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <mitsuba/mitsuba.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
|
@ -29,855 +29,30 @@
|
||||||
* (e.g. using Lighting/shading -> Batch bake in Maya).
|
* (e.g. using Lighting/shading -> Batch bake in Maya).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BOOST_FILESYSTEM_NO_LIB
|
#include "converter.h"
|
||||||
#define BOOST_SYSTEM_NO_LIB
|
|
||||||
|
|
||||||
#include <mitsuba/mitsuba.h>
|
|
||||||
#include <mitsuba/render/trimesh.h>
|
|
||||||
#include <mitsuba/hw/glrenderer.h>
|
#include <mitsuba/hw/glrenderer.h>
|
||||||
#include <mitsuba/core/fresolver.h>
|
#include <mitsuba/core/fresolver.h>
|
||||||
#include <dae.h>
|
|
||||||
#include <dom/domCOLLADA.h>
|
|
||||||
#include <dom/domProfile_COMMON.h>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#if defined(__OSX__)
|
class ConsoleColladaConverter : public ColladaConverter {
|
||||||
#include <OpenGL/glu.h>
|
|
||||||
#else
|
|
||||||
#include <GL/glu.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace mitsuba;
|
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> 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<Vec4 *> data;
|
|
||||||
std::vector<ESourceType> offsetToType;
|
|
||||||
std::vector<int> typeToOffset;
|
|
||||||
|
|
||||||
VertexData() : glPos(NULL) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~VertexData() {
|
|
||||||
for (size_t i=0; i<data.size(); ++i) {
|
|
||||||
if (data[i])
|
|
||||||
delete[] data[i];
|
|
||||||
}
|
|
||||||
if (glPos)
|
|
||||||
delete[] glPos;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Globals */
|
|
||||||
GLUtesselator *tess = NULL;
|
|
||||||
std::vector<domUint> 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; i<inputs.getCount(); ++i)
|
|
||||||
result->data[i] = NULL;
|
|
||||||
result->offsetToType.resize(inputs.getCount());
|
|
||||||
result->typeToOffset.resize(ELast);
|
|
||||||
for (int i=0; i<ELast; ++i)
|
|
||||||
result->typeToOffset[i] = -1;
|
|
||||||
|
|
||||||
for (size_t i=0; i<inputs.getCount(); ++i) {
|
|
||||||
int offset = (int) inputs[i]->getOffset();
|
|
||||||
daeURI &sourceRef = inputs[i]->getSource();
|
|
||||||
sourceRef.resolveElement();
|
|
||||||
domSource *source = daeSafeCast<domSource>(sourceRef.getElement());
|
|
||||||
|
|
||||||
if (!strcmp(inputs[i]->getSemantic(), "VERTEX")) {
|
|
||||||
SAssert(vertInputs.getCount() == 1);
|
|
||||||
sourceRef = vertInputs[0]->getSource();
|
|
||||||
sourceRef.resolveElement();
|
|
||||||
source = daeSafeCast<domSource>(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 <technique_common> tag!");
|
|
||||||
domAccessor *accessor = techniqueCommon->getAccessor();
|
|
||||||
if (!accessor)
|
|
||||||
SLog(EError, "Data source does not have a <accessor> 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; j<size; ++j) {
|
|
||||||
for (int k=0; k<nParams; ++k)
|
|
||||||
target[j][k] = (Float) floatArray[j*stride+k];
|
|
||||||
}
|
|
||||||
|
|
||||||
result->data[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<Vertex, Vertex, bool> {
|
|
||||||
public:
|
public:
|
||||||
bool operator()(const Vertex &v1, const Vertex &v2) const {
|
inline ConsoleColladaConverter() {
|
||||||
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;
|
std::string locateResource(const std::string &resource) {
|
||||||
else if (v1.v.y > v2.v.y) return false;
|
return "";
|
||||||
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<Vertex> vertexBuffer;
|
|
||||||
std::vector<Triangle> triangles;
|
|
||||||
std::map<Vertex, int, vertex_key_order> vertexMap;
|
|
||||||
size_t numMerged = 0, triangleIdx = 0;
|
|
||||||
Triangle triangle;
|
|
||||||
|
|
||||||
id += formatString("_%i", geomIndex);
|
|
||||||
|
|
||||||
for (size_t i=0; i<tess_data.size(); i+=tess_nSources) {
|
|
||||||
Vertex vertex;
|
|
||||||
domUint posRef = tess_data[i+vData->typeToOffset[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<TriMesh> 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<FileStream> 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<shape id=\"" << id << "\" type=\"serialized\">" << endl;
|
|
||||||
os << "\t\t<string name=\"filename\" value=\"" << filename.c_str() << "\"/>" << endl;
|
|
||||||
if (!transform.isIdentity()) {
|
|
||||||
os << "\t\t<transform name=\"toWorld\">" << endl;
|
|
||||||
os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
|
|
||||||
os << "\t\t</transform>" << endl;
|
|
||||||
}
|
|
||||||
if (matID != "")
|
|
||||||
os << "\t\t<ref name=\"bsdf\" id=\"" << matID << "\"/>" << endl;
|
|
||||||
os << "\t</shape>" << 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 <mesh>)!");
|
|
||||||
|
|
||||||
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; i<trianglesArray.getCount(); ++i) {
|
|
||||||
domTriangles *triangles = trianglesArray[i];
|
|
||||||
domInputLocalOffset_Array &inputs = triangles->getInput_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; j<indices.getCount(); ++j)
|
|
||||||
tess_data.push_back(indices[j]);
|
|
||||||
std::string matID;
|
|
||||||
if (triangles->getMaterial() == 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; i<polygonsArray.getCount(); ++i) {
|
|
||||||
domPolygons *polygons = polygonsArray[i];
|
|
||||||
domInputLocalOffset_Array &inputs = polygons->getInput_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; j<indexArray.getCount(); ++j) {
|
|
||||||
domListOfUInts &indices = indexArray[j]->getValue();
|
|
||||||
domUint *temp = new domUint[indices.getCount()];
|
|
||||||
for (size_t l = 0; l<indices.getCount(); ++l)
|
|
||||||
temp[l] = indices.get(l);
|
|
||||||
|
|
||||||
gluTessBeginPolygon(tess, NULL);
|
|
||||||
gluTessBeginContour(tess);
|
|
||||||
|
|
||||||
for (size_t k=0; k<indices.getCount(); k+=data->nSources)
|
|
||||||
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; i<polylistArray.getCount(); ++i) {
|
|
||||||
domPolylist *polylist = polylistArray[i];
|
|
||||||
domInputLocalOffset_Array &inputs = polylist->getInput_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; j<vcount.getCount(); ++j) {
|
|
||||||
size_t vertexCount = vcount.get(i);
|
|
||||||
|
|
||||||
domUint *temp = new domUint[vertexCount * data->nSources];
|
|
||||||
for (size_t l = 0; l<vertexCount * data->nSources; ++l)
|
|
||||||
temp[l] = indexArray.get(indexOffset++);
|
|
||||||
|
|
||||||
gluTessBeginPolygon(tess, NULL);
|
|
||||||
gluTessBeginContour(tess);
|
|
||||||
|
|
||||||
for (size_t k=0; k<vertexCount*data->nSources; 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<rgb name=\"" << name << "\" value=\""
|
|
||||||
<< colValue.get(0) << " " << colValue.get(1) << " "
|
|
||||||
<< colValue.get(2) << "\"/>" << endl;
|
|
||||||
} else if (texture && handleRefs) {
|
|
||||||
os << "\t\t<ref name=\"" << name << "\" id=\""
|
|
||||||
<< idToTexture[texture->getTexture()] << "\"/>" << 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\t<float name=\"" << name << "\" value=\""
|
|
||||||
<< floatValue->getValue() << "\"/>" << 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<domEffect>(effRef.getElement());
|
|
||||||
|
|
||||||
if (!effect)
|
|
||||||
SLog(EError, "Referenced effect not found!");
|
|
||||||
|
|
||||||
domProfile_COMMON *commonProfile = daeSafeCast<domProfile_COMMON>
|
|
||||||
(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<bsdf id=\"" << mat.getId() << "\" type=\"lambertian\">" << endl;
|
|
||||||
loadMaterialParam(os, "reflectance", idToTexture, diffuse, false);
|
|
||||||
loadMaterialParam(os, "reflectance", idToTexture, diffuse, true);
|
|
||||||
os << "\t</bsdf>" << endl << endl;
|
|
||||||
} else {
|
|
||||||
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"phong\">" << 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</bsdf>" << endl << endl;
|
|
||||||
}
|
|
||||||
} else if (lambert) {
|
|
||||||
domCommon_color_or_texture_type* diffuse = lambert->getDiffuse();
|
|
||||||
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"lambertian\">" << endl;
|
|
||||||
loadMaterialParam(os, "reflectance", idToTexture, diffuse, false);
|
|
||||||
loadMaterialParam(os, "reflectance", idToTexture, diffuse, true);
|
|
||||||
os << "\t</bsdf>" << 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; i<techniques.getCount(); ++i) {
|
|
||||||
domTechnique *tech = techniques.get(i);
|
|
||||||
|
|
||||||
daeElement *intensityElement = tech->getChild("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<luminaire id=\"" << light.getId() << "\" type=\"point\">" << endl;
|
|
||||||
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl << endl;
|
|
||||||
os << "\t\t<transform name=\"toWorld\">" << endl;
|
|
||||||
os << "\t\t\t<translate x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\"/>" << endl;
|
|
||||||
os << "\t\t</transform>" << endl;
|
|
||||||
os << "\t</luminaire>" << 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<luminaire id=\"" << light.getId() << "\" type=\"spot\">" << endl;
|
|
||||||
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl;
|
|
||||||
os << "\t\t<float name=\"cutoffAngle\" value=\"" << falloffAngle/2 << "\"/>" << endl << endl;
|
|
||||||
os << "\t\t<transform name=\"toWorld\">" << endl;
|
|
||||||
os << "\t\t\t<lookAt ox=\"" << pos.x << "\" oy=\"" << pos.y << "\" oz=\"" << pos.z << "\" tx=\"" << target.x << "\" ty=\"" << target.y << "\" tz=\"" << target.z << "\"/>" << endl;
|
|
||||||
os << "\t\t</transform>" << endl;
|
|
||||||
os << "\t</luminaire>" << endl << endl;
|
|
||||||
}
|
|
||||||
domLight::domTechnique_common::domAmbient *ambient = light.getTechnique_common()->getAmbient().cast();
|
|
||||||
if (ambient) {
|
|
||||||
domFloat3 &color = ambient->getColor()->getValue();
|
|
||||||
os << "\t<luminaire id=\"" << light.getId() << "\" type=\"constant\">" << endl;
|
|
||||||
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl;
|
|
||||||
os << "\t</luminaire>" << 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<FileStream> input = new FileStream(filename, FileStream::EReadOnly);
|
|
||||||
ref<FileStream> output = new FileStream(formatString("textures/%s", leaf.c_str()), FileStream::ETruncReadWrite);
|
|
||||||
input->copyTo(output);
|
|
||||||
|
|
||||||
os << "\t<texture id=\"" << image.getId() << "\" type=\"ldrtexture\">" << endl;
|
|
||||||
os << "\t\t<string name=\"filename\" value=\"textures/" << leaf << "\"/>" << endl;
|
|
||||||
os << "\t</texture>" << 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<camera id=\"" << camera.getId() << "\" type=\"orthographic\">" << 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<camera id=\"" << camera.getId() << "\" type=\"perspective\">" << 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\t<float name=\"fov\" value=\"" << persp->getXfov()->getValue() << "\"/>" << endl;
|
|
||||||
else
|
|
||||||
os << "\t\t<float name=\"fov\" value=\"" << yFov << "\"/>" << endl;
|
|
||||||
os << "\t\t<float name=\"nearClip\" value=\"" << persp->getZnear()->getValue() << "\"/>" << endl;
|
|
||||||
os << "\t\t<float name=\"farClip\" value=\"" << persp->getZfar()->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\t<float name=\"fov\" value=\"" << persp->getYfov()->getValue() << "\"/>" << endl;
|
|
||||||
else
|
|
||||||
os << "\t\t<float name=\"fov\" value=\"" << xFov << "\"/>" << endl;
|
|
||||||
os << "\t\t<float name=\"nearClip\" value=\"" << persp->getZnear()->getValue() << "\"/>" << endl;
|
|
||||||
os << "\t\t<float name=\"farClip\" value=\"" << persp->getZfar()->getValue() << "\"/>" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os << endl;
|
|
||||||
os << "\t\t<transform name=\"toWorld\">" << endl;
|
|
||||||
os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
|
|
||||||
os << "\t\t</transform>" << endl << endl;
|
|
||||||
|
|
||||||
os << "\t\t<sampler type=\"stratified\"/>" << endl << endl;
|
|
||||||
os << "\t\t<film type=\"exrfilm\">" << endl;
|
|
||||||
os << "\t\t\t<integer name=\"width\" value=\"" << xres << "\"/>" << endl;
|
|
||||||
os << "\t\t\t<integer name=\"height\" value=\"" << (int) (xres/aspect) << "\"/>" << endl;
|
|
||||||
os << "\t\t\t<rfilter type=\"gaussian\"/>" << endl;
|
|
||||||
os << "\t\t</film>" << endl;
|
|
||||||
os << "\t</camera>" << endl << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadNode(Transform transform, std::ostream &os, domNode &node) {
|
|
||||||
SLog(EInfo, "Converting node \"%s\" ..", node.getName());
|
|
||||||
|
|
||||||
daeTArray<daeSmartRef<daeElement> > children = node.getChildren();
|
|
||||||
/* Parse transformations */
|
|
||||||
for (size_t i=0; i<children.getCount(); ++i) {
|
|
||||||
daeElement *element = children.get(i);
|
|
||||||
if (element->typeID() == 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<double> value = daeSafeCast<domRotate>(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<double> value = daeSafeCast<domTranslate>(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<double> value = daeSafeCast<domScale>(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<double> value = daeSafeCast<domLookat>(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<instanceGeometries.getCount(); ++i) {
|
|
||||||
domInstance_geometry *inst = instanceGeometries[i];
|
|
||||||
domGeometry *geom = daeSafeCast<domGeometry>(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 <technique_common> element!");
|
|
||||||
domInstance_material_Array &instMaterials = technique->getInstance_material_array();
|
|
||||||
|
|
||||||
for (size_t i=0; i<instMaterials.getCount(); ++i) {
|
|
||||||
domInstance_material *instMat = instMaterials[i];
|
|
||||||
daeURI &matRef = instMat->getTarget();
|
|
||||||
matRef.resolveElement();
|
|
||||||
domMaterial *material = daeSafeCast<domMaterial>(matRef.getElement());
|
|
||||||
matLookupTable[instMat->getSymbol()] = material->getId();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SLog(EWarn, "instance_geometry does not contain a <bind_material> 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<instanceLights.getCount(); ++i) {
|
|
||||||
domInstance_light *inst = instanceLights[i];
|
|
||||||
domLight *light = daeSafeCast<domLight>(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<instanceCameras.getCount(); ++i) {
|
|
||||||
domInstance_camera *inst = instanceCameras[i];
|
|
||||||
domCamera *camera = daeSafeCast<domCamera>(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<nodes.getCount(); ++i)
|
|
||||||
loadNode(transform, os, *nodes[i]);
|
|
||||||
|
|
||||||
/* Recursively iterate through <instance_node> elements */
|
|
||||||
domInstance_node_Array &instanceNodes = node.getInstance_node_array();
|
|
||||||
for (size_t i=0; i<instanceNodes.getCount(); ++i) {
|
|
||||||
domNode *node = daeSafeCast<domNode>(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<tess_nSources; ++i)
|
|
||||||
tess_data.push_back(raw[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLvoid __stdcall tessCombine(GLdouble coords[3], void *vertex_data[4],
|
|
||||||
GLfloat weight[4], void **outData) {
|
|
||||||
SLog(EWarn, "Detected a self-intersecting polygon!");
|
|
||||||
}
|
|
||||||
|
|
||||||
GLvoid __stdcall tessEnd() {
|
|
||||||
}
|
|
||||||
|
|
||||||
GLvoid __stdcall tessError(GLenum error) {
|
|
||||||
SLog(EError, "The GLU tesselator generated an error: %s!", gluErrorString(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
GLvoid __stdcall tessEdgeFlag(GLboolean) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int colladaMain(int argc, char **argv) {
|
int colladaMain(int argc, char **argv) {
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
cout << "Syntax: mtsimport <DAE source file URL> <XML destination file>" << endl;
|
cout << "Syntax: mtsimport <DAE source file URL> <XML destination file> [Adjustment file]" << endl
|
||||||
|
<< "Please see the documentation for more information." << endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__LINUX__)
|
ConsoleColladaConverter converter;
|
||||||
std::string path = std::string("file://") +
|
converter.convert(argv[1], "", argv[2], argc > 3 ? argv[3] : "");
|
||||||
FileResolver::getInstance()->resolveAbsolute(argv[1]);
|
|
||||||
#else
|
|
||||||
std::string path = argv[1];
|
|
||||||
#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\"!", 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<domVisual_scene>
|
|
||||||
(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<GLvoid (__stdcall *)()>(&tessVertex));
|
|
||||||
gluTessCallback(tess, GLU_TESS_BEGIN, reinterpret_cast<GLvoid (__stdcall *)()>(&tessBegin));
|
|
||||||
gluTessCallback(tess, GLU_TESS_END, reinterpret_cast<GLvoid (__stdcall *)()>(&tessEnd));
|
|
||||||
gluTessCallback(tess, GLU_TESS_ERROR, reinterpret_cast<GLvoid (__stdcall *)()>(&tessError));
|
|
||||||
gluTessCallback(tess, GLU_TESS_COMBINE, reinterpret_cast<GLvoid (__stdcall *)()>(&tessCombine));
|
|
||||||
gluTessCallback(tess, GLU_TESS_EDGE_FLAG, reinterpret_cast<GLvoid (__stdcall *)()>(&tessEdgeFlag));
|
|
||||||
|
|
||||||
domNode_Array &nodes = visualScene->getNode_array();
|
|
||||||
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << endl;
|
|
||||||
os << "<!--" << endl;
|
|
||||||
os << "\tAutomatically converted from COLLADA" << endl;
|
|
||||||
os << "-->" << endl << endl;
|
|
||||||
os << "<scene>" << endl;
|
|
||||||
os << "\t<integrator type=\"direct\"/>" << 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; i<libraryImages.getCount(); ++i) {
|
|
||||||
domImage_Array &images = libraryImages[i]->getImage_array();
|
|
||||||
for (size_t j=0; j<images.getCount(); ++j)
|
|
||||||
loadImage(os, *images.get(j), idToTexture, fileToId);
|
|
||||||
}
|
|
||||||
|
|
||||||
domLibrary_materials_Array &libraryMaterials = document->getLibrary_materials_array();
|
|
||||||
for (size_t i=0; i<libraryMaterials.getCount(); ++i) {
|
|
||||||
domMaterial_Array &materials = libraryMaterials[i]->getMaterial_array();
|
|
||||||
for (size_t j=0; j<materials.getCount(); ++j)
|
|
||||||
loadMaterial(os, *materials.get(j), idToTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i=0; i<nodes.getCount(); ++i)
|
|
||||||
loadNode(Transform(), os, *nodes[i]);
|
|
||||||
|
|
||||||
os << "</scene>" << endl;
|
|
||||||
|
|
||||||
gluDeleteTess(tess);
|
|
||||||
delete dae;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,23 +67,26 @@ int ubi_main(int argc, char **argv) {
|
||||||
|
|
||||||
Thread::getThread()->getLogger()->setLogLevel(EInfo);
|
Thread::getThread()->getLogger()->setLogLevel(EInfo);
|
||||||
|
|
||||||
#ifdef WIN32
|
FileResolver *resolver = FileResolver::getInstance();
|
||||||
|
#if defined(WIN32)
|
||||||
char lpFilename[1024];
|
char lpFilename[1024];
|
||||||
if (GetModuleFileNameA(NULL,
|
if (GetModuleFileNameA(NULL,
|
||||||
lpFilename, sizeof(lpFilename))) {
|
lpFilename, sizeof(lpFilename))) {
|
||||||
FileResolver *resolver = FileResolver::getInstance();
|
|
||||||
resolver->addPathFromFile(lpFilename);
|
resolver->addPathFromFile(lpFilename);
|
||||||
} else {
|
} else {
|
||||||
SLog(EWarn, "Could not determine the executable path");
|
SLog(EWarn, "Could not determine the executable path");
|
||||||
}
|
}
|
||||||
#else
|
#elif defined(__LINUX__)
|
||||||
char exePath[PATH_MAX];
|
char exePath[PATH_MAX];
|
||||||
if (getcwd(exePath, PATH_MAX)) {
|
if (getcwd(exePath, PATH_MAX)) {
|
||||||
FileResolver *resolver = FileResolver::getInstance();
|
|
||||||
resolver->addPathFromFile(exePath);
|
resolver->addPathFromFile(exePath);
|
||||||
} else {
|
} else {
|
||||||
SLog(EWarn, "Could not determine the executable path");
|
SLog(EWarn, "Could not determine the executable path");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
MTS_AUTORELEASE_BEGIN()
|
||||||
|
resolver->addPath(__ubi_bundlepath());
|
||||||
|
MTS_AUTORELEASE_END()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
/* Number of luminaire samples for direct illumination */
|
/* Number of luminaire samples for direct illumination */
|
||||||
m_directSamples = props.getInteger("directSamples", 1);
|
m_directSamples = props.getInteger("directSamples", 1);
|
||||||
/* Number of BSDF samples when intersecting a glossy material */
|
/* 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 */
|
/* Depth to start using russian roulette when tracing photons */
|
||||||
m_rrDepth = props.getInteger("rrDepth", 10);
|
m_rrDepth = props.getInteger("rrDepth", 10);
|
||||||
/* Depth cutoff when tracing photons */
|
/* Depth cutoff when tracing photons */
|
||||||
|
|
|
@ -6,6 +6,8 @@ ImportDialog::ImportDialog(QWidget *parent) :
|
||||||
QDialog(parent, Qt::Sheet),
|
QDialog(parent, Qt::Sheet),
|
||||||
ui(new Ui::ImportDialog) {
|
ui(new Ui::ImportDialog) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
connect(ui->sceneEdit, SIGNAL(textChanged(const QString &)),
|
||||||
|
this, SLOT(refresh()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportDialog::~ImportDialog() {
|
ImportDialog::~ImportDialog() {
|
||||||
|
@ -22,3 +24,64 @@ void ImportDialog::changeEvent(QEvent *e) {
|
||||||
break;
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,13 @@ class ImportDialog : public QDialog {
|
||||||
public:
|
public:
|
||||||
ImportDialog(QWidget *parent);
|
ImportDialog(QWidget *parent);
|
||||||
~ImportDialog();
|
~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:
|
protected:
|
||||||
void changeEvent(QEvent *e);
|
void changeEvent(QEvent *e);
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>358</width>
|
<width>357</width>
|
||||||
<height>250</height>
|
<height>250</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
@ -67,14 +67,14 @@
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="4">
|
<item row="1" column="4">
|
||||||
<widget class="QLineEdit" name="lineEdit">
|
<widget class="QLineEdit" name="inputEdit">
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="5">
|
<item row="1" column="5">
|
||||||
<widget class="QPushButton" name="pushButton">
|
<widget class="QPushButton" name="inputBrowse">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>30</width>
|
<width>30</width>
|
||||||
|
@ -94,9 +94,9 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="4">
|
<item row="2" column="4">
|
||||||
<widget class="QLineEdit" name="lineEdit_2">
|
<widget class="QLineEdit" name="directoryEdit">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -104,9 +104,9 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="5">
|
<item row="2" column="5">
|
||||||
<widget class="QPushButton" name="pushButton_2">
|
<widget class="QPushButton" name="directoryBrowse">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
@ -128,42 +128,20 @@
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Target scene :</string>
|
<string>Target scene file :</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="4">
|
<item row="3" column="4">
|
||||||
<widget class="QLineEdit" name="lineEdit_3">
|
<widget class="QLineEdit" name="sceneEdit">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="5">
|
|
||||||
<widget class="QPushButton" name="pushButton_4">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>30</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" colspan="5">
|
<item row="4" column="0" colspan="5">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
|
@ -179,15 +157,18 @@
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1" colspan="2">
|
<item row="5" column="1" colspan="2">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Adjustment file :</string>
|
<string>Adjustment file :</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="4">
|
<item row="5" column="4">
|
||||||
<widget class="QLineEdit" name="lineEdit_4">
|
<widget class="QLineEdit" name="adjustmentEdit">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -195,9 +176,9 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="5">
|
<item row="5" column="5">
|
||||||
<widget class="QPushButton" name="pushButton_3">
|
<widget class="QPushButton" name="adjustmentBrowse">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
|
|
@ -326,7 +326,7 @@
|
||||||
encoding to reduce the storage footprint of photons.
|
encoding to reduce the storage footprint of photons.
|
||||||
</descr>
|
</descr>
|
||||||
<param name="directSamples" readableName="Direct samples" type="integer" default="1">Number of luminaire samples for direct illumination</param>
|
<param name="directSamples" readableName="Direct samples" type="integer" default="1">Number of luminaire samples for direct illumination</param>
|
||||||
<param name="glossySamples" readableName="Glossy samples" type="integer" default="1">Number of glossy samples for direct illumination</param>
|
<param name="glossySamples" readableName="Glossy samples" type="integer" default="32">Number of glossy samples for direct illumination</param>
|
||||||
<param name="maxDepth" readableName="Maximum depth" type="integer" default="40">Depth cutoff when tracing photons</param>
|
<param name="maxDepth" readableName="Maximum depth" type="integer" default="40">Depth cutoff when tracing photons</param>
|
||||||
<param name="maxSpecularDepth" readableName="Max. specular bounces" type="integer" default="6">Depth cutoff when recursively tracing specular materials</param>
|
<param name="maxSpecularDepth" readableName="Max. specular bounces" type="integer" default="6">Depth cutoff when recursively tracing specular materials</param>
|
||||||
<param name="granularity" readableName="Work unit granularity" importance="1" type="integer" default="1000">Granularity of photon tracing work units (in shot particles)</param>
|
<param name="granularity" readableName="Work unit granularity" importance="1" type="integer" default="1000">Granularity of photon tracing work units (in shot particles)</param>
|
||||||
|
|
Loading…
Reference in New Issue