@@ -1513,6 +1513,123 @@ struct ZeltnerBurleySheen final : public BSDF, MxSheenParams {
15131513 }
15141514};
15151515
1516+ // / @name Mediums
1517+ struct HenyeyGreenstein final : public BSDF {
1518+ const float g;
1519+ OSL_HOSTDEVICE HenyeyGreenstein (float g)
1520+ : BSDF(this ),
1521+ g(g)
1522+ {
1523+ }
1524+
1525+ static OSL_HOSTDEVICE float PhaseHG (float cos_theta, float g) {
1526+ const float denom = 1 + g * g + 2 * g * cos_theta;
1527+ return (1 - g * g) / (4 * M_PI * denom * sqrtf (denom));
1528+ }
1529+
1530+ OSL_HOSTDEVICE Sample eval (const Vec3& wo, const Vec3& wi) const
1531+ {
1532+ const float pdf = PhaseHG (dot (wo, wi), g);
1533+ return { wi, Color3 (pdf), pdf, 0 .0f };
1534+ }
1535+
1536+ OSL_HOSTDEVICE Sample sample (const Vec3& wo, float rx, float ry, float rz) const
1537+ {
1538+ TangentFrame frame = TangentFrame::from_normal (wo);
1539+
1540+ float cos_theta;
1541+ if (abs (g) < 1e-3f ) {
1542+ cos_theta = 1 .0f - 2 .0f * rx;
1543+ } else {
1544+ float sqr_term = (1 - g * g) / (1 - g + 2 * g * rx);
1545+ cos_theta = (1 + g * g - sqr_term * sqr_term) / (2 * g);
1546+ cos_theta = OIIO::clamp (cos_theta, -1 .0f , 1 .0f );
1547+ }
1548+
1549+ float sin_theta = sqrtf (OIIO::clamp (1 .0f - cos_theta * cos_theta, 0 .0f , 1 .0f ));
1550+ float phi = 2 * M_PI * ry;
1551+ Vec3 local_wi = Vec3 (sin_theta * cosf (phi), sin_theta * sinf (phi), cos_theta);
1552+
1553+ Vec3 wi = frame.toworld (local_wi);
1554+ float pdf_val = PhaseHG (cos_theta, g);
1555+
1556+ Color3 weight = Color3 (1 .0f );
1557+ return { wi, weight, pdf_val, 0 .0f };
1558+ }
1559+
1560+ };
1561+
1562+ struct HomogeneousVolume final : public Medium, MediumParams {
1563+
1564+ OSL_HOSTDEVICE HomogeneousVolume (const MediumParams& params)
1565+ : Medium(this ), MediumParams(params)
1566+ {
1567+ }
1568+
1569+ OSL_HOSTDEVICE static HomogeneousVolume* create (void * storage, const MediumParams& params) {
1570+ HomogeneousVolume* volume = new (storage) HomogeneousVolume (params);
1571+ volume->phase_func = new HenyeyGreenstein (params.medium_g ); // assuming g is anisotropy parameter
1572+ return volume;
1573+ }
1574+
1575+ OSL_HOSTDEVICE Medium::Sample sample (const Ray &ray, Sampler &sampler, Intersection& hit) const
1576+ {
1577+ Vec3 rand_vol = sampler.get ();
1578+ float max_sigma_t = std::max (std::max (sigma_t .x , sigma_t .y ), sigma_t .z );
1579+ /*
1580+ if (max_sigma_t <= 0.0f) {
1581+ // vacuum: no attenuation, pdf irrelevant
1582+ return Medium::Sample { hit.t, false, Color3(1.0f) };
1583+ }
1584+ */
1585+ float t_volume = -logf (1 .0f - rand_vol.x ) / max_sigma_t ;
1586+ bool volume_scatter = (t_volume < hit.t );
1587+
1588+ Color3 weight;
1589+ Color3 tr;
1590+
1591+ if (volume_scatter) {
1592+ tr = transmittance (t_volume);
1593+
1594+ Color3 albedo = Color3 (
1595+ sigma_s.x / sigma_t .x ,
1596+ sigma_s.y / sigma_t .y ,
1597+ sigma_s.z / sigma_t .z
1598+ );
1599+
1600+ weight = albedo / tr;
1601+ } else {
1602+ tr = transmittance (hit.t );
1603+ weight = Color3 (
1604+ 1.0 / tr.x ,
1605+ 1.0 / tr.y ,
1606+ 1.0 / tr.z
1607+ );
1608+ }
1609+ /*
1610+ if (pdf <= 0.0f) {
1611+ // ensure Tr is black in this degenerate case if we expected absorption
1612+ return Medium::Sample { hit.t, false, tr };
1613+ }
1614+ */
1615+ return Medium::Sample { volume_scatter, t_volume, tr, weight };
1616+ }
1617+
1618+ OSL_HOSTDEVICE Color3 transmittance (float distance) const
1619+ { // Beer-Lambert law
1620+ return Color3 (expf (-sigma_t .x * distance),
1621+ expf (-sigma_t .y * distance),
1622+ expf (-sigma_t .z * distance));
1623+ }
1624+ };
1625+
1626+ struct EmptyVolume final : public Medium {
1627+ OSL_HOSTDEVICE EmptyVolume () :
1628+ Medium(this )
1629+ {
1630+ }
1631+ };
1632+
15161633OSL_HOSTDEVICE Color3
15171634evaluate_layer_opacity (const ShaderGlobalsType& sg, float path_roughness,
15181635 const ClosureColor* closure)
@@ -1606,8 +1723,8 @@ evaluate_layer_opacity(const ShaderGlobalsType& sg, float path_roughness,
16061723
16071724OSL_HOSTDEVICE void
16081725process_medium_closure (const ShaderGlobalsType& sg, float path_roughness,
1609- ShadingResult& result, const ClosureColor* closure ,
1610- const Color3& w)
1726+ ShadingResult& result, MediumStack &medium_stack ,
1727+ const ClosureColor* closure, const Color3& w)
16111728{
16121729 if (!closure)
16131730 return ;
@@ -1652,6 +1769,11 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
16521769 result.medium_data .sigma_t = cw * params.extinction ;
16531770 result.medium_data .sigma_s = params.albedo * result.medium_data .sigma_t ;
16541771 result.medium_data .medium_g = params.anisotropy ;
1772+
1773+ if (!sg.backfacing ) { // if entering
1774+ medium_stack.push_medium <HomogeneousVolume>(result.medium_data );
1775+ }
1776+
16551777 closure = nullptr ;
16561778 break ;
16571779 }
@@ -1673,6 +1795,11 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
16731795 // Track IOR and priority here
16741796 result.medium_data .refraction_ior = sg.backfacing ? 1 .0f / params.ior
16751797 : params.ior ;
1798+
1799+ if (!sg.backfacing ) { // if entering
1800+ medium_stack.push_medium <HomogeneousVolume>(result.medium_data );
1801+ }
1802+
16761803 // result.medium_data.priority = params.priority;
16771804 closure = nullptr ;
16781805 break ;
@@ -1961,10 +2088,11 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
19612088
19622089OSL_HOSTDEVICE void
19632090process_closure (const ShaderGlobalsType& sg, float path_roughness,
1964- ShadingResult& result, const ClosureColor* Ci, bool light_only)
2091+ ShadingResult& result, MediumStack &medium_stack,
2092+ const ClosureColor* Ci, bool light_only)
19652093{
19662094 if (!light_only)
1967- process_medium_closure (sg, path_roughness, result, Ci, Color3 (1 ));
2095+ process_medium_closure (sg, path_roughness, result, medium_stack, Ci, Color3 (1 ));
19682096 process_bsdf_closure (sg, path_roughness, result, Ci, Color3 (1 ), light_only);
19692097}
19702098
@@ -2026,5 +2154,9 @@ BSDF::sample_vrtl(const Vec3& wo, float rx, float ry, float rz) const
20262154 return dispatch ([&](auto bsdf) { return bsdf.sample (wo, rx, ry, rz); });
20272155}
20282156
2157+ Medium::Sample Medium::sample_vrtl (const Ray &ray, Sampler &sampler, Intersection& hit) const
2158+ {
2159+ return dispatch ([&](auto volume) { return volume.sample (ray, sampler, hit); });
2160+ }
20292161
20302162OSL_NAMESPACE_END
0 commit comments