Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/cmake/testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ macro (osl_add_all_tests)
render-cornell
render-displacement
render-furnace-diffuse
render-mx-anisotropic-vdf
render-mx-furnace-burley-diffuse
render-mx-furnace-oren-nayar
render-mx-furnace-sheen
Expand All @@ -371,7 +372,9 @@ macro (osl_add_all_tests)
render-mx-generalized-schlick render-mx-generalized-schlick-glass
render-mx-layer
render-mx-sheen
render-microfacet render-oren-nayar
render-mx-medium-vdf
render-mx-medium-vdf-glass
render-microfacet render-oren-nayar
render-spi-thinlayer
render-uv render-veachmis render-ward
render-raytypes
Expand Down
281 changes: 241 additions & 40 deletions src/testrender/shading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,127 @@ struct ZeltnerBurleySheen final : public BSDF, MxSheenParams {
}
};


struct HenyeyGreenstein final : public BSDF {
const float g;
OSL_HOSTDEVICE HenyeyGreenstein(float g) : BSDF(this), g(g) {}

static OSL_HOSTDEVICE float PhaseHG(float cos_theta, float g)
{
const float denom = 1 + g * g + 2 * g * cos_theta;
return (1 - g * g) / (4 * M_PI * denom * sqrtf(denom));
}

OSL_HOSTDEVICE Sample eval(const Vec3& wo, const Vec3& wi) const
{
const float pdf = PhaseHG(dot(wo, wi), g);
return { wi, Color3(pdf), pdf, 0.0f };
}

OSL_HOSTDEVICE Sample sample(const Vec3& wo, float rx, float ry,
float rz) const
{
TangentFrame frame = TangentFrame::from_normal(wo);

float cos_theta;
if (abs(g) < 1e-3f) {
cos_theta = 1.0f - 2.0f * rx;
} else {
float sqr_term = (1 - g * g) / (1 - g + 2 * g * rx);
cos_theta = (1 + g * g - sqr_term * sqr_term) / (2 * g);
cos_theta = OIIO::clamp(cos_theta, -1.0f, 1.0f);
}

float sin_theta = sqrtf(
OIIO::clamp(1.0f - cos_theta * cos_theta, 0.0f, 1.0f));
float phi = 2 * M_PI * ry;
Vec3 local_wi = Vec3(sin_theta * cosf(phi), sin_theta * sinf(phi),
cos_theta);

Vec3 wi = frame.toworld(local_wi);
float pdf_val = PhaseHG(cos_theta, g);

return { wi, Color3(1.0f), pdf_val, 0.0f };
}
};

struct HomogeneousMedium final : public Medium {
MediumParams params;
HenyeyGreenstein phase_func;

OSL_HOSTDEVICE HomogeneousMedium(const MediumParams& params)
: Medium(this), params(params), phase_func(params.medium_g)
{
}

OSL_HOSTDEVICE Medium::Sample sample(Ray& r, Sampler& sampler,
Intersection& hit) const
{
Vec3 rand_vol = sampler.get();

float t_volume = -logf(1.0f - rand_vol.x) / params.avg_sigma_t();

Color3 weight;
Color3 tr;

if (t_volume < hit.t) {
r.origin = r.point(t_volume);
tr = transmittance(t_volume);

Color3 albedo = params.sigma_s / params.sigma_t;

weight = albedo / tr;
} else {
tr = transmittance(hit.t);
weight = Color3(1.0 / tr.x, 1.0 / tr.y, 1.0 / tr.z);
}

return Medium::Sample { t_volume, tr, weight };
}

OSL_HOSTDEVICE BSDF::Sample sample_phase_func(const Vec3& wo, float rx,
float ry,
float rz) const
{
return phase_func.sample(wo, rx, ry, rz);
}

OSL_HOSTDEVICE const MediumParams* get_params() const { return &params; }

OSL_HOSTDEVICE Color3 transmittance(float distance) const
{ // Beer-Lambert law
return Color3(expf(-params.sigma_t.x * distance),
expf(-params.sigma_t.y * distance),
expf(-params.sigma_t.z * distance));
}
};

struct EmptyMedium final : public Medium {
MediumParams params;

OSL_HOSTDEVICE EmptyMedium(const MediumParams& params)
: Medium(this), params(params)
{
}

OSL_HOSTDEVICE const MediumParams* get_params() const { return &params; }

OSL_HOSTDEVICE Medium::Sample sample(Ray& ray, Sampler& sampler,
Intersection& hit) const
{
return { 0.0f, Color3(1.0f), Color3(1.0f) };
}

OSL_HOSTDEVICE BSDF::Sample sample_phase_func(const Vec3& wo, float rx,
float ry,
float rz) const
{
return { Vec3(1.0f), Color3(1.0f), 0.0f, 0.0f };
}

};


OSL_HOSTDEVICE Color3
evaluate_layer_opacity(const ShaderGlobalsType& sg, float path_roughness,
const ClosureColor* closure)
Expand Down Expand Up @@ -1606,8 +1727,8 @@ evaluate_layer_opacity(const ShaderGlobalsType& sg, float path_roughness,

OSL_HOSTDEVICE void
process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
ShadingResult& result, const ClosureColor* closure,
const Color3& w)
ShadingResult& result, MediumStack& medium_stack,
const ClosureColor* closure, const Color3& w)
{
if (!closure)
return;
Expand Down Expand Up @@ -1649,37 +1770,72 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
const ClosureComponent* comp = closure->as_comp();
Color3 cw = weight * comp->w;
const auto& params = *comp->as<MxAnisotropicVdfParams>();
result.sigma_t = cw * params.extinction;
result.sigma_s = params.albedo * result.sigma_t;
result.medium_g = params.anisotropy;
closure = nullptr;
result.medium_data.sigma_t = cw * params.extinction;
result.medium_data.sigma_s = params.albedo
* result.medium_data.sigma_t;
result.medium_data.medium_g = params.anisotropy;
result.medium_data.priority = 0;

if (!sg.backfacing) { // if entering
if (result.medium_data.is_vaccum()) {
medium_stack.add_medium<EmptyMedium>(result.medium_data);
} else {
medium_stack.add_medium<HomogeneousMedium>(
result.medium_data);
}
}

closure = nullptr;
break;
}
case MX_MEDIUM_VDF_ID: {
const ClosureComponent* comp = closure->as_comp();
Color3 cw = weight * comp->w;
const auto& params = *comp->as<MxMediumVdfParams>();
result.sigma_t = { -OIIO::fast_log(params.transmission_color.x),
-OIIO::fast_log(params.transmission_color.y),
-OIIO::fast_log(params.transmission_color.z) };
// NOTE: closure weight scales the extinction parameter
result.sigma_t *= cw / params.transmission_depth;
result.sigma_s = params.albedo * result.sigma_t;
result.medium_g = params.anisotropy;
// TODO: properly track a medium stack here ...
result.refraction_ior = sg.backfacing ? 1.0f / params.ior
: params.ior;
result.priority = params.priority;
closure = nullptr;

result.medium_data.sigma_t
= Color3(-OIIO::fast_log(params.transmission_color.x),
-OIIO::fast_log(params.transmission_color.y),
-OIIO::fast_log(params.transmission_color.z));

result.medium_data.sigma_t *= cw / params.transmission_depth;
result.medium_data.sigma_s = params.albedo
* result.medium_data.sigma_t;
result.medium_data.medium_g = params.anisotropy;

result.medium_data.refraction_ior = sg.backfacing
? 1.0f / params.ior
: params.ior;
result.medium_data.priority = params.priority;

if (!sg.backfacing) { // if entering
if (result.medium_data.is_vaccum()) {
medium_stack.add_medium<EmptyMedium>(result.medium_data);
} else {
medium_stack.add_medium<HomogeneousMedium>(
result.medium_data);
}
}

closure = nullptr;
break;
}
case MxDielectric::closureid(): {
const ClosureComponent* comp = closure->as_comp();
const MxDielectric::Data& params = *comp->as<MxDielectric::Data>();
if (!is_black(weight * comp->w * params.refr_tint)) {
// TODO: properly track a medium stack here ...
result.refraction_ior = sg.backfacing ? 1.0f / params.IOR
: params.IOR;
float new_ior = sg.backfacing ? 1.0f / params.IOR : params.IOR;

result.medium_data.refraction_ior = new_ior;

const MediumParams* current_params
= medium_stack.current_params();
if (current_params
&& result.medium_data.priority
<= current_params->priority) {
result.medium_data.refraction_ior
= current_params->refraction_ior;
}
}
closure = nullptr;
break;
Expand All @@ -1688,13 +1844,23 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
const ClosureComponent* comp = closure->as_comp();
const auto& params = *comp->as<MxGeneralizedSchlickParams>();
if (!is_black(weight * comp->w * params.transmission_tint)) {
// TODO: properly track a medium stack here ...
float avg_F0 = clamp((params.f0.x + params.f0.y + params.f0.z)
/ 3.0f,
0.0f, 0.99f);
float sqrt_F0 = sqrtf(avg_F0);
float ior = (1 + sqrt_F0) / (1 - sqrt_F0);
result.refraction_ior = sg.backfacing ? 1.0f / ior : ior;
float new_ior = sg.backfacing ? 1.0f / ior : ior;

result.medium_data.refraction_ior = new_ior;

const MediumParams* current_params
= medium_stack.current_params();
if (current_params
&& result.medium_data.priority
<= current_params->priority) {
result.medium_data.refraction_ior
= current_params->refraction_ior;
}
}
closure = nullptr;
break;
Expand All @@ -1711,8 +1877,9 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness,
// recursively walk through the closure tree, creating bsdfs as we go
OSL_HOSTDEVICE void
process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
ShadingResult& result, const ClosureColor* closure,
const Color3& w, bool light_only)
ShadingResult& result, MediumStack& medium_stack,
const ClosureColor* closure, const Color3& w,
bool light_only)
{
static const ustringhash uh_ggx("ggx");
static const ustringhash uh_beckmann("beckmann");
Expand Down Expand Up @@ -1845,9 +2012,16 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
case MxDielectric::closureid(): {
const MxDielectric::Data& params
= *comp->as<MxDielectric::Data>();
ok = result.bsdf.add_bsdf<MxDielectric>(cw, params, -sg.I,
sg.backfacing,
path_roughness);

if (medium_stack.false_intersection_with(
result.medium_data)) {
ok = result.bsdf.add_bsdf<Transparent>(cw);
} else {
ok = result.bsdf.add_bsdf<MxDielectric>(cw, params,
-sg.I,
sg.backfacing,
path_roughness);
}
break;
}
case MxConductor::closureid(): {
Expand All @@ -1860,15 +2034,21 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,
case MX_GENERALIZED_SCHLICK_ID: {
const MxGeneralizedSchlickParams& params
= *comp->as<MxGeneralizedSchlickParams>();
if (is_black(params.transmission_tint))
ok = result.bsdf.add_bsdf<MxMicrofacet<
MxGeneralizedSchlickParams, GGXDist, false>>(cw,
params,
1.0f);
else
ok = result.bsdf.add_bsdf<MxMicrofacet<
MxGeneralizedSchlickParams, GGXDist, true>>(
cw, params, result.refraction_ior);

if (medium_stack.false_intersection_with(
result.medium_data)) {
ok = result.bsdf.add_bsdf<Transparent>(cw);
} else {
if (is_black(params.transmission_tint)) {
ok = result.bsdf.add_bsdf<MxMicrofacet<
MxGeneralizedSchlickParams, GGXDist, false>>(
cw, params, 1.0f);
} else {
ok = result.bsdf.add_bsdf<MxMicrofacet<
MxGeneralizedSchlickParams, GGXDist, true>>(
cw, params, result.medium_data.refraction_ior);
}
}
break;
};
case MX_TRANSLUCENT_ID: {
Expand Down Expand Up @@ -1957,11 +2137,14 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness,

OSL_HOSTDEVICE void
process_closure(const ShaderGlobalsType& sg, float path_roughness,
ShadingResult& result, const ClosureColor* Ci, bool light_only)
ShadingResult& result, MediumStack& medium_stack,
const ClosureColor* Ci, bool light_only)
{
if (!light_only)
process_medium_closure(sg, path_roughness, result, Ci, Color3(1));
process_bsdf_closure(sg, path_roughness, result, Ci, Color3(1), light_only);
process_medium_closure(sg, path_roughness, result, medium_stack, Ci,
Color3(1));
process_bsdf_closure(sg, path_roughness, result, medium_stack, Ci,
Color3(1), light_only);
}

OSL_HOSTDEVICE Vec3
Expand Down Expand Up @@ -2022,5 +2205,23 @@ BSDF::sample_vrtl(const Vec3& wo, float rx, float ry, float rz) const
return dispatch([&](auto bsdf) { return bsdf.sample(wo, rx, ry, rz); });
}

OSL_HOSTDEVICE Medium::Sample
Medium::sample_vrtl(Ray& ray, Sampler& sampler, Intersection& hit) const
{
return dispatch(
[&](const auto& medium) { return medium.sample(ray, sampler, hit); });
}

OSL_HOSTDEVICE BSDF::Sample
Medium::sample_phase_func_vrtl(const Vec3& wo, float rx, float ry, float rz) const
{
return dispatch([&](auto medium) { return medium.sample_phase_func(wo, rx, ry, rz); });
}

OSL_HOSTDEVICE const MediumParams*
Medium::get_params_vrtl() const
{
return dispatch([&](const auto& medium) { return medium.get_params(); });
}

OSL_NAMESPACE_END
Loading
Loading