significant rehaul of the dielectric.cpp implementation. Fixed some OpenGL errors on MacOS X

metadata
Wenzel Jakob 2011-07-01 18:54:46 +02:00
parent cb3dcdb377
commit 7c5f924fad
6 changed files with 214 additions and 116 deletions

View File

@ -17,17 +17,24 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/sampler.h>
#include <mitsuba/render/consttexture.h>
MTS_NAMESPACE_BEGIN
const bool importanceSampleComponents = true;
/**
/*! \plugin{dielectric}{Ideal dielectric/glass material}
*
* \parameters{
* \parameter{intIOR}{\Float}{Interior index of refraction \default{1.5046}}
* \parameter{extIOR}{\Float}{Exterior index of refraction \default{1.0}}
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
* factor used to modulate the reflectance component\default{1.0}}
* \parameter{specular\showbreak Transmittance}{\Spectrum\Or\Texture}{Optional
* factor used to modulate the transmittance component\default{1.0}}
* }
*
* Models an interface between two materials with non-matched indices of refraction.
* The microscopic surface structure is assumed to be perfectly flat, resulting
* in a BSDF equal to a Dirac delta function.
*
* The default settings are set to a borosilicate glass BK7/air interface.
*/
class Dielectric : public BSDF {
@ -38,10 +45,11 @@ public:
m_intIOR = props.getFloat("intIOR", 1.5046f);
/* Specifies the external index of refraction at the interface */
m_extIOR = props.getFloat("extIOR", 1);
/* Reflectance modulation term */
m_reflectance = props.getSpectrum("specularReflectance", Spectrum(1.0f));
/* Transmittance modulation term */
m_transmittance = props.getSpectrum("specularTransmittance", Spectrum(1.0f));
m_specularReflectance = new ConstantSpectrumTexture(
props.getSpectrum("specularReflectance", Spectrum(1.0f)));
m_specularTransmittance = new ConstantSpectrumTexture(
props.getSpectrum("specularTransmittance", Spectrum(1.0f)));
m_componentCount = 2;
m_type = new unsigned int[m_componentCount];
@ -55,8 +63,8 @@ public:
: BSDF(stream, manager) {
m_intIOR = stream->readFloat();
m_extIOR = stream->readFloat();
m_transmittance = Spectrum(stream);
m_reflectance = Spectrum(stream);
m_specularReflectance = static_cast<Texture *>(manager->getInstance(stream));
m_specularTransmittance = static_cast<Texture *>(manager->getInstance(stream));
m_componentCount = 2;
m_type = new unsigned int[m_componentCount];
@ -75,8 +83,8 @@ public:
stream->writeFloat(m_intIOR);
stream->writeFloat(m_extIOR);
m_transmittance.serialize(stream);
m_reflectance.serialize(stream);
manager->serialize(stream, m_specularReflectance.get());
manager->serialize(stream, m_specularTransmittance.get());
}
Spectrum getDiffuseReflectance(const Intersection &its) const {
@ -91,101 +99,187 @@ public:
return 0.0f;
}
inline void reflect(const Vector &wo, Vector &wi) const {
wi = Vector(-wo.x, -wo.y, wo.z);
/// Reflection in local coordinates
inline Vector reflect(const Vector &wi) const {
return Vector(-wi.x, -wi.y, wi.z);
}
Float refract(Float intIOR, Float extIOR,
const Vector &wi, Vector &wo, ETransportQuantity quantity) const {
Float cosThetaI = Frame::cosTheta(wi),
etaI = extIOR, etaT = intIOR;
bool entering = cosThetaI > 0.0f;
if (!entering)
std::swap(etaT, etaI);
Float eta = etaI / etaT;
/* Using Snell's law, calculate the squared sine of the
angle between the normal and the transmitted ray */
Float sinThetaTSqr = eta*eta * Frame::sinTheta2(wi);
if (sinThetaTSqr > 1.0f) /* Total internal reflection! */
return 0.0f;
Float cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
if (entering)
cosThetaT = -cosThetaT;
/* With cos(N, transmittedRay) avilable, calculating the
transmission direction is straightforward */
wo = Vector(-eta*wi.x, -eta*wi.y, cosThetaT);
/* Finally compute transmission coefficient. When transporting
radiance, account for the solid angle change at boundaries
with different indices of refraction. */
if (quantity == ERadiance)
return (etaI*etaI) / (etaT*etaT);
else
return 1.0f;
/// Refraction in local coordinates
inline Vector refract(const Vector &wi, Float eta, Float cosThetaT) const {
return Vector(-eta*wi.x, -eta*wi.y, cosThetaT);
}
inline Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
Float pdf = 0;
Spectrum spec = Dielectric::sample(bRec, pdf, sample);
if (pdf == 0 || spec.isZero())
return Spectrum(0.0f);
return spec/pdf;
}
inline Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const {
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
bool sampleReflection = (bRec.typeMask & EDeltaReflection)
&& (bRec.component == -1 || bRec.component == 0);
bool sampleTransmission = (bRec.typeMask & EDeltaTransmission)
&& (bRec.component == -1 || bRec.component == 1);
if (!sampleTransmission && !sampleReflection)
return Spectrum(0.0f);
Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR);
Float cosThetaI = Frame::cosTheta(bRec.wi),
etaI = m_extIOR,
etaT = m_intIOR;
bool entering = cosThetaI > 0.0f;
/* Determine the respective indices of refraction */
if (!entering)
std::swap(etaI, etaT);
/* Using Snell's law, calculate the squared sine of the
angle between the normal and the transmitted ray */
Float eta = etaI / etaT,
sinThetaTSqr = eta*eta * Frame::sinTheta2(bRec.wi);
Float Fr, cosThetaT = 0;
if (sinThetaTSqr >= 1.0f) {
/* Total internal reflection */
Fr = 1.0f;
} else {
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
/* Compute the Fresnel refletance */
Fr = fresnelDielectric(std::abs(cosThetaI),
cosThetaT, etaI, etaT);
if (entering)
cosThetaT = -cosThetaT;
}
/* Calculate the refracted/reflected vectors+coefficients */
if (sampleTransmission && sampleReflection) {
/* Importance sample according to the reflectance/transmittance */
if (sample.x < (importanceSampleComponents ? fr : 0.5f)) {
reflect(bRec.wi, bRec.wo);
if (sample.x <= Fr) {
bRec.sampledComponent = 0;
bRec.sampledType = EDeltaReflection;
pdf = (importanceSampleComponents ? fr : 0.5f) * std::abs(Frame::cosTheta(bRec.wo));
/* Cancel out the cosine term */
return m_reflectance * fr;
bRec.wo = reflect(bRec.wi);
return m_specularReflectance->getValue(bRec.its)
/ std::abs(Frame::cosTheta(bRec.wo));
} else {
pdf = importanceSampleComponents ? (1-fr) : 0.5f;
bRec.sampledComponent = 1;
bRec.sampledType = EDeltaTransmission;
Float result = refract(m_intIOR, m_extIOR, bRec.wi, bRec.wo, bRec.quantity);
if (result == 0)
return Spectrum(0.0f);
pdf *= std::abs(Frame::cosTheta(bRec.wo));
/* Given cos(N, transmittedRay), compute the
transmitted direction */
bRec.wo = refract(bRec.wi, eta, cosThetaT);
return m_transmittance * result * (1-fr);
/* When transporting radiance, account for the solid angle
change at boundaries with different indices of refraction. */
return m_specularTransmittance->getValue(bRec.its)
* (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1)
/ std::abs(Frame::cosTheta(bRec.wo));
}
} else if (sampleReflection) {
reflect(bRec.wi, bRec.wo);
bRec.sampledComponent = 0;
bRec.sampledType = EDeltaReflection;
pdf = std::abs(Frame::cosTheta(bRec.wo));
return m_reflectance * fr;
} else if (sampleTransmission) {
bRec.wo = reflect(bRec.wi);
return m_specularReflectance->getValue(bRec.its) * (Fr
/ std::abs(Frame::cosTheta(bRec.wo)));
} else {
bRec.sampledComponent = 1;
bRec.sampledType = EDeltaTransmission;
Float result = refract(m_intIOR, m_extIOR, bRec.wi, bRec.wo, bRec.quantity);
pdf = std::abs(Frame::cosTheta(bRec.wo));
if (result == 0)
if (Fr == 1.0f) /* Total internal reflection */
return Spectrum(0.0f);
return m_transmittance * result * (1-fr);
bRec.wo = refract(bRec.wi, eta, cosThetaT);
/* When transporting radiance, account for the solid angle
change at boundaries with different indices of refraction. */
return m_specularTransmittance->getValue(bRec.its)
* ((1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1))
/ std::abs(Frame::cosTheta(bRec.wo));
}
}
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const {
bool sampleReflection = (bRec.typeMask & EDeltaReflection)
&& (bRec.component == -1 || bRec.component == 0);
bool sampleTransmission = (bRec.typeMask & EDeltaTransmission)
&& (bRec.component == -1 || bRec.component == 1);
if (!sampleTransmission && !sampleReflection)
return Spectrum(0.0f);
Float cosThetaI = Frame::cosTheta(bRec.wi),
etaI = m_extIOR,
etaT = m_intIOR;
bool entering = cosThetaI > 0.0f;
/* Determine the respective indices of refraction */
if (!entering)
std::swap(etaI, etaT);
/* Using Snell's law, calculate the squared sine of the
angle between the normal and the transmitted ray */
Float eta = etaI / etaT,
sinThetaTSqr = eta*eta * Frame::sinTheta2(bRec.wi);
Float Fr, cosThetaT = 0;
if (sinThetaTSqr >= 1.0f) {
/* Total internal reflection */
Fr = 1.0f;
} else {
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
/* Compute the Fresnel refletance */
Fr = fresnelDielectric(std::abs(cosThetaI),
cosThetaT, etaI, etaT);
if (entering)
cosThetaT = -cosThetaT;
}
/* Calculate the refracted/reflected vectors+coefficients */
if (sampleTransmission && sampleReflection) {
/* Importance sample according to the reflectance/transmittance */
if (sample.x <= Fr) {
bRec.sampledComponent = 0;
bRec.sampledType = EDeltaReflection;
bRec.wo = reflect(bRec.wi);
pdf = Fr * std::abs(Frame::cosTheta(bRec.wo));
return m_specularReflectance->getValue(bRec.its) * Fr;
} else {
bRec.sampledComponent = 1;
bRec.sampledType = EDeltaTransmission;
/* Given cos(N, transmittedRay), compute the
transmitted direction */
bRec.wo = refract(bRec.wi, eta, cosThetaT);
pdf = (1-Fr) * std::abs(Frame::cosTheta(bRec.wo));
/* When transporting radiance, account for the solid angle
change at boundaries with different indices of refraction. */
return m_specularTransmittance->getValue(bRec.its)
* (1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1);
}
} else if (sampleReflection) {
bRec.sampledComponent = 0;
bRec.sampledType = EDeltaReflection;
bRec.wo = reflect(bRec.wi);
pdf = std::abs(Frame::cosTheta(bRec.wo));
return m_specularReflectance->getValue(bRec.its) * Fr;
} else {
bRec.sampledComponent = 1;
bRec.sampledType = EDeltaTransmission;
if (Fr == 1.0f) /* Total internal reflection */
return Spectrum(0.0f);
bRec.wo = refract(bRec.wi, eta, cosThetaT);
pdf = std::abs(Frame::cosTheta(bRec.wo));
/* When transporting radiance, account for the solid angle
change at boundaries with different indices of refraction. */
return m_specularTransmittance->getValue(bRec.its)
* ((1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1));
}
return Spectrum(0.0f);
}
Float pdfDelta(const BSDFQueryRecord &bRec) const {
@ -197,12 +291,8 @@ public:
Float result = 0.0f;
if (sampleTransmission && sampleReflection) {
if (!importanceSampleComponents) {
result = 0.5f;
} else {
Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR);
result = reflection ? fr : (1-fr);
}
Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR);
result = reflection ? fr : (1-fr);
} else if (sampleReflection) {
result = reflection ? 1.0f : 0.0f;
} else if (sampleTransmission) {
@ -225,7 +315,7 @@ public:
return Spectrum(0.0f);
if (reflection) {
return m_reflectance * fr;
return m_specularReflectance->getValue(bRec.its) * fr;
} else {
Float etaI = m_extIOR, etaT = m_intIOR;
bool entering = Frame::cosTheta(bRec.wi) > 0.0f;
@ -235,7 +325,7 @@ public:
Float factor = (bRec.quantity == ERadiance)
? (etaI*etaI) / (etaT*etaT) : 1.0f;
return m_transmittance * factor * (1 - fr);
return m_specularTransmittance->getValue(bRec.its) * factor * (1 - fr);
}
}
@ -245,8 +335,8 @@ public:
oss << "Dielectric[" << endl
<< " intIOR = " << m_intIOR << "," << endl
<< " extIOR = " << m_extIOR << "," << endl
<< " reflectance = " << m_reflectance.toString() << "," << endl
<< " transmittance = " << m_transmittance.toString() << endl
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << "," << endl
<< " specularTransmittance = " << indent(m_specularTransmittance->toString()) << endl
<< "]";
return oss.str();
}
@ -254,8 +344,8 @@ public:
MTS_DECLARE_CLASS()
private:
Float m_intIOR, m_extIOR;
Spectrum m_reflectance;
Spectrum m_transmittance;
ref<Texture> m_specularTransmittance;
ref<Texture> m_specularReflectance;
};

View File

@ -33,14 +33,14 @@ MTS_NAMESPACE_BEGIN
* Gaussian random surfaces. This is the default choice.
* \item \code{phong}: Classical $\cos^p\theta$ distribution.
* The Phong exponent $p$ is obtained using a transformation that
* produces roughness similar to a Beckmann distribution with the same
* produces roughness similar to a Beckmann distribution of the same
* parameter. Note that due to the underlying microfacet theory,
* the use of this distribution here leads to more realistic
* behavior than the separately available \pluginref{phong} plugin.
* \item \code{ggx}: New distribution proposed by
* Walter et al. meant to better handle the long
* tails observed in transmission measurements through
* ground glass.
* ground glass.
* \end{enumerate}
* Default: \code{beckmann}
* }
@ -51,11 +51,11 @@ MTS_NAMESPACE_BEGIN
* \default{0.1}
* }
* \parameter{intIOR}{\Float}{Interior index of refraction \default{1.5046}}
* \parameter{extIOR}{\Float}{Exterior index of refraction \default{1}}
* \parameter{extIOR}{\Float}{Exterior index of refraction \default{1.0}}
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
* factor used to modulate the reflectance component\default{1}}
* factor used to modulate the reflectance component\default{1.0}}
* \parameter{specular\showbreak Transmittance}{\Spectrum\Or\Texture}{Optional
* factor used to modulate the transmittance component\default{0.9}}
* factor used to modulate the transmittance component\default{1.0}}
* }
*
* This plugin implements a realistic microfacet scattering model for rendering
@ -66,18 +66,14 @@ MTS_NAMESPACE_BEGIN
* these facets, it is possible to reproduce the off-specular reflections
* peaks observed in measurements of real-world materials.
*
* This plugin is essentially the ``roughened'' equivalent of the
* plugin \pluginref{dielectric}. The model supports several types of
* microfacet distributions and a texturable roughness.
* The default settings are set to a borosilicate glass BK7/air interface
* with a light amount of rougness modeled by a Beckmann distribution.
*
* The implementation is based on the paper ``Microfacet Models for Refraction
* through Rough Surfaces'' \cite{Walter07Microfacet}. It furthermore uses an
* improved sampling technique presented in \cite{Zhao11Building} when given
* access to an arbitrarily long stream of random numbers.
* This plugin is essentially the ``roughened'' equivalent of the plugin
* \pluginref{dielectric}. Its implementation is based on the paper
* ``Microfacet Models for Refraction through Rough Surfaces''
* \cite{Walter07Microfacet}. The model supports several types of microfacet
* distributions and a texturable roughness. The default settings are set
* to a borosilicate glass BK7/air interface with a light amount of rougness
* modeled using a Beckmann distribution.
*/
class RoughGlass : public BSDF {
public:
//// Microfacet distribution types supported by the model
@ -95,7 +91,7 @@ public:
m_specularReflectance = new ConstantSpectrumTexture(
props.getSpectrum("specularReflectance", Spectrum(1.0f)));
m_specularTransmittance = new ConstantSpectrumTexture(
props.getSpectrum("specularTransmittance", Spectrum(0.9f)));
props.getSpectrum("specularTransmittance", Spectrum(1.9f)));
Float alpha;
if (props.hasProperty("alphaB")) {
@ -229,13 +225,13 @@ public:
case EGGX: {
/* Empirical GGX distribution function for rough surfaces */
const Float tanTheta = Frame::tanTheta(m);
const Float cosTheta = Frame::cosTheta(m);
const Float tanTheta = Frame::tanTheta(m),
cosTheta = Frame::cosTheta(m);
const Float root = alpha / (cosTheta*cosTheta *
(alpha*alpha + tanTheta*tanTheta));
result = INV_PI * (root*root);
result = INV_PI * (root * root);
}
break;

View File

@ -705,12 +705,12 @@ Float fresnel(Float cosThetaI, Float etaExt, Float etaInt) {
Float etaI = etaExt, etaT = etaInt;
/* Swap the indices of refraction if the interaction starts
at the inside of the object */
at the inside of the object */
if (cosThetaI < 0.0f)
std::swap(etaI, etaT);
/* Using Snell's law, calculate the sine of the angle
between the transmitted ray and the surface normal */
between the transmitted ray and the surface normal */
Float sinThetaT = etaI / etaT *
std::sqrt(std::max((Float) 0.0f, 1.0f - cosThetaI*cosThetaI));

View File

@ -29,11 +29,15 @@ MTS_NAMESPACE_BEGIN
GLProgram::GLProgram(const std::string &name)
: GPUProgram(name) {
m_id[0] = m_id[1] = m_program = 0;
m_id[EVertexProgram] = 0;
m_id[EFragmentProgram] = 0;
m_id[EGeometryProgram] = 0;
m_program = 0;
}
void GLProgram::init() {
Assert(m_id[0] == 0 && m_id[1] == 0 && m_program == 0);
Assert(m_id[EVertexProgram] == 0 && m_id[EFragmentProgram] == 0
&& m_id[EGeometryProgram] == 0 && m_program == 0);
Log(EDebug, "Uploading a GPU program : %s", toString().c_str());
if (!GLEW_ARB_shader_objects)

View File

@ -534,6 +534,7 @@ void GLRenderer::drawAll(const std::vector<std::pair<const GPUGeometry *, Transf
GLRenderer::beginDrawingMeshes(true);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
std::vector<std::pair<const GPUGeometry *, Transform> >::const_iterator it;
if (m_capabilities->isSupported(RendererCapabilities::EBindless)) {
for (it = geo.begin(); it != geo.end(); ++it) {
@ -577,7 +578,6 @@ void GLRenderer::drawAll(const std::vector<std::pair<const GPUGeometry *, Transf
finish();
}
}
glPopMatrix();
}
} else {
for (it = geo.begin(); it != geo.end(); ++it) {
@ -616,7 +616,6 @@ void GLRenderer::drawAll(const std::vector<std::pair<const GPUGeometry *, Transf
finish();
}
}
glPopMatrix();
}
}
GLRenderer::endDrawingMeshes();
@ -633,6 +632,10 @@ void GLRenderer::blitTexture(const GPUTexture *tex, bool flipVertically,
glGetIntegerv(GL_VIEWPORT, viewport);
Vector2i scrSize = Vector2i(viewport[2], viewport[3]);
Vector2i texSize = Vector2i(tex->getSize().x, tex->getSize().y);
if (scrSize.x == 0 || scrSize.y == 0) {
tex->unbind();
return;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

View File

@ -23,6 +23,11 @@ SceneInformationDialog::SceneInformationDialog(QWidget *parent, Scene *scene) :
QDialog(parent),
ui(new Ui::SceneInformationDialog) {
ui->setupUi(this);
#if defined(__OSX__)
QFont font = ui->textEdit->currentFont();
font.setPointSize(12);
ui->textEdit->setCurrentFont(font);
#endif
ui->textEdit->setText(scene->toString().c_str());
}