approximate GLSL shader for the rough coating
parent
a535eaf3ae
commit
1a5d962c4f
|
@ -2,6 +2,17 @@
|
||||||
to be tested for consistency. This is done
|
to be tested for consistency. This is done
|
||||||
using the testcase 'test_chisquare' -->
|
using the testcase 'test_chisquare' -->
|
||||||
<scene version="0.3.0">
|
<scene version="0.3.0">
|
||||||
|
<bsdf type="roughcoating">
|
||||||
|
<!--
|
||||||
|
<bsdf type="roughconductor">
|
||||||
|
<string name="distribution" value="beckmann"/>
|
||||||
|
<float name="alpha" value=".3"/>
|
||||||
|
</bsdf>
|
||||||
|
-->
|
||||||
|
<bsdf type="diffuse"/>
|
||||||
|
<float name="alpha" value=".3"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
<!-- Test the smooth diffuse model -->
|
<!-- Test the smooth diffuse model -->
|
||||||
<bsdf type="diffuse"/>
|
<bsdf type="diffuse"/>
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,8 @@ public:
|
||||||
Float probNested, probSpecular;
|
Float probNested, probSpecular;
|
||||||
if (hasSpecular && hasNested) {
|
if (hasSpecular && hasNested) {
|
||||||
/* Find the probability of sampling the specular component */
|
/* Find the probability of sampling the specular component */
|
||||||
probSpecular = 1-m_roughTransmittance->eval(std::abs(Frame::cosTheta(bRec.wi)));
|
probSpecular = 1-m_roughTransmittance->eval(
|
||||||
|
std::abs(Frame::cosTheta(bRec.wi)));
|
||||||
|
|
||||||
/* Reallocate samples */
|
/* Reallocate samples */
|
||||||
probSpecular = (probSpecular*m_specularSamplingWeight) /
|
probSpecular = (probSpecular*m_specularSamplingWeight) /
|
||||||
|
@ -271,7 +272,7 @@ public:
|
||||||
Float result = 0.0f;
|
Float result = 0.0f;
|
||||||
if (hasSpecular && Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) > 0) {
|
if (hasSpecular && Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) > 0) {
|
||||||
/* Jacobian of the half-direction transform */
|
/* Jacobian of the half-direction transform */
|
||||||
const Float dwh_dwo = 1.0f / (4.0f * dot(bRec.wo, H));
|
const Float dwh_dwo = 1.0f / (4.0f * absDot(bRec.wo, H));
|
||||||
|
|
||||||
/* Evaluate the microsurface normal distribution */
|
/* Evaluate the microsurface normal distribution */
|
||||||
const Float prob = m_distribution.pdf(H, m_alpha);
|
const Float prob = m_distribution.pdf(H, m_alpha);
|
||||||
|
@ -284,15 +285,15 @@ public:
|
||||||
bRecInt.wi = refractTo(EInterior, bRec.wi);
|
bRecInt.wi = refractTo(EInterior, bRec.wi);
|
||||||
bRecInt.wo = refractTo(EInterior, bRec.wo);
|
bRecInt.wo = refractTo(EInterior, bRec.wo);
|
||||||
|
|
||||||
Float pdf = m_nested->pdf(bRecInt, measure);
|
Float prob = m_nested->pdf(bRecInt, measure);
|
||||||
|
|
||||||
if (measure == ESolidAngle) {
|
if (measure == ESolidAngle) {
|
||||||
Float eta = m_extIOR / m_intIOR;
|
Float eta = m_extIOR / m_intIOR;
|
||||||
pdf *= eta * eta * Frame::cosTheta(bRec.wo)
|
prob *= eta * eta * Frame::cosTheta(bRec.wo)
|
||||||
/ Frame::cosTheta(bRecInt.wo);
|
/ Frame::cosTheta(bRecInt.wo);
|
||||||
}
|
}
|
||||||
|
|
||||||
result += pdf * probNested;
|
result += prob * probNested;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -310,7 +311,7 @@ public:
|
||||||
Float probSpecular;
|
Float probSpecular;
|
||||||
if (hasSpecular && hasNested) {
|
if (hasSpecular && hasNested) {
|
||||||
/* Find the probability of sampling the diffuse component */
|
/* Find the probability of sampling the diffuse component */
|
||||||
probSpecular = 1 - m_roughTransmittance->eval(Frame::cosTheta(bRec.wi));
|
probSpecular = 1 - m_roughTransmittance->eval(std::abs(Frame::cosTheta(bRec.wi)));
|
||||||
|
|
||||||
/* Reallocate samples */
|
/* Reallocate samples */
|
||||||
probSpecular = (probSpecular*m_specularSamplingWeight) /
|
probSpecular = (probSpecular*m_specularSamplingWeight) /
|
||||||
|
@ -336,18 +337,25 @@ public:
|
||||||
if (Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) <= 0)
|
if (Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) <= 0)
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
} else {
|
} else {
|
||||||
bRec.sampledComponent = 1;
|
Vector wiBackup = bRec.wi;
|
||||||
bRec.sampledType = EDiffuseReflection;
|
bRec.wi = refractTo(EInterior, bRec.wi);
|
||||||
bRec.wo = squareToHemispherePSA(sample);
|
Spectrum result = m_nested->sample(bRec, _pdf, sample);
|
||||||
|
bRec.wi = wiBackup;
|
||||||
|
if (result.isZero())
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
bRec.wo = refractTo(EExterior, bRec.wo);
|
||||||
|
if (bRec.wo.isZero())
|
||||||
|
return Spectrum(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guard against numerical imprecisions */
|
/* Guard against numerical imprecisions */
|
||||||
_pdf = pdf(bRec, ESolidAngle);
|
EMeasure measure = getMeasure(bRec.sampledType);
|
||||||
|
_pdf = pdf(bRec, measure);
|
||||||
|
|
||||||
if (_pdf == 0)
|
if (_pdf == 0)
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
else
|
else
|
||||||
return eval(bRec, ESolidAngle) / _pdf;
|
return eval(bRec, measure) / _pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
|
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
|
||||||
|
@ -396,7 +404,7 @@ public:
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shader *createShader(Renderer *renderer) const;
|
Shader *createShader(Renderer *renderer) const;
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
|
@ -408,7 +416,7 @@ private:
|
||||||
Float m_specularSamplingWeight;
|
Float m_specularSamplingWeight;
|
||||||
Float m_thickness;
|
Float m_thickness;
|
||||||
};
|
};
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* GLSL port of the rough coating shader. This version is much more
|
* GLSL port of the rough coating shader. This version is much more
|
||||||
* approximate -- it only supports the Beckmann distribution,
|
* approximate -- it only supports the Beckmann distribution,
|
||||||
|
@ -432,6 +440,7 @@ public:
|
||||||
m_sigmaAShader = renderer->registerShaderForResource(m_sigmaA.get());
|
m_sigmaAShader = renderer->registerShaderForResource(m_sigmaA.get());
|
||||||
m_alpha = std::max(m_alpha, (Float) 0.2f);
|
m_alpha = std::max(m_alpha, (Float) 0.2f);
|
||||||
m_R0 = fresnel(1.0f, m_extIOR, m_intIOR);
|
m_R0 = fresnel(1.0f, m_extIOR, m_intIOR);
|
||||||
|
m_eta = extIOR / intIOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isComplete() const {
|
bool isComplete() const {
|
||||||
|
@ -450,20 +459,43 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve(const GPUProgram *program, const std::string &evalName, std::vector<int> ¶meterIDs) const {
|
void resolve(const GPUProgram *program, const std::string &evalName, std::vector<int> ¶meterIDs) const {
|
||||||
parameterIDs.push_back(program->getParameterID(evalName + "_alpha", false));
|
|
||||||
parameterIDs.push_back(program->getParameterID(evalName + "_R0", false));
|
parameterIDs.push_back(program->getParameterID(evalName + "_R0", false));
|
||||||
|
parameterIDs.push_back(program->getParameterID(evalName + "_eta", false));
|
||||||
|
parameterIDs.push_back(program->getParameterID(evalName + "_alpha", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs, int &textureUnitOffset) const {
|
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs, int &textureUnitOffset) const {
|
||||||
program->setParameter(parameterIDs[0], m_alpha);
|
program->setParameter(parameterIDs[0], m_R0);
|
||||||
program->setParameter(parameterIDs[1], m_R0);
|
program->setParameter(parameterIDs[1], m_eta);
|
||||||
|
program->setParameter(parameterIDs[2], m_alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateCode(std::ostringstream &oss,
|
void generateCode(std::ostringstream &oss,
|
||||||
const std::string &evalName,
|
const std::string &evalName,
|
||||||
const std::vector<std::string> &depNames) const {
|
const std::vector<std::string> &depNames) const {
|
||||||
oss << "uniform float " << evalName << "_alpha;" << endl
|
oss << "uniform float " << evalName << "_R0;" << endl
|
||||||
<< "uniform float " << evalName << "_R0;" << endl
|
<< "uniform float " << evalName << "_eta;" << endl
|
||||||
|
<< "uniform float " << evalName << "_alpha;" << endl
|
||||||
|
<< endl
|
||||||
|
<< "float " << evalName << "_schlick(float ct) {" << endl
|
||||||
|
<< " float ctSqr = ct*ct, ct5 = ctSqr*ctSqr*ct;" << endl
|
||||||
|
<< " return " << evalName << "_R0 + (1.0 - " << evalName << "_R0) * ct5;" << endl
|
||||||
|
<< "}" << endl
|
||||||
|
<< endl
|
||||||
|
<< "vec3 " << evalName << "_refract(vec3 wi, out float T) {" << endl
|
||||||
|
<< " float cosThetaI = cosTheta(wi);" << endl
|
||||||
|
<< " bool entering = cosThetaI > 0.0;" << endl
|
||||||
|
<< " float eta = " << evalName << "_eta;" << endl
|
||||||
|
<< " float sinThetaTSqr = eta * eta * sinTheta2(wi);" << endl
|
||||||
|
<< " if (sinThetaTSqr >= 1.0) {" << endl
|
||||||
|
<< " T = 0.0; /* Total internal reflection */" << endl
|
||||||
|
<< " return vec3(0.0);" << endl
|
||||||
|
<< " } else {" << endl
|
||||||
|
<< " float cosThetaT = sqrt(1.0 - sinThetaTSqr);" << endl
|
||||||
|
<< " T = 1.0 - " << evalName << "_schlick(1.0 - abs(cosThetaI));" << endl
|
||||||
|
<< " return vec3(eta*wi.x, eta*wi.y, entering ? cosThetaT : -cosThetaT);" << endl
|
||||||
|
<< " }" << endl
|
||||||
|
<< "}" << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< "float " << evalName << "_D(vec3 m) {" << endl
|
<< "float " << evalName << "_D(vec3 m) {" << endl
|
||||||
<< " float ct = cosTheta(m);" << endl
|
<< " float ct = cosTheta(m);" << endl
|
||||||
|
@ -484,37 +516,40 @@ public:
|
||||||
<< " abs(2 * nDotM * cosTheta(wi) / dot(wi, m))));" << endl
|
<< " abs(2 * nDotM * cosTheta(wi) / dot(wi, m))));" << endl
|
||||||
<< "}" << endl
|
<< "}" << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< endl
|
|
||||||
<< "float " << evalName << "_schlick(float ct) {" << endl
|
|
||||||
<< " float ctSqr = ct*ct, ct5 = ctSqr*ctSqr*ct;" << endl
|
|
||||||
<< " return " << evalName << "_R0 + (1.0 - " << evalName << "_R0) * ct5;" << endl
|
|
||||||
<< "}" << endl
|
|
||||||
<< endl
|
|
||||||
<< "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
<< "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
<< " if (cosTheta(wi) <= 0 || cosTheta(wo) <= 0)" << endl
|
<< " float T12, T21;" << endl
|
||||||
<< " return vec3(0.0);" << endl
|
<< " vec3 wiPrime = " << evalName << "_refract(wi, T12);" << endl
|
||||||
<< " vec3 H = normalize(wi + wo);" << endl
|
<< " vec3 woPrime = " << evalName << "_refract(wo, T21);" << endl
|
||||||
<< " vec3 specRef = " << depNames[0] << "(uv);" << endl
|
<< " vec3 nested = " << depNames[0] << "(uv, wiPrime, woPrime);" << endl
|
||||||
<< " vec3 diffuseRef = " << depNames[1] << "(uv);" << endl
|
<< " vec3 sigmaA = " << depNames[1] << "(uv);" << endl
|
||||||
<< " float D = " << evalName << "_D(H)" << ";" << endl
|
<< " vec3 result = nested * " << evalName << "_eta * " << evalName << "_eta" << endl
|
||||||
<< " float G = " << evalName << "_G(H, wi, wo);" << endl
|
<< " * T12 * T21 * (cosTheta(wi)*cosTheta(wo)) /" << endl
|
||||||
<< " float F = " << evalName << "_schlick(1-dot(wi, H));" << endl
|
<< " (cosTheta(wiPrime)*cosTheta(woPrime));" << endl
|
||||||
<< " return specRef * (F * D * G / (4*cosTheta(wi))) + " << endl
|
<< " if (sigmaA != vec3(0.0))" << endl
|
||||||
<< " diffuseRef * ((1-F) * cosTheta(wo) * 0.31831);" << endl
|
<< " result *= exp(-sigmaA * (1/abs(cosTheta(wiPrime)) + " << endl
|
||||||
|
<< " 1/abs(cosTheta(woPrime))));" << endl
|
||||||
|
<< " if (cosTheta(wi)*cosTheta(wo) > 0) {" << endl
|
||||||
|
<< " vec3 H = normalize(wi + wo);" << endl
|
||||||
|
<< " float D = " << evalName << "_D(H)" << ";" << endl
|
||||||
|
<< " float G = " << evalName << "_G(H, wi, wo);" << endl
|
||||||
|
<< " float F = " << evalName << "_schlick(1-dot(wi, H));" << endl
|
||||||
|
<< " result += vec3(F * D * G / (4*cosTheta(wi)));" << endl
|
||||||
|
<< " }" << endl
|
||||||
|
<< " return result;" << endl
|
||||||
<< "}" << endl
|
<< "}" << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
<< " vec3 diffuseRef = " << depNames[1] << "(uv);" << endl
|
<< " return " << depNames[0] << "_diffuse(uv, wi, wo);" << endl
|
||||||
<< " return diffuseRef * 0.31831 * cosTheta(wo);"<< endl
|
|
||||||
<< "}" << endl;
|
<< "}" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
ref<const BSDF> m_nested;
|
ref<const BSDF> m_nested;
|
||||||
ref<Shader> m_nestedShader;
|
ref<Shader> m_nestedShader;
|
||||||
ref<const Texture> m_sigmaA;
|
ref<const Texture> m_sigmaA;
|
||||||
ref<Shader> m_sigmaAShader;
|
ref<Shader> m_sigmaAShader;
|
||||||
Float m_alpha, m_extIOR, m_intIOR, m_R0;
|
Float m_alpha, m_extIOR, m_intIOR, m_R0, m_eta;
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader *RoughCoating::createShader(Renderer *renderer) const {
|
Shader *RoughCoating::createShader(Renderer *renderer) const {
|
||||||
|
@ -523,7 +558,6 @@ Shader *RoughCoating::createShader(Renderer *renderer) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS(RoughCoatingShader, false, Shader)
|
MTS_IMPLEMENT_CLASS(RoughCoatingShader, false, Shader)
|
||||||
#endif
|
|
||||||
MTS_IMPLEMENT_CLASS_S(RoughCoating, false, BSDF)
|
MTS_IMPLEMENT_CLASS_S(RoughCoating, false, BSDF)
|
||||||
MTS_EXPORT_PLUGIN(RoughCoating, "Rough coating BSDF");
|
MTS_EXPORT_PLUGIN(RoughCoating, "Rough coating BSDF");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -46,10 +46,14 @@ MTS_NAMESPACE_BEGIN
|
||||||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||||
* \parameter{g}{\Float\Or\String}{Specifies the phase function anisotropy
|
* \parameter{g}{\Float\Or\String}{Specifies the phase function anisotropy
|
||||||
* --- see the \pluginref{hg} plugin for details\default{0, i.e. isotropic}}
|
* --- see the \pluginref{hg} plugin for details\default{0, i.e. isotropic}}
|
||||||
|
* \parameter{alpha}{\Float}{
|
||||||
|
* Specifies the roughness of the unresolved surface micro-geometry.
|
||||||
|
* \default{0.0, i.e. the surface has a smooth finish}
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* This plugin implements a BRDF scattering model that emulates interactions
|
* This plugin implements a BRDF scattering model that emulates interactions
|
||||||
* with a participating medium embedded inside a smooth dielectric layer. By
|
* with a participating medium embedded inside a dielectric layer. By
|
||||||
* approximating these events using a BRDF, any scattered illumination
|
* approximating these events using a BRDF, any scattered illumination
|
||||||
* is assumed to exit the material \emph{directly} at the original point of incidence.
|
* is assumed to exit the material \emph{directly} at the original point of incidence.
|
||||||
* To account for internal light transport with \emph{different} incident
|
* To account for internal light transport with \emph{different} incident
|
||||||
|
@ -60,9 +64,11 @@ MTS_NAMESPACE_BEGIN
|
||||||
* BSDF for single scattering in an infinitely thick layer together with
|
* BSDF for single scattering in an infinitely thick layer together with
|
||||||
* an approximate multiple scattering component based on Jensen's
|
* an approximate multiple scattering component based on Jensen's
|
||||||
* \cite{Jensen2001Practical} integrated dipole BRDF. These are then
|
* \cite{Jensen2001Practical} integrated dipole BRDF. These are then
|
||||||
* embedded into a dielectric layer using the \pluginref{coating} plugin.
|
* embedded into a dielectric layer using either the \pluginref{coating}
|
||||||
|
* or \pluginref{roughcoating} plugins depending on whether or not
|
||||||
|
* \code{alpha}=0.
|
||||||
* This yields a very convenient parameterization of a scattering model
|
* This yields a very convenient parameterization of a scattering model
|
||||||
* that roughly behaves like a coated diffuse material, but expressed
|
* that behaves similarly to a coated diffuse material, but expressed
|
||||||
* in terms of the scattering and absorption coefficients \code{sigmaS}
|
* in terms of the scattering and absorption coefficients \code{sigmaS}
|
||||||
* and \code{sigmaA}.
|
* and \code{sigmaA}.
|
||||||
*/
|
*/
|
||||||
|
@ -79,6 +85,8 @@ public:
|
||||||
Properties hgProps("hg");
|
Properties hgProps("hg");
|
||||||
hgProps.setFloat("g", g);
|
hgProps.setFloat("g", g);
|
||||||
|
|
||||||
|
Float alpha = props.getFloat("alpha", 0.0f);
|
||||||
|
|
||||||
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (
|
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (
|
||||||
PluginManager::getInstance()->createObject(
|
PluginManager::getInstance()->createObject(
|
||||||
MTS_CLASS(PhaseFunction), hgProps));
|
MTS_CLASS(PhaseFunction), hgProps));
|
||||||
|
@ -91,9 +99,11 @@ public:
|
||||||
m_hk->addChild(hg);
|
m_hk->addChild(hg);
|
||||||
|
|
||||||
Properties coatingProps(props);
|
Properties coatingProps(props);
|
||||||
coatingProps.setPluginName("coating");
|
coatingProps.setPluginName(alpha == 0 ? "coating" : "roughcoating");
|
||||||
if (!props.hasProperty("intIOR"))
|
if (!props.hasProperty("intIOR"))
|
||||||
coatingProps.setFloat("intIOR", eta);
|
coatingProps.setFloat("intIOR", eta);
|
||||||
|
if (alpha != 0)
|
||||||
|
coatingProps.setFloat("alpha", alpha);
|
||||||
|
|
||||||
m_coating = static_cast<BSDF *> (PluginManager::getInstance()->
|
m_coating = static_cast<BSDF *> (PluginManager::getInstance()->
|
||||||
createObject(MTS_CLASS(BSDF), coatingProps));
|
createObject(MTS_CLASS(BSDF), coatingProps));
|
||||||
|
@ -116,6 +126,7 @@ public:
|
||||||
props.markQueried("sigmaT");
|
props.markQueried("sigmaT");
|
||||||
props.markQueried("intIOR");
|
props.markQueried("intIOR");
|
||||||
props.markQueried("extIOR");
|
props.markQueried("extIOR");
|
||||||
|
props.markQueried("alpha");
|
||||||
}
|
}
|
||||||
|
|
||||||
SSSBRDF(Stream *stream, InstanceManager *manager)
|
SSSBRDF(Stream *stream, InstanceManager *manager)
|
||||||
|
|
Loading…
Reference in New Issue