From 9fed7118bf220ed7f3d16e24232f35f78ab9069e Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 18 Aug 2010 17:28:27 +0200 Subject: [PATCH] better obj parsing & gui scene saving support - do a better job at parsing OBJs with multiple objects - correctly save XML scenes when there is no integrator or sampler --- include/mitsuba/render/trimesh.h | 5 + src/librender/scene.cpp | 6 +- src/librender/shape.cpp | 2 +- src/librender/trimesh.cpp | 14 +- src/luminaires/area.cpp | 13 +- src/mitsuba/shandler.h | 4 +- src/qtgui/save.cpp | 17 +-- src/shapes/obj.cpp | 214 ++++++++++++++++++++++--------- 8 files changed, 193 insertions(+), 82 deletions(-) diff --git a/include/mitsuba/render/trimesh.h b/include/mitsuba/render/trimesh.h index b166d1ec..b8cf6780 100644 --- a/include/mitsuba/render/trimesh.h +++ b/include/mitsuba/render/trimesh.h @@ -14,6 +14,11 @@ public: /// Create a new, empty triangle mesh with the given triangle and vertex count TriMesh(size_t triangleCount, size_t vertexCount); + /// Create a new, empty triangle mesh with the specified data + TriMesh(const std::string &name, Transform worldToObject, + Triangle *triangles, size_t triangleCount, + Vertex *vertexBuffer, size_t vertexCount); + /// Unserialize a triangle mesh TriMesh(Stream *stream, InstanceManager *manager); diff --git a/src/librender/scene.cpp b/src/librender/scene.cpp index 2643c98d..da67deb8 100644 --- a/src/librender/scene.cpp +++ b/src/librender/scene.cpp @@ -184,13 +184,17 @@ void Scene::configure() { m_integrator->configure(); } if (m_camera == NULL) { - Log(EWarn, "No camera found -- adding a default camera"); + Log(EWarn, "No camera found! Adding a default camera."); Properties props("perspective"); /* Create a perspective camera with 45deg. FOV, which can see the whole scene */ AABB aabb; for (size_t i=0; igetAABB()); + for (size_t i=0; igetAABB()); + if (!aabb.isValid()) + Log(EError, "Unable to set up a default camera -- does the scene contain anything at all?"); Point center = aabb.getCenter(); Vector extents = aabb.getExtents(); Float maxExtents = std::max(extents.x, extents.y); diff --git a/src/librender/shape.cpp b/src/librender/shape.cpp index eec97fd9..44e9be93 100644 --- a/src/librender/shape.cpp +++ b/src/librender/shape.cpp @@ -91,7 +91,7 @@ void Shape::addChild(const std::string &name, ConfigurableObject *child) { Log(EError, "Shape: Invalid child node!"); } } - + /// Ray intersection test bool Shape::rayIntersect(const Ray &ray, Intersection &its) const { Log(EError, "Not implemented!"); diff --git a/src/librender/trimesh.cpp b/src/librender/trimesh.cpp index 53df96aa..59974880 100644 --- a/src/librender/trimesh.cpp +++ b/src/librender/trimesh.cpp @@ -8,10 +8,20 @@ MTS_NAMESPACE_BEGIN TriMesh::TriMesh(size_t triangleCount, size_t vertexCount) - : Shape(Properties()), m_triangleCount(triangleCount), m_vertexCount(vertexCount) { + : Shape(Properties()), m_triangleCount(triangleCount), + m_vertexCount(vertexCount), m_flipNormals(false) { m_triangles = new Triangle[m_triangleCount]; m_vertexBuffer = new Vertex[m_vertexCount]; - m_flipNormals = false; +} + +TriMesh::TriMesh(const std::string &name, Transform worldToObject, Triangle *triangles, + size_t triangleCount, Vertex *vertexBuffer, size_t vertexCount) + : Shape(Properties()), m_triangles(triangles), m_triangleCount(triangleCount), + m_vertexBuffer(vertexBuffer), m_vertexCount(vertexCount), m_flipNormals(false) { + m_name = name; + m_worldToObject = worldToObject; + m_objectToWorld.inverse(); + } TriMesh::TriMesh(const Properties &props) diff --git a/src/luminaires/area.cpp b/src/luminaires/area.cpp index 3422ad7f..bf3e03f5 100644 --- a/src/luminaires/area.cpp +++ b/src/luminaires/area.cpp @@ -117,10 +117,17 @@ public: } void setParent(ConfigurableObject *parent) { - ConfigurableObject::setParent(parent); - if (parent->getClass()->derivesFrom(Shape::m_theClass)) { - m_shape = static_cast(parent); + Shape *shape = static_cast(parent); + if (shape->isCompound()) + return; + + if (m_parent) + Log(EError, "An area light source cannot be parent of multiple shapes"); + + ConfigurableObject::setParent(shape); + + m_shape = shape; parent->configure(); m_surfaceArea = m_shape->getSurfaceArea(); } else { diff --git a/src/mitsuba/shandler.h b/src/mitsuba/shandler.h index 3f581236..29988f95 100644 --- a/src/mitsuba/shandler.h +++ b/src/mitsuba/shandler.h @@ -39,9 +39,9 @@ public: inline Scene *getScene() { return m_scene; } inline std::string transcode(const XMLCh * const xmlName) const { - const char *value = XMLString::transcode(xmlName); + char *value = XMLString::transcode(xmlName); std::string result(value); - delete[] value; + XMLString::release(&value); return result; } diff --git a/src/qtgui/save.cpp b/src/qtgui/save.cpp index 4f6a8aee..bdb25c05 100644 --- a/src/qtgui/save.cpp +++ b/src/qtgui/save.cpp @@ -164,7 +164,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) { QDomElement newSampler, sampler = findUniqueChild(camera, "sampler"); if (sampler.isNull()) { newSampler = doc.createElement("sampler"); - camera.appendChild(sampler); + camera.appendChild(newSampler); } else { newSampler = doc.createElement("sampler"); camera.insertAfter(newSampler, sampler); @@ -224,16 +224,13 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) { // ==================================================================== QDomElement oldIntegratorNode = findUniqueChild(root, "integrator"); - if (oldIntegratorNode.isNull()) { - QMessageBox::critical(parent, parent->tr("Unable to save"), - parent->tr("Unable to save changes: could not find the integrator descriptor in " - "%1. If you are using include files, make sure that the integrator " - "descriptor is located within the main scene file.").arg(ctx->fileName), - QMessageBox::Ok); - return; - } - QDomElement newIntegratorNode = doc.createElement("integrator"); + if (oldIntegratorNode.isNull()) { + film.appendChild(oldIntegratorNode); + } else { + film.insertAfter(newIntegratorNode, oldIntegratorNode); + film.removeChild(oldIntegratorNode); + } const Integrator *integrator = ctx->scene->getIntegrator(); setProperties(doc, newIntegratorNode, integrator->getProperties()); diff --git a/src/shapes/obj.cpp b/src/shapes/obj.cpp index 20978a41..5af598d2 100644 --- a/src/shapes/obj.cpp +++ b/src/shapes/obj.cpp @@ -29,9 +29,10 @@ public: std::vector normals; std::vector texcoords; std::vector triangles; + bool hasNormals = false, hasTexcoords = false; + bool firstVertex = true; - bool hasNormals = false; - bool hasTexCoords = false; + std::string name = m_name; while (is >> buf) { if (buf == "v") { @@ -39,6 +40,18 @@ public: Point p; is >> p.x >> p.y >> p.z; vertices.push_back(m_objectToWorld(p)); + if (firstVertex) { + if (triangles.size() > 0) { + generateGeometry(name, vertices, normals, texcoords, + triangles, hasNormals, hasTexcoords); + triangles.clear(); + } + hasNormals = false; + hasTexcoords = false; + firstVertex = false; + } + } else if (buf == "mtllib") { + cout << "Got mtllib" << endl; } else if (buf == "vn") { Normal n; is >> n.x >> n.y >> n.z; @@ -47,18 +60,23 @@ public: else normals.push_back(n); hasNormals = true; + } else if (buf == "g") { + std::string line; + std::getline(is, line); + name = line.substr(1, line.length()-2); } else if (buf == "vt") { std::string line; Float u, v, w; std::getline(is, line); std::istringstream iss(line); iss >> u >> v >> w; - hasTexCoords = true; texcoords.push_back(Point2(u, v)); + hasTexcoords = true; } else if (buf == "f") { std::string line, tmp; std::getline(is, line); std::istringstream iss(line); + firstVertex = true; OBJTriangle t; iss >> tmp; parse(t, 0, tmp); iss >> tmp; parse(t, 1, tmp); @@ -74,66 +92,8 @@ public: } } - std::vector vertexBuffer(vertices.size()); - std::vector touched(vertices.size()); - for (unsigned int i=0; i &vertices, + const std::vector &normals, + const std::vector &texcoords, + const std::vector &triangles, + bool hasNormals, bool hasTexcoords) { + if (triangles.size() == 0) + return; + Log(EInfo, "Creating geometry \"%s\"", name.c_str()); + std::vector vertexBuffer(vertices.size()); + std::vector touched(vertices.size()); + for (unsigned int i=0; i mesh = new TriMesh(name, m_worldToObject, triangleArray, + triangles.size(), vertexArray, vertexBuffer.size()); + mesh->incRef(); + mesh->calculateTangentSpaceBasis(hasNormals, hasTexcoords); + m_meshes.push_back(mesh); + } + + WavefrontOBJ(Stream *stream, InstanceManager *manager) : TriMesh(stream, manager) { + } + + virtual ~WavefrontOBJ() { + for (size_t i=0; idecRef(); + } + + void configure() { + Shape::configure(); + + m_aabb.reset(); + for (size_t i=0; iconfigure(); + m_aabb.expandBy(m_meshes[i]->getAABB()); + } + } + + void addChild(const std::string &name, ConfigurableObject *child) { + const Class *cClass = child->getClass(); + if (cClass->derivesFrom(BSDF::m_theClass)) { + m_bsdf = static_cast(child); + for (size_t i=0; iaddChild(name, child); + } else if (cClass->derivesFrom(Luminaire::m_theClass)) { + Assert(m_luminaire == NULL && m_meshes.size() == 1); + m_luminaire = static_cast(child); + for (size_t i=0; isetParent(m_meshes[i]); + m_meshes[i]->addChild(name, child); + } + } else if (cClass->derivesFrom(Subsurface::m_theClass)) { + Assert(m_subsurface == NULL); + m_subsurface = static_cast(child); + for (size_t i=0; isetParent(m_meshes[i]); + m_meshes[i]->addChild(name, child); + } + } else { + Shape::addChild(name, child); + } + } + + bool isCompound() const { + return true; + } + + Shape *getElement(int index) { + if (index >= (int) m_meshes.size()) + return NULL; + return m_meshes[index]; + } + MTS_DECLARE_CLASS() +private: + std::vector m_meshes; }; MTS_IMPLEMENT_CLASS_S(WavefrontOBJ, false, TriMesh)