Skip to content

Commit 969af58

Browse files
committed
Add testrender volumes
Alongside the rest of the initialization for subpixel_radiance, an empty MediumStack is initialized. It stores the medium params with pointers in two arrays. One tracks the entry order and the other sorted based on priority. There is a priority handling scheme that will shuffle the incumbent medium pointers to give high priority (lower integer priorities) mediums lower indices. When processing BSDF closures, intersections with MxDielectric or MxGeneralizedSchlick may only be added when priority < current_priority or are both 0 (the precious priority). MediumStack exposes an integrate method that operates on aggregated parameters from all media sharing the same priority as the topmost medium; these aggregated parameters are stored on the stack and updated whenever media are added. A CDF built from these parameters is then sampled to select one of the overlapping media for scattering. At present, only Henyey–Greenstein phase functions are supported, implemented as a BSDF subclass and wraps the implementation in BSDL. Signed-off-by: Owen O'Malley <theowen@email.com>
1 parent d9dfaa2 commit 969af58

37 files changed

Lines changed: 968 additions & 52 deletions

src/cmake/testing.cmake

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ macro (osl_add_all_tests)
362362
render-cornell
363363
render-displacement
364364
render-furnace-diffuse
365+
render-mx-anisotropic-vdf
365366
render-mx-furnace-burley-diffuse
366367
render-mx-furnace-oren-nayar
367368
render-mx-furnace-sheen
@@ -371,7 +372,9 @@ macro (osl_add_all_tests)
371372
render-mx-generalized-schlick render-mx-generalized-schlick-glass
372373
render-mx-layer
373374
render-mx-sheen
374-
render-microfacet render-oren-nayar
375+
render-mx-medium-vdf
376+
render-mx-medium-vdf-glass
377+
render-microfacet render-oren-nayar
375378
render-spi-thinlayer
376379
render-uv render-veachmis render-ward
377380
render-raytypes

src/libbsdl/include/BSDL/tools.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212

1313
BSDL_ENTER_NAMESPACE
1414

15+
BSDL_INLINE float
16+
MAX(float a, float b)
17+
{
18+
return std::max(a, b);
19+
}
20+
1521
BSDL_INLINE float
1622
MAX_ABS_XYZ(const Imath::V3f& v)
1723
{

src/testrender/optixraytracer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
11751175
if (format[j] == '%') {
11761176
fmt_string = "%";
11771177
bool format_end_found = false;
1178-
for (size_t i = 0; !format_end_found; i++) {
1178+
for (; !format_end_found; ) {
11791179
j++;
11801180
fmt_string += format[j];
11811181
switch (format[j]) {

src/testrender/shading.cpp

Lines changed: 143 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55

66
#include "shading.h"
7+
#include "OSL/oslconfig.h"
78
#include <OSL/genclosure.h>
89
#include "optics.h"
910
#include "sampling.h"
@@ -17,6 +18,7 @@
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

2123
using 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_empty) {
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+
11501198
OSL_HOSTDEVICE Color3
11511199
evaluate_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

12361284
OSL_HOSTDEVICE void
12371285
process_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,72 @@ 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+
result.medium_data.is_empty = result.medium_data.is_vaccum();
1336+
1337+
closure = nullptr;
12851338
break;
12861339
}
12871340
case MX_MEDIUM_VDF_ID: {
12881341
const ClosureComponent* comp = closure->as_comp();
12891342
Color3 cw = weight * comp->w;
12901343
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;
1344+
1345+
// when both albedo and transmission_color are black, this is
1346+
// a vacuum medium used only to carry the IOR for dielectric
1347+
// surfaces.
1348+
bool is_vacuum = is_black(params.albedo)
1349+
&& is_black(params.transmission_color);
1350+
1351+
if (is_vacuum) {
1352+
result.medium_data.sigma_t = Color3(0.0f);
1353+
result.medium_data.sigma_s = Color3(0.0f);
1354+
result.medium_data.is_empty = true;
1355+
} else {
1356+
constexpr float epsilon = 1e-10f;
1357+
const Color3& t_color = params.transmission_color;
1358+
result.medium_data.sigma_t
1359+
= Color3(-OIIO::fast_log(fmaxf(t_color.x, epsilon)),
1360+
-OIIO::fast_log(fmaxf(t_color.y, epsilon)),
1361+
-OIIO::fast_log(fmaxf(t_color.z, epsilon)));
1362+
1363+
result.medium_data.sigma_t *= cw / params.transmission_depth;
1364+
result.medium_data.sigma_s = params.albedo
1365+
* result.medium_data.sigma_t;
1366+
result.medium_data.is_empty = result.medium_data.is_vaccum();
1367+
}
1368+
1369+
result.medium_data.medium_g = params.anisotropy;
1370+
1371+
result.medium_data.refraction_ior = sg.backfacing
1372+
? 1.0f / params.ior
1373+
: params.ior;
1374+
result.medium_data.priority = params.priority;
1375+
1376+
closure = nullptr;
13031377
break;
13041378
}
13051379
case MxDielectric::closureid(): {
13061380
const ClosureComponent* comp = closure->as_comp();
13071381
const MxDielectric::Data& params = *comp->as<MxDielectric::Data>();
13081382
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;
1383+
float new_ior = sg.backfacing ? 1.0f / params.IOR : params.IOR;
1384+
1385+
result.medium_data.refraction_ior = new_ior;
1386+
1387+
const MediumParams* current_params
1388+
= medium_stack.get_current_params();
1389+
if (current_params
1390+
&& result.medium_data.priority
1391+
<= current_params->priority) {
1392+
result.medium_data.refraction_ior
1393+
= current_params->refraction_ior;
1394+
}
13121395
}
13131396
closure = nullptr;
13141397
break;
@@ -1324,7 +1407,18 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
13241407
0.0f, 0.99f);
13251408
float sqrt_F0 = sqrtf(avg_F0);
13261409
float ior = (1 + sqrt_F0) / (1 - sqrt_F0);
1327-
result.refraction_ior = sg.backfacing ? 1.0f / ior : ior;
1410+
float new_ior = sg.backfacing ? 1.0f / ior : ior;
1411+
1412+
result.medium_data.refraction_ior = new_ior;
1413+
1414+
const MediumParams* current_params
1415+
= medium_stack.get_current_params();
1416+
if (current_params
1417+
&& result.medium_data.priority
1418+
<= current_params->priority) {
1419+
result.medium_data.refraction_ior
1420+
= current_params->refraction_ior;
1421+
}
13281422
}
13291423
closure = nullptr;
13301424
break;
@@ -1341,8 +1435,9 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
13411435
// recursively walk through the closure tree, creating bsdfs as we go
13421436
OSL_HOSTDEVICE void
13431437
process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
1344-
ShadingResult& result, const ClosureColor* closure,
1345-
const Color3& w, bool light_only)
1438+
ShadingResult& result, MediumStack& medium_stack,
1439+
const ClosureColor* closure, const Color3& w,
1440+
bool light_only)
13461441
{
13471442
static const ustringhash uh_ggx("ggx");
13481443
static const ustringhash uh_beckmann("beckmann");
@@ -1472,16 +1567,29 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
14721567
case MxDielectric::closureid(): {
14731568
const MxDielectric::Data& params
14741569
= *comp->as<MxDielectric::Data>();
1475-
ok = result.bsdf.add_bsdf<MxDielectric>(cw, params, -sg.I,
1476-
sg.backfacing,
1477-
path_roughness);
1570+
1571+
if (medium_stack.false_intersection_with(
1572+
result.medium_data)) {
1573+
ok = result.bsdf.add_bsdf<Transparent>(cw);
1574+
} else {
1575+
ok = result.bsdf.add_bsdf<MxDielectric>(cw, params,
1576+
-sg.I,
1577+
sg.backfacing,
1578+
path_roughness);
1579+
}
14781580
break;
14791581
}
14801582
case MxGeneralizedSchlick::closureid(): {
14811583
const MxGeneralizedSchlick::Data& params
14821584
= *comp->as<MxGeneralizedSchlick::Data>();
1483-
ok = result.bsdf.add_bsdf<MxGeneralizedSchlick>(
1484-
cw, params, -sg.I, sg.backfacing, path_roughness);
1585+
1586+
if (medium_stack.false_intersection_with(
1587+
result.medium_data)) {
1588+
ok = result.bsdf.add_bsdf<Transparent>(cw);
1589+
} else {
1590+
ok = result.bsdf.add_bsdf<MxGeneralizedSchlick>(
1591+
cw, params, -sg.I, sg.backfacing, path_roughness);
1592+
}
14851593
break;
14861594
}
14871595
case MxConductor::closureid(): {
@@ -1574,11 +1682,14 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
15741682

15751683
OSL_HOSTDEVICE void
15761684
process_closure(const ShaderGlobalsType& sg, float path_roughness,
1577-
ShadingResult& result, const ClosureColor* Ci, bool light_only)
1685+
ShadingResult& result, MediumStack& medium_stack,
1686+
const ClosureColor* Ci, bool light_only)
15781687
{
15791688
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);
1689+
process_medium_closure(sg, path_roughness, result, medium_stack, Ci,
1690+
Color3(1));
1691+
process_bsdf_closure(sg, path_roughness, result, medium_stack, Ci,
1692+
Color3(1), light_only);
15821693
}
15831694

15841695
OSL_HOSTDEVICE Vec3
@@ -1639,5 +1750,4 @@ BSDF::sample_vrtl(const Vec3& wo, float rx, float ry, float rz) const
16391750
return dispatch([&](auto bsdf) { return bsdf.sample(wo, rx, ry, rz); });
16401751
}
16411752

1642-
16431753
OSL_NAMESPACE_END

0 commit comments

Comments
 (0)