approximate GLSL shader for the rough coating
parent
a535eaf3ae
commit
1a5d962c4f
|
@ -2,6 +2,17 @@
|
|||
to be tested for consistency. This is done
|
||||
using the testcase 'test_chisquare' -->
|
||||
<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 -->
|
||||
<bsdf type="diffuse"/>
|
||||
|
||||
|
|
|
@ -256,7 +256,8 @@ public:
|
|||
Float probNested, probSpecular;
|
||||
if (hasSpecular && hasNested) {
|
||||
/* 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 */
|
||||
probSpecular = (probSpecular*m_specularSamplingWeight) /
|
||||
|
@ -271,7 +272,7 @@ public:
|
|||
Float result = 0.0f;
|
||||
if (hasSpecular && Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) > 0) {
|
||||
/* 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 */
|
||||
const Float prob = m_distribution.pdf(H, m_alpha);
|
||||
|
@ -284,15 +285,15 @@ public:
|
|||
bRecInt.wi = refractTo(EInterior, bRec.wi);
|
||||
bRecInt.wo = refractTo(EInterior, bRec.wo);
|
||||
|
||||
Float pdf = m_nested->pdf(bRecInt, measure);
|
||||
Float prob = m_nested->pdf(bRecInt, measure);
|
||||
|
||||
if (measure == ESolidAngle) {
|
||||
Float eta = m_extIOR / m_intIOR;
|
||||
pdf *= eta * eta * Frame::cosTheta(bRec.wo)
|
||||
prob *= eta * eta * Frame::cosTheta(bRec.wo)
|
||||
/ Frame::cosTheta(bRecInt.wo);
|
||||
}
|
||||
|
||||
result += pdf * probNested;
|
||||
result += prob * probNested;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -310,7 +311,7 @@ public:
|
|||
Float probSpecular;
|
||||
if (hasSpecular && hasNested) {
|
||||
/* 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 */
|
||||
probSpecular = (probSpecular*m_specularSamplingWeight) /
|
||||
|
@ -336,18 +337,25 @@ public:
|
|||
if (Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) <= 0)
|
||||
return Spectrum(0.0f);
|
||||
} else {
|
||||
bRec.sampledComponent = 1;
|
||||
bRec.sampledType = EDiffuseReflection;
|
||||
bRec.wo = squareToHemispherePSA(sample);
|
||||
Vector wiBackup = bRec.wi;
|
||||
bRec.wi = refractTo(EInterior, bRec.wi);
|
||||
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 */
|
||||
_pdf = pdf(bRec, ESolidAngle);
|
||||
EMeasure measure = getMeasure(bRec.sampledType);
|
||||
_pdf = pdf(bRec, measure);
|
||||
|
||||
if (_pdf == 0)
|
||||
return Spectrum(0.0f);
|
||||
else
|
||||
return eval(bRec, ESolidAngle) / _pdf;
|
||||
return eval(bRec, measure) / _pdf;
|
||||
}
|
||||
|
||||
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
|
||||
|
@ -396,7 +404,7 @@ public:
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
// Shader *createShader(Renderer *renderer) const;
|
||||
Shader *createShader(Renderer *renderer) const;
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
|
@ -408,7 +416,7 @@ private:
|
|||
Float m_specularSamplingWeight;
|
||||
Float m_thickness;
|
||||
};
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* GLSL port of the rough coating shader. This version is much more
|
||||
* approximate -- it only supports the Beckmann distribution,
|
||||
|
@ -432,6 +440,7 @@ public:
|
|||
m_sigmaAShader = renderer->registerShaderForResource(m_sigmaA.get());
|
||||
m_alpha = std::max(m_alpha, (Float) 0.2f);
|
||||
m_R0 = fresnel(1.0f, m_extIOR, m_intIOR);
|
||||
m_eta = extIOR / intIOR;
|
||||
}
|
||||
|
||||
bool isComplete() const {
|
||||
|
@ -450,20 +459,43 @@ public:
|
|||
}
|
||||
|
||||
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 + "_eta", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_alpha", false));
|
||||
}
|
||||
|
||||
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs, int &textureUnitOffset) const {
|
||||
program->setParameter(parameterIDs[0], m_alpha);
|
||||
program->setParameter(parameterIDs[1], m_R0);
|
||||
program->setParameter(parameterIDs[0], m_R0);
|
||||
program->setParameter(parameterIDs[1], m_eta);
|
||||
program->setParameter(parameterIDs[2], m_alpha);
|
||||
}
|
||||
|
||||
void generateCode(std::ostringstream &oss,
|
||||
const std::string &evalName,
|
||||
const std::vector<std::string> &depNames) const {
|
||||
oss << "uniform float " << evalName << "_alpha;" << endl
|
||||
<< "uniform float " << evalName << "_R0;" << endl
|
||||
oss << "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
|
||||
<< "float " << evalName << "_D(vec3 m) {" << endl
|
||||
<< " float ct = cosTheta(m);" << endl
|
||||
|
@ -484,37 +516,40 @@ public:
|
|||
<< " abs(2 * nDotM * cosTheta(wi) / dot(wi, m))));" << 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
|
||||
<< " if (cosTheta(wi) <= 0 || cosTheta(wo) <= 0)" << endl
|
||||
<< " return vec3(0.0);" << endl
|
||||
<< " vec3 H = normalize(wi + wo);" << endl
|
||||
<< " vec3 specRef = " << depNames[0] << "(uv);" << endl
|
||||
<< " vec3 diffuseRef = " << depNames[1] << "(uv);" << endl
|
||||
<< " float D = " << evalName << "_D(H)" << ";" << endl
|
||||
<< " float G = " << evalName << "_G(H, wi, wo);" << endl
|
||||
<< " float F = " << evalName << "_schlick(1-dot(wi, H));" << endl
|
||||
<< " return specRef * (F * D * G / (4*cosTheta(wi))) + " << endl
|
||||
<< " diffuseRef * ((1-F) * cosTheta(wo) * 0.31831);" << endl
|
||||
<< " float T12, T21;" << endl
|
||||
<< " vec3 wiPrime = " << evalName << "_refract(wi, T12);" << endl
|
||||
<< " vec3 woPrime = " << evalName << "_refract(wo, T21);" << endl
|
||||
<< " vec3 nested = " << depNames[0] << "(uv, wiPrime, woPrime);" << endl
|
||||
<< " vec3 sigmaA = " << depNames[1] << "(uv);" << endl
|
||||
<< " vec3 result = nested * " << evalName << "_eta * " << evalName << "_eta" << endl
|
||||
<< " * T12 * T21 * (cosTheta(wi)*cosTheta(wo)) /" << endl
|
||||
<< " (cosTheta(wiPrime)*cosTheta(woPrime));" << endl
|
||||
<< " if (sigmaA != vec3(0.0))" << 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
|
||||
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||
<< " vec3 diffuseRef = " << depNames[1] << "(uv);" << endl
|
||||
<< " return diffuseRef * 0.31831 * cosTheta(wo);"<< endl
|
||||
<< " return " << depNames[0] << "_diffuse(uv, wi, wo);" << endl
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
ref<const BSDF> m_nested;
|
||||
ref<Shader> m_nestedShader;
|
||||
ref<const Texture> m_sigmaA;
|
||||
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 {
|
||||
|
@ -523,7 +558,6 @@ Shader *RoughCoating::createShader(Renderer *renderer) const {
|
|||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS(RoughCoatingShader, false, Shader)
|
||||
#endif
|
||||
MTS_IMPLEMENT_CLASS_S(RoughCoating, false, BSDF)
|
||||
MTS_EXPORT_PLUGIN(RoughCoating, "Rough coating BSDF");
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -46,10 +46,14 @@ MTS_NAMESPACE_BEGIN
|
|||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||
* \parameter{g}{\Float\Or\String}{Specifies the phase function anisotropy
|
||||
* --- 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
|
||||
* 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
|
||||
* is assumed to exit the material \emph{directly} at the original point of incidence.
|
||||
* 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
|
||||
* an approximate multiple scattering component based on Jensen's
|
||||
* \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
|
||||
* 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}
|
||||
* and \code{sigmaA}.
|
||||
*/
|
||||
|
@ -79,6 +85,8 @@ public:
|
|||
Properties hgProps("hg");
|
||||
hgProps.setFloat("g", g);
|
||||
|
||||
Float alpha = props.getFloat("alpha", 0.0f);
|
||||
|
||||
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (
|
||||
PluginManager::getInstance()->createObject(
|
||||
MTS_CLASS(PhaseFunction), hgProps));
|
||||
|
@ -91,9 +99,11 @@ public:
|
|||
m_hk->addChild(hg);
|
||||
|
||||
Properties coatingProps(props);
|
||||
coatingProps.setPluginName("coating");
|
||||
coatingProps.setPluginName(alpha == 0 ? "coating" : "roughcoating");
|
||||
if (!props.hasProperty("intIOR"))
|
||||
coatingProps.setFloat("intIOR", eta);
|
||||
if (alpha != 0)
|
||||
coatingProps.setFloat("alpha", alpha);
|
||||
|
||||
m_coating = static_cast<BSDF *> (PluginManager::getInstance()->
|
||||
createObject(MTS_CLASS(BSDF), coatingProps));
|
||||
|
@ -116,6 +126,7 @@ public:
|
|||
props.markQueried("sigmaT");
|
||||
props.markQueried("intIOR");
|
||||
props.markQueried("extIOR");
|
||||
props.markQueried("alpha");
|
||||
}
|
||||
|
||||
SSSBRDF(Stream *stream, InstanceManager *manager)
|
||||
|
|
Loading…
Reference in New Issue