style cleanup

This commit is contained in:
Campbell Barton
2012-06-04 22:44:58 +00:00
parent f94123a5c6
commit 2d290040a1
22 changed files with 1682 additions and 1635 deletions

View File

@@ -48,17 +48,17 @@ using namespace OSL;
/// ///
class GenericBackgroundClosure : public BackgroundClosure { class GenericBackgroundClosure : public BackgroundClosure {
public: public:
GenericBackgroundClosure() { } GenericBackgroundClosure() {}
void setup() {}; void setup() {};
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "background"; } const char *name() const { return "background"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ()"; out << name() << " ()";
} }
}; };
@@ -72,27 +72,29 @@ public:
/// ///
class HoldoutClosure : ClosurePrimitive { class HoldoutClosure : ClosurePrimitive {
public: public:
HoldoutClosure () : ClosurePrimitive (Holdout) { } HoldoutClosure () : ClosurePrimitive(Holdout) {}
void setup() {}; void setup() {};
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "holdout"; } const char *name() const { return "holdout"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ()"; out << name() << " ()";
} }
}; };
ClosureParam closure_background_params[] = { ClosureParam closure_background_params[] = {
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(GenericBackgroundClosure) }; CLOSURE_FINISH_PARAM(GenericBackgroundClosure)
};
CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure) CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure)
ClosureParam closure_holdout_params[] = { ClosureParam closure_holdout_params[] = {
CLOSURE_FINISH_PARAM(HoldoutClosure) }; CLOSURE_FINISH_PARAM(HoldoutClosure)
};
CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure) CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure)

View File

@@ -44,132 +44,134 @@ using namespace OSL;
class AshikhminVelvetClosure : public BSDFClosure { class AshikhminVelvetClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
float m_sigma; float m_sigma;
float m_invsigma2; float m_invsigma2;
AshikhminVelvetClosure() : BSDFClosure(Labels::DIFFUSE) { } AshikhminVelvetClosure() : BSDFClosure(Labels::DIFFUSE) {}
void setup() void setup()
{ {
m_sigma = max(m_sigma, 0.01f); m_sigma = max(m_sigma, 0.01f);
m_invsigma2 = 1.0f/(m_sigma * m_sigma); m_invsigma2 = 1.0f / (m_sigma * m_sigma);
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const AshikhminVelvetClosure *comp = (const AshikhminVelvetClosure *)other; const AshikhminVelvetClosure *comp = (const AshikhminVelvetClosure *)other;
return m_N == comp->m_N && m_sigma == comp->m_sigma && return m_N == comp->m_N && m_sigma == comp->m_sigma &&
BSDFClosure::mergeable(other); BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "ashikhmin_velvet"; } const char *name() const { return "ashikhmin_velvet"; }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
out << m_sigma; out << m_sigma;
out << ")"; out << ")";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNO > 0 && cosNI > 0) { if (cosNO > 0 && cosNI > 0) {
Vec3 H = omega_in + omega_out; Vec3 H = omega_in + omega_out;
H.normalize(); H.normalize();
float cosNH = m_N.dot(H); float cosNH = m_N.dot(H);
float cosHO = fabsf(omega_out.dot(H)); float cosHO = fabsf(omega_out.dot(H));
float cosNHdivHO = cosNH / cosHO; float cosNHdivHO = cosNH / cosHO;
cosNHdivHO = max(cosNHdivHO, 0.00001f); cosNHdivHO = max(cosNHdivHO, 0.00001f);
float fac1 = 2 * fabsf(cosNHdivHO * cosNO); float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
float fac2 = 2 * fabsf(cosNHdivHO * cosNI); float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
float sinNH2 = 1 - cosNH * cosNH; float sinNH2 = 1 - cosNH * cosNH;
float sinNH4 = sinNH2 * sinNH2; float sinNH4 = sinNH2 * sinNH2;
float cotangent2 = (cosNH * cosNH) / sinNH2; float cotangent2 = (cosNH * cosNH) / sinNH2;
float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4; float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4;
float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically
float out = 0.25f * (D * G) / cosNO; float out = 0.25f * (D * G) / cosNO;
pdf = 0.5f * (float) M_1_PI; pdf = 0.5f * (float) M_1_PI;
return Color3 (out, out, out); return Color3(out, out, out);
} }
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
// we are viewing the surface from above - send a ray out with uniform // we are viewing the surface from above - send a ray out with uniform
// distribution over the hemisphere // distribution over the hemisphere
sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); sample_uniform_hemisphere(m_N, omega_out, randu, randv, omega_in, pdf);
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
Vec3 H = omega_in + omega_out; Vec3 H = omega_in + omega_out;
H.normalize(); H.normalize();
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNH = m_N.dot(H); float cosNH = m_N.dot(H);
float cosHO = fabsf(omega_out.dot(H)); float cosHO = fabsf(omega_out.dot(H));
float cosNHdivHO = cosNH / cosHO; float cosNHdivHO = cosNH / cosHO;
cosNHdivHO = max(cosNHdivHO, 0.00001f); cosNHdivHO = max(cosNHdivHO, 0.00001f);
float fac1 = 2 * fabsf(cosNHdivHO * cosNO); float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
float fac2 = 2 * fabsf(cosNHdivHO * cosNI); float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
float sinNH2 = 1 - cosNH * cosNH; float sinNH2 = 1 - cosNH * cosNH;
float sinNH4 = sinNH2 * sinNH2; float sinNH4 = sinNH2 * sinNH2;
float cotangent2 = (cosNH * cosNH) / sinNH2; float cotangent2 = (cosNH * cosNH) / sinNH2;
float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4; float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4;
float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically
float power = 0.25f * (D * G) / cosNO; float power = 0.25f * (D * G) / cosNO;
eval.setValue(power, power, power); eval.setValue(power, power, power);
// TODO: find a better approximation for the retroreflective bounce // TODO: find a better approximation for the retroreflective bounce
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
domega_in_dx *= 125; domega_in_dx *= 125;
domega_in_dy *= 125; domega_in_dy *= 125;
} else }
pdf = 0; else
return Labels::REFLECT; pdf = 0;
} return Labels::REFLECT;
}
}; };
ClosureParam bsdf_ashikhmin_velvet_params[] = { ClosureParam bsdf_ashikhmin_velvet_params[] = {
CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N), CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N),
CLOSURE_FLOAT_PARAM (AshikhminVelvetClosure, m_sigma), CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, m_sigma),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(AshikhminVelvetClosure) }; CLOSURE_FINISH_PARAM(AshikhminVelvetClosure)
};
CLOSURE_PREPARE(bsdf_ashikhmin_velvet_prepare, AshikhminVelvetClosure) CLOSURE_PREPARE(bsdf_ashikhmin_velvet_prepare, AshikhminVelvetClosure)

View File

@@ -44,137 +44,141 @@ using namespace OSL;
class DiffuseClosure : public BSDFClosure { class DiffuseClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
DiffuseClosure() : BSDFClosure(Labels::DIFFUSE) { } DiffuseClosure() : BSDFClosure(Labels::DIFFUSE) {}
void setup() {}; void setup() {};
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const DiffuseClosure *comp = (const DiffuseClosure *)other; const DiffuseClosure *comp = (const DiffuseClosure *)other;
return m_N == comp->m_N && BSDFClosure::mergeable(other); return m_N == comp->m_N && BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "diffuse"; } const char *name() const { return "diffuse"; }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))"; out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
float cos_pi = max(m_N.dot(omega_in),0.0f) * (float) M_1_PI; float cos_pi = max(m_N.dot(omega_in), 0.0f) * (float) M_1_PI;
pdf = cos_pi; pdf = cos_pi;
return Color3 (cos_pi, cos_pi, cos_pi); return Color3(cos_pi, cos_pi, cos_pi);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
// we are viewing the surface from the right side - send a ray out with cosine // we are viewing the surface from the right side - send a ray out with cosine
// distribution over the hemisphere // distribution over the hemisphere
sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); sample_cos_hemisphere(m_N, omega_out, randu, randv, omega_in, pdf);
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
eval.setValue(pdf, pdf, pdf); eval.setValue(pdf, pdf, pdf);
// TODO: find a better approximation for the diffuse bounce // TODO: find a better approximation for the diffuse bounce
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
domega_in_dx *= 125; domega_in_dx *= 125;
domega_in_dy *= 125; domega_in_dy *= 125;
} else }
pdf = 0; else
return Labels::REFLECT; pdf = 0;
} return Labels::REFLECT;
}
}; };
class TranslucentClosure : public BSDFClosure { class TranslucentClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
TranslucentClosure() : BSDFClosure(Labels::DIFFUSE, Back) { } TranslucentClosure() : BSDFClosure(Labels::DIFFUSE, Back) {}
void setup() {}; void setup() {};
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const TranslucentClosure *comp = (const TranslucentClosure *)other; const TranslucentClosure *comp = (const TranslucentClosure *)other;
return m_N == comp->m_N && BSDFClosure::mergeable(other); return m_N == comp->m_N && BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "translucent"; } const char *name() const { return "translucent"; }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))"; out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
float cos_pi = max(-m_N.dot(omega_in), 0.0f) * (float) M_1_PI; float cos_pi = max(-m_N.dot(omega_in), 0.0f) * (float) M_1_PI;
pdf = cos_pi; pdf = cos_pi;
return Color3 (cos_pi, cos_pi, cos_pi); return Color3(cos_pi, cos_pi, cos_pi);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
// we are viewing the surface from the right side - send a ray out with cosine // we are viewing the surface from the right side - send a ray out with cosine
// distribution over the hemisphere // distribution over the hemisphere
sample_cos_hemisphere (-m_N, omega_out, randu, randv, omega_in, pdf); sample_cos_hemisphere(-m_N, omega_out, randu, randv, omega_in, pdf);
if (Ng.dot(omega_in) < 0) { if (Ng.dot(omega_in) < 0) {
eval.setValue(pdf, pdf, pdf); eval.setValue(pdf, pdf, pdf);
// TODO: find a better approximation for the diffuse bounce // TODO: find a better approximation for the diffuse bounce
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
domega_in_dx *= -125; domega_in_dx *= -125;
domega_in_dy *= -125; domega_in_dy *= -125;
} else }
pdf = 0; else
return Labels::TRANSMIT; pdf = 0;
} return Labels::TRANSMIT;
}
}; };
ClosureParam bsdf_diffuse_params[] = { ClosureParam bsdf_diffuse_params[] = {
CLOSURE_VECTOR_PARAM (DiffuseClosure, m_N), CLOSURE_VECTOR_PARAM(DiffuseClosure, m_N),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM (DiffuseClosure) }; CLOSURE_FINISH_PARAM(DiffuseClosure)
};
ClosureParam bsdf_translucent_params[] = { ClosureParam bsdf_translucent_params[] = {
CLOSURE_VECTOR_PARAM (TranslucentClosure, m_N), CLOSURE_VECTOR_PARAM(TranslucentClosure, m_N),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM (TranslucentClosure) }; CLOSURE_FINISH_PARAM(TranslucentClosure)
};
CLOSURE_PREPARE(bsdf_diffuse_prepare, DiffuseClosure) CLOSURE_PREPARE(bsdf_diffuse_prepare, DiffuseClosure)
CLOSURE_PREPARE(bsdf_translucent_prepare, TranslucentClosure) CLOSURE_PREPARE(bsdf_translucent_prepare, TranslucentClosure)

View File

@@ -52,85 +52,85 @@ CCL_NAMESPACE_BEGIN
template <int Refractive = 0> template <int Refractive = 0>
class MicrofacetGGXClosure : public BSDFClosure { class MicrofacetGGXClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
float m_ag; // width parameter (roughness) float m_ag; // width parameter (roughness)
float m_eta; // index of refraction (for fresnel term) float m_eta; // index of refraction (for fresnel term)
MicrofacetGGXClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { m_eta = 1.0f; } MicrofacetGGXClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { m_eta = 1.0f; }
void setup() void setup()
{ {
m_ag = clamp(m_ag, 1e-5f, 1.0f); m_ag = clamp(m_ag, 1e-5f, 1.0f);
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const MicrofacetGGXClosure *comp = (const MicrofacetGGXClosure *)other; const MicrofacetGGXClosure *comp = (const MicrofacetGGXClosure *)other;
return m_N == comp->m_N && m_ag == comp->m_ag && return m_N == comp->m_N && m_ag == comp->m_ag &&
m_eta == comp->m_eta && BSDFClosure::mergeable(other); m_eta == comp->m_eta && BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { const char *name() const {
return Refractive ? "microfacet_ggx_refraction" : "microfacet_ggx"; return Refractive ? "microfacet_ggx_refraction" : "microfacet_ggx";
} }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
out << m_ag << ", "; out << m_ag << ", ";
out << m_eta; out << m_eta;
out << ")"; out << ")";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
if (Refractive == 1) return Color3 (0, 0, 0); if (Refractive == 1) return Color3(0, 0, 0);
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNI > 0 && cosNO > 0) { if (cosNI > 0 && cosNO > 0) {
// get half vector // get half vector
Vec3 Hr = omega_in + omega_out; Vec3 Hr = omega_in + omega_out;
Hr.normalize(); Hr.normalize();
// eq. 20: (F*G*D)/(4*in*on) // eq. 20: (F*G*D)/(4*in*on)
// eq. 33: first we calculate D(m) with m=Hr: // eq. 33: first we calculate D(m) with m=Hr:
float alpha2 = m_ag * m_ag; float alpha2 = m_ag * m_ag;
float cosThetaM = m_N.dot(Hr); float cosThetaM = m_N.dot(Hr);
float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM2 = cosThetaM * cosThetaM;
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
float cosThetaM4 = cosThetaM2 * cosThetaM2; float cosThetaM4 = cosThetaM2 * cosThetaM2;
float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
// eq. 34: now calculate G1(i,m) and G1(o,m) // eq. 34: now calculate G1(i,m) and G1(o,m)
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
float G = G1o * G1i; float G = G1o * G1i;
float out = (G * D) * 0.25f / cosNO; float out = (G * D) * 0.25f / cosNO;
// eq. 24 // eq. 24
float pm = D * cosThetaM; float pm = D * cosThetaM;
// convert into pdf of the sampled direction // convert into pdf of the sampled direction
// eq. 38 - but see also: // eq. 38 - but see also:
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
pdf = pm * 0.25f / Hr.dot(omega_out); pdf = pm * 0.25f / Hr.dot(omega_out);
return Color3 (out, out, out); return Color3(out, out, out);
} }
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
if (Refractive == 0) return Color3 (0, 0, 0); if (Refractive == 0) return Color3(0, 0, 0);
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNO <= 0 || cosNI >= 0) if (cosNO <= 0 || cosNI >= 0)
return Color3 (0, 0, 0); // vectors on same side -- not possible return Color3(0, 0, 0); // vectors on same side -- not possible
// compute half-vector of the refraction (eq. 16) // compute half-vector of the refraction (eq. 16)
Vec3 ht = -(m_eta * omega_in + omega_out); Vec3 ht = -(m_eta * omega_in + omega_out);
Vec3 Ht = ht; Ht.normalize(); Vec3 Ht = ht; Ht.normalize();
float cosHO = Ht.dot(omega_out); float cosHO = Ht.dot(omega_out);
float cosHI = Ht.dot(omega_in); float cosHI = Ht.dot(omega_in);
// eq. 33: first we calculate D(m) with m=Ht: // eq. 33: first we calculate D(m) with m=Ht:
@@ -148,122 +148,123 @@ public:
float invHt2 = 1 / ht.dot(ht); float invHt2 = 1 / ht.dot(ht);
pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2; pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO; float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
return Color3 (out, out, out); return Color3(out, out, out);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
if (cosNO > 0) { if (cosNO > 0) {
Vec3 X, Y, Z = m_N; Vec3 X, Y, Z = m_N;
make_orthonormals(Z, X, Y); make_orthonormals(Z, X, Y);
// generate a random microfacet normal m // generate a random microfacet normal m
// eq. 35,36: // eq. 35,36:
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
// and sin(atan(x)) == x/sqrt(1+x^2) // and sin(atan(x)) == x/sqrt(1+x^2)
float alpha2 = m_ag * m_ag; float alpha2 = m_ag * m_ag;
float tanThetaM2 = alpha2 * randu / (1 - randu); float tanThetaM2 = alpha2 * randu / (1 - randu);
float cosThetaM = 1 / sqrtf(1 + tanThetaM2); float cosThetaM = 1 / sqrtf(1 + tanThetaM2);
float sinThetaM = cosThetaM * sqrtf(tanThetaM2); float sinThetaM = cosThetaM * sqrtf(tanThetaM2);
float phiM = 2 * float(M_PI) * randv; float phiM = 2 * float(M_PI) * randv;
Vec3 m = (cosf(phiM) * sinThetaM) * X + Vec3 m = (cosf(phiM) * sinThetaM) * X +
(sinf(phiM) * sinThetaM) * Y + (sinf(phiM) * sinThetaM) * Y +
cosThetaM * Z; cosThetaM * Z;
if (Refractive == 0) { if (Refractive == 0) {
float cosMO = m.dot(omega_out); float cosMO = m.dot(omega_out);
if (cosMO > 0) { if (cosMO > 0) {
// eq. 39 - compute actual reflected direction // eq. 39 - compute actual reflected direction
omega_in = 2 * cosMO * m - omega_out; omega_in = 2 * cosMO * m - omega_out;
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
// microfacet normal is visible to this ray // microfacet normal is visible to this ray
// eq. 33 // eq. 33
float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM2 = cosThetaM * cosThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2; float cosThetaM4 = cosThetaM2 * cosThetaM2;
float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
// eq. 24 // eq. 24
float pm = D * cosThetaM; float pm = D * cosThetaM;
// convert into pdf of the sampled direction // convert into pdf of the sampled direction
// eq. 38 - but see also: // eq. 38 - but see also:
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
pdf = pm * 0.25f / cosMO; pdf = pm * 0.25f / cosMO;
// eval BRDF*cosNI // eval BRDF*cosNI
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
// eq. 34: now calculate G1(i,m) and G1(o,m) // eq. 34: now calculate G1(i,m) and G1(o,m)
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
float G = G1o * G1i; float G = G1o * G1i;
// eq. 20: (F*G*D)/(4*in*on) // eq. 20: (F*G*D)/(4*in*on)
float out = (G * D) * 0.25f / cosNO; float out = (G * D) * 0.25f / cosNO;
eval.setValue(out, out, out); eval.setValue(out, out, out);
domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx; domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy; domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
/* disabled for now - gives texture filtering problems */ /* disabled for now - gives texture filtering problems */
#if 0 #if 0
// Since there is some blur to this reflection, make the // Since there is some blur to this reflection, make the
// derivatives a bit bigger. In theory this varies with the // derivatives a bit bigger. In theory this varies with the
// roughness but the exact relationship is complex and // roughness but the exact relationship is complex and
// requires more ops than are practical. // requires more ops than are practical.
domega_in_dx *= 10; domega_in_dx *= 10;
domega_in_dy *= 10; domega_in_dy *= 10;
#endif #endif
} }
} }
} else { }
// CAUTION: the i and o variables are inverted relative to the paper else {
// eq. 39 - compute actual refractive direction // CAUTION: the i and o variables are inverted relative to the paper
Vec3 R, dRdx, dRdy; // eq. 39 - compute actual refractive direction
Vec3 T, dTdx, dTdy; Vec3 R, dRdx, dRdy;
bool inside; Vec3 T, dTdx, dTdy;
fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy, bool inside;
R, dRdx, dRdy, fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
T, dTdx, dTdy, R, dRdx, dRdy,
inside); T, dTdx, dTdy,
inside);
if (!inside) { if (!inside) {
omega_in = T; omega_in = T;
domega_in_dx = dTdx; domega_in_dx = dTdx;
domega_in_dy = dTdy; domega_in_dy = dTdy;
// eq. 33 // eq. 33
float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM2 = cosThetaM * cosThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2; float cosThetaM4 = cosThetaM2 * cosThetaM2;
float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
// eq. 24 // eq. 24
float pm = D * cosThetaM; float pm = D * cosThetaM;
// eval BRDF*cosNI // eval BRDF*cosNI
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
// eq. 34: now calculate G1(i,m) and G1(o,m) // eq. 34: now calculate G1(i,m) and G1(o,m)
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
float G = G1o * G1i; float G = G1o * G1i;
// eq. 21 // eq. 21
float cosHI = m.dot(omega_in); float cosHI = m.dot(omega_in);
float cosHO = m.dot(omega_out); float cosHO = m.dot(omega_out);
float Ht2 = m_eta * cosHI + cosHO; float Ht2 = m_eta * cosHI + cosHO;
Ht2 *= Ht2; Ht2 *= Ht2;
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2); float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
// eq. 38 and eq. 17 // eq. 38 and eq. 17
pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2; pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
eval.setValue(out, out, out); eval.setValue(out, out, out);
/* disabled for now - gives texture filtering problems */ /* disabled for now - gives texture filtering problems */
#if 0 #if 0
// Since there is some blur to this refraction, make the // Since there is some blur to this refraction, make the
// derivatives a bit bigger. In theory this varies with the // derivatives a bit bigger. In theory this varies with the
// roughness but the exact relationship is complex and // roughness but the exact relationship is complex and
// requires more ops than are practical. // requires more ops than are practical.
domega_in_dx *= 10; domega_in_dx *= 10;
domega_in_dy *= 10; domega_in_dy *= 10;
#endif #endif
} }
} }
} }
return Refractive ? Labels::TRANSMIT : Labels::REFLECT; return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
} }
}; };
// microfacet model with Beckmann facet distribution // microfacet model with Beckmann facet distribution
@@ -271,89 +272,92 @@ public:
template <int Refractive = 0> template <int Refractive = 0>
class MicrofacetBeckmannClosure : public BSDFClosure { class MicrofacetBeckmannClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
float m_ab; // width parameter (roughness) float m_ab; // width parameter (roughness)
float m_eta; // index of refraction (for fresnel term) float m_eta; // index of refraction (for fresnel term)
MicrofacetBeckmannClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { } MicrofacetBeckmannClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) {
}
void setup() void setup()
{ {
m_ab = clamp(m_ab, 1e-5f, 1.0f); m_ab = clamp(m_ab, 1e-5f, 1.0f);
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const MicrofacetBeckmannClosure *comp = (const MicrofacetBeckmannClosure *)other; const MicrofacetBeckmannClosure *comp = (const MicrofacetBeckmannClosure *)other;
return m_N == comp->m_N && m_ab == comp->m_ab && return m_N == comp->m_N && m_ab == comp->m_ab &&
m_eta == comp->m_eta && BSDFClosure::mergeable(other); m_eta == comp->m_eta && BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const {
return sizeof(*this);
}
const char * name () const { const char *name() const {
return Refractive ? "microfacet_beckmann_refraction" return Refractive ? "microfacet_beckmann_refraction"
: "microfacet_beckmann"; : "microfacet_beckmann";
} }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
out << m_ab << ", "; out << m_ab << ", ";
out << m_eta; out << m_eta;
out << ")"; out << ")";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
if (Refractive == 1) return Color3 (0, 0, 0); if (Refractive == 1) return Color3(0, 0, 0);
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNO > 0 && cosNI > 0) { if (cosNO > 0 && cosNI > 0) {
// get half vector // get half vector
Vec3 Hr = omega_in + omega_out; Vec3 Hr = omega_in + omega_out;
Hr.normalize(); Hr.normalize();
// eq. 20: (F*G*D)/(4*in*on) // eq. 20: (F*G*D)/(4*in*on)
// eq. 25: first we calculate D(m) with m=Hr: // eq. 25: first we calculate D(m) with m=Hr:
float alpha2 = m_ab * m_ab; float alpha2 = m_ab * m_ab;
float cosThetaM = m_N.dot(Hr); float cosThetaM = m_N.dot(Hr);
float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM2 = cosThetaM * cosThetaM;
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
float cosThetaM4 = cosThetaM2 * cosThetaM2; float cosThetaM4 = cosThetaM2 * cosThetaM2;
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
// eq. 26, 27: now calculate G1(i,m) and G1(o,m) // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
float G = G1o * G1i; float G = G1o * G1i;
float out = (G * D) * 0.25f / cosNO; float out = (G * D) * 0.25f / cosNO;
// eq. 24 // eq. 24
float pm = D * cosThetaM; float pm = D * cosThetaM;
// convert into pdf of the sampled direction // convert into pdf of the sampled direction
// eq. 38 - but see also: // eq. 38 - but see also:
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
pdf = pm * 0.25f / Hr.dot(omega_out); pdf = pm * 0.25f / Hr.dot(omega_out);
return Color3 (out, out, out); return Color3(out, out, out);
} }
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
if (Refractive == 0) return Color3 (0, 0, 0); if (Refractive == 0) return Color3(0, 0, 0);
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNO <= 0 || cosNI >= 0) if (cosNO <= 0 || cosNI >= 0)
return Color3 (0, 0, 0); return Color3(0, 0, 0);
// compute half-vector of the refraction (eq. 16) // compute half-vector of the refraction (eq. 16)
Vec3 ht = -(m_eta * omega_in + omega_out); Vec3 ht = -(m_eta * omega_in + omega_out);
Vec3 Ht = ht; Ht.normalize(); Vec3 Ht = ht; Ht.normalize();
float cosHO = Ht.dot(omega_out); float cosHO = Ht.dot(omega_out);
float cosHI = Ht.dot(omega_in); float cosHI = Ht.dot(omega_in);
// eq. 33: first we calculate D(m) with m=Ht: // eq. 33: first we calculate D(m) with m=Ht:
@@ -373,156 +377,161 @@ public:
float invHt2 = 1 / ht.dot(ht); float invHt2 = 1 / ht.dot(ht);
pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2; pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO; float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
return Color3 (out, out, out); return Color3(out, out, out);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
if (cosNO > 0) { if (cosNO > 0) {
Vec3 X, Y, Z = m_N; Vec3 X, Y, Z = m_N;
make_orthonormals(Z, X, Y); make_orthonormals(Z, X, Y);
// generate a random microfacet normal m // generate a random microfacet normal m
// eq. 35,36: // eq. 35,36:
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
// and sin(atan(x)) == x/sqrt(1+x^2) // and sin(atan(x)) == x/sqrt(1+x^2)
float alpha2 = m_ab * m_ab; float alpha2 = m_ab * m_ab;
float tanThetaM = sqrtf(-alpha2 * logf(1 - randu)); float tanThetaM = sqrtf(-alpha2 * logf(1 - randu));
float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM); float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM);
float sinThetaM = cosThetaM * tanThetaM; float sinThetaM = cosThetaM * tanThetaM;
float phiM = 2 * float(M_PI) * randv; float phiM = 2 * float(M_PI) * randv;
Vec3 m = (cosf(phiM) * sinThetaM) * X + Vec3 m = (cosf(phiM) * sinThetaM) * X +
(sinf(phiM) * sinThetaM) * Y + (sinf(phiM) * sinThetaM) * Y +
cosThetaM * Z; cosThetaM * Z;
if (Refractive == 0) { if (Refractive == 0) {
float cosMO = m.dot(omega_out); float cosMO = m.dot(omega_out);
if (cosMO > 0) { if (cosMO > 0) {
// eq. 39 - compute actual reflected direction // eq. 39 - compute actual reflected direction
omega_in = 2 * cosMO * m - omega_out; omega_in = 2 * cosMO * m - omega_out;
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
// microfacet normal is visible to this ray // microfacet normal is visible to this ray
// eq. 25 // eq. 25
float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM2 = cosThetaM * cosThetaM;
float tanThetaM2 = tanThetaM * tanThetaM; float tanThetaM2 = tanThetaM * tanThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2; float cosThetaM4 = cosThetaM2 * cosThetaM2;
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
// eq. 24 // eq. 24
float pm = D * cosThetaM; float pm = D * cosThetaM;
// convert into pdf of the sampled direction // convert into pdf of the sampled direction
// eq. 38 - but see also: // eq. 38 - but see also:
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
pdf = pm * 0.25f / cosMO; pdf = pm * 0.25f / cosMO;
// Eval BRDF*cosNI // Eval BRDF*cosNI
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
// eq. 26, 27: now calculate G1(i,m) and G1(o,m) // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
float G = G1o * G1i; float G = G1o * G1i;
// eq. 20: (F*G*D)/(4*in*on) // eq. 20: (F*G*D)/(4*in*on)
float out = (G * D) * 0.25f / cosNO; float out = (G * D) * 0.25f / cosNO;
eval.setValue(out, out, out); eval.setValue(out, out, out);
domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx; domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy; domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
/* disabled for now - gives texture filtering problems */ /* disabled for now - gives texture filtering problems */
#if 0 #if 0
// Since there is some blur to this reflection, make the // Since there is some blur to this reflection, make the
// derivatives a bit bigger. In theory this varies with the // derivatives a bit bigger. In theory this varies with the
// roughness but the exact relationship is complex and // roughness but the exact relationship is complex and
// requires more ops than are practical. // requires more ops than are practical.
domega_in_dx *= 10; domega_in_dx *= 10;
domega_in_dy *= 10; domega_in_dy *= 10;
#endif #endif
} }
} }
} else { }
// CAUTION: the i and o variables are inverted relative to the paper else {
// eq. 39 - compute actual refractive direction // CAUTION: the i and o variables are inverted relative to the paper
Vec3 R, dRdx, dRdy; // eq. 39 - compute actual refractive direction
Vec3 T, dTdx, dTdy; Vec3 R, dRdx, dRdy;
bool inside; Vec3 T, dTdx, dTdy;
fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy, bool inside;
R, dRdx, dRdy, fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
T, dTdx, dTdy, R, dRdx, dRdy,
inside); T, dTdx, dTdy,
if (!inside) { inside);
omega_in = T; if (!inside) {
domega_in_dx = dTdx; omega_in = T;
domega_in_dy = dTdy; domega_in_dx = dTdx;
// eq. 33 domega_in_dy = dTdy;
float cosThetaM2 = cosThetaM * cosThetaM; // eq. 33
float tanThetaM2 = tanThetaM * tanThetaM; float cosThetaM2 = cosThetaM * cosThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2; float tanThetaM2 = tanThetaM * tanThetaM;
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); float cosThetaM4 = cosThetaM2 * cosThetaM2;
// eq. 24 float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
float pm = D * cosThetaM; // eq. 24
// eval BRDF*cosNI float pm = D * cosThetaM;
float cosNI = m_N.dot(omega_in); // eval BRDF*cosNI
// eq. 26, 27: now calculate G1(i,m) and G1(o,m) float cosNI = m_N.dot(omega_in);
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
float G = G1o * G1i; float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
// eq. 21 float G = G1o * G1i;
float cosHI = m.dot(omega_in); // eq. 21
float cosHO = m.dot(omega_out); float cosHI = m.dot(omega_in);
float Ht2 = m_eta * cosHI + cosHO; float cosHO = m.dot(omega_out);
Ht2 *= Ht2; float Ht2 = m_eta * cosHI + cosHO;
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2); Ht2 *= Ht2;
// eq. 38 and eq. 17 float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2; // eq. 38 and eq. 17
eval.setValue(out, out, out); pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
eval.setValue(out, out, out);
/* disabled for now - gives texture filtering problems */ /* disabled for now - gives texture filtering problems */
#if 0 #if 0
// Since there is some blur to this refraction, make the // Since there is some blur to this refraction, make the
// derivatives a bit bigger. In theory this varies with the // derivatives a bit bigger. In theory this varies with the
// roughness but the exact relationship is complex and // roughness but the exact relationship is complex and
// requires more ops than are practical. // requires more ops than are practical.
domega_in_dx *= 10; domega_in_dx *= 10;
domega_in_dy *= 10; domega_in_dy *= 10;
#endif #endif
} }
} }
} }
return Refractive ? Labels::TRANSMIT : Labels::REFLECT; return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
} }
}; };
ClosureParam bsdf_microfacet_ggx_params[] = { ClosureParam bsdf_microfacet_ggx_params[] = {
CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N), CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N),
CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<0>, m_ag), CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<0>, m_ag),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) }; CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>)
};
ClosureParam bsdf_microfacet_ggx_refraction_params[] = { ClosureParam bsdf_microfacet_ggx_refraction_params[] = {
CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N), CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N),
CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_ag), CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<1>, m_ag),
CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_eta), CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure<1>, m_eta),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) }; CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>)
};
ClosureParam bsdf_microfacet_beckmann_params[] = { ClosureParam bsdf_microfacet_beckmann_params[] = {
CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N), CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N),
CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<0>, m_ab), CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<0>, m_ab),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) }; CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>)
};
ClosureParam bsdf_microfacet_beckmann_refraction_params[] = { ClosureParam bsdf_microfacet_beckmann_refraction_params[] = {
CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N), CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N),
CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_ab), CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<1>, m_ab),
CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_eta), CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure<1>, m_eta),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) }; CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>)
};
CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare, MicrofacetGGXClosure<0>) CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare, MicrofacetGGXClosure<0>)
CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare, MicrofacetGGXClosure<1>) CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare, MicrofacetGGXClosure<1>)

View File

@@ -26,13 +26,13 @@ CCL_NAMESPACE_BEGIN
using namespace OSL; using namespace OSL;
class OrenNayarClosure: public BSDFClosure { class OrenNayarClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
float m_sigma; float m_sigma;
float m_a, m_b; float m_a, m_b;
OrenNayarClosure(): BSDFClosure(Labels::DIFFUSE) {} OrenNayarClosure() : BSDFClosure(Labels::DIFFUSE) {}
void setup() { void setup() {
m_sigma = clamp(m_sigma, 0.0f, 1.0f); m_sigma = clamp(m_sigma, 0.0f, 1.0f);
@@ -43,19 +43,19 @@ public:
m_b = m_sigma * div; m_b = m_sigma * div;
} }
bool mergeable(const ClosurePrimitive* other) const { bool mergeable(const ClosurePrimitive *other) const {
const OrenNayarClosure* comp = static_cast<const OrenNayarClosure*>(other); const OrenNayarClosure *comp = static_cast<const OrenNayarClosure *>(other);
return return
m_N == comp->m_N && m_N == comp->m_N &&
m_sigma == comp->m_sigma && m_sigma == comp->m_sigma &&
BSDFClosure::mergeable(other); BSDFClosure::mergeable(other);
} }
size_t memsize() const { size_t memsize() const {
return sizeof(*this); return sizeof(*this);
} }
const char* name() const { const char *name() const {
return "oren_nayar"; return "oren_nayar";
} }
@@ -87,13 +87,13 @@ public:
} }
ustring sample( ustring sample(
const Vec3& Ng, const Vec3& Ng,
const Vec3& omega_out, const Vec3& domega_out_dx, const Vec3& domega_out_dy, const Vec3& omega_out, const Vec3& domega_out_dx, const Vec3& domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3& omega_in, Vec3& domega_in_dx, Vec3& domega_in_dy, Vec3& omega_in, Vec3& domega_in_dx, Vec3& domega_in_dy,
float& pdf, Color3& eval float& pdf, Color3& eval
) const { ) const {
sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); sample_uniform_hemisphere(m_N, omega_out, randu, randv, omega_in, pdf);
if (Ng.dot(omega_in) > 0.0f) { if (Ng.dot(omega_in) > 0.0f) {
float is = get_intensity(m_N, omega_out, omega_in); float is = get_intensity(m_N, omega_out, omega_in);
@@ -118,7 +118,7 @@ private:
float nv = max(n.dot(v), 0.0f); float nv = max(n.dot(v), 0.0f);
float t = l.dot(v) - nl * nv; float t = l.dot(v) - nl * nv;
if(t > 0.0f) { if (t > 0.0f) {
t /= max(nl, nv) + 1e-8f; t /= max(nl, nv) + 1e-8f;
} }
return nl * (m_a + m_b * t); return nl * (m_a + m_b * t);
@@ -126,10 +126,10 @@ private:
}; };
ClosureParam bsdf_oren_nayar_params[] = { ClosureParam bsdf_oren_nayar_params[] = {
CLOSURE_VECTOR_PARAM (OrenNayarClosure, m_N), CLOSURE_VECTOR_PARAM(OrenNayarClosure, m_N),
CLOSURE_FLOAT_PARAM (OrenNayarClosure, m_sigma), CLOSURE_FLOAT_PARAM(OrenNayarClosure, m_sigma),
CLOSURE_STRING_KEYPARAM ("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM (OrenNayarClosure) CLOSURE_FINISH_PARAM(OrenNayarClosure)
}; };
CLOSURE_PREPARE(bsdf_oren_nayar_prepare, OrenNayarClosure) CLOSURE_PREPARE(bsdf_oren_nayar_prepare, OrenNayarClosure)

View File

@@ -42,65 +42,66 @@ using namespace OSL;
class ReflectionClosure : public BSDFClosure { class ReflectionClosure : public BSDFClosure {
public: public:
Vec3 m_N; // shading normal Vec3 m_N; // shading normal
ReflectionClosure() : BSDFClosure(Labels::SINGULAR) { } ReflectionClosure() : BSDFClosure(Labels::SINGULAR) {}
void setup() {}; void setup() {};
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const ReflectionClosure *comp = (const ReflectionClosure *)other; const ReflectionClosure *comp = (const ReflectionClosure *)other;
return m_N == comp->m_N && BSDFClosure::mergeable(other); return m_N == comp->m_N && BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "reflection"; } const char *name() const { return "reflection"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))"; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
// only one direction is possible // only one direction is possible
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
if (cosNO > 0) { if (cosNO > 0) {
omega_in = (2 * cosNO) * m_N - omega_out; omega_in = (2 * cosNO) * m_N - omega_out;
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
domega_in_dx = 2 * m_N.dot(domega_out_dx) * m_N - domega_out_dx; domega_in_dx = 2 * m_N.dot(domega_out_dx) * m_N - domega_out_dx;
domega_in_dy = 2 * m_N.dot(domega_out_dy) * m_N - domega_out_dy; domega_in_dy = 2 * m_N.dot(domega_out_dy) * m_N - domega_out_dy;
pdf = 1; pdf = 1;
eval.setValue(1, 1, 1); eval.setValue(1, 1, 1);
} }
} }
return Labels::REFLECT; return Labels::REFLECT;
} }
}; };
ClosureParam bsdf_reflection_params[] = { ClosureParam bsdf_reflection_params[] = {
CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N), CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(ReflectionClosure) }; CLOSURE_FINISH_PARAM(ReflectionClosure)
};
CLOSURE_PREPARE(bsdf_reflection_prepare, ReflectionClosure) CLOSURE_PREPARE(bsdf_reflection_prepare, ReflectionClosure)

View File

@@ -42,77 +42,78 @@ using namespace OSL;
class RefractionClosure : public BSDFClosure { class RefractionClosure : public BSDFClosure {
public: public:
Vec3 m_N; // shading normal Vec3 m_N; // shading normal
float m_eta; // ratio of indices of refraction (inside / outside) float m_eta; // ratio of indices of refraction (inside / outside)
RefractionClosure() : BSDFClosure(Labels::SINGULAR, Back) { } RefractionClosure() : BSDFClosure(Labels::SINGULAR, Back) {}
void setup() {} void setup() {}
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const RefractionClosure *comp = (const RefractionClosure *)other; const RefractionClosure *comp = (const RefractionClosure *)other;
return m_N == comp->m_N && m_eta == comp->m_eta && return m_N == comp->m_N && m_eta == comp->m_eta &&
BSDFClosure::mergeable(other); BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "refraction"; } const char *name() const { return "refraction"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
out << m_eta; out << m_eta;
out << ")"; out << ")";
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
Vec3 R, dRdx, dRdy; Vec3 R, dRdx, dRdy;
Vec3 T, dTdx, dTdy; Vec3 T, dTdx, dTdy;
bool inside; bool inside;
fresnel_dielectric(m_eta, m_N, fresnel_dielectric(m_eta, m_N,
omega_out, domega_out_dx, domega_out_dy, omega_out, domega_out_dx, domega_out_dy,
R, dRdx, dRdy, R, dRdx, dRdy,
T, dTdx, dTdy, T, dTdx, dTdy,
inside); inside);
if (!inside) { if (!inside) {
pdf = 1; pdf = 1;
eval.setValue(1.0f, 1.0f, 1.0f); eval.setValue(1.0f, 1.0f, 1.0f);
omega_in = T; omega_in = T;
domega_in_dx = dTdx; domega_in_dx = dTdx;
domega_in_dy = dTdy; domega_in_dy = dTdy;
} }
return Labels::TRANSMIT; return Labels::TRANSMIT;
} }
}; };
ClosureParam bsdf_refraction_params[] = { ClosureParam bsdf_refraction_params[] = {
CLOSURE_VECTOR_PARAM(RefractionClosure, m_N), CLOSURE_VECTOR_PARAM(RefractionClosure, m_N),
CLOSURE_FLOAT_PARAM (RefractionClosure, m_eta), CLOSURE_FLOAT_PARAM(RefractionClosure, m_eta),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(RefractionClosure) }; CLOSURE_FINISH_PARAM(RefractionClosure)
};
CLOSURE_PREPARE(bsdf_refraction_prepare, RefractionClosure) CLOSURE_PREPARE(bsdf_refraction_prepare, RefractionClosure)

View File

@@ -42,54 +42,55 @@ using namespace OSL;
class TransparentClosure : public BSDFClosure { class TransparentClosure : public BSDFClosure {
public: public:
TransparentClosure() : BSDFClosure(Labels::STRAIGHT, Back) { } TransparentClosure() : BSDFClosure(Labels::STRAIGHT, Back) {}
void setup() {} void setup() {}
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "transparent"; } const char *name() const { return "transparent"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ()"; out << name() << " ()";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
// only one direction is possible // only one direction is possible
omega_in = -omega_out; omega_in = -omega_out;
domega_in_dx = -domega_out_dx; domega_in_dx = -domega_out_dx;
domega_in_dy = -domega_out_dy; domega_in_dy = -domega_out_dy;
pdf = 1; pdf = 1;
eval.setValue(1, 1, 1); eval.setValue(1, 1, 1);
return Labels::TRANSMIT; return Labels::TRANSMIT;
} }
}; };
ClosureParam bsdf_transparent_params[] = { ClosureParam bsdf_transparent_params[] = {
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(TransparentClosure) }; CLOSURE_FINISH_PARAM(TransparentClosure)
};
CLOSURE_PREPARE(bsdf_transparent_prepare, TransparentClosure) CLOSURE_PREPARE(bsdf_transparent_prepare, TransparentClosure)

View File

@@ -46,175 +46,179 @@ using namespace OSL;
// see http://www.graphics.cornell.edu/~bjw/wardnotes.pdf // see http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
class WardClosure : public BSDFClosure { class WardClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
Vec3 m_T; Vec3 m_T;
float m_ax, m_ay; float m_ax, m_ay;
WardClosure() : BSDFClosure(Labels::GLOSSY) { } WardClosure() : BSDFClosure(Labels::GLOSSY) {}
void setup() void setup()
{ {
m_ax = clamp(m_ax, 1e-5f, 1.0f); m_ax = clamp(m_ax, 1e-5f, 1.0f);
m_ay = clamp(m_ay, 1e-5f, 1.0f); m_ay = clamp(m_ay, 1e-5f, 1.0f);
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const WardClosure *comp = (const WardClosure *)other; const WardClosure *comp = (const WardClosure *)other;
return m_N == comp->m_N && m_T == comp->m_T && return m_N == comp->m_N && m_T == comp->m_T &&
m_ax == comp->m_ax && m_ay == comp->m_ay && m_ax == comp->m_ax && m_ay == comp->m_ay &&
BSDFClosure::mergeable(other); BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "ward"; } const char *name() const { return "ward"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " (("; out << name() << " ((";
out << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ("; out << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), (";
out << m_T[0] << ", " << m_T[1] << ", " << m_T[2] << "), "; out << m_T[0] << ", " << m_T[1] << ", " << m_T[2] << "), ";
out << m_ax << ", " << m_ay << ")"; out << m_ax << ", " << m_ay << ")";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNI > 0 && cosNO > 0) { if (cosNI > 0 && cosNO > 0) {
// get half vector and get x,y basis on the surface for anisotropy // get half vector and get x,y basis on the surface for anisotropy
Vec3 H = omega_in + omega_out; Vec3 H = omega_in + omega_out;
H.normalize(); // normalize needed for pdf H.normalize(); // normalize needed for pdf
Vec3 X, Y; Vec3 X, Y;
make_orthonormals(m_N, m_T, X, Y); make_orthonormals(m_N, m_T, X, Y);
// eq. 4 // eq. 4
float dotx = H.dot(X) / m_ax; float dotx = H.dot(X) / m_ax;
float doty = H.dot(Y) / m_ay; float doty = H.dot(Y) / m_ay;
float dotn = H.dot(m_N); float dotn = H.dot(m_N);
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
float denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI)); float denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI));
float exp_val = expf(-exp_arg); float exp_val = expf(-exp_arg);
float out = cosNI * exp_val / denom; float out = cosNI * exp_val / denom;
float oh = H.dot(omega_out); float oh = H.dot(omega_out);
denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn; denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn;
pdf = exp_val / denom; pdf = exp_val / denom;
return Color3 (out, out, out); return Color3(out, out, out);
} }
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
if (cosNO > 0) { if (cosNO > 0) {
// get x,y basis on the surface for anisotropy // get x,y basis on the surface for anisotropy
Vec3 X, Y; Vec3 X, Y;
make_orthonormals(m_N, m_T, X, Y); make_orthonormals(m_N, m_T, X, Y);
// generate random angles for the half vector // generate random angles for the half vector
// eq. 7 (taking care around discontinuities to keep // eq. 7 (taking care around discontinuities to keep
// output angle in the right quadrant) // output angle in the right quadrant)
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
// and sin(atan(x)) == x/sqrt(1+x^2) // and sin(atan(x)) == x/sqrt(1+x^2)
float alphaRatio = m_ay / m_ax; float alphaRatio = m_ay / m_ax;
float cosPhi, sinPhi; float cosPhi, sinPhi;
if (randu < 0.25f) { if (randu < 0.25f) {
float val = 4 * randu; float val = 4 * randu;
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
sinPhi = tanPhi * cosPhi; sinPhi = tanPhi * cosPhi;
} else if (randu < 0.5) { }
float val = 1 - 4 * (0.5f - randu); else if (randu < 0.5) {
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); float val = 1 - 4 * (0.5f - randu);
// phi = (float) M_PI - phi; float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); // phi = (float) M_PI - phi;
sinPhi = -tanPhi * cosPhi; cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
} else if (randu < 0.75f) { sinPhi = -tanPhi * cosPhi;
float val = 4 * (randu - 0.5f); }
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); else if (randu < 0.75f) {
//phi = (float) M_PI + phi; float val = 4 * (randu - 0.5f);
cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
sinPhi = tanPhi * cosPhi; //phi = (float) M_PI + phi;
} else { cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
float val = 1 - 4 * (1 - randu); sinPhi = tanPhi * cosPhi;
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); }
// phi = 2 * (float) M_PI - phi; else {
cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); float val = 1 - 4 * (1 - randu);
sinPhi = -tanPhi * cosPhi; float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
} // phi = 2 * (float) M_PI - phi;
// eq. 6 cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) sinPhi = -tanPhi * cosPhi;
// and sin(atan(x)) == x/sqrt(1+x^2) }
float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay); // eq. 6
float tanTheta2 = -logf(1 - randv) / thetaDenom; // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
float cosTheta = 1 / sqrtf(1 + tanTheta2); // and sin(atan(x)) == x/sqrt(1+x^2)
float sinTheta = cosTheta * sqrtf(tanTheta2); float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay);
float tanTheta2 = -logf(1 - randv) / thetaDenom;
float cosTheta = 1 / sqrtf(1 + tanTheta2);
float sinTheta = cosTheta * sqrtf(tanTheta2);
Vec3 h; // already normalized becaused expressed from spherical coordinates Vec3 h; // already normalized becaused expressed from spherical coordinates
h.x = sinTheta * cosPhi; h.x = sinTheta * cosPhi;
h.y = sinTheta * sinPhi; h.y = sinTheta * sinPhi;
h.z = cosTheta; h.z = cosTheta;
// compute terms that are easier in local space // compute terms that are easier in local space
float dotx = h.x / m_ax; float dotx = h.x / m_ax;
float doty = h.y / m_ay; float doty = h.y / m_ay;
float dotn = h.z; float dotn = h.z;
// transform to world space // transform to world space
h = h.x * X + h.y * Y + h.z * m_N; h = h.x * X + h.y * Y + h.z * m_N;
// generate the final sample // generate the final sample
float oh = h.dot(omega_out); float oh = h.dot(omega_out);
omega_in.x = 2 * oh * h.x - omega_out.x; omega_in.x = 2 * oh * h.x - omega_out.x;
omega_in.y = 2 * oh * h.y - omega_out.y; omega_in.y = 2 * oh * h.y - omega_out.y;
omega_in.z = 2 * oh * h.z - omega_out.z; omega_in.z = 2 * oh * h.z - omega_out.z;
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNI > 0) { if (cosNI > 0) {
// eq. 9 // eq. 9
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
float denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn; float denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn;
pdf = expf(-exp_arg) / denom; pdf = expf(-exp_arg) / denom;
// compiler will reuse expressions already computed // compiler will reuse expressions already computed
denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI)); denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI));
float power = cosNI * expf(-exp_arg) / denom; float power = cosNI * expf(-exp_arg) / denom;
eval.setValue(power, power, power); eval.setValue(power, power, power);
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
/* disabled for now - gives texture filtering problems */ /* disabled for now - gives texture filtering problems */
#if 0 #if 0
// Since there is some blur to this reflection, make the // Since there is some blur to this reflection, make the
// derivatives a bit bigger. In theory this varies with the // derivatives a bit bigger. In theory this varies with the
// roughness but the exact relationship is complex and // roughness but the exact relationship is complex and
// requires more ops than are practical. // requires more ops than are practical.
domega_in_dx *= 10; domega_in_dx *= 10;
domega_in_dy *= 10; domega_in_dy *= 10;
#endif #endif
} }
} }
} }
return Labels::REFLECT; return Labels::REFLECT;
} }
}; };
ClosureParam bsdf_ward_params[] = { ClosureParam bsdf_ward_params[] = {
CLOSURE_VECTOR_PARAM(WardClosure, m_N), CLOSURE_VECTOR_PARAM(WardClosure, m_N),
CLOSURE_VECTOR_PARAM(WardClosure, m_T), CLOSURE_VECTOR_PARAM(WardClosure, m_T),
CLOSURE_FLOAT_PARAM (WardClosure, m_ax), CLOSURE_FLOAT_PARAM(WardClosure, m_ax),
CLOSURE_FLOAT_PARAM (WardClosure, m_ay), CLOSURE_FLOAT_PARAM(WardClosure, m_ay),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(WardClosure) }; CLOSURE_FINISH_PARAM(WardClosure)
};
CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure) CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure)

View File

@@ -44,193 +44,197 @@ using namespace OSL;
class WestinBackscatterClosure : public BSDFClosure { class WestinBackscatterClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
float m_roughness; float m_roughness;
float m_invroughness; float m_invroughness;
WestinBackscatterClosure() : BSDFClosure(Labels::GLOSSY) { } WestinBackscatterClosure() : BSDFClosure(Labels::GLOSSY) {}
void setup() void setup()
{ {
m_roughness = clamp(m_roughness, 1e-5f, 1.0f); m_roughness = clamp(m_roughness, 1e-5f, 1.0f);
m_invroughness = m_roughness > 0 ? 1 / m_roughness : 0; m_invroughness = m_roughness > 0 ? 1 / m_roughness : 0;
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const WestinBackscatterClosure *comp = (const WestinBackscatterClosure *)other; const WestinBackscatterClosure *comp = (const WestinBackscatterClosure *)other;
return m_N == comp->m_N && m_roughness == comp->m_roughness && return m_N == comp->m_N && m_roughness == comp->m_roughness &&
BSDFClosure::mergeable(other); BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "westin_backscatter"; } const char *name() const { return "westin_backscatter"; }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
out << m_roughness; out << m_roughness;
out << ")"; out << ")";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
{ {
// pdf is implicitly 0 (no indirect sampling) // pdf is implicitly 0 (no indirect sampling)
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNO > 0 && cosNI > 0) { if (cosNO > 0 && cosNI > 0) {
float cosine = omega_out.dot(omega_in); float cosine = omega_out.dot(omega_in);
pdf = cosine > 0 ? (m_invroughness + 1) * powf(cosine, m_invroughness) : 0; pdf = cosine > 0 ? (m_invroughness + 1) * powf(cosine, m_invroughness) : 0;
pdf *= 0.5f * float(M_1_PI); pdf *= 0.5f * float(M_1_PI);
return Color3 (pdf, pdf, pdf); return Color3(pdf, pdf, pdf);
} }
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
if (cosNO > 0) { if (cosNO > 0) {
domega_in_dx = domega_out_dx; domega_in_dx = domega_out_dx;
domega_in_dy = domega_out_dy; domega_in_dy = domega_out_dy;
Vec3 T, B; Vec3 T, B;
make_orthonormals (omega_out, T, B); make_orthonormals(omega_out, T, B);
float phi = 2 * (float) M_PI * randu; float phi = 2 * (float) M_PI * randu;
float cosTheta = powf(randv, 1 / (m_invroughness + 1)); float cosTheta = powf(randv, 1 / (m_invroughness + 1));
float sinTheta2 = 1 - cosTheta * cosTheta; float sinTheta2 = 1 - cosTheta * cosTheta;
float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0;
omega_in = (cosf(phi) * sinTheta) * T + omega_in = (cosf(phi) * sinTheta) * T +
(sinf(phi) * sinTheta) * B + (sinf(phi) * sinTheta) * B +
( cosTheta) * omega_out; (cosTheta) * omega_out;
if (Ng.dot(omega_in) > 0) if (Ng.dot(omega_in) > 0)
{ {
// common terms for pdf and eval // common terms for pdf and eval
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
// make sure the direction we chose is still in the right hemisphere // make sure the direction we chose is still in the right hemisphere
if (cosNI > 0) if (cosNI > 0)
{ {
pdf = 0.5f * (float) M_1_PI * powf(cosTheta, m_invroughness); pdf = 0.5f * (float) M_1_PI * powf(cosTheta, m_invroughness);
pdf = (m_invroughness + 1) * pdf; pdf = (m_invroughness + 1) * pdf;
eval.setValue(pdf, pdf, pdf); eval.setValue(pdf, pdf, pdf);
// Since there is some blur to this reflection, make the // Since there is some blur to this reflection, make the
// derivatives a bit bigger. In theory this varies with the // derivatives a bit bigger. In theory this varies with the
// exponent but the exact relationship is complex and // exponent but the exact relationship is complex and
// requires more ops than are practical. // requires more ops than are practical.
domega_in_dx *= 10; domega_in_dx *= 10;
domega_in_dy *= 10; domega_in_dy *= 10;
} }
} }
} }
return Labels::REFLECT; return Labels::REFLECT;
} }
}; };
class WestinSheenClosure : public BSDFClosure { class WestinSheenClosure : public BSDFClosure {
public: public:
Vec3 m_N; Vec3 m_N;
float m_edginess; float m_edginess;
// float m_normalization; // float m_normalization;
WestinSheenClosure() : BSDFClosure(Labels::DIFFUSE) { } WestinSheenClosure() : BSDFClosure(Labels::DIFFUSE) {}
void setup() {}; void setup() {};
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const WestinSheenClosure *comp = (const WestinSheenClosure *)other; const WestinSheenClosure *comp = (const WestinSheenClosure *)other;
return m_N == comp->m_N && m_edginess == comp->m_edginess && return m_N == comp->m_N && m_edginess == comp->m_edginess &&
BSDFClosure::mergeable(other); BSDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "westin_sheen"; } const char *name() const { return "westin_sheen"; }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ("; out << name() << " (";
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
out << m_edginess; out << m_edginess;
out << ")"; out << ")";
} }
float albedo (const Vec3 &omega_out) const float albedo(const Vec3 &omega_out) const
{ {
return 1.0f; return 1.0f;
} }
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const Color3 eval_reflect(const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
{ {
// pdf is implicitly 0 (no indirect sampling) // pdf is implicitly 0 (no indirect sampling)
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float cosNI = m_N.dot(omega_in); float cosNI = m_N.dot(omega_in);
if (cosNO > 0 && cosNI > 0) { if (cosNO > 0 && cosNI > 0) {
float sinNO2 = 1 - cosNO * cosNO; float sinNO2 = 1 - cosNO * cosNO;
pdf = cosNI * float(M_1_PI); pdf = cosNI * float(M_1_PI);
float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0; float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0;
return Color3 (westin, westin, westin); return Color3(westin, westin, westin);
} }
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const Color3 eval_transmit(const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
{ {
return Color3 (0, 0, 0); return Color3(0, 0, 0);
} }
ustring sample (const Vec3 &Ng, ustring sample(const Vec3 &Ng,
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
float randu, float randv, float randu, float randv,
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
float &pdf, Color3 &eval) const float &pdf, Color3 &eval) const
{ {
// we are viewing the surface from the right side - send a ray out with cosine // we are viewing the surface from the right side - send a ray out with cosine
// distribution over the hemisphere // distribution over the hemisphere
sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); sample_cos_hemisphere(m_N, omega_out, randu, randv, omega_in, pdf);
if (Ng.dot(omega_in) > 0) { if (Ng.dot(omega_in) > 0) {
// TODO: account for sheen when sampling // TODO: account for sheen when sampling
float cosNO = m_N.dot(omega_out); float cosNO = m_N.dot(omega_out);
float sinNO2 = 1 - cosNO * cosNO; float sinNO2 = 1 - cosNO * cosNO;
float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0; float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0;
eval.setValue(westin, westin, westin); eval.setValue(westin, westin, westin);
// TODO: find a better approximation for the diffuse bounce // TODO: find a better approximation for the diffuse bounce
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
domega_in_dx *= 125; domega_in_dx *= 125;
domega_in_dy *= 125; domega_in_dy *= 125;
} else }
pdf = 0; else {
return Labels::REFLECT; pdf = 0;
} }
return Labels::REFLECT;
}
}; };
ClosureParam bsdf_westin_backscatter_params[] = { ClosureParam bsdf_westin_backscatter_params[] = {
CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N), CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N),
CLOSURE_FLOAT_PARAM (WestinBackscatterClosure, m_roughness), CLOSURE_FLOAT_PARAM(WestinBackscatterClosure, m_roughness),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(WestinBackscatterClosure) }; CLOSURE_FINISH_PARAM(WestinBackscatterClosure)
};
ClosureParam bsdf_westin_sheen_params[] = { ClosureParam bsdf_westin_sheen_params[] = {
CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N), CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N),
CLOSURE_FLOAT_PARAM (WestinSheenClosure, m_edginess), CLOSURE_FLOAT_PARAM(WestinSheenClosure, m_edginess),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(WestinSheenClosure) }; CLOSURE_FINISH_PARAM(WestinSheenClosure)
};
CLOSURE_PREPARE(bsdf_westin_backscatter_prepare, WestinBackscatterClosure) CLOSURE_PREPARE(bsdf_westin_backscatter_prepare, WestinBackscatterClosure)
CLOSURE_PREPARE(bsdf_westin_sheen_prepare, WestinSheenClosure) CLOSURE_PREPARE(bsdf_westin_sheen_prepare, WestinSheenClosure)

View File

@@ -42,62 +42,63 @@ using namespace OSL;
class BSSRDFCubicClosure : public BSSRDFClosure { class BSSRDFCubicClosure : public BSSRDFClosure {
public: public:
Color3 m_radius; Color3 m_radius;
Color3 m_scale; Color3 m_scale;
float m_max_radius; float m_max_radius;
template <typename T> template <typename T>
static inline T pow3 (const T &x) { return x * x * x; } static inline T pow3(const T &x) { return x * x * x; }
template <typename T> template <typename T>
static inline T pow5 (const T &x) { T x2 = x * x; return x2 * x2 * x; } static inline T pow5(const T &x) { T x2 = x * x; return x2 * x2 * x; }
BSSRDFCubicClosure() { } BSSRDFCubicClosure() {}
void setup() void setup()
{ {
// pre-compute some terms // pre-compute some terms
m_max_radius = 0; m_max_radius = 0;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
m_scale[i] = m_radius[i] > 0 ? 4 / pow5 (m_radius[i]) : 0; m_scale[i] = m_radius[i] > 0 ? 4 / pow5(m_radius[i]) : 0;
m_max_radius = std::max (m_max_radius, m_radius[i]); m_max_radius = std::max(m_max_radius, m_radius[i]);
} }
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const BSSRDFCubicClosure *comp = (const BSSRDFCubicClosure *)other; const BSSRDFCubicClosure *comp = (const BSSRDFCubicClosure *)other;
return m_radius == comp->m_radius && BSSRDFClosure::mergeable(other); return m_radius == comp->m_radius && BSSRDFClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "bssrdf_cubic"; } const char *name() const { return "bssrdf_cubic"; }
void print_on (std::ostream &out) const void print_on(std::ostream &out) const
{ {
out << name() << " ((" << m_radius[0] << ", " << m_radius[1] << ", " << m_radius[2] << "), (" out << name() << " ((" << m_radius[0] << ", " << m_radius[1] << ", " << m_radius[2] << "), ("
<< m_scale[0] << ", " << m_scale[1] << ", " << m_scale[2] << "))"; << m_scale[0] << ", " << m_scale[1] << ", " << m_scale[2] << "))";
} }
Color3 eval (float r) const Color3 eval(float r) const
{ {
return Color3 ((r < m_radius.x) ? pow3 (m_radius.x - r) * m_scale.x : 0, return Color3((r < m_radius.x) ? pow3(m_radius.x - r) * m_scale.x : 0,
(r < m_radius.y) ? pow3 (m_radius.y - r) * m_scale.y : 0, (r < m_radius.y) ? pow3(m_radius.y - r) * m_scale.y : 0,
(r < m_radius.z) ? pow3 (m_radius.z - r) * m_scale.z : 0); (r < m_radius.z) ? pow3(m_radius.z - r) * m_scale.z : 0);
} }
float max_radius() const float max_radius() const
{ {
return m_max_radius; return m_max_radius;
} }
}; };
ClosureParam closure_bssrdf_cubic_params[] = { ClosureParam closure_bssrdf_cubic_params[] = {
CLOSURE_COLOR_PARAM (BSSRDFCubicClosure, m_radius), CLOSURE_COLOR_PARAM(BSSRDFCubicClosure, m_radius),
CLOSURE_STRING_KEYPARAM ("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(BSSRDFCubicClosure) }; CLOSURE_FINISH_PARAM(BSSRDFCubicClosure)
};
CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, BSSRDFCubicClosure) CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, BSSRDFCubicClosure)

View File

@@ -49,30 +49,31 @@ using namespace OSL;
class DebugClosure : public ClosurePrimitive { class DebugClosure : public ClosurePrimitive {
public: public:
ustring m_tag; ustring m_tag;
DebugClosure () : ClosurePrimitive (Debug) { } DebugClosure () : ClosurePrimitive(Debug) {}
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const DebugClosure *comp = (const DebugClosure *)other; const DebugClosure *comp = (const DebugClosure *)other;
return m_tag == comp->m_tag && return m_tag == comp->m_tag &&
ClosurePrimitive::mergeable(other); ClosurePrimitive::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "debug"; } const char *name() const { return "debug"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " (\"" << m_tag.c_str() << "\")"; out << name() << " (\"" << m_tag.c_str() << "\")";
} }
}; };
ClosureParam closure_debug_params[] = { ClosureParam closure_debug_params[] = {
CLOSURE_STRING_PARAM(DebugClosure, m_tag), CLOSURE_STRING_PARAM(DebugClosure, m_tag),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(DebugClosure) }; CLOSURE_FINISH_PARAM(DebugClosure)
};
CLOSURE_PREPARE(closure_debug_prepare, DebugClosure) CLOSURE_PREPARE(closure_debug_prepare, DebugClosure)

View File

@@ -49,57 +49,58 @@ using namespace OSL;
/// ///
class GenericEmissiveClosure : public EmissiveClosure { class GenericEmissiveClosure : public EmissiveClosure {
public: public:
GenericEmissiveClosure() { } GenericEmissiveClosure() { }
void setup() { } void setup() {}
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "emission"; } const char *name() const { return "emission"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << "()"; out << name() << "()";
} }
Color3 eval (const Vec3 &Ng, const Vec3 &omega_out) const Color3 eval(const Vec3 &Ng, const Vec3 &omega_out) const
{ {
float cosNO = fabsf(Ng.dot(omega_out)); float cosNO = fabsf(Ng.dot(omega_out));
float res = cosNO > 0 ? 1.0f: 0.0f; float res = cosNO > 0 ? 1.0f : 0.0f;
return Color3(res, res, res); return Color3(res, res, res);
} }
void sample (const Vec3 &Ng, float randu, float randv, void sample(const Vec3 &Ng, float randu, float randv,
Vec3 &omega_out, float &pdf) const Vec3 &omega_out, float &pdf) const
{ {
// We don't do anything sophisticated here for the step // We don't do anything sophisticated here for the step
// We just sample the whole cone uniformly to the cosine // We just sample the whole cone uniformly to the cosine
Vec3 T, B; Vec3 T, B;
make_orthonormals(Ng, T, B); make_orthonormals(Ng, T, B);
float phi = 2 * (float) M_PI * randu; float phi = 2 * (float) M_PI * randu;
float cosTheta = sqrtf(1.0f - 1.0f * randv); float cosTheta = sqrtf(1.0f - 1.0f * randv);
float sinTheta = sqrtf(1.0f - cosTheta * cosTheta); float sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
omega_out = (cosf(phi) * sinTheta) * T + omega_out = (cosf(phi) * sinTheta) * T +
(sinf(phi) * sinTheta) * B + (sinf(phi) * sinTheta) * B +
cosTheta * Ng; cosTheta * Ng;
pdf = 1.0f / float(M_PI); pdf = 1.0f / float(M_PI);
} }
/// Return the probability distribution function in the direction omega_out, /// Return the probability distribution function in the direction omega_out,
/// given the parameters and the light's surface normal. This MUST match /// given the parameters and the light's surface normal. This MUST match
/// the PDF computed by sample(). /// the PDF computed by sample().
float pdf (const Vec3 &Ng, float pdf(const Vec3 &Ng,
const Vec3 &omega_out) const const Vec3 &omega_out) const
{ {
float cosNO = Ng.dot(omega_out); float cosNO = Ng.dot(omega_out);
return cosNO > 0 ? 1.0f: 0.0f; return cosNO > 0 ? 1.0f : 0.0f;
} }
}; };
ClosureParam closure_emission_params[] = { ClosureParam closure_emission_params[] = {
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(GenericEmissiveClosure) }; CLOSURE_FINISH_PARAM(GenericEmissiveClosure)
};
CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure) CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure)

View File

@@ -18,18 +18,18 @@
float color_srgb_to_scene_linear(float c) float color_srgb_to_scene_linear(float c)
{ {
if(c < 0.04045) if (c < 0.04045)
return (c < 0.0)? 0.0: c * (1.0/12.92); return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
else else
return pow((c + 0.055)*(1.0/1.055), 2.4); return pow((c + 0.055) * (1.0 / 1.055), 2.4);
} }
float color_scene_linear_to_srgb(float c) float color_scene_linear_to_srgb(float c)
{ {
if(c < 0.0031308) if (c < 0.0031308)
return (c < 0.0)? 0.0: c * 12.92; return (c < 0.0) ? 0.0 : c * 12.92;
else else
return 1.055 * pow(c, 1.0/2.4) - 0.055; return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
} }
color color_srgb_to_scene_linear(color c) color color_srgb_to_scene_linear(color c)
@@ -61,27 +61,27 @@ color rgb_to_hsv(color rgb)
v = cmax; v = cmax;
if(cmax != 0.0) { if (cmax != 0.0) {
s = cdelta/cmax; s = cdelta / cmax;
} }
else { else {
s = 0.0; s = 0.0;
h = 0.0; h = 0.0;
} }
if(s == 0.0) { if (s == 0.0) {
h = 0.0; h = 0.0;
} }
else { else {
c = (color(cmax, cmax, cmax) - rgb)/cdelta; c = (color(cmax, cmax, cmax) - rgb) / cdelta;
if(rgb[0] == cmax) h = c[2] - c[1]; if (rgb[0] == cmax) h = c[2] - c[1];
else if(rgb[1] == cmax) h = 2.0 + c[0] - c[2]; else if (rgb[1] == cmax) h = 2.0 + c[0] - c[2];
else h = 4.0 + c[1] - c[0]; else h = 4.0 + c[1] - c[0];
h /= 6.0; h /= 6.0;
if(h < 0.0) if (h < 0.0)
h += 1.0; h += 1.0;
} }
@@ -97,26 +97,26 @@ color hsv_to_rgb(color hsv)
s = hsv[1]; s = hsv[1];
v = hsv[2]; v = hsv[2];
if(s==0.0) { if (s == 0.0) {
rgb = color(v, v, v); rgb = color(v, v, v);
} }
else { else {
if(h==1.0) if (h == 1.0)
h = 0.0; h = 0.0;
h *= 6.0; h *= 6.0;
i = floor(h); i = floor(h);
f = h - i; f = h - i;
rgb = color(f, f, f); rgb = color(f, f, f);
p = v*(1.0-s); p = v * (1.0 - s);
q = v*(1.0-(s*f)); q = v * (1.0 - (s * f));
t = v*(1.0-(s*(1.0-f))); t = v * (1.0 - (s * (1.0 - f)));
if(i == 0.0) rgb = color(v, t, p); if (i == 0.0) rgb = color(v, t, p);
else if(i == 1.0) rgb = color(q, v, p); else if (i == 1.0) rgb = color(q, v, p);
else if(i == 2.0) rgb = color(p, v, t); else if (i == 2.0) rgb = color(p, v, t);
else if(i == 3.0) rgb = color(p, q, v); else if (i == 3.0) rgb = color(p, q, v);
else if(i == 4.0) rgb = color(t, p, v); else if (i == 4.0) rgb = color(t, p, v);
else rgb = color(v, p, q); else rgb = color(v, p, q);
} }

View File

@@ -7,11 +7,11 @@ float fresnel_dielectric(vector Incoming, normal Normal, float eta)
float g = eta * eta - 1 + c * c; float g = eta * eta - 1 + c * c;
float result; float result;
if(g > 0) { if (g > 0) {
g = sqrt(g); g = sqrt(g);
float A =(g - c)/(g + c); float A = (g - c) / (g + c);
float B =(c *(g + c)- 1)/(c *(g - c)+ 1); float B = (c * (g + c) - 1) / (c * (g - c) + 1);
result = 0.5 * A * A *(1 + B * B); result = 0.5 * A * A * (1 + B * B);
} }
else else
result = 1.0; /* TIR (no refracted component) */ result = 1.0; /* TIR (no refracted component) */

View File

@@ -20,20 +20,20 @@ float voronoi_distance(string distance_metric, vector d, float e)
{ {
float result = 0.0; float result = 0.0;
if(distance_metric == "Distance Squared") if (distance_metric == "Distance Squared")
result = dot(d, d); result = dot(d, d);
if(distance_metric == "Actual Distance") if (distance_metric == "Actual Distance")
result = length(d); result = length(d);
if(distance_metric == "Manhattan") if (distance_metric == "Manhattan")
result = fabs(d[0]) + fabs(d[1]) + fabs(d[2]); result = fabs(d[0]) + fabs(d[1]) + fabs(d[2]);
if(distance_metric == "Chebychev") if (distance_metric == "Chebychev")
result = max(fabs(d[0]), max(fabs(d[1]), fabs(d[2]))); result = max(fabs(d[0]), max(fabs(d[1]), fabs(d[2])));
if(distance_metric == "Minkovsky 1/2") if (distance_metric == "Minkovsky 1/2")
result = sqrt(fabs(d[0])) + sqrt(fabs(d[1])) + sqrt(fabs(d[1])); result = sqrt(fabs(d[0])) + sqrt(fabs(d[1])) + sqrt(fabs(d[1]));
if(distance_metric == "Minkovsky 4") if (distance_metric == "Minkovsky 4")
result = sqrt(sqrt(dot(d*d, d*d))); result = sqrt(sqrt(dot(d * d, d * d)));
if(distance_metric == "Minkovsky") if (distance_metric == "Minkovsky")
result = pow(pow(fabs(d[0]), e) + pow(fabs(d[1]), e) + pow(fabs(d[2]), e), 1.0/e); result = pow(pow(fabs(d[0]), e) + pow(fabs(d[1]), e) + pow(fabs(d[2]), e), 1.0 / e);
return result; return result;
} }
@@ -63,9 +63,9 @@ void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
da[2] = 1e10; da[2] = 1e10;
da[3] = 1e10; da[3] = 1e10;
for(xx = xi-1; xx <= xi+1; xx++) { for (xx = xi - 1; xx <= xi + 1; xx++) {
for(yy = yi-1; yy <= yi+1; yy++) { for (yy = yi - 1; yy <= yi + 1; yy++) {
for(zz = zi-1; zz <= zi+1; zz++) { for (zz = zi - 1; zz <= zi + 1; zz++) {
point ip = point(xx, yy, zz); point ip = point(xx, yy, zz);
point vp = (point)cellnoise_color(ip); point vp = (point)cellnoise_color(ip);
point pd = p - (vp + ip); point pd = p - (vp + ip);
@@ -73,7 +73,7 @@ void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
vp += point(xx, yy, zz); vp += point(xx, yy, zz);
if(d < da[0]) { if (d < da[0]) {
da[3] = da[2]; da[3] = da[2];
da[2] = da[1]; da[2] = da[1];
da[1] = da[0]; da[1] = da[0];
@@ -84,7 +84,7 @@ void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
pa[1] = pa[0]; pa[1] = pa[0];
pa[0] = vp; pa[0] = vp;
} }
else if(d < da[1]) { else if (d < da[1]) {
da[3] = da[2]; da[3] = da[2];
da[2] = da[1]; da[2] = da[1];
da[1] = d; da[1] = d;
@@ -93,14 +93,14 @@ void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
pa[2] = pa[1]; pa[2] = pa[1];
pa[1] = vp; pa[1] = vp;
} }
else if(d < da[2]) { else if (d < da[2]) {
da[3] = da[2]; da[3] = da[2];
da[2] = d; da[2] = d;
pa[3] = pa[2]; pa[3] = pa[2];
pa[2] = vp; pa[2] = vp;
} }
else if(d < da[3]) { else if (d < da[3]) {
da[3] = d; da[3] = d;
pa[3] = vp; pa[3] = vp;
} }
@@ -138,16 +138,16 @@ float voronoi_F1F2(point p) { return voronoi_FnFn(p, 0, 1); }
float voronoi_Cr(point p) float voronoi_Cr(point p)
{ {
/* crackle type pattern, just a scale/clamp of F2-F1 */ /* crackle type pattern, just a scale/clamp of F2-F1 */
float t = 10.0*voronoi_F1F2(p); float t = 10.0 * voronoi_F1F2(p);
return (t > 1.0)? 1.0: t; return (t > 1.0) ? 1.0 : t;
} }
float voronoi_F1S(point p) { return 2.0*voronoi_F1(p) - 1.0; } float voronoi_F1S(point p) { return 2.0 * voronoi_F1(p) - 1.0; }
float voronoi_F2S(point p) { return 2.0*voronoi_F2(p) - 1.0; } float voronoi_F2S(point p) { return 2.0 * voronoi_F2(p) - 1.0; }
float voronoi_F3S(point p) { return 2.0*voronoi_F3(p) - 1.0; } float voronoi_F3S(point p) { return 2.0 * voronoi_F3(p) - 1.0; }
float voronoi_F4S(point p) { return 2.0*voronoi_F4(p) - 1.0; } float voronoi_F4S(point p) { return 2.0 * voronoi_F4(p) - 1.0; }
float voronoi_F1F2S(point p) { return 2.0*voronoi_F1F2(p) - 1.0; } float voronoi_F1F2S(point p) { return 2.0 * voronoi_F1F2(p) - 1.0; }
float voronoi_CrS(point p) { return 2.0*voronoi_Cr(p) - 1.0; } float voronoi_CrS(point p) { return 2.0 * voronoi_Cr(p) - 1.0; }
/* Noise Bases */ /* Noise Bases */
@@ -155,21 +155,21 @@ float noise_basis(point p, string basis)
{ {
float result = 0.0; float result = 0.0;
if(basis == "Perlin") if (basis == "Perlin")
result = noise(p); result = noise(p);
if(basis == "Voronoi F1") if (basis == "Voronoi F1")
result = voronoi_F1S(p); result = voronoi_F1S(p);
if(basis == "Voronoi F2") if (basis == "Voronoi F2")
result = voronoi_F2S(p); result = voronoi_F2S(p);
if(basis == "Voronoi F3") if (basis == "Voronoi F3")
result = voronoi_F3S(p); result = voronoi_F3S(p);
if(basis == "Voronoi F4") if (basis == "Voronoi F4")
result = voronoi_F4S(p); result = voronoi_F4S(p);
if(basis == "Voronoi F2-F1") if (basis == "Voronoi F2-F1")
result = voronoi_F1F2S(p); result = voronoi_F1F2S(p);
if(basis == "Voronoi Crackle") if (basis == "Voronoi Crackle")
result = voronoi_CrS(p); result = voronoi_CrS(p);
if(basis == "Cell Noise") if (basis == "Cell Noise")
result = cellnoise(p); result = cellnoise(p);
return result; return result;
@@ -180,7 +180,7 @@ float noise_basis(point p, string basis)
float noise_basis_hard(point p, string basis, int hard) float noise_basis_hard(point p, string basis, int hard)
{ {
float t = noise_basis(p, basis); float t = noise_basis(p, basis);
return (hard)? fabs(2.0*t - 1.0): t; return (hard) ? fabs(2.0 * t - 1.0) : t;
} }
/* Waves */ /* Waves */
@@ -189,22 +189,22 @@ float noise_wave(string wave, float a)
{ {
float result = 0.0; float result = 0.0;
if(wave == "Sine") { if (wave == "Sine") {
result = 0.5 + 0.5*sin(a); result = 0.5 + 0.5 * sin(a);
} }
else if(wave == "Saw") { else if (wave == "Saw") {
float b = 2*M_PI; float b = 2 * M_PI;
int n = (int)(a / b); int n = (int)(a / b);
a -= n*b; a -= n * b;
if(a < 0) a += b; if (a < 0) a += b;
result = a / b; result = a / b;
} }
else if(wave == "Tri") { else if (wave == "Tri") {
float b = 2*M_PI; float b = 2 * M_PI;
float rmax = 1.0; float rmax = 1.0;
result = rmax - 2.0*fabs(floor((a*(1.0/b))+0.5) - (a*(1.0/b))); result = rmax - 2.0 * fabs(floor((a * (1.0 / b)) + 0.5) - (a * (1.0 / b)));
} }
return result; return result;
@@ -219,18 +219,18 @@ float noise_turbulence(point p, string basis, int octaves, int hard)
float sum = 0.0; float sum = 0.0;
int i; int i;
for(i = 0; i <= octaves; i++) { for (i = 0; i <= octaves; i++) {
float t = noise_basis(fscale*p, basis); float t = noise_basis(fscale * p, basis);
if(hard) if (hard)
t = fabs(2.0*t - 1.0); t = fabs(2.0 * t - 1.0);
sum += t*amp; sum += t * amp;
amp *= 0.5; amp *= 0.5;
fscale *= 2.0; fscale *= 2.0;
} }
sum *= ((float)(1 << octaves)/(float)((1 << (octaves+1)) - 1)); sum *= ((float)(1 << octaves) / (float)((1 << (octaves + 1)) - 1));
return sum; return sum;
} }
@@ -241,8 +241,8 @@ float nonzero(float f, float eps)
{ {
float r; float r;
if(abs(f) < eps) if (abs(f) < eps)
r = sign(f)*eps; r = sign(f) * eps;
else else
r = f; r = f;

View File

@@ -163,241 +163,246 @@ vector normalize (vector v) BUILTIN;
vector faceforward (vector N, vector I, vector Nref) BUILTIN; vector faceforward (vector N, vector I, vector Nref) BUILTIN;
vector faceforward (vector N, vector I) BUILTIN; vector faceforward (vector N, vector I) BUILTIN;
vector reflect (vector I, vector N) { return I - 2*dot(N,I)*N; } vector reflect (vector I, vector N) { return I - 2*dot(N,I)*N; }
vector refract (vector I, vector N, float eta) { vector refract(vector I, vector N, float eta) {
float IdotN = dot (I, N); float IdotN = dot(I, N);
float k = 1 - eta*eta * (1 - IdotN*IdotN); float k = 1 - eta * eta * (1 - IdotN * IdotN);
return (k < 0) ? vector(0,0,0) : (eta*I - N * (eta*IdotN + sqrt(k))); return (k < 0) ? vector(0, 0, 0) : (eta * I - N * (eta * IdotN + sqrt(k)));
} }
void fresnel (vector I, normal N, float eta, void fresnel(vector I, normal N, float eta,
output float Kr, output float Kt, output float Kr, output float Kt,
output vector R, output vector T) output vector R, output vector T)
{ {
float sqr(float x) { return x*x; } float sqr(float x) {
float c = dot(I, N); return x * x;
if (c < 0) }
c = -c; float c = dot(I, N);
R = reflect(I, N); if (c < 0)
float g = 1.0 / sqr(eta) - 1.0 + c * c; c = -c;
if (g >= 0.0) { R = reflect(I, N);
g = sqrt (g); float g = 1.0 / sqr(eta) - 1.0 + c * c;
float beta = g - c; if (g >= 0.0) {
float F = (c * (g+c) - 1.0) / (c * beta + 1.0); g = sqrt(g);
F = 0.5 * (1.0 + sqr(F)); float beta = g - c;
F *= sqr (beta / (g+c)); float F = (c * (g + c) - 1.0) / (c * beta + 1.0);
Kr = F; F = 0.5 * (1.0 + sqr(F));
Kt = (1.0 - Kr) * eta*eta; F *= sqr(beta / (g + c));
// OPT: the following recomputes some of the above values, but it Kr = F;
// gives us the same result as if the shader-writer called refract() Kt = (1.0 - Kr) * eta * eta;
T = refract(I, N, eta); // OPT: the following recomputes some of the above values, but it
} else { // gives us the same result as if the shader-writer called refract()
// total internal reflection T = refract(I, N, eta);
Kr = 1.0; }
Kt = 0.0; else {
T = vector (0,0,0); // total internal reflection
} Kr = 1.0;
Kt = 0.0;
T = vector(0, 0, 0);
}
#undef sqr #undef sqr
} }
void fresnel (vector I, normal N, float eta, void fresnel(vector I, normal N, float eta,
output float Kr, output float Kt) output float Kr, output float Kt)
{ {
vector R, T; vector R, T;
fresnel(I, N, eta, Kr, Kt, R, T); fresnel(I, N, eta, Kr, Kt, R, T);
} }
point rotate (point q, float angle, point a, point b) BUILTIN; point rotate(point q, float angle, point a, point b) BUILTIN;
normal transform (matrix Mto, normal p) BUILTIN; normal transform(matrix Mto, normal p) BUILTIN;
vector transform (matrix Mto, vector p) BUILTIN; vector transform(matrix Mto, vector p) BUILTIN;
point transform (matrix Mto, point p) BUILTIN; point transform(matrix Mto, point p) BUILTIN;
// Implementation of transform-with-named-space in terms of matrices: // Implementation of transform-with-named-space in terms of matrices:
point transform (string tospace, point x) point transform(string tospace, point x)
{ {
return transform (matrix ("common", tospace), x); return transform(matrix("common", tospace), x);
} }
point transform (string fromspace, string tospace, point x) point transform(string fromspace, string tospace, point x)
{ {
return transform (matrix (fromspace, tospace), x); return transform(matrix(fromspace, tospace), x);
} }
vector transform (string tospace, vector x) vector transform(string tospace, vector x)
{ {
return transform (matrix ("common", tospace), x); return transform(matrix("common", tospace), x);
} }
vector transform (string fromspace, string tospace, vector x) vector transform(string fromspace, string tospace, vector x)
{ {
return transform (matrix (fromspace, tospace), x); return transform(matrix(fromspace, tospace), x);
} }
normal transform (string tospace, normal x) normal transform(string tospace, normal x)
{ {
return transform (matrix ("common", tospace), x); return transform(matrix("common", tospace), x);
} }
normal transform (string fromspace, string tospace, normal x) normal transform(string fromspace, string tospace, normal x)
{ {
return transform (matrix (fromspace, tospace), x); return transform(matrix(fromspace, tospace), x);
} }
float transformu (string tounits, float x) BUILTIN; float transformu(string tounits, float x) BUILTIN;
float transformu (string fromunits, string tounits, float x) BUILTIN; float transformu(string fromunits, string tounits, float x) BUILTIN;
// Color functions // Color functions
float luminance (color c) { float luminance(color c) {
return dot ((vector)c, vector(0.2126, 0.7152, 0.0722)); return dot((vector)c, vector(0.2126, 0.7152, 0.0722));
} }
color transformc (string to, color x) color transformc(string to, color x)
{ {
color rgb_to_hsv (color rgb) { // See Foley & van Dam color rgb_to_hsv(color rgb) { // See Foley & van Dam
float r = rgb[0], g = rgb[1], b = rgb[2]; float r = rgb[0], g = rgb[1], b = rgb[2];
float mincomp = min (r, min (g, b)); float mincomp = min(r, min(g, b));
float maxcomp = max (r, max (g, b)); float maxcomp = max(r, max(g, b));
float delta = maxcomp - mincomp; // chroma float delta = maxcomp - mincomp; // chroma
float h, s, v; float h, s, v;
v = maxcomp; v = maxcomp;
if (maxcomp > 0) if (maxcomp > 0)
s = delta / maxcomp; s = delta / maxcomp;
else s = 0; else s = 0;
if (s <= 0) if (s <= 0)
h = 0; h = 0;
else { else {
if (r >= maxcomp) h = (g-b) / delta; if (r >= maxcomp) h = (g - b) / delta;
else if (g >= maxcomp) h = 2 + (b-r) / delta; else if (g >= maxcomp) h = 2 + (b - r) / delta;
else h = 4 + (r-g) / delta; else h = 4 + (r - g) / delta;
h /= 6; h /= 6;
if (h < 0) if (h < 0)
h += 1; h += 1;
} }
return color (h, s, v); return color(h, s, v);
} }
color rgb_to_hsl (color rgb) { // See Foley & van Dam color rgb_to_hsl(color rgb) { // See Foley & van Dam
// First convert rgb to hsv, then to hsl // First convert rgb to hsv, then to hsl
float minval = min (rgb[0], min (rgb[1], rgb[2])); float minval = min(rgb[0], min(rgb[1], rgb[2]));
color hsv = rgb_to_hsv (rgb); color hsv = rgb_to_hsv(rgb);
float maxval = hsv[2]; // v == maxval float maxval = hsv[2]; // v == maxval
float h = hsv[0], s, l = (minval+maxval) / 2; float h = hsv[0], s, l = (minval + maxval) / 2;
if (minval == maxval) if (minval == maxval)
s = 0; // special 'achromatic' case, hue is 0 s = 0; // special 'achromatic' case, hue is 0
else if (l <= 0.5) else if (l <= 0.5)
s = (maxval - minval) / (maxval + minval); s = (maxval - minval) / (maxval + minval);
else else
s = (maxval - minval) / (2 - maxval - minval); s = (maxval - minval) / (2 - maxval - minval);
return color (h, s, l); return color(h, s, l);
} }
color r; color r;
if (to == "rgb" || to == "RGB") if (to == "rgb" || to == "RGB")
r = x; r = x;
else if (to == "hsv") else if (to == "hsv")
r = rgb_to_hsv (x); r = rgb_to_hsv(x);
else if (to == "hsl") else if (to == "hsl")
r = rgb_to_hsl (x); r = rgb_to_hsl(x);
else if (to == "YIQ") else if (to == "YIQ")
r = color (dot (vector(0.299, 0.587, 0.114), (vector)x), r = color(dot(vector(0.299, 0.587, 0.114), (vector)x),
dot (vector(0.596, -0.275, -0.321), (vector)x), dot(vector(0.596, -0.275, -0.321), (vector)x),
dot (vector(0.212, -0.523, 0.311), (vector)x)); dot(vector(0.212, -0.523, 0.311), (vector)x));
else if (to == "xyz") else if (to == "xyz")
r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x), r = color(dot(vector(0.412453, 0.357580, 0.180423), (vector)x),
dot (vector(0.212671, 0.715160, 0.072169), (vector)x), dot(vector(0.212671, 0.715160, 0.072169), (vector)x),
dot (vector(0.019334, 0.119193, 0.950227), (vector)x)); dot(vector(0.019334, 0.119193, 0.950227), (vector)x));
else { else {
error ("Unknown color space \"%s\"", to); error("Unknown color space \"%s\"", to);
r = x; r = x;
} }
return r; return r;
} }
color transformc (string from, string to, color x) color transformc(string from, string to, color x)
{ {
color hsv_to_rgb (color c) { // Reference: Foley & van Dam color hsv_to_rgb(color c) { // Reference: Foley & van Dam
float h = c[0], s = c[1], v = c[2]; float h = c[0], s = c[1], v = c[2];
color r; color r;
if (s < 0.0001) { if (s < 0.0001) {
r = v; r = v;
} else { }
h = 6 * (h - floor(h)); // expand to [0..6) else {
int hi = (int)h; h = 6 * (h - floor(h)); // expand to [0..6)
float f = h - hi; int hi = (int)h;
float p = v * (1-s); float f = h - hi;
float q = v * (1-s*f); float p = v * (1 - s);
float t = v * (1-s*(1-f)); float q = v * (1 - s * f);
if (hi == 0) r = color (v, t, p); float t = v * (1 - s * (1 - f));
else if (hi == 1) r = color (q, v, p); if (hi == 0) r = color(v, t, p);
else if (hi == 2) r = color (p, v, t); else if (hi == 1) r = color(q, v, p);
else if (hi == 3) r = color (p, q, v); else if (hi == 2) r = color(p, v, t);
else if (hi == 4) r = color (t, p, v); else if (hi == 3) r = color(p, q, v);
else r = color (v, p, q); else if (hi == 4) r = color(t, p, v);
} else r = color(v, p, q);
return r; }
} return r;
}
color hsl_to_rgb (color c) { color hsl_to_rgb(color c) {
float h = c[0], s = c[1], l = c[2]; float h = c[0], s = c[1], l = c[2];
// Easiest to convert hsl -> hsv, then hsv -> RGB (per Foley & van Dam) // Easiest to convert hsl -> hsv, then hsv -> RGB (per Foley & van Dam)
float v = (l <= 0.5) ? (l * (1 + s)) : (l * (1 - s) + s); float v = (l <= 0.5) ? (l * (1 + s)) : (l * (1 - s) + s);
color r; color r;
if (v <= 0) { if (v <= 0) {
r = 0; r = 0;
} else { }
float min = 2 * l - v; else {
s = (v - min) / v; float min = 2 * l - v;
r = hsv_to_rgb (color (h, s, v)); s = (v - min) / v;
} r = hsv_to_rgb(color(h, s, v));
return r; }
} return r;
}
color r; color r;
if (from == "rgb" || from == "RGB") if (from == "rgb" || from == "RGB")
r = x; r = x;
else if (from == "hsv") else if (from == "hsv")
r = hsv_to_rgb (x); r = hsv_to_rgb(x);
else if (from == "hsl") else if (from == "hsl")
r = hsl_to_rgb (x); r = hsl_to_rgb(x);
else if (from == "YIQ") else if (from == "YIQ")
r = color (dot (vector(1, 0.9557, 0.6199), (vector)x), r = color(dot(vector(1, 0.9557, 0.6199), (vector)x),
dot (vector(1, -0.2716, -0.6469), (vector)x), dot(vector(1, -0.2716, -0.6469), (vector)x),
dot (vector(1, -1.1082, 1.7051), (vector)x)); dot(vector(1, -1.1082, 1.7051), (vector)x));
else if (from == "xyz") else if (from == "xyz")
r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x), r = color(dot(vector(3.240479, -1.537150, -0.498535), (vector)x),
dot (vector(-0.969256, 1.875991, 0.041556), (vector)x), dot(vector(-0.969256, 1.875991, 0.041556), (vector)x),
dot (vector( 0.055648, -0.204043, 1.057311), (vector)x)); dot(vector(0.055648, -0.204043, 1.057311), (vector)x));
else { else {
error ("Unknown color space \"%s\"", to); error("Unknown color space \"%s\"", to);
r = x; r = x;
} }
return transformc (to, r); return transformc(to, r);
} }
// Matrix functions // Matrix functions
float determinant (matrix m) BUILTIN; float determinant(matrix m) BUILTIN;
matrix transpose (matrix m) BUILTIN; matrix transpose(matrix m) BUILTIN;
// Pattern generation // Pattern generation
float step (float edge, float x) BUILTIN; float step(float edge, float x) BUILTIN;
color step (color edge, color x) BUILTIN; color step(color edge, color x) BUILTIN;
point step (point edge, point x) BUILTIN; point step(point edge, point x) BUILTIN;
vector step (vector edge, vector x) BUILTIN; vector step(vector edge, vector x) BUILTIN;
normal step (normal edge, normal x) BUILTIN; normal step(normal edge, normal x) BUILTIN;
float smoothstep (float edge0, float edge1, float x) BUILTIN; float smoothstep(float edge0, float edge1, float x) BUILTIN;
// Derivatives and area operators // Derivatives and area operators
@@ -408,24 +413,26 @@ float smoothstep (float edge0, float edge1, float x) BUILTIN;
// String functions // String functions
int strlen (string s) BUILTIN; int strlen(string s) BUILTIN;
int startswith (string s, string prefix) BUILTIN; int startswith(string s, string prefix) BUILTIN;
int endswith (string s, string suffix) BUILTIN; int endswith(string s, string suffix) BUILTIN;
string substr (string s, int start, int len) BUILTIN; string substr(string s, int start, int len) BUILTIN;
string substr (string s, int start) { return substr (s, start, strlen(s)); } string substr(string s, int start) {
return substr(s, start, strlen(s));
}
// Define concat in terms of shorter concat // Define concat in terms of shorter concat
string concat (string a, string b, string c) { string concat(string a, string b, string c) {
return concat(concat(a,b), c); return concat(concat(a, b), c);
} }
string concat (string a, string b, string c, string d) { string concat(string a, string b, string c, string d) {
return concat(concat(a,b,c), d); return concat(concat(a, b, c), d);
} }
string concat (string a, string b, string c, string d, string e) { string concat(string a, string b, string c, string d, string e) {
return concat(concat(a,b,c,d), e); return concat(concat(a, b, c, d), e);
} }
string concat (string a, string b, string c, string d, string e, string f) { string concat(string a, string b, string c, string d, string e, string f) {
return concat(concat(a,b,c,d,e), f); return concat(concat(a, b, c, d, e), f);
} }
@@ -438,7 +445,7 @@ closure color diffuse(normal N) BUILTIN;
closure color oren_nayar(normal N, float sigma) BUILTIN; closure color oren_nayar(normal N, float sigma) BUILTIN;
closure color translucent(normal N) BUILTIN; closure color translucent(normal N) BUILTIN;
closure color reflection(normal N, float eta) BUILTIN; closure color reflection(normal N, float eta) BUILTIN;
closure color reflection(normal N) { return reflection (N, 0.0); } closure color reflection(normal N) { return reflection(N, 0.0); }
closure color refraction(normal N, float eta) BUILTIN; closure color refraction(normal N, float eta) BUILTIN;
closure color dielectric(normal N, float eta) BUILTIN; closure color dielectric(normal N, float eta) BUILTIN;
closure color transparent() BUILTIN; closure color transparent() BUILTIN;
@@ -446,7 +453,7 @@ closure color microfacet_ggx(normal N, float ag) BUILTIN;
closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN;
closure color microfacet_beckmann(normal N, float ab) BUILTIN; closure color microfacet_beckmann(normal N, float ab) BUILTIN;
closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN;
closure color ward(normal N, vector T,float ax, float ay) BUILTIN; closure color ward(normal N, vector T, float ax, float ay) BUILTIN;
closure color ashikhmin_velvet(normal N, float sigma) BUILTIN; closure color ashikhmin_velvet(normal N, float sigma) BUILTIN;
closure color westin_backscatter(normal N, float roughness) BUILTIN; closure color westin_backscatter(normal N, float roughness) BUILTIN;
closure color westin_sheen(normal N, float edginess) BUILTIN; closure color westin_sheen(normal N, float edginess) BUILTIN;
@@ -460,7 +467,7 @@ closure color holdout() BUILTIN;
closure color subsurface(float eta, float g, float mfp, float albedo) BUILTIN; closure color subsurface(float eta, float g, float mfp, float albedo) BUILTIN;
// Renderer state // Renderer state
int raytype (string typename) BUILTIN; int raytype(string typename) BUILTIN;
#undef BUILTIN #undef BUILTIN
#undef BUILTIN_DERIV #undef BUILTIN_DERIV

View File

@@ -37,7 +37,7 @@ CCL_NAMESPACE_BEGIN
/* RenderServices implementation */ /* RenderServices implementation */
#define TO_MATRIX44(m) (*(OSL::Matrix44*)&(m)) #define TO_MATRIX44(m) (*(OSL::Matrix44 *)&(m))
/* static ustrings */ /* static ustrings */
ustring OSLRenderServices::u_distance("distance"); ustring OSLRenderServices::u_distance("distance");
@@ -66,12 +66,12 @@ bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr
{ {
/* this is only used for shader and object space, we don't really have /* this is only used for shader and object space, we don't really have
a concept of shader space, so we just use object space for both. */ a concept of shader space, so we just use object space for both. */
if(xform) { if (xform) {
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = kernel_globals;
const ShaderData *sd = (const ShaderData*)xform; const ShaderData *sd = (const ShaderData *)xform;
int object = sd->object; int object = sd->object;
if(object != ~0) { if (object != ~0) {
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
tfm = transform_transpose(tfm); tfm = transform_transpose(tfm);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
@@ -87,12 +87,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::Transform
{ {
/* this is only used for shader and object space, we don't really have /* this is only used for shader and object space, we don't really have
a concept of shader space, so we just use object space for both. */ a concept of shader space, so we just use object space for both. */
if(xform) { if (xform) {
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = kernel_globals;
const ShaderData *sd = (const ShaderData*)xform; const ShaderData *sd = (const ShaderData *)xform;
int object = sd->object; int object = sd->object;
if(object != ~0) { if (object != ~0) {
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
tfm = transform_transpose(tfm); tfm = transform_transpose(tfm);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
@@ -108,22 +108,22 @@ bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float ti
{ {
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = kernel_globals;
if(from == u_ndc) { if (from == u_ndc) {
Transform tfm = transform_transpose(kernel_data.cam.ndctoworld); Transform tfm = transform_transpose(kernel_data.cam.ndctoworld);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
} }
else if(from == u_raster) { else if (from == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.rastertoworld); Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
} }
else if(from == u_screen) { else if (from == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.screentoworld); Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
} }
else if(from == u_camera) { else if (from == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.cameratoworld); Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
@@ -136,22 +136,22 @@ bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, fl
{ {
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = kernel_globals;
if(to == u_ndc) { if (to == u_ndc) {
Transform tfm = transform_transpose(kernel_data.cam.worldtondc); Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
} }
else if(to == u_raster) { else if (to == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoraster); Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
} }
else if(to == u_screen) { else if (to == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen); Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
} }
else if(to == u_camera) { else if (to == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.worldtocamera); Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
result = TO_MATRIX44(tfm); result = TO_MATRIX44(tfm);
return true; return true;
@@ -161,56 +161,57 @@ bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, fl
} }
bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives, bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives,
ustring object, TypeDesc type, ustring name, ustring object, TypeDesc type, ustring name,
int index, void *val) int index, void *val)
{ {
return false; return false;
} }
static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd,
const OSLGlobals::Attribute& attr, bool derivatives, void *val) const OSLGlobals::Attribute& attr, bool derivatives, void *val)
{ {
if(attr.type == TypeDesc::TypeFloat) { if (attr.type == TypeDesc::TypeFloat) {
float *fval = (float*)val; float *fval = (float *)val;
fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset, fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
(derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL); (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
} }
else { else {
/* todo: this won't work when float3 has w component */ /* todo: this won't work when float3 has w component */
float3 *fval = (float3*)val; float3 *fval = (float3 *)val;
fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset, fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
(derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL); (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
} }
return true; return true;
} }
static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd, static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd,
const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val) const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val)
{ {
if(attr.type == TypeDesc::TypeFloat) { if (attr.type == TypeDesc::TypeFloat) {
float tmp[3]; float tmp[3];
float3 *fval = (float3*)val; float3 *fval = (float3 *)val;
get_mesh_attribute(kg, sd, attr, derivatives, tmp); get_mesh_attribute(kg, sd, attr, derivatives, tmp);
fval[0] = make_float3(tmp[0], tmp[0], tmp[0]); fval[0] = make_float3(tmp[0], tmp[0], tmp[0]);
if(derivatives) { if (derivatives) {
fval[1] = make_float3(tmp[1], tmp[1], tmp[1]); fval[1] = make_float3(tmp[1], tmp[1], tmp[1]);
fval[2] = make_float3(tmp[2], tmp[2], tmp[2]); fval[2] = make_float3(tmp[2], tmp[2], tmp[2]);
} }
return true; return true;
} }
else if(attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector || else if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) { attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
float3 tmp[3]; float3 tmp[3];
float *fval = (float*)val; float *fval = (float *)val;
get_mesh_attribute(kg, sd, attr, derivatives, tmp); get_mesh_attribute(kg, sd, attr, derivatives, tmp);
fval[0] = average(tmp[0]); fval[0] = average(tmp[0]);
if(derivatives) { if (derivatives) {
fval[1] = average(tmp[1]); fval[1] = average(tmp[1]);
fval[2] = average(tmp[2]); fval[2] = average(tmp[2]);
} }
@@ -226,29 +227,29 @@ static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivat
size_t datasize = attr.value.datasize(); size_t datasize = attr.value.datasize();
memcpy(val, attr.value.data(), datasize); memcpy(val, attr.value.data(), datasize);
if(derivatives) if (derivatives)
memset((char*)val + datasize, 0, datasize*2); memset((char *)val + datasize, 0, datasize * 2);
} }
bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name, bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
TypeDesc type, ustring name, void *val) TypeDesc type, ustring name, void *val)
{ {
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = kernel_globals;
const ShaderData *sd = (const ShaderData*)renderstate; const ShaderData *sd = (const ShaderData *)renderstate;
int object = sd->object; int object = sd->object;
int tri = sd->prim; int tri = sd->prim;
/* lookup of attribute on another object */ /* lookup of attribute on another object */
if(object_name != u_empty) { if (object_name != u_empty) {
OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name); OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
if(it == kg->osl.object_name_map.end()) if (it == kg->osl.object_name_map.end())
return false; return false;
object = it->second; object = it->second;
tri = ~0; tri = ~0;
} }
else if(object == ~0) { else if (object == ~0) {
/* no background attributes supported */ /* no background attributes supported */
return false; return false;
} }
@@ -257,20 +258,23 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object]; OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
if(it == attribute_map.end()) if (it == attribute_map.end())
return false; return false;
/* type mistmatch? */ /* type mistmatch? */
const OSLGlobals::Attribute& attr = it->second; const OSLGlobals::Attribute& attr = it->second;
if(attr.elem != ATTR_ELEMENT_VALUE) { if (attr.elem != ATTR_ELEMENT_VALUE) {
/* triangle and vertex attributes */ /* triangle and vertex attributes */
if(tri != ~0) { if (tri != ~0) {
if(attr.type == type || (attr.type == TypeDesc::TypeColor && if (attr.type == type || (attr.type == TypeDesc::TypeColor &&
(type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal))) (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal)))
{
return get_mesh_attribute(kg, sd, attr, derivatives, val); return get_mesh_attribute(kg, sd, attr, derivatives, val);
else }
else {
return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val); return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val);
}
} }
} }
else { else {
@@ -283,7 +287,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
} }
bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type,
void *renderstate, void *val) void *renderstate, void *val)
{ {
return false; /* disabled by lockgeom */ return false; /* disabled by lockgeom */
} }
@@ -294,7 +298,7 @@ bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderst
} }
void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names, void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names,
TypeDesc *attr_types, int nattrs) TypeDesc *attr_types, int nattrs)
{ {
#ifdef WITH_PARTIO #ifdef WITH_PARTIO
m_attr_queries.push_back(AttrQuery()); m_attr_queries.push_back(AttrQuery());
@@ -308,28 +312,32 @@ void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names,
to the query. Just to prevent buffer overruns */ to the query. Just to prevent buffer overruns */
query.capacity = -1; query.capacity = -1;
for(int i = 0; i < nattrs; ++i) for (int i = 0; i < nattrs; ++i) {
{
query.attr_names[i] = attr_names[i]; query.attr_names[i] = attr_names[i];
TypeDesc element_type = attr_types[i].elementtype (); TypeDesc element_type = attr_types[i].elementtype();
if(query.capacity < 0) if (query.capacity < 0)
query.capacity = attr_types[i].numelements(); query.capacity = attr_types[i].numelements();
else else
query.capacity = min(query.capacity, (int)attr_types[i].numelements()); query.capacity = min(query.capacity, (int)attr_types[i].numelements());
/* convert the OSL (OIIO) type to the equivalent Partio type so /* convert the OSL (OIIO) type to the equivalent Partio type so
we can do a fast check at query time. */ we can do a fast check at query time. */
if(element_type == TypeDesc::TypeFloat) if (element_type == TypeDesc::TypeFloat) {
query.attr_partio_types[i] = Partio::FLOAT; query.attr_partio_types[i] = Partio::FLOAT;
else if(element_type == TypeDesc::TypeInt) }
query.attr_partio_types[i] = Partio::INT; else if (element_type == TypeDesc::TypeInt) {
else if(element_type == TypeDesc::TypeColor || element_type == TypeDesc::TypePoint || query.attr_partio_types[i] = Partio::INT;
element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal) }
query.attr_partio_types[i] = Partio::VECTOR; else if (element_type == TypeDesc::TypeColor || element_type == TypeDesc::TypePoint ||
else element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal)
return NULL; /* report some error of unknown type */ {
query.attr_partio_types[i] = Partio::VECTOR;
}
else {
return NULL; /* report some error of unknown type */
}
} }
/* this is valid until the end of RenderServices */ /* this is valid until the end of RenderServices */
@@ -348,18 +356,18 @@ Partio::ParticlesData *OSLRenderServices::get_pointcloud(ustring filename)
#endif #endif
int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, float radius, int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, float radius,
int max_points, void *_attr_query, void **attr_outdata) int max_points, void *_attr_query, void **attr_outdata)
{ {
/* todo: this code has never been tested, and most likely does not /* todo: this code has never been tested, and most likely does not
work. it's based on the example code in OSL */ work. it's based on the example code in OSL */
#ifdef WITH_PARTIO #ifdef WITH_PARTIO
/* query Partio for this pointcloud lookup using cached attr_query */ /* query Partio for this pointcloud lookup using cached attr_query */
if(!_attr_query) if (!_attr_query)
return 0; return 0;
AttrQuery *attr_query = (AttrQuery *)_attr_query; AttrQuery *attr_query = (AttrQuery *)_attr_query;
if(attr_query->capacity < max_points) if (attr_query->capacity < max_points)
return 0; return 0;
/* get the pointcloud entry for the given filename */ /* get the pointcloud entry for the given filename */
@@ -370,13 +378,13 @@ int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, flo
int nattrs = attr_query->attr_names.size(); int nattrs = attr_query->attr_names.size();
Partio::ParticleAttribute *attr = (Partio::ParticleAttribute *)alloca(sizeof(Partio::ParticleAttribute) * nattrs); Partio::ParticleAttribute *attr = (Partio::ParticleAttribute *)alloca(sizeof(Partio::ParticleAttribute) * nattrs);
for(int i = 0; i < nattrs; ++i) { for (int i = 0; i < nattrs; ++i) {
/* special case attributes */ /* special case attributes */
if(attr_query->attr_names[i] == u_distance || attr_query->attr_names[i] == u_index) if (attr_query->attr_names[i] == u_distance || attr_query->attr_names[i] == u_index)
continue; continue;
/* lookup the attribute by name*/ /* lookup the attribute by name*/
if(!cloud->attributeInfo(attr_query->attr_names[i].c_str(), attr[i])) { if (!cloud->attributeInfo(attr_query->attr_names[i].c_str(), attr[i])) {
/* issue an error here and return, types don't match */ /* issue an error here and return, types don't match */
Partio::endCachedAccess(cloud); Partio::endCachedAccess(cloud);
cloud->release(); cloud->release();
@@ -394,14 +402,14 @@ int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, flo
int count = indices.size(); int count = indices.size();
/* retrieve the attributes directly to user space */ /* retrieve the attributes directly to user space */
for(int j = 0; j < nattrs; ++j) { for (int j = 0; j < nattrs; ++j) {
/* special cases */ /* special cases */
if(attr_query->attr_names[j] == u_distance) { if (attr_query->attr_names[j] == u_distance) {
for(int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
((float *)attr_outdata[j])[i] = sqrtf(dist2[i]); ((float *)attr_outdata[j])[i] = sqrtf(dist2[i]);
} }
else if(attr_query->attr_names[j] == u_index) { else if (attr_query->attr_names[j] == u_index) {
for(int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
((int *)attr_outdata[j])[i] = indices[i]; ((int *)attr_outdata[j])[i] = indices[i];
} }
else { else {

View File

@@ -57,19 +57,19 @@ public:
bool get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time); bool get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time);
bool get_array_attribute(void *renderstate, bool derivatives, bool get_array_attribute(void *renderstate, bool derivatives,
ustring object, TypeDesc type, ustring name, ustring object, TypeDesc type, ustring name,
int index, void *val); int index, void *val);
bool get_attribute(void *renderstate, bool derivatives, ustring object, bool get_attribute(void *renderstate, bool derivatives, ustring object,
TypeDesc type, ustring name, void *val); TypeDesc type, ustring name, void *val);
bool get_userdata(bool derivatives, ustring name, TypeDesc type, bool get_userdata(bool derivatives, ustring name, TypeDesc type,
void *renderstate, void *val); void *renderstate, void *val);
bool has_userdata(ustring name, TypeDesc type, void *renderstate); bool has_userdata(ustring name, TypeDesc type, void *renderstate);
void *get_pointcloud_attr_query(ustring *attr_names, void *get_pointcloud_attr_query(ustring *attr_names,
TypeDesc *attr_types, int nattrs); TypeDesc *attr_types, int nattrs);
int pointcloud(ustring filename, const OSL::Vec3 &center, float radius, int pointcloud(ustring filename, const OSL::Vec3 &center, float radius,
int max_points, void *attr_query, void **attr_outdata); int max_points, void *attr_query, void **attr_outdata);
private: private:
KernelGlobals *kernel_globals; KernelGlobals *kernel_globals;
@@ -79,8 +79,7 @@ private:
right now it only caches the types already converted to right now it only caches the types already converted to
Partio constants. this is what get_pointcloud_attr_query Partio constants. this is what get_pointcloud_attr_query
returns */ returns */
struct AttrQuery struct AttrQuery {
{
/* names of the attributes to query */ /* names of the attributes to query */
std::vector<ustring> attr_names; std::vector<ustring> attr_names;
/* types as (enum Partio::ParticleAttributeType) of the /* types as (enum Partio::ParticleAttributeType) of the

View File

@@ -37,7 +37,7 @@ tls_ptr(OSLGlobals::ThreadData, OSLGlobals::thread_data);
void OSLShader::thread_init(KernelGlobals *kg) void OSLShader::thread_init(KernelGlobals *kg)
{ {
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = new OSLGlobals::ThreadData(); OSLGlobals::ThreadData *tdata = new OSLGlobals::ThreadData();
@@ -46,12 +46,12 @@ void OSLShader::thread_init(KernelGlobals *kg)
tls_set(kg->osl.thread_data, tdata); tls_set(kg->osl.thread_data, tdata);
((OSLRenderServices*)ssi->renderer())->thread_init(kg); ((OSLRenderServices *)ssi->renderer())->thread_init(kg);
} }
void OSLShader::thread_free(KernelGlobals *kg) void OSLShader::thread_free(KernelGlobals *kg)
{ {
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
@@ -62,12 +62,12 @@ void OSLShader::thread_free(KernelGlobals *kg)
/* Globals */ /* Globals */
#define TO_VEC3(v) (*(OSL::Vec3*)&(v)) #define TO_VEC3(v) (*(OSL::Vec3 *)&(v))
#define TO_COLOR3(v) (*(OSL::Color3*)&(v)) #define TO_COLOR3(v) (*(OSL::Color3 *)&(v))
#define TO_FLOAT3(v) make_float3(v[0], v[1], v[2]) #define TO_FLOAT3(v) make_float3(v[0], v[1], v[2])
static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
int path_flag, OSL::ShaderGlobals *globals) int path_flag, OSL::ShaderGlobals *globals)
{ {
/* copy from shader data to shader globals */ /* copy from shader data to shader globals */
globals->P = TO_VEC3(sd->P); globals->P = TO_VEC3(sd->P);
@@ -86,7 +86,7 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
globals->dvdy = sd->dv.dy; globals->dvdy = sd->dv.dy;
globals->dPdu = TO_VEC3(sd->dPdu); globals->dPdu = TO_VEC3(sd->dPdu);
globals->dPdv = TO_VEC3(sd->dPdv); globals->dPdv = TO_VEC3(sd->dPdv);
globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object); globals->surfacearea = (sd->object == ~0) ? 1.0f : object_surface_area(kg, sd->object);
/* booleans */ /* booleans */
globals->raytype = path_flag; /* todo: add our own ray types */ globals->raytype = path_flag; /* todo: add our own ray types */
@@ -109,35 +109,35 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
/* Surface */ /* Surface */
static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy, static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
{ {
/* OSL gives use a closure tree, we flatten it into arrays per /* OSL gives use a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */ * closure type, for evaluation, sampling, etc later on. */
if(closure->type == OSL::ClosureColor::COMPONENT) { if (closure->type == OSL::ClosureColor::COMPONENT) {
OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
if(prim) { if (prim) {
ShaderClosure sc; ShaderClosure sc;
sc.prim = prim; sc.prim = prim;
sc.weight = weight; sc.weight = weight;
switch(prim->category()) { switch (prim->category()) {
case ClosurePrimitive::BSDF: { case ClosurePrimitive::BSDF: {
if(sd->num_closure == MAX_CLOSURE) if (sd->num_closure == MAX_CLOSURE)
return; return;
OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)prim; OSL::BSDFClosure *bsdf = (OSL::BSDFClosure *)prim;
ustring scattering = bsdf->scattering(); ustring scattering = bsdf->scattering();
/* no caustics option */ /* no caustics option */
if(no_glossy && scattering == OSL::Labels::GLOSSY) if (no_glossy && scattering == OSL::Labels::GLOSSY)
return; return;
/* sample weight */ /* sample weight */
float albedo = bsdf->albedo(TO_VEC3(sd->I)); float albedo = bsdf->albedo(TO_VEC3(sd->I));
float sample_weight = fabsf(average(weight))*albedo; float sample_weight = fabsf(average(weight)) * albedo;
float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight; float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight;
sc.sample_weight = sample_weight; sc.sample_weight = sample_weight;
@@ -145,10 +145,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sd->osl_closure.bsdf_sample_sum = sample_sum; sd->osl_closure.bsdf_sample_sum = sample_sum;
/* scattering flags */ /* scattering flags */
if(scattering == OSL::Labels::DIFFUSE) if (scattering == OSL::Labels::DIFFUSE)
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL; sd->flag |= SD_BSDF | SD_BSDF_HAS_EVAL;
else if(scattering == OSL::Labels::GLOSSY) else if (scattering == OSL::Labels::GLOSSY)
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; sd->flag |= SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_GLOSSY;
else else
sd->flag |= SD_BSDF; sd->flag |= SD_BSDF;
@@ -157,7 +157,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
break; break;
} }
case ClosurePrimitive::Emissive: { case ClosurePrimitive::Emissive: {
if(sd->num_closure == MAX_CLOSURE) if (sd->num_closure == MAX_CLOSURE)
return; return;
/* sample weight */ /* sample weight */
@@ -175,7 +175,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
break; break;
} }
case ClosurePrimitive::Holdout: case ClosurePrimitive::Holdout:
if(sd->num_closure == MAX_CLOSURE) if (sd->num_closure == MAX_CLOSURE)
return; return;
sc.sample_weight = 0.0f; sc.sample_weight = 0.0f;
@@ -192,12 +192,12 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
} }
} }
} }
else if(closure->type == OSL::ClosureColor::MUL) { else if (closure->type == OSL::ClosureColor::MUL) {
OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight); flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight);
} }
else if(closure->type == OSL::ClosureColor::ADD) { else if (closure->type == OSL::ClosureColor::ADD) {
OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight); flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight);
flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight); flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight);
} }
@@ -206,7 +206,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag) void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
{ {
/* gather pointers */ /* gather pointers */
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShaderGlobals *globals = &tdata->globals; OSL::ShaderGlobals *globals = &tdata->globals;
OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
@@ -218,14 +218,14 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int
/* execute shader for this point */ /* execute shader for this point */
int shader = sd->shader & SHADER_MASK; int shader = sd->shader & SHADER_MASK;
if(kg->osl.surface_state[shader]) if (kg->osl.surface_state[shader])
ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.surface_state[shader]), *globals); ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.surface_state[shader]), *globals);
/* flatten closure tree */ /* flatten closure tree */
sd->num_closure = 0; sd->num_closure = 0;
sd->randb_closure = randb; sd->randb_closure = randb;
if(globals->Ci) { if (globals->Ci) {
bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics; bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics;
flatten_surface_closure_tree(sd, no_glossy, globals->Ci); flatten_surface_closure_tree(sd, no_glossy, globals->Ci);
} }
@@ -239,23 +239,23 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
* is only one supported closure type at the moment, which has no evaluation * is only one supported closure type at the moment, which has no evaluation
* functions, so we just sum the weights */ * functions, so we just sum the weights */
if(closure->type == OSL::ClosureColor::COMPONENT) { if (closure->type == OSL::ClosureColor::COMPONENT) {
OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
if(prim && prim->category() == OSL::ClosurePrimitive::Background) if (prim && prim->category() == OSL::ClosurePrimitive::Background)
return make_float3(1.0f, 1.0f, 1.0f); return make_float3(1.0f, 1.0f, 1.0f);
} }
else if(closure->type == OSL::ClosureColor::MUL) { else if (closure->type == OSL::ClosureColor::MUL) {
OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure); return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
} }
else if(closure->type == OSL::ClosureColor::ADD) { else if (closure->type == OSL::ClosureColor::ADD) {
OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
return flatten_background_closure_tree(add->closureA) + return flatten_background_closure_tree(add->closureA) +
flatten_background_closure_tree(add->closureB); flatten_background_closure_tree(add->closureB);
} }
return make_float3(0.0f, 0.0f, 0.0f); return make_float3(0.0f, 0.0f, 0.0f);
@@ -264,7 +264,7 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag) float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
{ {
/* gather pointers */ /* gather pointers */
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShaderGlobals *globals = &tdata->globals; OSL::ShaderGlobals *globals = &tdata->globals;
OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
@@ -274,11 +274,11 @@ float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_fl
shaderdata_to_shaderglobals(kg, sd, path_flag, globals); shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
/* execute shader for this point */ /* execute shader for this point */
if(kg->osl.background_state) if (kg->osl.background_state)
ctx->execute(OSL::pvt::ShadUseSurface, *kg->osl.background_state, *globals); ctx->execute(OSL::pvt::ShadUseSurface, *kg->osl.background_state, *globals);
/* return background color immediately */ /* return background color immediately */
if(globals->Ci) if (globals->Ci)
return flatten_background_closure_tree(globals->Ci); return flatten_background_closure_tree(globals->Ci);
return make_float3(0.0f, 0.0f, 0.0f); return make_float3(0.0f, 0.0f, 0.0f);
@@ -287,23 +287,23 @@ float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_fl
/* Volume */ /* Volume */
static void flatten_volume_closure_tree(ShaderData *sd, static void flatten_volume_closure_tree(ShaderData *sd,
const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
{ {
/* OSL gives use a closure tree, we flatten it into arrays per /* OSL gives use a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */ * closure type, for evaluation, sampling, etc later on. */
if(closure->type == OSL::ClosureColor::COMPONENT) { if (closure->type == OSL::ClosureColor::COMPONENT) {
OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
if(prim) { if (prim) {
ShaderClosure sc; ShaderClosure sc;
sc.prim = prim; sc.prim = prim;
sc.weight = weight; sc.weight = weight;
switch(prim->category()) { switch (prim->category()) {
case ClosurePrimitive::Volume: { case ClosurePrimitive::Volume: {
if(sd->num_closure == MAX_CLOSURE) if (sd->num_closure == MAX_CLOSURE)
return; return;
/* sample weight */ /* sample weight */
@@ -329,12 +329,12 @@ static void flatten_volume_closure_tree(ShaderData *sd,
} }
} }
} }
else if(closure->type == OSL::ClosureColor::MUL) { else if (closure->type == OSL::ClosureColor::MUL) {
OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight); flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
} }
else if(closure->type == OSL::ClosureColor::ADD) { else if (closure->type == OSL::ClosureColor::ADD) {
OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
flatten_volume_closure_tree(sd, add->closureA, weight); flatten_volume_closure_tree(sd, add->closureA, weight);
flatten_volume_closure_tree(sd, add->closureB, weight); flatten_volume_closure_tree(sd, add->closureB, weight);
} }
@@ -343,7 +343,7 @@ static void flatten_volume_closure_tree(ShaderData *sd,
void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag) void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
{ {
/* gather pointers */ /* gather pointers */
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShaderGlobals *globals = &tdata->globals; OSL::ShaderGlobals *globals = &tdata->globals;
OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
@@ -355,7 +355,7 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
/* execute shader */ /* execute shader */
int shader = sd->shader & SHADER_MASK; int shader = sd->shader & SHADER_MASK;
if(kg->osl.volume_state[shader]) if (kg->osl.volume_state[shader])
ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.volume_state[shader]), *globals); ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.volume_state[shader]), *globals);
/* retrieve resulting closures */ /* retrieve resulting closures */
@@ -363,7 +363,7 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
sd->osl_closure.num_volume = 0; sd->osl_closure.num_volume = 0;
sd->osl_closure.randb = randb; sd->osl_closure.randb = randb;
if(globals->Ci) if (globals->Ci)
flatten_volume_closure_tree(sd, globals->Ci); flatten_volume_closure_tree(sd, globals->Ci);
} }
@@ -372,7 +372,7 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd) void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
{ {
/* gather pointers */ /* gather pointers */
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShaderGlobals *globals = &tdata->globals; OSL::ShaderGlobals *globals = &tdata->globals;
OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
@@ -384,7 +384,7 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
/* execute shader */ /* execute shader */
int shader = sd->shader & SHADER_MASK; int shader = sd->shader & SHADER_MASK;
if(kg->osl.displacement_state[shader]) if (kg->osl.displacement_state[shader])
ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.displacement_state[shader]), *globals); ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.displacement_state[shader]), *globals);
/* get back position */ /* get back position */
@@ -393,17 +393,17 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
void OSLShader::release(KernelGlobals *kg, const ShaderData *sd) void OSLShader::release(KernelGlobals *kg, const ShaderData *sd)
{ {
OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl *)kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
ssi->release_context((OSL::pvt::ShadingContext*)sd->osl_ctx, tdata->thread_info); ssi->release_context((OSL::pvt::ShadingContext *)sd->osl_ctx, tdata->thread_info);
} }
/* BSDF Closure */ /* BSDF Closure */
int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf) int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
{ {
OSL::BSDFClosure *sample_bsdf = (OSL::BSDFClosure*)sc->prim; OSL::BSDFClosure *sample_bsdf = (OSL::BSDFClosure *)sc->prim;
int label = LABEL_NONE; int label = LABEL_NONE;
pdf = 0.0f; pdf = 0.0f;
@@ -412,27 +412,27 @@ int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float
ustring ulabel; ustring ulabel;
ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng), ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng),
TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy), TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy),
randu, randv, randu, randv,
TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy), TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy),
pdf, TO_COLOR3(eval)); pdf, TO_COLOR3(eval));
/* convert OSL label */ /* convert OSL label */
if(ulabel == OSL::Labels::REFLECT) if (ulabel == OSL::Labels::REFLECT)
label = LABEL_REFLECT; label = LABEL_REFLECT;
else if(ulabel == OSL::Labels::TRANSMIT) else if (ulabel == OSL::Labels::TRANSMIT)
label = LABEL_TRANSMIT; label = LABEL_TRANSMIT;
else else
return LABEL_NONE; /* sampling failed */ return LABEL_NONE; /* sampling failed */
/* convert scattering to our bitflag label */ /* convert scattering to our bitflag label */
ustring uscattering = sample_bsdf->scattering(); ustring uscattering = sample_bsdf->scattering();
if(uscattering == OSL::Labels::DIFFUSE) if (uscattering == OSL::Labels::DIFFUSE)
label |= LABEL_DIFFUSE; label |= LABEL_DIFFUSE;
else if(uscattering == OSL::Labels::GLOSSY) else if (uscattering == OSL::Labels::GLOSSY)
label |= LABEL_GLOSSY; label |= LABEL_GLOSSY;
else if(uscattering == OSL::Labels::SINGULAR) else if (uscattering == OSL::Labels::SINGULAR)
label |= LABEL_SINGULAR; label |= LABEL_SINGULAR;
else else
label |= LABEL_TRANSPARENT; label |= LABEL_TRANSPARENT;
@@ -442,10 +442,10 @@ int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float
float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf) float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
{ {
OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)sc->prim; OSL::BSDFClosure *bsdf = (OSL::BSDFClosure *)sc->prim;
OSL::Color3 bsdf_eval; OSL::Color3 bsdf_eval;
if(dot(sd->Ng, omega_in) >= 0.0f) if (dot(sd->Ng, omega_in) >= 0.0f)
bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf); bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf);
else else
bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf); bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf);
@@ -457,7 +457,7 @@ float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const
float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc) float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc)
{ {
OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)sc->prim; OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure *)sc->prim;
OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I)); OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
eval += TO_FLOAT3(emissive_eval); eval += TO_FLOAT3(emissive_eval);
@@ -468,9 +468,9 @@ float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc)
float3 OSLShader::volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) float3 OSLShader::volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
{ {
OSL::VolumeClosure *volume = (OSL::VolumeClosure*)sc->prim; OSL::VolumeClosure *volume = (OSL::VolumeClosure *)sc->prim;
OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out)); OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
return TO_FLOAT3(volume_eval)*sc->weight; return TO_FLOAT3(volume_eval) * sc->weight;
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -68,15 +68,15 @@ public:
/* sample & eval */ /* sample & eval */
static int bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, static int bsdf_sample(const ShaderData *sd, const ShaderClosure *sc,
float randu, float randv, float randu, float randv,
float3& eval, float3& omega_in, differential3& domega_in, float& pdf); float3& eval, float3& omega_in, differential3& domega_in, float& pdf);
static float3 bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, static float3 bsdf_eval(const ShaderData *sd, const ShaderClosure *sc,
const float3& omega_in, float& pdf); const float3& omega_in, float& pdf);
static float3 emissive_eval(const ShaderData *sd, const ShaderClosure *sc); static float3 emissive_eval(const ShaderData *sd, const ShaderClosure *sc);
static float3 volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, static float3 volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc,
const float3 omega_in, const float3 omega_out); const float3 omega_in, const float3 omega_out);
/* release */ /* release */
static void release(KernelGlobals *kg, const ShaderData *sd); static void release(KernelGlobals *kg, const ShaderData *sd);

View File

@@ -46,88 +46,90 @@ using namespace OSL;
class SubsurfaceClosure : public VolumeClosure { class SubsurfaceClosure : public VolumeClosure {
public: public:
float m_g; float m_g;
float m_eta; float m_eta;
Color3 m_mfp, m_albedo; Color3 m_mfp, m_albedo;
static float root_find_Rd(const float Rd0, const float A) { static float root_find_Rd(const float Rd0, const float A) {
// quick exit for trivial cases // quick exit for trivial cases
if (Rd0 <= 0) return 0; if (Rd0 <= 0) return 0;
const float A43 = A * 4.0f / 3.0f; const float A43 = A * 4.0f / 3.0f;
// Find alpha such that f(alpha) = Rd (see eq.15). A simple bisection // Find alpha such that f(alpha) = Rd (see eq.15). A simple bisection
// method can be used because this function is monotonicaly increasing. // method can be used because this function is monotonicaly increasing.
float lo = 0, hi = 1; float lo = 0, hi = 1;
for (int i = 0; i < 20; i++) { // 2^20 divisions should be sufficient for (int i = 0; i < 20; i++) { // 2^20 divisions should be sufficient
// eval function at midpoint // eval function at midpoint
float alpha = 0.5f * (lo + hi); float alpha = 0.5f * (lo + hi);
float a1 = sqrtf(3 * (1 - alpha)); float a1 = sqrtf(3 * (1 - alpha));
float e1 = expf(-a1); float e1 = expf(-a1);
float e2 = expf(-A43 * a1); float e2 = expf(-A43 * a1);
float Rd = 0.5f * alpha * (1 + e2) * e1 - Rd0; float Rd = 0.5f * alpha * (1 + e2) * e1 - Rd0;
if (fabsf(Rd) < 1e-6f) if (fabsf(Rd) < 1e-6f)
return alpha; // close enough return alpha; // close enough
else if (Rd > 0) else if (Rd > 0)
hi = alpha; // root is on left side hi = alpha; // root is on left side
else else
lo = alpha; // root is on right side lo = alpha; // root is on right side
} }
// didn't quite converge, pick result in the middle of remaining interval // didn't quite converge, pick result in the middle of remaining interval
return 0.5f * (lo + hi); return 0.5f * (lo + hi);
} }
SubsurfaceClosure() { } SubsurfaceClosure() {
}
void setup() void setup()
{ {
ior(m_eta); ior(m_eta);
if (m_g >= 0.99f) m_g = 0.99f; if (m_g >= 0.99f) m_g = 0.99f;
if (m_g <= -0.99f) m_g = -0.99f; if (m_g <= -0.99f) m_g = -0.99f;
// eq.10 // eq.10
float inv_eta = 1 / m_eta; float inv_eta = 1 / m_eta;
float Fdr = -1.440f * inv_eta * inv_eta + 0.710 * inv_eta + 0.668f + 0.0636 * m_eta; float Fdr = -1.440f * inv_eta * inv_eta + 0.710 * inv_eta + 0.668f + 0.0636 * m_eta;
float A = (1 + Fdr) / (1 - Fdr); float A = (1 + Fdr) / (1 - Fdr);
// compute sigma_s, sigma_a (eq.16) // compute sigma_s, sigma_a (eq.16)
Color3 alpha_prime = Color3 (root_find_Rd(m_albedo[0], A), Color3 alpha_prime = Color3(root_find_Rd(m_albedo[0], A),
root_find_Rd(m_albedo[1], A), root_find_Rd(m_albedo[1], A),
root_find_Rd(m_albedo[2], A)); root_find_Rd(m_albedo[2], A));
Color3 sigma_t_prime = Color3 (m_mfp.x > 0 ? 1.0f / (m_mfp[0] * sqrtf(3 * (1 - alpha_prime[0]))) : 0.0f, Color3 sigma_t_prime = Color3(m_mfp.x > 0 ? 1.0f / (m_mfp[0] * sqrtf(3 * (1 - alpha_prime[0]))) : 0.0f,
m_mfp.y > 0 ? 1.0f / (m_mfp[1] * sqrtf(3 * (1 - alpha_prime[1]))) : 0.0f, m_mfp.y > 0 ? 1.0f / (m_mfp[1] * sqrtf(3 * (1 - alpha_prime[1]))) : 0.0f,
m_mfp.z > 0 ? 1.0f / (m_mfp[2] * sqrtf(3 * (1 - alpha_prime[2]))) : 0.0f); m_mfp.z > 0 ? 1.0f / (m_mfp[2] * sqrtf(3 * (1 - alpha_prime[2]))) : 0.0f);
Color3 sigma_s_prime = alpha_prime * sigma_t_prime; Color3 sigma_s_prime = alpha_prime * sigma_t_prime;
sigma_s((1.0f / (1 - m_g)) * sigma_s_prime); sigma_s((1.0f / (1 - m_g)) * sigma_s_prime);
sigma_a(sigma_t_prime - sigma_s_prime); sigma_a(sigma_t_prime - sigma_s_prime);
} }
bool mergeable (const ClosurePrimitive *other) const { bool mergeable(const ClosurePrimitive *other) const {
const SubsurfaceClosure *comp = (const SubsurfaceClosure *)other; const SubsurfaceClosure *comp = (const SubsurfaceClosure *)other;
return m_g == comp->m_g && VolumeClosure::mergeable(other); return m_g == comp->m_g && VolumeClosure::mergeable(other);
} }
size_t memsize () const { return sizeof(*this); } size_t memsize() const { return sizeof(*this); }
const char *name () const { return "subsurface"; } const char *name() const { return "subsurface"; }
void print_on (std::ostream &out) const { void print_on(std::ostream &out) const {
out << name() << " ()"; out << name() << " ()";
} }
virtual Color3 eval_phase(const Vec3 &omega_in, const Vec3 &omega_out) const { virtual Color3 eval_phase(const Vec3 &omega_in, const Vec3 &omega_out) const {
float costheta = omega_in.dot(omega_out); float costheta = omega_in.dot(omega_out);
float ph = 0.25f * float(M_1_PI) * ((1 - m_g * m_g) / powf(1 + m_g * m_g - 2.0f * m_g * costheta, 1.5f)); float ph = 0.25f * float(M_1_PI) * ((1 - m_g * m_g) / powf(1 + m_g * m_g - 2.0f * m_g * costheta, 1.5f));
return Color3 (ph, ph, ph); return Color3(ph, ph, ph);
} }
}; };
ClosureParam closure_subsurface_params[] = { ClosureParam closure_subsurface_params[] = {
CLOSURE_FLOAT_PARAM (SubsurfaceClosure, m_eta), CLOSURE_FLOAT_PARAM(SubsurfaceClosure, m_eta),
CLOSURE_FLOAT_PARAM (SubsurfaceClosure, m_g), CLOSURE_FLOAT_PARAM(SubsurfaceClosure, m_g),
CLOSURE_COLOR_PARAM (SubsurfaceClosure, m_mfp), CLOSURE_COLOR_PARAM(SubsurfaceClosure, m_mfp),
CLOSURE_COLOR_PARAM (SubsurfaceClosure, m_albedo), CLOSURE_COLOR_PARAM(SubsurfaceClosure, m_albedo),
CLOSURE_STRING_KEYPARAM("label"), CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(SubsurfaceClosure) }; CLOSURE_FINISH_PARAM(SubsurfaceClosure)
};
CLOSURE_PREPARE(closure_subsurface_prepare, SubsurfaceClosure) CLOSURE_PREPARE(closure_subsurface_prepare, SubsurfaceClosure)