44
55
66#include " shading.h"
7+ #include " OSL/oslconfig.h"
78#include < OSL/genclosure.h>
89#include " optics.h"
910#include " sampling.h"
1617#include < BSDL/MTX/bsdf_sheen_impl.h>
1718#include < BSDL/MTX/bsdf_translucent_impl.h>
1819#include < BSDL/SPI/bsdf_thinlayer_impl.h>
20+ #include < BSDL/SPI/bsdf_volume_impl.h>
1921#include < BSDL/spectrum_impl.h>
2022
2123using namespace OSL ;
@@ -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,86 @@ 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 ,
1338+ result.medium_data .sigma_t .x ),
1339+ std::min (result.medium_data .sigma_s .y ,
1340+ result.medium_data .sigma_t .y ),
1341+ std::min (result.medium_data .sigma_s .z ,
1342+ result.medium_data .sigma_t .z ) };
1343+
1344+ closure = nullptr ;
12851345 break ;
12861346 }
12871347 case MX_MEDIUM_VDF_ID : {
12881348 const ClosureComponent* comp = closure->as_comp ();
12891349 Color3 cw = weight * comp->w ;
12901350 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 ;
1351+
1352+ // when both albedo and transmission_color are black, this is
1353+ // a vacuum medium used only to carry the IOR for dielectric
1354+ // surfaces.
1355+ bool is_vacuum = is_black (params.albedo )
1356+ && is_black (params.transmission_color );
1357+
1358+ if (is_vacuum) {
1359+ result.medium_data .sigma_t = Color3 (0 .0f );
1360+ result.medium_data .sigma_s = Color3 (0 .0f );
1361+ } else {
1362+ constexpr float epsilon = 1e-10f ;
1363+ const Color3& t_color = params.transmission_color ;
1364+ result.medium_data .sigma_t
1365+ = Color3 (-OIIO::fast_log (fmaxf (t_color.x , epsilon)),
1366+ -OIIO::fast_log (fmaxf (t_color.y , epsilon)),
1367+ -OIIO::fast_log (fmaxf (t_color.z , epsilon)));
1368+
1369+ result.medium_data .sigma_t *= cw / params.transmission_depth ;
1370+ result.medium_data .sigma_s = params.albedo
1371+ * result.medium_data .sigma_t ;
1372+
1373+ // clamp sigma_s to be less than sigma_t
1374+ result.medium_data .sigma_s
1375+ = { std::min (result.medium_data .sigma_s .x ,
1376+ result.medium_data .sigma_t .x ),
1377+ std::min (result.medium_data .sigma_s .y ,
1378+ result.medium_data .sigma_t .y ),
1379+ std::min (result.medium_data .sigma_s .z ,
1380+ result.medium_data .sigma_t .z ) };
1381+ }
1382+
1383+ result.medium_data .medium_g = params.anisotropy ;
1384+
1385+ result.medium_data .refraction_ior = sg.backfacing
1386+ ? 1 .0f / params.ior
1387+ : params.ior ;
1388+ result.medium_data .priority = params.priority ;
1389+
1390+ closure = nullptr ;
13031391 break ;
13041392 }
13051393 case MxDielectric::closureid (): {
13061394 const ClosureComponent* comp = closure->as_comp ();
13071395 const MxDielectric::Data& params = *comp->as <MxDielectric::Data>();
13081396 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 ;
1397+ float new_ior = sg.backfacing ? 1 .0f / params.IOR : params.IOR ;
1398+
1399+ result.medium_data .refraction_ior = new_ior;
1400+
1401+ const MediumParams* current_params
1402+ = medium_stack.get_current_params ();
1403+ if (current_params
1404+ && result.medium_data .priority
1405+ <= current_params->priority ) {
1406+ result.medium_data .refraction_ior
1407+ = current_params->refraction_ior ;
1408+ }
13121409 }
13131410 closure = nullptr ;
13141411 break ;
@@ -1318,13 +1415,23 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
13181415 const MxGeneralizedSchlick::Data& params
13191416 = *comp->as <MxGeneralizedSchlick::Data>();
13201417 if (!is_black (weight * comp->w * params.refr_tint )) {
1321- // TODO: properly track a medium stack here ...
13221418 float avg_F0 = clamp ((params.F0 .x + params.F0 .y + params.F0 .z )
13231419 / 3 .0f ,
13241420 0 .0f , 0 .99f );
13251421 float sqrt_F0 = sqrtf (avg_F0);
13261422 float ior = (1 + sqrt_F0) / (1 - sqrt_F0);
1327- result.refraction_ior = sg.backfacing ? 1 .0f / ior : ior;
1423+ float new_ior = sg.backfacing ? 1 .0f / ior : ior;
1424+
1425+ result.medium_data .refraction_ior = new_ior;
1426+
1427+ const MediumParams* current_params
1428+ = medium_stack.get_current_params ();
1429+ if (current_params
1430+ && result.medium_data .priority
1431+ <= current_params->priority ) {
1432+ result.medium_data .refraction_ior
1433+ = current_params->refraction_ior ;
1434+ }
13281435 }
13291436 closure = nullptr ;
13301437 break ;
@@ -1341,8 +1448,9 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
13411448// recursively walk through the closure tree, creating bsdfs as we go
13421449OSL_HOSTDEVICE void
13431450process_bsdf_closure (const ShaderGlobalsType& sg, float path_roughness,
1344- ShadingResult& result, const ClosureColor* closure,
1345- const Color3& w, bool light_only)
1451+ ShadingResult& result, MediumStack& medium_stack,
1452+ const ClosureColor* closure, const Color3& w,
1453+ bool light_only)
13461454{
13471455 static const ustringhash uh_ggx (" ggx" );
13481456 static const ustringhash uh_beckmann (" beckmann" );
@@ -1472,16 +1580,29 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
14721580 case MxDielectric::closureid (): {
14731581 const MxDielectric::Data& params
14741582 = *comp->as <MxDielectric::Data>();
1475- ok = result.bsdf .add_bsdf <MxDielectric>(cw, params, -sg.I ,
1476- sg.backfacing ,
1477- path_roughness);
1583+
1584+ if (medium_stack.false_intersection_with (
1585+ result.medium_data )) {
1586+ ok = result.bsdf .add_bsdf <Transparent>(cw);
1587+ } else {
1588+ ok = result.bsdf .add_bsdf <MxDielectric>(cw, params,
1589+ -sg.I ,
1590+ sg.backfacing ,
1591+ path_roughness);
1592+ }
14781593 break ;
14791594 }
14801595 case MxGeneralizedSchlick::closureid (): {
14811596 const MxGeneralizedSchlick::Data& params
14821597 = *comp->as <MxGeneralizedSchlick::Data>();
1483- ok = result.bsdf .add_bsdf <MxGeneralizedSchlick>(
1484- cw, params, -sg.I , sg.backfacing , path_roughness);
1598+
1599+ if (medium_stack.false_intersection_with (
1600+ result.medium_data )) {
1601+ ok = result.bsdf .add_bsdf <Transparent>(cw);
1602+ } else {
1603+ ok = result.bsdf .add_bsdf <MxGeneralizedSchlick>(
1604+ cw, params, -sg.I , sg.backfacing , path_roughness);
1605+ }
14851606 break ;
14861607 }
14871608 case MxConductor::closureid (): {
@@ -1574,11 +1695,14 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
15741695
15751696OSL_HOSTDEVICE void
15761697process_closure (const ShaderGlobalsType& sg, float path_roughness,
1577- ShadingResult& result, const ClosureColor* Ci, bool light_only)
1698+ ShadingResult& result, MediumStack& medium_stack,
1699+ const ClosureColor* Ci, bool light_only)
15781700{
15791701 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);
1702+ process_medium_closure (sg, path_roughness, result, medium_stack, Ci,
1703+ Color3 (1 ));
1704+ process_bsdf_closure (sg, path_roughness, result, medium_stack, Ci,
1705+ Color3 (1 ), light_only);
15821706}
15831707
15841708OSL_HOSTDEVICE Vec3
@@ -1639,5 +1763,4 @@ BSDF::sample_vrtl(const Vec3& wo, float rx, float ry, float rz) const
16391763 return dispatch ([&](auto bsdf) { return bsdf.sample (wo, rx, ry, rz); });
16401764}
16411765
1642-
16431766OSL_NAMESPACE_END
0 commit comments