added a HK GLSL shader

metadata
Wenzel Jakob 2011-08-06 23:31:45 -04:00
parent 0f9b046141
commit 9401714298
5 changed files with 99 additions and 19 deletions

View File

@ -53,6 +53,18 @@
<bsdf type="diffuse"/> <bsdf type="diffuse"/>
</bsdf> </bsdf>
<!-- Test the Hanrahan-Krueger model with an
isotropic phase function -->
<bsdf type="hk"/>
<!-- Test the Hanrahan-Krueger model with a
forward-scattering phase function -->
<bsdf type="hk">
<phase type="hg">
<float name="g" value="0.8"/>
</phase>
</bsdf>
<!-- Test the rough glass model with the <!-- Test the rough glass model with the
Beckmann microfacet distribution --> Beckmann microfacet distribution -->
<bsdf type="roughdielectric"> <bsdf type="roughdielectric">
@ -137,18 +149,6 @@
<bsdf type="diffuse"/> <bsdf type="diffuse"/>
</bsdf> </bsdf>
<!-- Test the Hanrahan-Krueger model with an
isotropic phase function -->
<bsdf type="hk"/>
<!-- Test the Hanrahan-Krueger model with a
forward-scattering phase function -->
<bsdf type="hk">
<phase type="hg">
<float name="g" value="0.8"/>
</phase>
</bsdf>
<!-- Test the smooth coating over a diffuse base material --> <!-- Test the smooth coating over a diffuse base material -->
<bsdf type="coating"> <bsdf type="coating">
<float name="intIOR" value="1.5"/> <float name="intIOR" value="1.5"/>

View File

@ -185,7 +185,6 @@ public:
for (int i = 0; i < SPECTRUM_SAMPLES; i++) for (int i = 0; i < SPECTRUM_SAMPLES; i++)
albedo[i] = sigmaT[i] > 0 ? (sigmaS[i]/sigmaT[i]) : (Float) 0; albedo[i] = sigmaT[i] > 0 ? (sigmaS[i]/sigmaT[i]) : (Float) 0;
const Float cosThetaI = Frame::cosTheta(bRec.wi), const Float cosThetaI = Frame::cosTheta(bRec.wi),
cosThetaO = Frame::cosTheta(bRec.wo), cosThetaO = Frame::cosTheta(bRec.wo),
dp = cosThetaI*cosThetaO; dp = cosThetaI*cosThetaO;
@ -202,7 +201,7 @@ public:
const Float phaseVal = m_phase->eval(pRec); const Float phaseVal = m_phase->eval(pRec);
result = albedo * (phaseVal*cosThetaI/(cosThetaI+cosThetaO)) * result = albedo * (phaseVal*cosThetaI/(cosThetaI+cosThetaO)) *
(Spectrum(1.0f)-((-tauD/std::abs(cosThetaI))+(-tauD/std::abs(cosThetaO))).exp()); (Spectrum(1.0f)-((-1.0f/std::abs(cosThetaI)-1.0f/std::abs(cosThetaO)) * tauD).exp());
} }
/* ==================================================================== */ /* ==================================================================== */
@ -378,6 +377,8 @@ public:
<< "]"; << "]";
return oss.str(); return oss.str();
} }
Shader *createShader(Renderer *renderer) const;
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
private: private:
@ -387,6 +388,71 @@ private:
Float m_thickness; Float m_thickness;
}; };
// ================ Hardware shader implementation ================
/**
* This is a relatively approximate GLSL shader for the HK model.
* It assumes that the layer is infinitely thick (i.e. there is no
* transmission) and that the phase function is isotropic
*/
class HanrahanKruegerShader : public Shader {
public:
HanrahanKruegerShader(Renderer *renderer, const Texture *sigmaS, const Texture *sigmaA)
: Shader(renderer, EBSDFShader), m_sigmaS(sigmaS), m_sigmaA(sigmaA) {
m_sigmaSShader = renderer->registerShaderForResource(m_sigmaS.get());
m_sigmaAShader = renderer->registerShaderForResource(m_sigmaA.get());
}
bool isComplete() const {
return m_sigmaSShader.get() != NULL
&& m_sigmaAShader.get() != NULL;
}
void cleanup(Renderer *renderer) {
renderer->unregisterShaderForResource(m_sigmaS.get());
renderer->unregisterShaderForResource(m_sigmaA.get());
}
void putDependencies(std::vector<Shader *> &deps) {
deps.push_back(m_sigmaSShader.get());
deps.push_back(m_sigmaAShader.get());
}
void generateCode(std::ostringstream &oss,
const std::string &evalName,
const std::vector<std::string> &depNames) const {
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
<< " vec3 sigmaS = " << depNames[0] << "(uv);" << endl
<< " vec3 sigmaA = " << depNames[1] << "(uv);" << endl
<< " vec3 albedo = sigmaS/(sigmaS + sigmaA);" << endl
<< " float cosThetaI = abs(cosTheta(wi));" << endl
<< " float cosThetaO = abs(cosTheta(wo));" << endl
<< " return albedo * (0.079577*cosThetaI*cosThetaO/(cosThetaI + cosThetaO));" << endl
<< "}" << endl
<< endl
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
<< " vec3 sigmaS = " << depNames[0] << "(uv);" << endl
<< " vec3 sigmaA = " << depNames[1] << "(uv);" << endl
<< " vec3 albedo = sigmaS/(sigmaS + sigmaA);" << endl
<< " float cosThetaO = abs(cosTheta(wo));" << endl
<< " return albedo * 0.079577 * cosThetaO;" << endl
<< "}" << endl;
}
MTS_DECLARE_CLASS()
private:
ref<const Texture> m_sigmaS;
ref<const Texture> m_sigmaA;
ref<Shader> m_sigmaSShader;
ref<Shader> m_sigmaAShader;
};
Shader *HanrahanKrueger::createShader(Renderer *renderer) const {
return new HanrahanKruegerShader(renderer, m_sigmaS.get(), m_sigmaA.get());
}
MTS_IMPLEMENT_CLASS(HanrahanKruegerShader, false, Shader)
MTS_IMPLEMENT_CLASS_S(HanrahanKrueger, false, BSDF) MTS_IMPLEMENT_CLASS_S(HanrahanKrueger, false, BSDF)
MTS_EXPORT_PLUGIN(HanrahanKrueger, "Hanrahan-Krueger BSDF"); MTS_EXPORT_PLUGIN(HanrahanKrueger, "Hanrahan-Krueger BSDF");
MTS_NAMESPACE_END MTS_NAMESPACE_END

View File

@ -367,6 +367,10 @@ public:
+ alphaV * sinPhiM*sinPhiM; + alphaV * sinPhiM*sinPhiM;
pdf = std::sqrt((alphaU + 1) * (alphaV + 1)) pdf = std::sqrt((alphaU + 1) * (alphaV + 1))
* INV_TWOPI * std::pow(cosThetaM, exponent); * INV_TWOPI * std::pow(cosThetaM, exponent);
/* Prevent potential numerical issues in other stages of the model */
if (pdf < 1e-20f)
pdf = 0;
return Vector( return Vector(
sinThetaM * cosPhiM, sinThetaM * cosPhiM,
@ -379,6 +383,10 @@ public:
SLog(EError, "Invalid distribution function!"); SLog(EError, "Invalid distribution function!");
} }
/* Prevent potential numerical issues in other stages of the model */
if (pdf < 1e-20f)
pdf = 0;
const Float sinThetaM = std::sqrt( const Float sinThetaM = std::sqrt(
std::max((Float) 0, 1 - cosThetaM*cosThetaM)); std::max((Float) 0, 1 - cosThetaM*cosThetaM));
Float phiM = (2.0f * M_PI) * sample.y; Float phiM = (2.0f * M_PI) * sample.y;

View File

@ -302,6 +302,9 @@ public:
const Normal m = m_distribution.sample(sample, const Normal m = m_distribution.sample(sample,
alphaU, alphaV, microfacetPDF); alphaU, alphaV, microfacetPDF);
if (microfacetPDF == 0)
return Spectrum(0.0f);
/* Perfect specular reflection based on the microsurface normal */ /* Perfect specular reflection based on the microsurface normal */
bRec.wo = reflect(bRec.wi, m); bRec.wo = reflect(bRec.wi, m);
bRec.sampledComponent = 0; bRec.sampledComponent = 0;
@ -341,6 +344,9 @@ public:
const Normal m = m_distribution.sample(sample, const Normal m = m_distribution.sample(sample,
alphaU, alphaV, pdf); alphaU, alphaV, pdf);
if (pdf == 0)
return Spectrum(0.0f);
/* Perfect specular reflection based on the microsurface normal */ /* Perfect specular reflection based on the microsurface normal */
bRec.wo = reflect(bRec.wi, m); bRec.wo = reflect(bRec.wi, m);
bRec.sampledComponent = 0; bRec.sampledComponent = 0;

View File

@ -464,6 +464,9 @@ public:
const Normal m = m_distribution.sample(sample, const Normal m = m_distribution.sample(sample,
sampleAlphaU, sampleAlphaV, microfacetPDF); sampleAlphaU, sampleAlphaV, microfacetPDF);
if (microfacetPDF == 0)
return Spectrum(0.0f);
Float F = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR), Float F = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR),
numerator = 1.0f; numerator = 1.0f;
@ -551,11 +554,8 @@ public:
const Normal m = m_distribution.sample(sample, const Normal m = m_distribution.sample(sample,
sampleAlphaU, sampleAlphaV, microfacetPDF); sampleAlphaU, sampleAlphaV, microfacetPDF);
#if 1 if (microfacetPDF == 0)
Float ref = m_distribution.pdf(m, sampleAlphaU, sampleAlphaV); return Spectrum(0.0f);
if (std::abs(ref-microfacetPDF)/ref > Epsilon)
cout << "OOPS! ref=" << ref << ", got=" << microfacetPDF << endl;
#endif
pdf = microfacetPDF; pdf = microfacetPDF;