概述:
(Oren and Nayar 主要是模拟 粗糙表面的,主要是利用反射模型去模拟)
Oren and Nayar (1994) observed(观察) that real-world objects tend not to exhibit perfect Lambertian
reflection. Specifically, rough surfaces generally appear brighter as the illumination
direction approaches the viewing direction. They developed a reflection model that
describes rough surfaces as a collection of symmetric V-shaped grooves in an effort to
better model effects like these. They further assumed that each individual microfacet
(groove face) exhibited perfect Lambertian reflection and derived a BRDF that models
the aggregate reflection of the collection of grooves. The distribution of microfacets was
modeled with a Gaussian distribution with a single parameter σ, the standard deviation
of the orientation angle.
The resulting model, which accounts for shadowing, masking, and interreflection among
the microfacets, does not have a closed-form solution, so they found the following approximation
that fit it well:
where if σ is in radians,
OrenNayar 类
class OrenNayar : public BxDF {
public:
// OrenNayar Public Methods
Spectrum f(const Vector &wo, const Vector &wi) const;
OrenNayar(const Spectrum &reflectance, float sig)
: BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)),
R(reflectance) {
float sigma = Radians(sig);
float sigma2 = sigma*sigma;
A = 1.f - (sigma2 / (2.f * (sigma2 + 0.33f)));
B = 0.45f * sigma2 / (sigma2 + 0.09f);
}
private:
// OrenNayar Private Data
Spectrum R;
float A, B;
};
1. 构造函数:
OrenNayar(const Spectrum &reflectance, float sig)
: BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)),
R(reflectance) {
float sigma = Radians(sig);
float sigma2 = sigma*sigma;
A = 1.f - (sigma2 / (2.f * (sigma2 + 0.33f)));
B = 0.45f * sigma2 / (sigma2 + 0.09f);
}
(预计算 A,B,为了之后计算 BRDF的时候,节省计算量)
The implementation precomputes and stores the values of the A and B parameters
in the constructor to save work in evaluating the BRDF later.
2. Spectrum f(const Vector &wo, const Vector &wi) const;
(下面的代码其实就是 翻译上面公式)
Spectrum OrenNayar::f(const Vector &wo, const Vector &wi) const {
float sinthetai = SinTheta(wi);
float sinthetao = SinTheta(wo);
// Compute cosine term of Oren-Nayar model
float maxcos = 0.f;
if (sinthetai > 1e-4 && sinthetao > 1e-4) {
float sinphii = SinPhi(wi), cosphii = CosPhi(wi);
float sinphio = SinPhi(wo), cosphio = CosPhi(wo);
float dcos = cosphii * cosphio + sinphii * sinphio;
maxcos = max(0.f, dcos);
}
// Compute sine and tangent terms of Oren-Nayar model
float sinalpha, tanbeta;
if (AbsCosTheta(wi) > AbsCosTheta(wo)) {
sinalpha = sinthetao;
tanbeta = sinthetai / AbsCosTheta(wi);
}
else {
sinalpha = sinthetai;
tanbeta = sinthetao / AbsCosTheta(wo);
}
return R * INV_PI * (A + B * maxcos * sinalpha * tanbeta);
}
细节:
a.
float sinthetai = SinTheta(wi);
float sinthetao = SinTheta(wo);
作用:
(先计算 sin θi 和 sin θo)
Application of trigonometry(三角函数) can substantially improve the efficiency of the evaluation
routine compared to a naive implementation. The implementation starts by computing
the values of sin θi and sin θo.
b.
float maxcos = 0.f;
if (sinthetai > 1e-4 && sinthetao > 1e-4) {
float sinphii = SinPhi(wi), cosphii = CosPhi(wi);
float sinphio = SinPhi(wo), cosphio = CosPhi(wo);
float dcos = cosphii * cosphio + sinphii * sinphio;
maxcos = max(0.f, dcos);
}
作用:
(利用三角函数公式,可以计算 cos(φi − φo))
It is now necessary to compute the max(0, cos(φi − φo)) term.We can apply the trigonometric
identity
such that we just need to compute the sines and cosines of φi and φo
c.
float sinalpha, tanbeta;
if (AbsCosTheta(wi) > AbsCosTheta(wo)) {
sinalpha = sinthetao;
tanbeta = sinthetai / AbsCosTheta(wi);
}
else {
sinalpha = sinthetai;
tanbeta = sinthetao / AbsCosTheta(wo);
}
作用:
(计算 sin α 和 tan β,在计算这两个的时候,主要是要考虑比较大小)
Finally, the sin α and tan β terms are found. Note that whichever of ωi or ωo has a larger
value for cos θ (i.e., a larger z component) has a smaller value for θ. We can set sin α
using the appropriate sine value computed at the beginning of the method. The tangent
can then be computed using the identity tan a = sin a/ cos a.