support face normals in the preview

metadata
Wenzel Jakob 2010-10-16 04:01:21 +02:00
parent 4afd9afb25
commit 781006c968
12 changed files with 107 additions and 244 deletions

View File

@ -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'])

View File

@ -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";
}
};

View File

@ -62,7 +62,8 @@ public:
m_renderer->beginDrawingMeshes();
for (unsigned int j=0; j<meshes.size(); j++) {
m_shaderManager->configure(vpl, meshes[j]->getBSDF(),
meshes[j]->getLuminaire(), camPos);
meshes[j]->getLuminaire(), camPos,
!meshes[j]->hasVertexNormals());
m_renderer->drawTriMesh(meshes[j]);
m_shaderManager->unbind();
}

View File

@ -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 != "") {

View File

@ -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<std::string, ProgramAndConfiguration>::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; i<gl_VerticesIn; ++i) {" << endl
<< " gl_Position = gl_PositionIn[i];" << endl
<< " uv = uv_vertex[i];" << endl
<< " vertexColor = vertexColor_vertex[i];" << endl
<< " lightVec = lightVec_vertex[i];" << endl
<< " camVec = camVec_vertex[i];" << endl
<< " EmitVertex();" << endl
<< " }" << endl
<< " EndPrimitive();" << endl
<< "}" << endl;
program->setMaxVertices(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;

View File

@ -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 {

View File

@ -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);

View File

@ -252,7 +252,8 @@ void TriMesh::configure() {
for (size_t i=0; i<m_vertexCount; i++)
m_bsphere.expandBy(m_positions[i]);
computeNormals();
if (m_bsdf->getType() & BSDF::EAnisotropicMaterial && !m_tangents)
if ((m_bsdf->getType() & BSDF::EAnisotropicMaterial
|| m_bsdf->usesRayDifferentials()) && !m_tangents)
computeTangentSpaceBasis();
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/render/scene.h>
#include <mitsuba/hw/gpuprogram.h>
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; i<m_luminaires.size(); ++i)
m_luminaires[i]->decRef();
}
PortalLuminaire(Stream *stream, InstanceManager *manager)
: Luminaire(stream, manager) {
m_shape = static_cast<Shape *>(manager->getInstance(stream));
int luminaireCount = stream->readInt();
for (int i=0; i<luminaireCount; ++i)
addChild("", static_cast<Luminaire *>(manager->getInstance(stream)));
configure();
}
void preprocess(const Scene *scene) {
for (size_t i=0; i<m_luminaires.size(); ++i)
m_luminaires[i]->preprocess(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; i<m_luminaires.size(); ++i)
manager->serialize(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<Luminaire *>(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<Shape *>(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; i<m_luminaires.size(); ++i) {
m_luminaires[i]->configure();
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; i<m_luminaires.size(); ++i)
result += m_luminaires[i]->Le(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; i<m_luminaires.size(); ++i)
result += m_luminaires[i]->Le(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<Luminaire *> m_luminaires;
};
MTS_IMPLEMENT_CLASS_S(PortalLuminaire, false, Luminaire)
MTS_EXPORT_PLUGIN(PortalLuminaire, "Portal luminaire");
MTS_NAMESPACE_END

View File

@ -488,7 +488,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_renderer->beginDrawingMeshes();
for (unsigned int j=0; j<meshes.size(); j++) {
m_shaderManager->configure(vpl, meshes[j]->getBSDF(),
meshes[j]->getLuminaire(), camPos);
meshes[j]->getLuminaire(), camPos, !meshes[j]->hasVertexNormals());
m_renderer->drawTriMesh(meshes[j]);
m_shaderManager->unbind();
}