From a3842d5e2cdb135a34e0f09ecfd10f1259d23497 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Mon, 25 Oct 2010 09:05:30 +0200 Subject: [PATCH] realtime preview: render triangle approximations of analytic shapes --- include/mitsuba/hw/vpl.h | 4 ++ include/mitsuba/render/shape.h | 14 +++++ include/mitsuba/render/trimesh.h | 17 ++++++ src/integrators/vpl/vpl.cpp | 2 +- src/libhw/vpl.cpp | 24 +++++---- src/librender/shape.cpp | 3 ++ src/librender/trimesh.cpp | 44 ++++++++++++++++ src/qtgui/preview.cpp | 2 +- src/shapes/cylinder.cpp | 58 +++++++++++++++++---- src/shapes/hair.cpp | 78 +++++++++++++++++++++++++++- src/shapes/sphere.cpp | 88 ++++++++++++++++++++++++++++++++ 11 files changed, 311 insertions(+), 23 deletions(-) diff --git a/include/mitsuba/hw/vpl.h b/include/mitsuba/hw/vpl.h index ae03efdd..96aa3fd5 100644 --- a/include/mitsuba/hw/vpl.h +++ b/include/mitsuba/hw/vpl.h @@ -55,6 +55,9 @@ public: /// Release bound resources void unbind(); + /// Return all bound triangle meshes + inline const std::vector &getMeshes() const { return m_meshes; } + /// Return the shadow cube map for debugging purposes inline GPUTexture *getShadowMap() { return m_shadowMap; } @@ -268,6 +271,7 @@ private: VPLProgramConfiguration m_targetConfig; ref m_backgroundProgram; VPLDependencyNode m_backgroundDependencies; + std::vector m_meshes; }; MTS_NAMESPACE_END diff --git a/include/mitsuba/render/shape.h b/include/mitsuba/render/shape.h index d2dbe2fc..67c35df4 100644 --- a/include/mitsuba/render/shape.h +++ b/include/mitsuba/render/shape.h @@ -251,10 +251,22 @@ public: */ virtual const AbstractKDTree *getKDTree() const; + /** + * \brief Create a triangle mesh approximation of this shape + * + * This function is used by the realtime preview and + * certain integrators, which rely on hardware rasterization. + * + * The default implementation simply returns \a NULL. + */ + virtual ref createTriMesh(); + /// Return the shape's BSDF inline const BSDF *getBSDF() const { return m_bsdf.get(); } /// Return the shape's BSDF inline BSDF *getBSDF() { return m_bsdf.get(); } + /// Set the BSDF of this shape + inline void setBSDF(BSDF *bsdf) { m_bsdf = bsdf; } /// Return the name of this shape virtual std::string getName() const; @@ -272,6 +284,8 @@ public: inline Luminaire *getLuminaire() { return m_luminaire; } /// Return the associated luminaire (if any) inline const Luminaire *getLuminaire() const { return m_luminaire.get(); } + /// Set the luminaire of this shape + inline void setLuminaire(Luminaire *luminaire) { m_luminaire = luminaire; } /// Called once after parsing virtual void configure(); diff --git a/include/mitsuba/render/trimesh.h b/include/mitsuba/render/trimesh.h index 1bb8ad8c..1dbc1c78 100644 --- a/include/mitsuba/render/trimesh.h +++ b/include/mitsuba/render/trimesh.h @@ -22,6 +22,9 @@ #include #include #include +#include + +namespace fs = boost::filesystem; MTS_NAMESPACE_BEGIN @@ -115,6 +118,20 @@ public: /// Return the number of vertices inline size_t getVertexCount() const { return m_vertexCount; } + + /** + * \brief Create a triangle mesh approximation of this shape + * + * Since instances are already triangle meshes, the implementation + * just returns a pointer to \a this. + */ + ref createTriMesh(); + + /// Export an Wavefront OBJ version of this file + void writeOBJ(const fs::path &path) const; + + /// Return the shape's BSDF + inline const BSDF *getBSDF() const { return m_bsdf.get(); } /// Sample a point on the mesh Float sampleArea(ShapeSamplingRecord &sRec, const Point2 &sample) const; diff --git a/src/integrators/vpl/vpl.cpp b/src/integrators/vpl/vpl.cpp index 473320b6..b7c8b1fa 100644 --- a/src/integrators/vpl/vpl.cpp +++ b/src/integrators/vpl/vpl.cpp @@ -56,7 +56,7 @@ public: Transform projectionTransform = camera->getGLProjectionTransform(jitter); m_renderer->setCamera(projectionTransform.getMatrix(), camera->getViewTransform().getMatrix()); Transform clipToWorld = camera->getViewTransform().inverse() * projectionTransform.inverse(); - const std::vector meshes = scene->getMeshes(); + const std::vector meshes = m_shaderManager->getMeshes(); Point camPos = scene->getCamera()->getPosition(); m_renderer->beginDrawingMeshes(); diff --git a/src/libhw/vpl.cpp b/src/libhw/vpl.cpp index 1108a8d2..e9560293 100644 --- a/src/libhw/vpl.cpp +++ b/src/libhw/vpl.cpp @@ -115,14 +115,19 @@ void VPLShaderManager::init() { m_altShadowProgramParam_depthVec = m_altShadowProgram->getParameterID("depthVec"); - const std::vector meshes = m_scene->getMeshes(); + const std::vector shapes = m_scene->getShapes(); const std::vector luminaires = m_scene->getLuminaires(); - for (size_t i=0; iregisterGeometry(meshes[i]); - Shader *shader = m_renderer->registerShaderForResource(meshes[i]->getBSDF()); + for (size_t i=0; i triMesh = shapes[i]->createTriMesh(); + if (!triMesh) + continue; + m_renderer->registerGeometry(triMesh); + Shader *shader = m_renderer->registerShaderForResource(triMesh->getBSDF()); if (shader != NULL && !shader->isComplete()) - m_renderer->unregisterShaderForResource(meshes[i]->getBSDF()); + m_renderer->unregisterShaderForResource(triMesh->getBSDF()); + triMesh->incRef(); + m_meshes.push_back(triMesh); } for (size_t i=0; i meshes = m_scene->getMeshes(); const std::vector luminaires = m_scene->getLuminaires(); - for (size_t i=0; iunregisterGeometry(meshes[i]); - m_renderer->unregisterShaderForResource(meshes[i]->getBSDF()); + for (size_t i=0; iunregisterGeometry(m_meshes[i]); + m_renderer->unregisterShaderForResource(m_meshes[i]->getBSDF()); + m_meshes[i]->decRef(); } + m_meshes.clear(); for (size_t i=0; iunregisterShaderForResource(luminaires[i]); m_initialized = false; diff --git a/src/librender/shape.cpp b/src/librender/shape.cpp index e43fbc56..876726a7 100644 --- a/src/librender/shape.cpp +++ b/src/librender/shape.cpp @@ -146,6 +146,9 @@ Float Shape::pdfArea(const ShapeSamplingRecord &sRec) const { return 0.0f; } +ref Shape::createTriMesh() { + return NULL; +} std::string ShapeSamplingRecord::toString() const { std::ostringstream oss; diff --git a/src/librender/trimesh.cpp b/src/librender/trimesh.cpp index d5267f19..a4750601 100644 --- a/src/librender/trimesh.cpp +++ b/src/librender/trimesh.cpp @@ -465,6 +465,10 @@ void TriMesh::computeTangentSpaceBasis() { m_name.c_str(), zeroArea, zeroNormals); } +ref TriMesh::createTriMesh() { + return this; +} + void TriMesh::serialize(Stream *stream, InstanceManager *manager) const { Shape::serialize(stream, manager); uint32_t flags = 0; @@ -497,6 +501,46 @@ void TriMesh::serialize(Stream *stream, InstanceManager *manager) const { m_triangleCount * sizeof(Triangle)/sizeof(uint32_t)); } +void TriMesh::writeOBJ(const fs::path &path) const { + fs::ofstream os(path); + os << "o " << m_name << endl; + for (size_t i=0; i stream = _stream; diff --git a/src/qtgui/preview.cpp b/src/qtgui/preview.cpp index 77541662..3d87ecd2 100644 --- a/src/qtgui/preview.cpp +++ b/src/qtgui/preview.cpp @@ -463,7 +463,7 @@ void PreviewThread::run() { } void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) { - const std::vector meshes = m_context->scene->getMeshes(); + const std::vector meshes = m_shaderManager->getMeshes(); m_shaderManager->setVPL(vpl); diff --git a/src/shapes/cylinder.cpp b/src/shapes/cylinder.cpp index 7c0712c5..d2fe0cdc 100644 --- a/src/shapes/cylinder.cpp +++ b/src/shapes/cylinder.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include MTS_NAMESPACE_BEGIN @@ -373,24 +374,59 @@ public: return clippedAABB; } -#if 0 - inline AABB getAABB(Float start, Float end) const { - AABB result; - const Float r = m_radius; - const Point a = m_objectToWorld(Point(0, 0, start)); - const Point b = m_objectToWorld(Point(0, 0, end)); + ref createTriMesh() { + /// Choice of discretization + const size_t phiSteps = 20; + const Float dPhi = (2*M_PI) / phiSteps; + ref mesh = new TriMesh("Cylinder approximation", + phiSteps*2, phiSteps*2, true, false, false); + + Point *vertices = mesh->getVertexPositions(); + Normal *normals = mesh->getVertexNormals(); + Triangle *triangles = mesh->getTriangles(); + size_t triangleIdx = 0, vertexIdx = 0; + + for (size_t phi=0; phisetBSDF(m_bsdf); + mesh->setLuminaire(m_luminaire); + mesh->configure(); + + return mesh.get(); + } + +#if 0 + AABB getAABB() const { + const Point a = m_objectToWorld(Point(0, 0, 0)); + const Point b = m_objectToWorld(Point(0, 0, m_length)); + + const Float r = m_radius; + AABB result; result.expandBy(a - Vector(r, r, r)); result.expandBy(a + Vector(r, r, r)); result.expandBy(b - Vector(r, r, r)); result.expandBy(b + Vector(r, r, r)); return result; } - - AABB getAABB() const { - /* Very approximate .. */ - return getAABB(0, m_length); - } #endif Float getSurfaceArea() const { diff --git a/src/shapes/hair.cpp b/src/shapes/hair.cpp index 51034c0f..2a464a13 100644 --- a/src/shapes/hair.cpp +++ b/src/shapes/hair.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -46,9 +47,10 @@ public: for (size_t i=0; i m_vertices; std::vector m_vertexStartsFiber; std::vector m_segIndex; + size_t m_segmentCount; Float m_radius; }; @@ -366,6 +374,74 @@ public: its.shape = this; } + ref createTriMesh() { + /// Choice of discretization + const size_t phiSteps = 6; + const Float dPhi = (2*M_PI) / phiSteps; + + size_t nSegments = m_kdtree->getSegmentCount(); + ref mesh = new TriMesh("Hair mesh approximation", + phiSteps*2*nSegments, phiSteps*2*nSegments, true, false, false); + + Point *vertices = mesh->getVertexPositions(); + Normal *normals = mesh->getVertexNormals(); + Triangle *triangles = mesh->getTriangles(); + size_t triangleIdx = 0, vertexIdx = 0; + + const std::vector &hairVertices = m_kdtree->getVertices(); + const std::vector &vertexStartsFiber = m_kdtree->getStartFiber(); + const Float radius = m_kdtree->getRadius(); + Float *cosPhi = new Float[phiSteps]; + Float *sinPhi = new Float[phiSteps]; + for (size_t i=0; itangent(iv); + Vector dir = Normal(Frame(tangent).toWorld( + Vector(cosPhi[phi], sinPhi[phi], 0))); + Normal miterNormal1 = m_kdtree->firstMiterNormal(iv); + Normal miterNormal2 = m_kdtree->secondMiterNormal(iv); + Float t1 = dot(miterNormal1, radius*dir) / dot(miterNormal1, tangent); + Float t2 = dot(miterNormal2, radius*dir) / dot(miterNormal2, tangent); + + normals[vertexIdx] = Normal(dir); + vertices[vertexIdx++] = m_kdtree->firstVertex(iv) + radius*dir - tangent*t1; + normals[vertexIdx] = Normal(dir); + vertices[vertexIdx++] = m_kdtree->secondVertex(iv) + radius*dir - tangent*t2; + + int idx0 = 2*(phi + hairIdx*phiSteps), idx1 = idx0+1; + int idx2 = (2*phi+2) % (2*phiSteps) + 2*hairIdx*phiSteps, idx3 = idx2+1; + triangles[triangleIdx].idx[0] = idx0; + triangles[triangleIdx].idx[1] = idx2; + triangles[triangleIdx].idx[2] = idx1; + triangleIdx++; + triangles[triangleIdx].idx[0] = idx1; + triangles[triangleIdx].idx[1] = idx2; + triangles[triangleIdx].idx[2] = idx3; + triangleIdx++; + } + hairIdx++; + } + } + Assert(triangleIdx == phiSteps*2*nSegments); + Assert(vertexIdx == phiSteps*2*nSegments); + + delete[] cosPhi; + delete[] sinPhi; + + mesh->setBSDF(m_bsdf); + mesh->setLuminaire(m_luminaire); + mesh->configure(); + + return mesh.get(); + } + const AbstractKDTree *getKDTree() const { return m_kdtree.get(); } diff --git a/src/shapes/sphere.cpp b/src/shapes/sphere.cpp index 1a0746e0..c87d6c97 100644 --- a/src/shapes/sphere.cpp +++ b/src/shapes/sphere.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include MTS_NAMESPACE_BEGIN @@ -257,6 +258,93 @@ public: Float cosThetaMax = std::sqrt(std::max((Float) 0, 1 - squareTerm*squareTerm)); return squareToConePdf(cosThetaMax); } + + ref createTriMesh() { + /// Choice of discretization + const size_t thetaSteps = 20; + const size_t phiSteps = thetaSteps * 2; + const Float dTheta = M_PI / (thetaSteps-1); + const Float dPhi = (2*M_PI) / phiSteps; + size_t topIdx = (thetaSteps-2) * phiSteps, botIdx = topIdx+1; + + /// Precompute cosine and sine tables + Float *cosPhi = new Float[phiSteps]; + Float *sinPhi = new Float[phiSteps]; + for (size_t i=0; i mesh = new TriMesh("Sphere approximation", + numTris, botIdx+1, true, false, false); + + Point *vertices = mesh->getVertexPositions(); + Normal *normals = mesh->getVertexNormals(); + Triangle *triangles = mesh->getTriangles(); + size_t vertexIdx = 0; + for (size_t theta=1; thetasetBSDF(m_bsdf); + mesh->setLuminaire(m_luminaire); + mesh->configure(); + + return mesh.get(); + } std::string toString() const { std::ostringstream oss;