Skip to content

Commit

Permalink
Fix volume mixes in MDL (#1395)
Browse files Browse the repository at this point in the history
Change the implementation of the volume mix functions in MDL.
The mix weight is now interpreted as probability to encounter a particle of one of the mixed media.
  • Loading branch information
krohmerNV authored Jul 12, 2023
1 parent 2c50d91 commit 6211e9a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 25 deletions.
79 changes: 56 additions & 23 deletions source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -669,14 +669,39 @@ export material mx_displacement_vector3(
);


// helper function to mix two scattering volumes:
// - combined scattering coefficient is just the sum of the two
// - VDF mixer weight is the relative probability of encountering the corresponding
// particle type
// NOTE: mixer weight should be a color, but due to a bug in current MDL compilers
// the color mixers don't accept non-uniform weights yet
struct volume_mix_return {
color scattering_coefficient;
float mix_weight1; // mix_weight2 = 1.0 - mix_weight1, can use any mixer
};
volume_mix_return volume_mix(
color scattering_coefficient1,
float weight1,
color scattering_coefficient2,
float weight2)
{
color s1 = weight1 * scattering_coefficient1;
color s = s1 + weight2 * scattering_coefficient2;
return volume_mix_return(scattering_coefficient: s, mix_weight1: math::average(s1 / s));
}

export material mx_mix_bsdf(
material mxp_fg = material() [[ anno::usage( "materialx:bsdf") ]],
material mxp_bg = material() [[ anno::usage( "materialx:bsdf") ]],
float mxp_mix = 0.0
) [[
anno::usage( "materialx:bsdf")
]]
= material(
= let {
volume_mix_return v = volume_mix(
mxp_fg.volume.scattering_coefficient, mxp_mix,
mxp_bg.volume.scattering_coefficient, (1.0f - mxp_mix));
} in material(
surface: material_surface(
scattering: df::weighted_layer(
weight: mxp_mix,
Expand All @@ -687,15 +712,14 @@ export material mx_mix_bsdf(
// we need to carry volume properties along for SSS
ior: mxp_fg.ior, // NOTE: IOR is uniform, cannot mix here
volume: material_volume(
scattering: df::clamped_mix(
scattering: df::unbounded_mix(
df::vdf_component[](
df::vdf_component( mxp_mix, mxp_fg.volume.scattering),
df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering))
df::vdf_component(v.mix_weight1, mxp_fg.volume.scattering),
df::vdf_component(1.0 - v.mix_weight1, mxp_bg.volume.scattering))
),
absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient +
(1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient,
scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient +
(1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient
scattering_coefficient: v.scattering_coefficient
)
);

Expand All @@ -709,7 +733,7 @@ export material mx_mix_edf(
= material(
surface: material_surface(
emission: material_emission(
emission: df::clamped_mix(
emission: df::unbounded_mix( // unbounded_mix is cheaper
df::edf_component[](
df::edf_component( mxp_mix, mxp_fg.surface.emission.emission),
df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission))
Expand All @@ -727,18 +751,21 @@ export material mx_mix_vdf(
) [[
anno::usage( "materialx:vdf")
]]
= material(
= let {
volume_mix_return v = volume_mix(
mxp_fg.volume.scattering_coefficient, mxp_mix,
mxp_bg.volume.scattering_coefficient, (1.0f - mxp_mix));
} in material(
ior: mxp_fg.ior, // NOTE: IOR is uniform, cannot mix here
volume: material_volume(
scattering: df::clamped_mix(
scattering: df::unbounded_mix(
df::vdf_component[](
df::vdf_component( mxp_mix, mxp_fg.volume.scattering),
df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering))
df::vdf_component( v.mix_weight1, mxp_fg.volume.scattering),
df::vdf_component( 1.0 - v.mix_weight1, mxp_bg.volume.scattering))
),
absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient +
(1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient,
scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient +
(1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient
scattering_coefficient: v.scattering_coefficient
)
);

Expand All @@ -751,7 +778,11 @@ export material mx_add_bsdf(
) [[
anno::usage( "materialx:bsdf")
]]
= material(
= let {
volume_mix_return v = volume_mix(
mxp_in1.volume.scattering_coefficient, 1.0f,
mxp_in2.volume.scattering_coefficient, 1.0f);
} in material(
surface: material_surface(
scattering: df::unbounded_mix(
df::bsdf_component[](
Expand All @@ -764,13 +795,12 @@ export material mx_add_bsdf(
volume: material_volume(
scattering: df::unbounded_mix(
df::vdf_component[](
df::vdf_component( 1.0, mxp_in1.volume.scattering),
df::vdf_component( 1.0, mxp_in2.volume.scattering))
df::vdf_component( v.mix_weight1, mxp_in1.volume.scattering),
df::vdf_component( 1.0 - v.mix_weight1, mxp_in2.volume.scattering))
),
absorption_coefficient: mxp_in1.volume.absorption_coefficient +
mxp_in2.volume.absorption_coefficient,
scattering_coefficient: mxp_in1.volume.scattering_coefficient +
mxp_in2.volume.scattering_coefficient
scattering_coefficient: v.scattering_coefficient
)
);

Expand Down Expand Up @@ -806,19 +836,22 @@ export material mx_add_vdf(
) [[
anno::usage( "materialx:vdf")
]]
= material(
= let {
volume_mix_return v = volume_mix(
mxp_in1.volume.scattering_coefficient, 1.0f,
mxp_in2.volume.scattering_coefficient, 1.0f);
} in material(
// assuming mixing the IOR is the best we can do here
ior: 0.5 * mxp_in1.ior + 0.5 * mxp_in2.ior,
volume: material_volume(
scattering: df::unbounded_mix(
df::vdf_component[](
df::vdf_component( 1.0, mxp_in1.volume.scattering),
df::vdf_component( 1.0, mxp_in2.volume.scattering))
df::vdf_component( v.mix_weight1, mxp_in1.volume.scattering),
df::vdf_component( 1.0 - v.mix_weight1, mxp_in2.volume.scattering))
),
absorption_coefficient: mxp_in1.volume.absorption_coefficient +
mxp_in2.volume.absorption_coefficient,
scattering_coefficient: mxp_in1.volume.scattering_coefficient +
mxp_in2.volume.scattering_coefficient
scattering_coefficient: v.scattering_coefficient
)
);

Expand Down
4 changes: 2 additions & 2 deletions source/MaterialXGenMdl/mdl/materialx/stdlib.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -2981,7 +2981,7 @@ export material mx_mix_surfaceshader(
base: mxp_bg.surface.scattering
),
emission: material_emission(
emission: df::clamped_mix(
emission: df::unbounded_mix( // unbounded_mix is cheaper
df::edf_component[](
df::edf_component( mxp_mix, mxp_fg.surface.emission.emission),
df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission))
Expand All @@ -2994,7 +2994,7 @@ export material mx_mix_surfaceshader(
// we need to carry volume properties along for SSS
ior: mxp_fg.ior, // NOTE: IOR is uniform, cannot mix here
volume: material_volume(
scattering: df::clamped_mix(
scattering: df::unbounded_mix( // unbounded_mix is cheaper
df::vdf_component[](
df::vdf_component( mxp_mix, mxp_fg.volume.scattering),
df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering))
Expand Down

0 comments on commit 6211e9a

Please sign in to comment.