1616
1717#include " optics.h"
1818#include " sampling.h"
19- #include " volume.h"
20-
2119
2220OSL_NAMESPACE_BEGIN
2321
@@ -262,6 +260,7 @@ struct EnergyCompensatedOrenNayar;
262260struct ZeltnerBurleySheen ;
263261struct CharlieSheen ;
264262struct SpiThinLayer ;
263+ struct HenyeyGreenstein ;
265264
266265// StaticVirtual generates a switch/case dispatch method for us given
267266// a list of possible subtypes. We just need to forward declare them.
@@ -271,7 +270,8 @@ using AbstractBSDF = bsdl::StaticVirtual<
271270 MicrofacetBeckmannBoth, MicrofacetGGXRefl, MicrofacetGGXRefr,
272271 MicrofacetGGXBoth, MxConductor, MxDielectric, MxBurleyDiffuse,
273272 EnergyCompensatedOrenNayar, ZeltnerBurleySheen, CharlieSheen,
274- MxGeneralizedSchlickOpaque, MxGeneralizedSchlick, SpiThinLayer>;
273+ MxGeneralizedSchlickOpaque, MxGeneralizedSchlick, SpiThinLayer,
274+ HenyeyGreenstein>;
275275
276276// Then we just need to inherit from AbstractBSDF
277277
@@ -455,13 +455,84 @@ struct CompositeBSDF {
455455 int num_bsdfs, num_bytes;
456456};
457457
458- struct MediumProperties ;
458+ struct VolumeParams {
459+ Color3 sigma_t = Color3(0 .0f ); // extinction coefficient
460+ Color3 sigma_s = Color3(0 .0f ); // scattering
461+ float medium_g = 0 .0f ; // volumetric anisotropy
462+ float refraction_ior = 1 .0f ;
463+ // int priority = 0;
459464
465+ OSL_HOSTDEVICE bool is_vacuum () const
466+ {
467+ return sigma_t .x <= 0 .0f && sigma_t .y <= 0 .0f && sigma_t .z <= 0 .0f ;
468+ }
469+
470+ OSL_HOSTDEVICE bool operator ==(const VolumeParams &rhs) const {
471+ return refraction_ior == rhs.refraction_ior &&
472+ medium_g == rhs.medium_g &&
473+ sigma_t .x == rhs.sigma_t .x &&
474+ sigma_t .y == rhs.sigma_t .y &&
475+ sigma_t .z == rhs.sigma_t .z &&
476+ sigma_s.x == rhs.sigma_s .x &&
477+ sigma_s.y == rhs.sigma_s .y &&
478+ sigma_s.z == rhs.sigma_s .z ;
479+ }
480+
481+ OSL_HOSTDEVICE float max_sigma_t () const
482+ {
483+ return std::max (std::max (sigma_t .x , sigma_t .y ), sigma_t .z );
484+ }
485+ };
460486
461487struct ShadingResult {
462488 Color3 Le = Color3(0 .0f );
463489 CompositeBSDF bsdf = {};
464- MediumProperties medium_data = {};
490+ VolumeParams medium_data = {};
491+ };
492+
493+ struct HenyeyGreenstein final : public BSDF {
494+ const float g;
495+ OSL_HOSTDEVICE HenyeyGreenstein (float g)
496+ : BSDF(this ),
497+ g(g)
498+ {
499+ }
500+
501+ static OSL_HOSTDEVICE float PhaseHG (float cos_theta, float g) {
502+ const float denom = 1 + g * g + 2 * g * cos_theta;
503+ return (1 - g * g) / (4 * M_PI * denom * sqrtf (denom));
504+ }
505+
506+ OSL_HOSTDEVICE Sample eval (const Vec3& wo, const Vec3& wi) const
507+ {
508+ const float pdf = PhaseHG (dot (wo, wi), g);
509+ return { wi, Color3 (pdf), pdf, 0 .0f };
510+ }
511+
512+ OSL_HOSTDEVICE Sample sample (const Vec3& wo, float rx, float ry, float rz) const
513+ {
514+ TangentFrame frame = TangentFrame::from_normal (wo);
515+
516+ float cos_theta;
517+ if (abs (g) < 1e-3f ) {
518+ cos_theta = 1 .0f - 2 .0f * rx;
519+ } else {
520+ float sqr_term = (1 - g * g) / (1 - g + 2 * g * rx);
521+ cos_theta = (1 + g * g - sqr_term * sqr_term) / (2 * g);
522+ cos_theta = OIIO::clamp (cos_theta, -1 .0f , 1 .0f );
523+ }
524+
525+ float sin_theta = sqrtf (OIIO::clamp (1 .0f - cos_theta * cos_theta, 0 .0f , 1 .0f ));
526+ float phi = 2 * M_PI * ry;
527+ Vec3 local_wi = Vec3 (sin_theta * cosf (phi), sin_theta * sinf (phi), cos_theta);
528+
529+ Vec3 wi = frame.toworld (local_wi);
530+ float pdf_val = PhaseHG (cos_theta, g);
531+
532+ Color3 weight = Color3 (1 .0f );
533+ return { wi, weight, pdf_val, 0 .0f };
534+ }
535+
465536};
466537
467538void
0 commit comments