Exemplo n.º 1
0
def test01_isotropic(variant_scalar_rgb):
    # Reference data from "Multiple Light Scattering" by C. van de Hulst, 1980
    # Volume 1, Table 12 p.260-261 (Isotropic scattering, finite slabs)
    albedo = 0.8
    thickness = 2.0

    mu, w = mitsuba.core.quad.gauss_lobatto(50)
    layer = mitsuba.layer.Layer(mu, w)
    layer.set_isotropic(albedo)
    layer.expand(thickness)
    print(layer)

    # Intensities leaving out at top
    mu_i_top = [1.0, 0.9, 0.7, 0.5, 0.3, 0.1]
    mu_o_top = 0.5
    ref_top = [0.28616, 0.30277, 0.34188, 0.39102, 0.45353, 0.53214]
    for i in range(len(mu_i_top)):
        table = ref_top[i]
        computed = layer.eval(mu_o_top, -mu_i_top[i]) * np.pi
        assert np.allclose(table, computed, rtol=0.001)

    # Intensities leaving out at bottom
    mu_i_bot = [1.0, 0.9, 0.7, 0.3, 0.1]
    mu_o_bot = -0.5
    ref_bot = [0.14864, 0.14731, 0.13963, 0.09425, 0.06601]
    for i in range(len(mu_i_bot)):
        table = ref_bot[i]
        computed = layer.eval(mu_o_bot, -mu_i_bot[i]) * np.pi
        assert np.allclose(table, computed, rtol=0.003)
Exemplo n.º 2
0
def test02_hg(variant_scalar_rgb):
    # Reproduce same results from test01_isotropic using the HG implementation
    albedo = 0.8
    thickness = 2.0
    g = 0.0001

    n, ms, md = mitsuba.layer.henyey_greenstein_parameter_heuristic(g)
    n = 100
    mu, w = mitsuba.core.quad.gauss_lobatto(n)
    layer = mitsuba.layer.Layer(mu, w, ms, md)
    layer.set_henyey_greenstein(albedo, g)
    layer.expand(thickness)

    # Intensities leaving out at top
    mu_i_top = [1.0, 0.9, 0.7, 0.5, 0.3, 0.1]
    mu_o_top = 0.5
    ref_top = [0.28616, 0.30277, 0.34188, 0.39102, 0.45353, 0.53214]
    for i in range(len(mu_i_top)):
        table = ref_top[i]
        computed = layer.eval(mu_o_top, -mu_i_top[i]) * np.pi
        assert np.allclose(table, computed, rtol=0.001)

    # Intensities leaving out at bottom
    mu_i_bot = [1.0, 0.9, 0.7, 0.3, 0.1]
    mu_o_bot = -0.5
    ref_bot = [0.14864, 0.14731, 0.13963, 0.09425, 0.06601]
    for i in range(len(mu_i_bot)):
        table = ref_bot[i]
        computed = layer.eval(mu_o_bot, -mu_i_bot[i]) * np.pi
        assert np.allclose(table, computed, rtol=0.003)
Exemplo n.º 3
0
def plot_layer(ax1,
               layer,
               zenith_i=30.0,
               azimuth_i=0.0,
               transmission=False,
               levels=None,
               clamp=True,
               center=True,
               vmin=None,
               vmax=None):
    if zenith_i < 90 and not transmission:
        component = 'Rt'
    elif zenith_i < 90 and transmission:
        component = 'Ttb'
    elif zenith_i >= 90 and not transmission:
        component = 'Rb'
    else:
        component = 'Tbt'

    phi_i = np.radians(azimuth_i)
    theta_i = np.radians(zenith_i)
    mu_i = np.cos(theta_i)

    azimuths = np.linspace(0, 360, 200)
    if component == 'Rt' or component == 'Tbt':
        zeniths = np.linspace(0, 90, 200)
        theta_ticks_deg = [10, 30, 50, 70, 90]
        theta_labels = ['0˚', '', '', '', '90˚']
    elif component == 'Rb' or component == 'Ttb':
        zeniths = np.linspace(180, 90, 200)
        theta_ticks_deg = [180, 160, 140, 120, 100]
        theta_labels = ['90˚', '', '', '', '180˚']

    theta_o, phi_o = np.meshgrid(np.radians(zeniths), np.radians(azimuths))
    mu_o = -np.cos(theta_o)

    phi_s = phi_o + phi_i
    phi_d = phi_o - phi_i

    data = layer.eval(mu_o, mu_i, phi_s, phi_d, clamp)
    #     data *= np.abs(mu_o)
    storage = mitsuba.layer.BSDFStorage.from_layer("tmp.bsdf", layer, 1e-8)
    data = storage.eval(mu_i, mu_o, 0.5 * (phi_s - phi_d),
                        0.5 * (phi_s + phi_d), clamp)
    data /= np.abs(mu_o)

    ax1.grid(linestyle='-', linewidth=0.6, alpha=0.3, color='w')

    text_col = 'k'
    ax1.set_rgrids(np.radians(theta_ticks_deg),
                   labels=theta_labels,
                   angle=270,
                   color=text_col,
                   fontweight='ultralight',
                   size='10',
                   ha='center',
                   alpha=0.8)

    phi_ticks_deg = np.array([0, 45, 90, 135, 180, 225, 270, 315],
                             dtype=np.float32)
    phi_labels = [("%d˚" % i) for i in phi_ticks_deg]
    phi_labels[0] = ""
    phi_labels[4] = ""
    phi_ticks_deg -= np.degrees(phi_i)
    phi_ticks_deg = np.where(phi_ticks_deg < 0, phi_ticks_deg + 360,
                             phi_ticks_deg)
    phi_ticks_deg = np.where(phi_ticks_deg > 360, phi_ticks_deg - 360,
                             phi_ticks_deg)
    ax1.set_thetagrids(phi_ticks_deg,
                       labels=phi_labels,
                       color='k',
                       fontweight='ultralight',
                       size='10',
                       ha='center',
                       alpha=0.8)

    if center and not (vmin and vmax) and clamp:
        vmin = 0.001
        vmax = np.max(data)
        norm = None
    if center and not (vmin and vmax):
        vmin = np.min(data)
        vmax = np.max(data)
        norm = MyNormalize(vmin, vmax)
    elif center:
        norm = MyNormalize(vmin, vmax)
    else:
        vmin = np.min(data)
        vmax = np.max(data)
        norm = None

    theta_o_plot = theta_o if component == 'Rt' or component == 'Tbt' else np.radians(
        270) - theta_o
    view = ax1.contourf(phi_o - phi_i,
                        theta_o_plot,
                        data,
                        200,
                        cmap='coolwarm',
                        norm=norm,
                        levels=levels,
                        vmin=vmin,
                        vmax=vmax)
    out_info = (phi_o - phi_i, theta_o_plot, data)
    for c in view.collections:
        c.set_edgecolor("face")
        c.set_rasterized(True)

    theta_i_mark = theta_i
    phi_i_plot = np.pi
    if component == 'Ttb' or component == 'Tbt':
        theta_i_mark = np.pi - theta_i
    theta_i_plot = theta_i_mark if component == 'Rt' or component == 'Tbt' else np.radians(
        270) - theta_i_mark
    xy = (phi_i_plot, np.abs(theta_i_plot))
    xytext = (phi_i_plot - 0.3, np.abs(theta_i_plot) + 0.1)
    ax1.plot(xy[0], xy[1], 'x', color=text_col, ms='10', mew=2)
    ax1.annotate('$\omega_i$',
                 xy=xy,
                 textcoords='data',
                 color=text_col,
                 fontweight='black',
                 size='14',
                 xytext=xytext)

    dr = 0.16
    if component == 'Rb' or component == 'Ttb':
        dstart = 1.033 * np.pi
        orientation_line_radii = [dstart, dstart + dr]
    else:
        dstart = 0.533 * np.pi
        orientation_line_radii = [dstart, dstart + dr]
    x, y = np.array([[-phi_i, -phi_i], orientation_line_radii])
    line = mlines.Line2D(x, y, lw=14, color='k')
    line.set_clip_on(False)
    ax1.add_line(line)
    x, y = np.array([[-phi_i - np.pi, -phi_i - np.pi], orientation_line_radii])
    line = mlines.Line2D(x, y, lw=14, color='k')
    line.set_clip_on(False)
    ax1.add_line(line)

    [i.set_linewidth(2) for i in ax1.spines.values()]

    return view, out_info
Exemplo n.º 4
0
def test01_roughplastic(variant_scalar_rgb):
    from mitsuba.core.xml import load_string
    from mitsuba.render import BSDF, BSDFContext, SurfaceInteraction3f
    from mitsuba.core import Frame3f

    thetas = np.linspace(0, np.pi / 2, 20)
    phi = np.pi

    values_ref = []

    # Create plastic reference BSDF
    bsdf = load_string("""<bsdf version="2.0.0" type="roughplastic">
                              <spectrum name="diffuse_reflectance" value="0.5"/>
                              <float name="alpha" value="0.3"/>
                              <string name="distribution" value="beckmann"/>
                              <float name="int_ior" value="1.5"/>
                              <float name="ext_ior" value="1.0"/>
                              <boolean name="nonlinear" value="true"/>
                          </bsdf>""")

    theta_i = np.radians(30.0)
    si = SurfaceInteraction3f()
    si.p = [0, 0, 0]
    si.n = [0, 0, 1]
    si.wi = [np.sin(theta_i), 0, np.cos(theta_i)]
    si.sh_frame = Frame3f(si.n)
    ctx = BSDFContext()

    for theta in thetas:
        wo = [
            np.sin(theta) * np.cos(phi),
            np.sin(theta) * np.sin(phi),
            np.cos(theta)
        ]
        values_ref.append(bsdf.eval(ctx, si, wo=wo)[0])

    # Create same BSDF as layer representation by applying adding equations
    n, ms, md = mitsuba.layer.microfacet_parameter_heuristic(0.3, 0.3, 1.5)
    mu, w = mitsuba.core.quad.gauss_lobatto(n)

    coating = mitsuba.layer.Layer(mu, w, ms, md)
    coating.set_microfacet(1.5, 0.3, 0.3)
    base = mitsuba.layer.Layer(mu, w, ms, md)
    base.set_diffuse(0.5)

    layer = mitsuba.layer.Layer.add(coating, base)

    for i, theta in enumerate(thetas):
        l_eval = layer.eval(-np.cos(theta), np.cos(theta_i)) * np.abs(
            np.cos(theta))
        # Values should be close (except if they are insignificantly small).
        # We have less precision at grazing angles because of Fourier representation.
        assert values_ref[i] < 1e-5 or np.allclose(
            values_ref[i], l_eval, rtol=0.05 / (np.abs(np.cos(theta))))

    # Convert into BSDF storage representation
    base_path = os.path.dirname(os.path.realpath(__file__)) + "/data/"
    if not os.path.exists(base_path):
        os.makedirs(base_path)
    path = base_path + "roughplastic.bsdf"
    storage = mitsuba.layer.BSDFStorage.from_layer(path, layer, 1e-5)

    for i, theta in enumerate(thetas):
        s_eval = storage.eval(np.cos(theta_i), -np.cos(theta))[0]
        # Values should be close (except if they are insignificantly small).
        # We have less precision at grazing angles because of Fourier representation.
        assert values_ref[i] < 1e-5 or np.allclose(
            values_ref[i], s_eval, rtol=0.05 / (np.abs(np.cos(theta))))
    storage.close()

    # And load via the "fourier" BSDF plugin
    fourier = load_string("""<bsdf version="2.0.0" type="fourier">
                                 <string name="filename" value="{}"/>
                             </bsdf>""".format(path))

    for i, theta in enumerate(thetas):
        wo = [
            np.sin(theta) * np.cos(phi),
            np.sin(theta) * np.sin(phi),
            np.cos(theta)
        ]
        f_eval = fourier.eval(ctx, si, wo=wo)[0]
        assert values_ref[i] < 1e-5 or np.allclose(
            values_ref[i], f_eval, rtol=0.05 / (np.abs(np.cos(theta))))
    del fourier
Exemplo n.º 5
0
def test02_roughconductor(variant_scalar_rgb):
    from mitsuba.core.xml import load_string
    from mitsuba.render import BSDF, BSDFContext, SurfaceInteraction3f
    from mitsuba.core import Frame3f

    for alpha in [(0.3, 0.3), (0.3 + 1e-5, 0.3 - 1e-5), (0.2, 0.4)]:
        alpha_u = alpha[0]
        alpha_v = alpha[1]

        thetas = np.linspace(0, np.pi / 2, 20)
        phi = np.pi

        values_ref = []

        # Create conductor reference BSDF
        bsdf = load_string("""<bsdf version="2.0.0" type="roughconductor">
                                  <float name="alpha_u" value="{}"/>
                                  <float name="alpha_v" value="{}"/>
                                  <string name="distribution" value="beckmann"/>
                                  <spectrum name="eta" value="0.0"/>
                                  <spectrum name="k" value="1.0"/>
                              </bsdf>""".format(alpha_u, alpha_v))

        theta_i = np.radians(30.0)
        si = SurfaceInteraction3f()
        si.p = [0, 0, 0]
        si.n = [0, 0, 1]
        si.wi = [np.sin(theta_i), 0, np.cos(theta_i)]
        si.sh_frame = Frame3f(si.n)
        ctx = BSDFContext()

        for theta in thetas:
            wo = [
                np.sin(theta) * np.cos(phi),
                np.sin(theta) * np.sin(phi),
                np.cos(theta)
            ]
            values_ref.append(bsdf.eval(ctx, si, wo=wo)[0])

        # Create same BSDF as layer representation
        n, ms, md = mitsuba.layer.microfacet_parameter_heuristic(
            alpha_u, alpha_v, 0 + 1j)
        mu, w = mitsuba.core.quad.gauss_lobatto(n)
        layer = mitsuba.layer.Layer(mu, w, ms, md)
        layer.set_microfacet(0 + 1j, alpha_u, alpha_v)

        for i, theta in enumerate(thetas):
            l_eval = layer.eval(-np.cos(theta), np.cos(theta_i)) * np.abs(
                np.cos(theta))
            # Values should be close (except if they are insignificantly small).
            # We have less precision at grazing angles because of Fourier representation.
            print(values_ref[i], l_eval)
            assert values_ref[i] < 1e-5 or np.allclose(
                values_ref[i], l_eval, rtol=0.05 / (np.abs(np.cos(theta))))

        # Convert into BSDF storage representation
        base_path = os.path.dirname(os.path.realpath(__file__)) + "/data/"
        if not os.path.exists(base_path):
            os.makedirs(base_path)
        path = base_path + "roughconductor.bsdf"
        storage = mitsuba.layer.BSDFStorage.from_layer(path, layer, 1e-8)

        for i, theta in enumerate(thetas):
            s_eval = storage.eval(np.cos(theta_i), -np.cos(theta))[0]
            # Values should be close (except if they are insignificantly small).
            # We have less precision at grazing angles because of Fourier representation.
            assert values_ref[i] < 1e-5 or np.allclose(
                values_ref[i], s_eval, rtol=0.05 / (np.abs(np.cos(theta))))
        storage.close()

        # And load via the "fourier" BSDF plugin
        fourier = load_string("""<bsdf version="2.0.0" type="fourier">
                                     <string name="filename" value="{}"/>
                                 </bsdf>""".format(path))

        for i, theta in enumerate(thetas):
            wo = [
                np.sin(theta) * np.cos(phi),
                np.sin(theta) * np.sin(phi),
                np.cos(theta)
            ]
            f_eval = fourier.eval(ctx, si, wo=wo)[0]
            assert values_ref[i] < 1e-5 or np.allclose(
                values_ref[i], f_eval, rtol=0.05 / (np.abs(np.cos(theta))))
        del fourier
Exemplo n.º 6
0
def test01_diffuse(variant_scalar_rgb):
    from mitsuba.core.xml import load_string
    from mitsuba.render import BSDF, BSDFContext, SurfaceInteraction3f
    from mitsuba.core import Frame3f

    thetas = np.linspace(0, np.pi / 2, 20)
    phi = np.pi

    values_ref = []

    # Create diffuse reference BSDF
    bsdf = load_string("""<bsdf version="2.0.0" type="diffuse">
                              <spectrum name="reflectance" value="0.5"/>
                          </bsdf>""")

    theta_i = np.radians(30.0)
    si = SurfaceInteraction3f()
    si.p = [0, 0, 0]
    si.n = [0, 0, 1]
    si.wi = [np.sin(theta_i), 0, np.cos(theta_i)]
    si.sh_frame = Frame3f(si.n)
    ctx = BSDFContext()

    for theta in thetas:
        wo = [
            np.sin(theta) * np.cos(phi),
            np.sin(theta) * np.sin(phi),
            np.cos(theta)
        ]
        values_ref.append(bsdf.eval(ctx, si, wo=wo)[0])

    # Create same BSDF as layer representation
    n = 100
    ms = 1
    md = 1
    mu, w = mitsuba.core.quad.gauss_lobatto(n)
    layer = mitsuba.layer.Layer(mu, w, ms, md)
    layer.set_diffuse(0.5)

    for i, theta in enumerate(thetas):
        l_eval = layer.eval(-np.cos(theta), np.cos(theta_i)) * np.abs(
            np.cos(theta))
        # Values should be close (except if they are insignificantly small).
        # We have less precision at grazing angles because of Fourier representation.
        assert np.allclose(values_ref[i], l_eval, rtol=0.01)

    # Convert into BSDF storage representation
    base_path = os.path.dirname(os.path.realpath(__file__)) + "/data/"
    if not os.path.exists(base_path):
        os.makedirs(base_path)
    path = base_path + "diffuse.bsdf"
    storage = mitsuba.layer.BSDFStorage.from_layer(path, layer, 1e-5)

    for i, theta in enumerate(thetas):
        s_eval = storage.eval(np.cos(theta_i), -np.cos(theta))[0]
        # Values should be close (except if they are insignificantly small).
        # We have less precision at grazing angles because of Fourier representation.
        assert np.allclose(values_ref[i], s_eval, rtol=0.01)
    storage.close()

    # And load via the "fourier" BSDF plugin
    fourier = load_string("""<bsdf version="2.0.0" type="fourier">
                                 <string name="filename" value="{}"/>
                             </bsdf>""".format(path))

    for i, theta in enumerate(thetas):
        wo = [
            np.sin(theta) * np.cos(phi),
            np.sin(theta) * np.sin(phi),
            np.cos(theta)
        ]
        f_eval = fourier.eval(ctx, si, wo=wo)[0]
        assert np.allclose(values_ref[i], f_eval, rtol=0.02)
    del fourier