Skip to content

Commit 6211e9a

Browse files
authored
Fix volume mixes in MDL (#1395)
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.
1 parent 2c50d91 commit 6211e9a

2 files changed

Lines changed: 58 additions & 25 deletions

File tree

source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -669,14 +669,39 @@ export material mx_displacement_vector3(
669669
);
670670

671671

672+
// helper function to mix two scattering volumes:
673+
// - combined scattering coefficient is just the sum of the two
674+
// - VDF mixer weight is the relative probability of encountering the corresponding
675+
// particle type
676+
// NOTE: mixer weight should be a color, but due to a bug in current MDL compilers
677+
// the color mixers don't accept non-uniform weights yet
678+
struct volume_mix_return {
679+
color scattering_coefficient;
680+
float mix_weight1; // mix_weight2 = 1.0 - mix_weight1, can use any mixer
681+
};
682+
volume_mix_return volume_mix(
683+
color scattering_coefficient1,
684+
float weight1,
685+
color scattering_coefficient2,
686+
float weight2)
687+
{
688+
color s1 = weight1 * scattering_coefficient1;
689+
color s = s1 + weight2 * scattering_coefficient2;
690+
return volume_mix_return(scattering_coefficient: s, mix_weight1: math::average(s1 / s));
691+
}
692+
672693
export material mx_mix_bsdf(
673694
material mxp_fg = material() [[ anno::usage( "materialx:bsdf") ]],
674695
material mxp_bg = material() [[ anno::usage( "materialx:bsdf") ]],
675696
float mxp_mix = 0.0
676697
) [[
677698
anno::usage( "materialx:bsdf")
678699
]]
679-
= material(
700+
= let {
701+
volume_mix_return v = volume_mix(
702+
mxp_fg.volume.scattering_coefficient, mxp_mix,
703+
mxp_bg.volume.scattering_coefficient, (1.0f - mxp_mix));
704+
} in material(
680705
surface: material_surface(
681706
scattering: df::weighted_layer(
682707
weight: mxp_mix,
@@ -687,15 +712,14 @@ export material mx_mix_bsdf(
687712
// we need to carry volume properties along for SSS
688713
ior: mxp_fg.ior, // NOTE: IOR is uniform, cannot mix here
689714
volume: material_volume(
690-
scattering: df::clamped_mix(
715+
scattering: df::unbounded_mix(
691716
df::vdf_component[](
692-
df::vdf_component( mxp_mix, mxp_fg.volume.scattering),
693-
df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering))
717+
df::vdf_component(v.mix_weight1, mxp_fg.volume.scattering),
718+
df::vdf_component(1.0 - v.mix_weight1, mxp_bg.volume.scattering))
694719
),
695720
absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient +
696721
(1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient,
697-
scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient +
698-
(1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient
722+
scattering_coefficient: v.scattering_coefficient
699723
)
700724
);
701725

@@ -709,7 +733,7 @@ export material mx_mix_edf(
709733
= material(
710734
surface: material_surface(
711735
emission: material_emission(
712-
emission: df::clamped_mix(
736+
emission: df::unbounded_mix( // unbounded_mix is cheaper
713737
df::edf_component[](
714738
df::edf_component( mxp_mix, mxp_fg.surface.emission.emission),
715739
df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission))
@@ -727,18 +751,21 @@ export material mx_mix_vdf(
727751
) [[
728752
anno::usage( "materialx:vdf")
729753
]]
730-
= material(
754+
= let {
755+
volume_mix_return v = volume_mix(
756+
mxp_fg.volume.scattering_coefficient, mxp_mix,
757+
mxp_bg.volume.scattering_coefficient, (1.0f - mxp_mix));
758+
} in material(
731759
ior: mxp_fg.ior, // NOTE: IOR is uniform, cannot mix here
732760
volume: material_volume(
733-
scattering: df::clamped_mix(
761+
scattering: df::unbounded_mix(
734762
df::vdf_component[](
735-
df::vdf_component( mxp_mix, mxp_fg.volume.scattering),
736-
df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering))
763+
df::vdf_component( v.mix_weight1, mxp_fg.volume.scattering),
764+
df::vdf_component( 1.0 - v.mix_weight1, mxp_bg.volume.scattering))
737765
),
738766
absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient +
739767
(1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient,
740-
scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient +
741-
(1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient
768+
scattering_coefficient: v.scattering_coefficient
742769
)
743770
);
744771

@@ -751,7 +778,11 @@ export material mx_add_bsdf(
751778
) [[
752779
anno::usage( "materialx:bsdf")
753780
]]
754-
= material(
781+
= let {
782+
volume_mix_return v = volume_mix(
783+
mxp_in1.volume.scattering_coefficient, 1.0f,
784+
mxp_in2.volume.scattering_coefficient, 1.0f);
785+
} in material(
755786
surface: material_surface(
756787
scattering: df::unbounded_mix(
757788
df::bsdf_component[](
@@ -764,13 +795,12 @@ export material mx_add_bsdf(
764795
volume: material_volume(
765796
scattering: df::unbounded_mix(
766797
df::vdf_component[](
767-
df::vdf_component( 1.0, mxp_in1.volume.scattering),
768-
df::vdf_component( 1.0, mxp_in2.volume.scattering))
798+
df::vdf_component( v.mix_weight1, mxp_in1.volume.scattering),
799+
df::vdf_component( 1.0 - v.mix_weight1, mxp_in2.volume.scattering))
769800
),
770801
absorption_coefficient: mxp_in1.volume.absorption_coefficient +
771802
mxp_in2.volume.absorption_coefficient,
772-
scattering_coefficient: mxp_in1.volume.scattering_coefficient +
773-
mxp_in2.volume.scattering_coefficient
803+
scattering_coefficient: v.scattering_coefficient
774804
)
775805
);
776806

@@ -806,19 +836,22 @@ export material mx_add_vdf(
806836
) [[
807837
anno::usage( "materialx:vdf")
808838
]]
809-
= material(
839+
= let {
840+
volume_mix_return v = volume_mix(
841+
mxp_in1.volume.scattering_coefficient, 1.0f,
842+
mxp_in2.volume.scattering_coefficient, 1.0f);
843+
} in material(
810844
// assuming mixing the IOR is the best we can do here
811845
ior: 0.5 * mxp_in1.ior + 0.5 * mxp_in2.ior,
812846
volume: material_volume(
813847
scattering: df::unbounded_mix(
814848
df::vdf_component[](
815-
df::vdf_component( 1.0, mxp_in1.volume.scattering),
816-
df::vdf_component( 1.0, mxp_in2.volume.scattering))
849+
df::vdf_component( v.mix_weight1, mxp_in1.volume.scattering),
850+
df::vdf_component( 1.0 - v.mix_weight1, mxp_in2.volume.scattering))
817851
),
818852
absorption_coefficient: mxp_in1.volume.absorption_coefficient +
819853
mxp_in2.volume.absorption_coefficient,
820-
scattering_coefficient: mxp_in1.volume.scattering_coefficient +
821-
mxp_in2.volume.scattering_coefficient
854+
scattering_coefficient: v.scattering_coefficient
822855
)
823856
);
824857

source/MaterialXGenMdl/mdl/materialx/stdlib.mdl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2981,7 +2981,7 @@ export material mx_mix_surfaceshader(
29812981
base: mxp_bg.surface.scattering
29822982
),
29832983
emission: material_emission(
2984-
emission: df::clamped_mix(
2984+
emission: df::unbounded_mix( // unbounded_mix is cheaper
29852985
df::edf_component[](
29862986
df::edf_component( mxp_mix, mxp_fg.surface.emission.emission),
29872987
df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission))
@@ -2994,7 +2994,7 @@ export material mx_mix_surfaceshader(
29942994
// we need to carry volume properties along for SSS
29952995
ior: mxp_fg.ior, // NOTE: IOR is uniform, cannot mix here
29962996
volume: material_volume(
2997-
scattering: df::clamped_mix(
2997+
scattering: df::unbounded_mix( // unbounded_mix is cheaper
29982998
df::vdf_component[](
29992999
df::vdf_component( mxp_mix, mxp_fg.volume.scattering),
30003000
df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering))

0 commit comments

Comments
 (0)