44
55
66#include " shading.h"
7+ #include " OSL/oslconfig.h"
78#include < OSL/genclosure.h>
89#include " optics.h"
910#include " sampling.h"
1718#include < BSDL/MTX/bsdf_translucent_impl.h>
1819#include < BSDL/SPI/bsdf_thinlayer_impl.h>
1920#include < BSDL/spectrum_impl.h>
21+ #include < BSDL/SPI/bsdf_volume_impl.h>
2022
2123using namespace OSL ;
2224
@@ -1147,6 +1149,52 @@ struct Transparent final : public BSDF {
11471149 }
11481150};
11491151
1152+ struct HenyeyGreenstein : public bsdl ::spi::VolumeLobe<BSDLLobe> {
1153+ using Base = bsdl::spi::VolumeLobe<BSDLLobe>;
1154+
1155+ OSL_HOSTDEVICE HenyeyGreenstein (const Data& data, const Vec3& wo,
1156+ float path_roughness)
1157+ : Base(this ,
1158+ bsdl::BsdfGlobals (wo,
1159+ Vec3 (0 ), // Nf
1160+ Vec3(0 ), // Ngf
1161+ false, path_roughness,
1162+ 1.0f, // outer_ior
1163+ 0), // hero wavelength off
1164+ data)
1165+ {
1166+ }
1167+
1168+ OSL_HOSTDEVICE BSDF::Sample eval (const Vec3& wo, const Vec3& wi) const
1169+ {
1170+ bsdl::Sample s = Base::eval_impl (Base::frame.local (wo),
1171+ Base::frame.local (wi));
1172+ return { wi, s.weight .toRGB (0 ), s.pdf , s.roughness };
1173+ }
1174+ OSL_HOSTDEVICE BSDF::Sample sample (const Vec3& wo, float rx, float ry,
1175+ float rz) const
1176+ {
1177+ bsdl::Sample s = Base::sample_impl (Base::frame.local (wo),
1178+ { rx, ry, rz });
1179+ return { Base::frame.world (s.wi ), s.weight .toRGB (0 ), s.pdf ,
1180+ s.roughness };
1181+ }
1182+ };
1183+
1184+
1185+ BSDF::Sample
1186+ MediumParams::sample_phase_func (const Vec3& wo, float rx, float ry,
1187+ float rz) const
1188+ {
1189+ if (is_vaccum ()) {
1190+ return { Vec3 (1 .0f ), Color3 (1 .0f ), 0 .0f , 0 .0f };
1191+ }
1192+
1193+ HenyeyGreenstein::Data data { medium_g, medium_g, 0 .0f };
1194+ HenyeyGreenstein phase_func (data, wo, 0 .0f );
1195+ return phase_func.sample (wo, rx, ry, rz);
1196+ }
1197+
11501198OSL_HOSTDEVICE Color3
11511199evaluate_layer_opacity (const ShaderGlobalsType& sg, float path_roughness,
11521200 const ClosureColor* closure)
@@ -1235,8 +1283,8 @@ evaluate_layer_opacity(const ShaderGlobalsType& sg, float path_roughness,
12351283
12361284OSL_HOSTDEVICE void
12371285process_medium_closure (const ShaderGlobalsType& sg, float path_roughness,
1238- ShadingResult& result, const ClosureColor* closure ,
1239- const Color3& w)
1286+ ShadingResult& result, MediumStack& medium_stack ,
1287+ const ClosureColor* closure, const Color3& w)
12401288{
12411289 if (!closure)
12421290 return ;
@@ -1278,37 +1326,82 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
12781326 const ClosureComponent* comp = closure->as_comp ();
12791327 Color3 cw = weight * comp->w ;
12801328 const auto & params = *comp->as <MxAnisotropicVdfParams>();
1281- result.sigma_t = cw * params.extinction ;
1282- result.sigma_s = params.albedo * result.sigma_t ;
1283- result.medium_g = params.anisotropy ;
1284- closure = nullptr ;
1329+ result.medium_data .sigma_t = cw * params.extinction ;
1330+ result.medium_data .sigma_s = params.albedo
1331+ * result.medium_data .sigma_t ;
1332+ result.medium_data .medium_g = params.anisotropy ;
1333+ result.medium_data .priority = 0 ; // always intersect
1334+
1335+ // clamp sigma_s to be less than sigma_t
1336+ result.medium_data .sigma_s = {
1337+ std::min (result.medium_data .sigma_s .x , result.medium_data .sigma_t .x ),
1338+ std::min (result.medium_data .sigma_s .y , result.medium_data .sigma_t .y ),
1339+ std::min (result.medium_data .sigma_s .z , result.medium_data .sigma_t .z )
1340+ };
1341+
1342+ closure = nullptr ;
12851343 break ;
12861344 }
12871345 case MX_MEDIUM_VDF_ID: {
12881346 const ClosureComponent* comp = closure->as_comp ();
12891347 Color3 cw = weight * comp->w ;
12901348 const auto & params = *comp->as <MxMediumVdfParams>();
1291- result.sigma_t = { -OIIO::fast_log (params.transmission_color .x ),
1292- -OIIO::fast_log (params.transmission_color .y ),
1293- -OIIO::fast_log (params.transmission_color .z ) };
1294- // NOTE: closure weight scales the extinction parameter
1295- result.sigma_t *= cw / params.transmission_depth ;
1296- result.sigma_s = params.albedo * result.sigma_t ;
1297- result.medium_g = params.anisotropy ;
1298- // TODO: properly track a medium stack here ...
1299- result.refraction_ior = sg.backfacing ? 1 .0f / params.ior
1300- : params.ior ;
1301- result.priority = params.priority ;
1302- closure = nullptr ;
1349+
1350+ // when both albedo and transmission_color are black, this is
1351+ // a vacuum medium used only to carry the IOR for dielectric
1352+ // surfaces.
1353+ bool is_vacuum = is_black (params.albedo )
1354+ && is_black (params.transmission_color );
1355+
1356+ if (is_vacuum) {
1357+ result.medium_data .sigma_t = Color3 (0 .0f );
1358+ result.medium_data .sigma_s = Color3 (0 .0f );
1359+ } else {
1360+ constexpr float epsilon = 1e-10f ;
1361+ const Color3& t_color = params.transmission_color ;
1362+ result.medium_data .sigma_t
1363+ = Color3 (-OIIO::fast_log (fmaxf (t_color.x , epsilon)),
1364+ -OIIO::fast_log (fmaxf (t_color.y , epsilon)),
1365+ -OIIO::fast_log (fmaxf (t_color.z , epsilon)));
1366+
1367+ result.medium_data .sigma_t *= cw / params.transmission_depth ;
1368+ result.medium_data .sigma_s = params.albedo
1369+ * result.medium_data .sigma_t ;
1370+
1371+ // clamp sigma_s to be less than sigma_t
1372+ result.medium_data .sigma_s = {
1373+ std::min (result.medium_data .sigma_s .x , result.medium_data .sigma_t .x ),
1374+ std::min (result.medium_data .sigma_s .y , result.medium_data .sigma_t .y ),
1375+ std::min (result.medium_data .sigma_s .z , result.medium_data .sigma_t .z )
1376+ };
1377+ }
1378+
1379+ result.medium_data .medium_g = params.anisotropy ;
1380+
1381+ result.medium_data .refraction_ior = sg.backfacing
1382+ ? 1 .0f / params.ior
1383+ : params.ior ;
1384+ result.medium_data .priority = params.priority ;
1385+
1386+ closure = nullptr ;
13031387 break ;
13041388 }
13051389 case MxDielectric::closureid (): {
13061390 const ClosureComponent* comp = closure->as_comp ();
13071391 const MxDielectric::Data& params = *comp->as <MxDielectric::Data>();
13081392 if (!is_black (weight * comp->w * params.refr_tint )) {
1309- // TODO: properly track a medium stack here ...
1310- result.refraction_ior = sg.backfacing ? 1 .0f / params.IOR
1311- : params.IOR ;
1393+ float new_ior = sg.backfacing ? 1 .0f / params.IOR : params.IOR ;
1394+
1395+ result.medium_data .refraction_ior = new_ior;
1396+
1397+ const MediumParams* current_params
1398+ = medium_stack.get_current_params ();
1399+ if (current_params
1400+ && result.medium_data .priority
1401+ <= current_params->priority ) {
1402+ result.medium_data .refraction_ior
1403+ = current_params->refraction_ior ;
1404+ }
13121405 }
13131406 closure = nullptr ;
13141407 break ;
@@ -1324,7 +1417,18 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
13241417 0 .0f , 0 .99f );
13251418 float sqrt_F0 = sqrtf (avg_F0);
13261419 float ior = (1 + sqrt_F0) / (1 - sqrt_F0);
1327- result.refraction_ior = sg.backfacing ? 1 .0f / ior : ior;
1420+ float new_ior = sg.backfacing ? 1 .0f / ior : ior;
1421+
1422+ result.medium_data .refraction_ior = new_ior;
1423+
1424+ const MediumParams* current_params
1425+ = medium_stack.get_current_params ();
1426+ if (current_params
1427+ && result.medium_data .priority
1428+ <= current_params->priority ) {
1429+ result.medium_data .refraction_ior
1430+ = current_params->refraction_ior ;
1431+ }
13281432 }
13291433 closure = nullptr ;
13301434 break ;
@@ -1341,8 +1445,9 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
13411445// recursively walk through the closure tree, creating bsdfs as we go
13421446OSL_HOSTDEVICE void
13431447process_bsdf_closure (const ShaderGlobalsType& sg, float path_roughness,
1344- ShadingResult& result, const ClosureColor* closure,
1345- const Color3& w, bool light_only)
1448+ ShadingResult& result, MediumStack& medium_stack,
1449+ const ClosureColor* closure, const Color3& w,
1450+ bool light_only)
13461451{
13471452 static const ustringhash uh_ggx (" ggx" );
13481453 static const ustringhash uh_beckmann (" beckmann" );
@@ -1472,16 +1577,29 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
14721577 case MxDielectric::closureid (): {
14731578 const MxDielectric::Data& params
14741579 = *comp->as <MxDielectric::Data>();
1475- ok = result.bsdf .add_bsdf <MxDielectric>(cw, params, -sg.I ,
1476- sg.backfacing ,
1477- path_roughness);
1580+
1581+ if (medium_stack.false_intersection_with (
1582+ result.medium_data )) {
1583+ ok = result.bsdf .add_bsdf <Transparent>(cw);
1584+ } else {
1585+ ok = result.bsdf .add_bsdf <MxDielectric>(cw, params,
1586+ -sg.I ,
1587+ sg.backfacing ,
1588+ path_roughness);
1589+ }
14781590 break ;
14791591 }
14801592 case MxGeneralizedSchlick::closureid (): {
14811593 const MxGeneralizedSchlick::Data& params
14821594 = *comp->as <MxGeneralizedSchlick::Data>();
1483- ok = result.bsdf .add_bsdf <MxGeneralizedSchlick>(
1484- cw, params, -sg.I , sg.backfacing , path_roughness);
1595+
1596+ if (medium_stack.false_intersection_with (
1597+ result.medium_data )) {
1598+ ok = result.bsdf .add_bsdf <Transparent>(cw);
1599+ } else {
1600+ ok = result.bsdf .add_bsdf <MxGeneralizedSchlick>(
1601+ cw, params, -sg.I , sg.backfacing , path_roughness);
1602+ }
14851603 break ;
14861604 }
14871605 case MxConductor::closureid (): {
@@ -1574,11 +1692,14 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
15741692
15751693OSL_HOSTDEVICE void
15761694process_closure (const ShaderGlobalsType& sg, float path_roughness,
1577- ShadingResult& result, const ClosureColor* Ci, bool light_only)
1695+ ShadingResult& result, MediumStack& medium_stack,
1696+ const ClosureColor* Ci, bool light_only)
15781697{
15791698 if (!light_only)
1580- process_medium_closure (sg, path_roughness, result, Ci, Color3 (1 ));
1581- process_bsdf_closure (sg, path_roughness, result, Ci, Color3 (1 ), light_only);
1699+ process_medium_closure (sg, path_roughness, result, medium_stack, Ci,
1700+ Color3 (1 ));
1701+ process_bsdf_closure (sg, path_roughness, result, medium_stack, Ci,
1702+ Color3 (1 ), light_only);
15821703}
15831704
15841705OSL_HOSTDEVICE Vec3
@@ -1639,5 +1760,4 @@ BSDF::sample_vrtl(const Vec3& wo, float rx, float ry, float rz) const
16391760 return dispatch ([&](auto bsdf) { return bsdf.sample (wo, rx, ry, rz); });
16401761}
16411762
1642-
16431763OSL_NAMESPACE_END
0 commit comments