From 781006c9684ba936e2bd5dd3b7cc2f65d55ab248 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 16 Oct 2010 04:01:21 +0200 Subject: [PATCH] support face normals in the preview --- SConstruct | 1 - include/mitsuba/hw/vpl.h | 10 +- src/integrators/vpl/vpl.cpp | 3 +- src/libhw/glprogram.cpp | 11 +- src/libhw/vpl.cpp | 84 ++++++++++--- src/librender/intersection.cpp | 4 +- src/librender/preview.cpp | 16 ++- src/librender/trimesh.cpp | 3 +- src/luminaires/constant.cpp | 2 +- src/luminaires/directional.cpp | 3 +- src/luminaires/portal.cpp | 212 --------------------------------- src/qtgui/preview.cpp | 2 +- 12 files changed, 107 insertions(+), 244 deletions(-) delete mode 100644 src/luminaires/portal.cpp diff --git a/SConstruct b/SConstruct index dc260cdf..6d43bcb4 100644 --- a/SConstruct +++ b/SConstruct @@ -579,7 +579,6 @@ plugins += env.SharedLibrary('plugins/spot', ['src/luminaires/spot.cpp']) plugins += env.SharedLibrary('plugins/point', ['src/luminaires/point.cpp']) plugins += env.SharedLibrary('plugins/collimated', ['src/luminaires/collimated.cpp']) plugins += env.SharedLibrary('plugins/directional', ['src/luminaires/directional.cpp']) -plugins += env.SharedLibrary('plugins/portal', ['src/luminaires/portal.cpp']) # Integrators plugins += env.SharedLibrary('plugins/direct', ['src/integrators/direct/direct.cpp']) diff --git a/include/mitsuba/hw/vpl.h b/include/mitsuba/hw/vpl.h index 1dc737e2..ae03efdd 100644 --- a/include/mitsuba/hw/vpl.h +++ b/include/mitsuba/hw/vpl.h @@ -47,7 +47,7 @@ public: /// Prepare for rendering a material with BSDF 'bsdf' illuminated by VPL 'vpl'. void configure(const VPL &vpl, const BSDF *bsdf, - const Luminaire *luminaire, const Point &camPos); + const Luminaire *luminaire, const Point &camPos, bool faceNormals); /// Draw the background if there is an environment luminaire void drawBackground(const Transform &clipToWorld, const Point &camPos); @@ -171,7 +171,7 @@ private: struct VPLProgramConfiguration { VPLDependencyNode vpl, bsdf, luminaire; - bool hasLuminaire; + bool hasLuminaire, faceNormals; int param_shadowMap, param_vplPos, param_camPos, param_vplPower; int param_vplN, param_vplS, param_vplT, param_vplWi, param_vplUV; int param_nearClip, param_invClipRange, param_minDist; @@ -179,8 +179,8 @@ private: inline VPLProgramConfiguration() { } - inline VPLProgramConfiguration(Shader *vpl, Shader *bsdf, Shader *luminaire) - : vpl(vpl), bsdf(bsdf), luminaire(luminaire) { + inline VPLProgramConfiguration(Shader *vpl, Shader *bsdf, Shader *luminaire, bool faceNormals) + : vpl(vpl), bsdf(bsdf), luminaire(luminaire), faceNormals(faceNormals) { hasLuminaire = (luminaire != NULL); } @@ -224,6 +224,8 @@ private: oss << ", luminaire="; luminaire.toString(oss); } + if (faceNormals) + oss << ", faceNormals"; } }; diff --git a/src/integrators/vpl/vpl.cpp b/src/integrators/vpl/vpl.cpp index 935dcd96..473320b6 100644 --- a/src/integrators/vpl/vpl.cpp +++ b/src/integrators/vpl/vpl.cpp @@ -62,7 +62,8 @@ public: m_renderer->beginDrawingMeshes(); for (unsigned int j=0; jconfigure(vpl, meshes[j]->getBSDF(), - meshes[j]->getLuminaire(), camPos); + meshes[j]->getLuminaire(), camPos, + !meshes[j]->hasVertexNormals()); m_renderer->drawTriMesh(meshes[j]); m_shaderManager->unbind(); } diff --git a/src/libhw/glprogram.cpp b/src/libhw/glprogram.cpp index 99ebc8d3..785ec8f5 100644 --- a/src/libhw/glprogram.cpp +++ b/src/libhw/glprogram.cpp @@ -97,8 +97,17 @@ int GLProgram::createShader(int type, const std::string &source) { glGetObjectParameterivARB(id, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { cleanup(); + std::string typeStr; + if (type == GL_VERTEX_SHADER_ARB) + typeStr = "vertex"; + else if (type == GL_FRAGMENT_SHADER_ARB) + typeStr = "fragment"; + else if (type == GL_GEOMETRY_SHADER_ARB) + typeStr = "geometry"; + else + typeStr = "unknown"; if (infoLog != "") - Log(EError, "Error compiling a shader: %s", infoLog.c_str()); + Log(EError, "Error compiling a %s shader: %s", typeStr.c_str(), infoLog.c_str()); else Log(EError, "Unknown error encountered while compiling a shader!"); } else if (infoLog != "") { diff --git a/src/libhw/vpl.cpp b/src/libhw/vpl.cpp index 16ce9d75..1108a8d2 100644 --- a/src/libhw/vpl.cpp +++ b/src/libhw/vpl.cpp @@ -281,7 +281,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) { } void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, - const Luminaire *luminaire, const Point &camPos) { + const Luminaire *luminaire, const Point &camPos, bool faceNormals) { Shader *bsdfShader = m_renderer->getShaderForResource(bsdf); Shader *vplShader = (vpl.type == ELuminaireVPL) ? m_renderer->getShaderForResource(vpl.luminaire) @@ -300,7 +300,8 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, bool anisotropic = bsdf->getType() & BSDF::EAnisotropicMaterial; - m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader, lumShader); + m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader, + lumShader, faceNormals); m_targetConfig.toString(oss); std::string configName = oss.str(); std::map::iterator it = @@ -315,24 +316,79 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, /* No program for this particular combination exists -- create one */ program = m_renderer->createGPUProgram(configName); + if (faceNormals) { + /* Generate face normals in a geometry shader */ + + if (!m_renderer->getCapabilities()->isSupported( + RendererCapabilities::EGeometryShaders)) + Log(EError, "Face normals require geometry shader support!"); + if (anisotropic) + Log(EError, "Anisotropy and face normals can't be combined at the moment"); + + oss.str(""); + oss << "#version 120" << endl + << "#extension GL_EXT_geometry_shader4 : enable" << endl + << "varying in vec3 lightVec_vertex[3], camVec_vertex[3];" << endl + << "varying in vec2 uv_vertex[3];" << endl + << "varying in vec3 vertexColor_vertex[3];" << endl + << "varying out vec3 normal;" << endl + << "varying out vec3 lightVec, camVec;" << endl + << "varying out vec2 uv;" << endl + << "varying out vec3 vertexColor;" << endl + << endl + << "void main() {" << endl + << " normal = normalize(cross(" << endl + << " gl_PositionIn[1].xyz-gl_PositionIn[0].xyz," << endl + << " gl_PositionIn[2].xyz-gl_PositionIn[0].xyz));" << endl + << " for (int i=0; isetMaxVertices(3); + program->setSource(GPUProgram::EGeometryProgram, oss.str()); + } + /* Vertex program */ oss.str(""); oss << "#version 120" << endl; if (anisotropic) oss << "varying vec3 tangent;" << endl; + if (!faceNormals) + oss << "varying vec3 normal;" << endl; + oss << "uniform vec3 vplPos, camPos;" << endl; - oss << "uniform vec3 vplPos, camPos;" << endl - << "varying vec3 normal, lightVec, camVec;" << endl - << "varying vec2 uv;" << endl - << "varying vec3 vertexColor;" << endl - << endl - << "void main() {" << endl - << " normal = gl_Normal;" << endl - << " uv = gl_MultiTexCoord0.xy;" << endl - << " camVec = camPos - gl_Vertex.xyz;" << endl - << " lightVec = vplPos - gl_Vertex.xyz;" << endl - << " gl_Position = ftransform();" << endl - << " vertexColor = gl_Color.rgb;" << endl; + if (!faceNormals) { + oss << "varying vec3 lightVec, camVec;" << endl + << "varying vec2 uv;" << endl + << "varying vec3 vertexColor;" << endl + << endl + << "void main() {" << endl + << " uv = gl_MultiTexCoord0.xy;" << endl + << " camVec = camPos - gl_Vertex.xyz;" << endl + << " lightVec = vplPos - gl_Vertex.xyz;" << endl + << " gl_Position = ftransform();" << endl + << " vertexColor = gl_Color.rgb;" << endl; + } else { + oss << "varying vec3 lightVec_vertex, camVec_vertex;" << endl + << "varying vec2 uv_vertex;" << endl + << "varying vec3 vertexColor_vertex;" << endl + << endl + << "void main() {" << endl + << " uv_vertex = gl_MultiTexCoord0.xy;" << endl + << " camVec_vertex = camPos - gl_Vertex.xyz;" << endl + << " lightVec_vertex = vplPos - gl_Vertex.xyz;" << endl + << " gl_Position = ftransform();" << endl + << " vertexColor_vertex = gl_Color.rgb;" << endl; + } + if (!faceNormals) + oss << " normal = gl_Normal;" << endl; if (anisotropic) oss << " tangent = gl_MultiTexCoord1.xyz;" << endl; oss << "}" << endl; diff --git a/src/librender/intersection.cpp b/src/librender/intersection.cpp index 0a8517ce..69bdd4ef 100644 --- a/src/librender/intersection.cpp +++ b/src/librender/intersection.cpp @@ -52,14 +52,14 @@ void Intersection::computePartials(const RayDifferential &ray) { A[0][1] = dpdv[axes[0]]; A[1][0] = dpdu[axes[1]]; A[1][1] = dpdv[axes[1]]; - + /* Auxilary intersection point of the adjacent rays */ Point px = ray.rx(tx), py = ray.ry(ty); Bx[0] = px[axes[0]] - p[axes[0]]; Bx[1] = px[axes[1]] - p[axes[1]]; By[0] = py[axes[0]] - p[axes[0]]; By[1] = py[axes[1]] - p[axes[1]]; - + if (EXPECT_TAKEN(solveLinearSystem2x2(A, Bx, x))) { dudx = x[0]; dvdx = x[1]; } else { diff --git a/src/librender/preview.cpp b/src/librender/preview.cpp index 696901fa..4168f265 100644 --- a/src/librender/preview.cpp +++ b/src/librender/preview.cpp @@ -312,7 +312,11 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe &p1 = positions[idx1], &p2 = positions[idx2]; Vector sideA = p1 - p0, sideB = p2 - p0; - its.shFrame.n = Normal(cross(sideA, sideB)); + Vector n = cross(sideA, sideB); + Float nLengthSqr = n.lengthSquared(); + if (nLengthSqr != 0) + n /= std::sqrt(nLengthSqr); + its.shFrame.n = Normal(n); } if (EXPECT_TAKEN(texcoords)) { @@ -369,9 +373,13 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe its.p.x = secRay4.o[0].f[idx]; its.p.y = secRay4.o[1].f[idx]; its.p.z = secRay4.o[2].f[idx]; - its.shFrame.s = normalize(its.dpdu - its.shFrame.n - * dot(its.shFrame.n, its.dpdu)); - its.shFrame.t = cross(its.shFrame.n, its.shFrame.s); + if (EXPECT_NOT_TAKEN(bsdf->getType() & BSDF::EAnisotropicMaterial)) { + its.shFrame.s = normalize(its.dpdu - its.shFrame.n + * dot(its.shFrame.n, its.dpdu)); + its.shFrame.t = cross(its.shFrame.n, its.shFrame.s); + } else { + coordinateSystem(its.shFrame.n, its.shFrame.s, its.shFrame.t); + } const Float ctLight = cosThetaLight.f[idx]; wi = normalize(wi); diff --git a/src/librender/trimesh.cpp b/src/librender/trimesh.cpp index 56f08b73..97d2eb4f 100644 --- a/src/librender/trimesh.cpp +++ b/src/librender/trimesh.cpp @@ -252,7 +252,8 @@ void TriMesh::configure() { for (size_t i=0; igetType() & BSDF::EAnisotropicMaterial && !m_tangents) + if ((m_bsdf->getType() & BSDF::EAnisotropicMaterial + || m_bsdf->usesRayDifferentials()) && !m_tangents) computeTangentSpaceBasis(); } diff --git a/src/luminaires/constant.cpp b/src/luminaires/constant.cpp index 58af8b19..2ee5136f 100644 --- a/src/luminaires/constant.cpp +++ b/src/luminaires/constant.cpp @@ -28,7 +28,7 @@ class ConstantLuminaire : public Luminaire { public: ConstantLuminaire(const Properties &props) : Luminaire(props) { m_intensity = props.getSpectrum("intensity", Spectrum(1.0f)); - m_type = EOnSurface; + m_type = EOnSurface | EDiffuseDirection; } ConstantLuminaire(Stream *stream, InstanceManager *manager) diff --git a/src/luminaires/directional.cpp b/src/luminaires/directional.cpp index 97199c0b..37fab3d0 100644 --- a/src/luminaires/directional.cpp +++ b/src/luminaires/directional.cpp @@ -67,7 +67,7 @@ public: Spectrum Le(const LuminaireSamplingRecord &lRec) const { /* Directional luminaire is not part of the scene */ - Log(EWarn, "This function should never be called."); + Log(EError, "This function should never be called."); return Spectrum(0.0f); } @@ -123,7 +123,6 @@ public: Spectrum f(const EmissionRecord &eRec) const { /* Directional luminaire beam is not part of the scene */ - Log(EWarn, "This function should never be called."); return Spectrum(0.0f); } diff --git a/src/luminaires/portal.cpp b/src/luminaires/portal.cpp deleted file mode 100644 index 32f03c2f..00000000 --- a/src/luminaires/portal.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - This file is part of Mitsuba, a physically based rendering system. - - Copyright (c) 2007-2010 by Wenzel Jakob and others. - - Mitsuba is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License Version 3 - as published by the Free Software Foundation. - - Mitsuba is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include - -MTS_NAMESPACE_BEGIN - -/** - * Portal luminaire -- can be used to turn a surface into a - * portal that exposes luminaires behind it, such as an - * environment map. This is often necessary to make interior - * lighting work efficiently enough when using algorithms like - * path tracing or photon mapping. - */ -class PortalLuminaire : public Luminaire { -public: - PortalLuminaire(const Properties &props) : Luminaire(props), m_shape(NULL) { - AssertEx(m_luminaireToWorld.isIdentity(), "Error: non-identity transformation found. " - "Portal luminaires inherit their transformation from the associated shape!"); - m_type = EDiffuseDirection | EOnSurface; - m_intersectable = true; - } - - virtual ~PortalLuminaire() { - for (size_t i=0; idecRef(); - } - - PortalLuminaire(Stream *stream, InstanceManager *manager) - : Luminaire(stream, manager) { - m_shape = static_cast(manager->getInstance(stream)); - int luminaireCount = stream->readInt(); - for (int i=0; i(manager->getInstance(stream))); - configure(); - } - - void preprocess(const Scene *scene) { - for (size_t i=0; ipreprocess(scene); - configure(); - } - - void serialize(Stream *stream, InstanceManager *manager) const { - Luminaire::serialize(stream, manager); - - manager->serialize(stream, m_shape); - stream->writeInt((int) m_luminaires.size()); - for (size_t i=0; iserialize(stream, m_luminaires[i]); - } - - void addChild(const std::string &name, ConfigurableObject *child) { - const Class *cClass = child->getClass(); - if (cClass->derivesFrom(Luminaire::m_theClass)) { - Luminaire *luminaire = static_cast(child); - m_luminaires.push_back(luminaire); - luminaire->incRef(); - } else { - Luminaire::addChild(name, child); - } - } - - void setParent(ConfigurableObject *parent) { - ConfigurableObject::setParent(parent); - - if (parent->getClass()->derivesFrom(Shape::m_theClass)) { - m_shape = static_cast(parent); - parent->configure(); - m_surfaceArea = m_shape->getSurfaceArea(); - } else { - Log(EError, "A portal light source must be child of a shape instance"); - } - } - - void configure() { - m_power = Spectrum(0.0f); - if (m_luminaires.size() == 0) - Log(EError, "Portal luminaire must have one or more child luminaires!"); - for (size_t i=0; iconfigure(); - m_power += m_luminaires[i]->getPower(); - } - } - - Spectrum getPower() const { - return m_power; - } - - Spectrum Le(const EmissionRecord &eRec) const { - Spectrum result(0.0f); - - if (dot(eRec.d, eRec.sRec.n) <= 0) - return Spectrum(0.0f); - - for (size_t i=0; iLe(Ray(eRec.sRec.p, -eRec.d)); - - return result; - } - - Spectrum Le(const LuminaireSamplingRecord &lRec) const { - Spectrum result(0.0f); - - if (dot(lRec.d, lRec.sRec.n) <= 0) - return Spectrum(0.0f); - - for (size_t i=0; iLe(Ray(lRec.sRec.p, -lRec.d)); - - return result; - } - - inline void sample(const Point &p, LuminaireSamplingRecord &lRec, - const Point2 &sample) const { - lRec.pdf = m_shape->sampleSolidAngle(lRec.sRec, p, sample); - lRec.d = p - lRec.sRec.p; - - if (EXPECT_TAKEN(lRec.pdf > 0 && dot(lRec.d, lRec.sRec.n) > 0)) { - lRec.d = normalize(lRec.d); - lRec.Le = Le(lRec); - } else { - lRec.pdf = 0; - } - } - - inline void sample(const Intersection &its, LuminaireSamplingRecord &lRec, - const Point2 &sample) const { - PortalLuminaire::sample(its.p, lRec, sample); - } - - inline Float pdf(const Point &p, const LuminaireSamplingRecord &lRec) const { - return m_shape->pdfSolidAngle(lRec.sRec, p); - } - - Float pdf(const Intersection &its, const LuminaireSamplingRecord &lRec) const { - return pdf(its.p, lRec); - } - - void sampleEmission(EmissionRecord &eRec, - const Point2 &sample1, const Point2 &sample2) const { - eRec.pdfArea = m_shape->sampleArea(eRec.sRec, sample1); - Vector wo = squareToHemispherePSA(sample2); - eRec.pdfDir = Frame::cosTheta(wo) * INV_PI; - eRec.d = Frame(eRec.sRec.n).toWorld(wo); - eRec.P = Le(eRec); - } - - void sampleEmissionArea(EmissionRecord &eRec, const Point2 &sample) const { - eRec.pdfArea = m_shape->sampleArea(eRec.sRec, sample); - eRec.P = Spectrum(1.0f); - } - - Spectrum fArea(const EmissionRecord &eRec) const { - return Spectrum(1.0f); - } - - Spectrum sampleEmissionDirection(EmissionRecord &eRec, const Point2 &sample) const { - Vector wo = squareToHemispherePSA(sample); - eRec.d = Frame(eRec.sRec.n).toWorld(wo); - eRec.pdfDir = Frame::cosTheta(wo) * INV_PI; - return Le(eRec); - } - - Spectrum f(const EmissionRecord &eRec) const { - Float dp = dot(eRec.sRec.n, eRec.d); - if (dp > 0) - return Le(eRec); - else - return Spectrum(0.0f); - } - - void pdfEmission(EmissionRecord &eRec) const { - Float dp = dot(eRec.sRec.n, eRec.d); - if (dp > 0) - eRec.pdfDir = dp * INV_PI; - else { - eRec.pdfDir = 0; - } - eRec.pdfArea = m_shape->pdfArea(eRec.sRec); - } - - std::string toString() const { - return "PortalLuminaire[]"; - } - - MTS_DECLARE_CLASS() -private: - const Shape *m_shape; - Spectrum m_power; - std::vector m_luminaires; -}; - -MTS_IMPLEMENT_CLASS_S(PortalLuminaire, false, Luminaire) -MTS_EXPORT_PLUGIN(PortalLuminaire, "Portal luminaire"); -MTS_NAMESPACE_END diff --git a/src/qtgui/preview.cpp b/src/qtgui/preview.cpp index 9a8f5227..97237fd5 100644 --- a/src/qtgui/preview.cpp +++ b/src/qtgui/preview.cpp @@ -488,7 +488,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) { m_renderer->beginDrawingMeshes(); for (unsigned int j=0; jconfigure(vpl, meshes[j]->getBSDF(), - meshes[j]->getLuminaire(), camPos); + meshes[j]->getLuminaire(), camPos, !meshes[j]->hasVertexNormals()); m_renderer->drawTriMesh(meshes[j]); m_shaderManager->unbind(); }