def interaction():
    from mitsuba.core import Frame3f
    from mitsuba.render import SurfaceInteraction3f
    si = SurfaceInteraction3f()
    si.t = 0.1
    si.p = [0, 0, 0]
    si.n = [0, 0, 1]
    si.sh_frame = Frame3f(si.n)
    return si
示例#2
0
def test02_sample_spectrum(variant_scalar_spectral, obj):
    from mitsuba.render import SurfaceInteraction3f

    si = SurfaceInteraction3f()
    assert ek.allclose(obj.sample_spectrum(si, 0), [500, 150])
    assert ek.allclose(obj.sample_spectrum(si, 1), [600, 150])
    assert ek.allclose(
        obj.sample_spectrum(si, .5),
        [500 + 100 * (ek.sqrt(10) / 2 - 1), 150]
    )
示例#3
0
def test01_eval(variant_packet_spectral, spectrum_key):
    # Check the correctness of the eval() method

    from mitsuba.core import warp
    from mitsuba.core.math import InvFourPi
    from mitsuba.render import SurfaceInteraction3f

    emitter, spectrum = create_emitter_and_spectrum(spectrum_key)

    it = SurfaceInteraction3f.zero()
    assert ek.allclose(emitter.eval(it), spectrum.eval(it))
def test_eval(variant_packet_spectral, spectrum_key, lookat, cutoff_angle):
    # Check the correctness of the eval() method

    from mitsuba.render import SurfaceInteraction3f
    emitter, spectrum = create_emitter_and_spectrum(lookat, cutoff_angle,
                                                    spectrum_key)

    # Check that incident direction in the illuminated direction is zero (because hitting a delta light is impossible)
    it = SurfaceInteraction3f.zero(3)
    it.wi = [0, 1, 0]
    assert ek.allclose(emitter.eval(it), 0.)
def test04_srgb_d65(variant_scalar_spectral):
    """srgb_d65 emitters should evaluate to the product of D65 and sRGB spectra,
    with intensity factored out when evaluating the sRGB model."""

    from mitsuba.core.xml import load_string
    from mitsuba.core import MTS_WAVELENGTH_SAMPLES
    from mitsuba.render import PositionSample3f
    from mitsuba.render import SurfaceInteraction3f
    import numpy as np

    np.random.seed(12345)
    wavelengths = np.linspace(300, 800, MTS_WAVELENGTH_SAMPLES)
    wavelengths += (10 * np.random.uniform(size=wavelengths.shape)).astype(
        np.int)
    d65 = load_string("<spectrum version='2.0.0' type='d65'/>").expand()[0]

    ps = PositionSample3f()
    d65_eval = d65.eval(SurfaceInteraction3f(ps, wavelengths))

    for color in [[1, 1, 1], [0.1, 0.2, 0.3], [34, 0.1, 62],
                  [0.001, 0.02, 11.4]]:
        intensity = (np.max(color) * 2.0) or 1.0
        normalized = np.array(color) / intensity

        srgb_d65 = load_string("""
            <spectrum version="2.0.0" type="srgb_d65">
                <rgb name="color" value="{}"/>
            </spectrum>
        """.format(', '.join(map(str, color))))

        srgb = load_string("""
            <spectrum version="2.0.0" type="srgb">
                <rgb name="color" value="{}"/>
            </spectrum>
        """.format(', '.join(map(str, normalized))))

        assert ek.allclose(srgb_d65.eval(SurfaceInteraction3f(ps,
                                                              wavelengths)),
                           d65_eval * intensity *
                           srgb.eval(SurfaceInteraction3f(ps, wavelengths)),
                           atol=1e-5)
def test03_sample_half_wave_local(variant_scalar_mono_polarized):
    from mitsuba.core import Frame3f, Transform4f, Spectrum
    from mitsuba.core.xml import load_string
    from mitsuba.render import BSDFContext, TransportMode, SurfaceInteraction3f

    def spectrum_from_stokes(v):
        res = Spectrum(0.0)
        for i in range(4):
            res[i, 0] = v[i]
        return res

    # Test polarized implementation. Special case of delta = 180˚, also known
    # as a half-wave plate. (In local BSDF coordinates.)
    #
    # Following "Polarized Light - Fundamentals and Applications" by Edward Collett
    # Chapter 5.3:
    #
    # Case 1 & 2) Switch between diagonal linear polarization states (-45˚ & + 45˚)
    # Case 3 & 4) Switch circular polarization direction

    linear_pos = spectrum_from_stokes([1, 0, +1, 0])
    linear_neg = spectrum_from_stokes([1, 0, -1, 0])
    circular_right = spectrum_from_stokes([1, 0, 0, +1])
    circular_left = spectrum_from_stokes([1, 0, 0, -1])

    bsdf = load_string("""<bsdf version='2.0.0' type='retarder'>
                          <spectrum name="theta" value="0"/>
                          <spectrum name="delta" value="180.0"/>
                      </bsdf>""")

    # Incident direction
    wi = [0, 0, 1]

    ctx = BSDFContext()
    ctx.mode = TransportMode.Importance
    si = SurfaceInteraction3f()
    si.p = [0, 0, 0]
    si.wi = wi
    n = [0, 0, 1]
    si.n = n
    si.sh_frame = Frame3f(si.n)

    bs, M = bsdf.sample(ctx, si, 0.0, [0.0, 0.0])

    # Case 1)
    assert ek.allclose(M @ linear_pos, linear_neg, atol=1e-3)
    # Case 2)
    assert ek.allclose(M @ linear_neg, linear_pos, atol=1e-3)
    # Case 3)
    assert ek.allclose(M @ circular_right, circular_left, atol=1e-3)
    # Case 4)
    assert ek.allclose(M @ circular_left, circular_right, atol=1e-3)
def test02_intersection_partials(variant_scalar_rgb):
    from mitsuba.core import Frame3f, Ray3f, RayDifferential3f
    from mitsuba.render import SurfaceInteraction3f

    # Test the texture partial computation with some random data

    o = [0.44650541, 0.16336525, 0.74225088]
    d = [0.2956123, 0.67325977, 0.67774232]
    time = 0.5
    w = []
    r = RayDifferential3f(o, d, time, w)
    r.o_x = r.o + [0.1, 0, 0]
    r.o_y = r.o + [0, 0.1, 0]
    r.d_x = r.d
    r.d_y = r.d
    r.has_differentials = True

    si = SurfaceInteraction3f()
    si.p = r(10)
    si.dp_du = [0.5514372, 0.84608955, 0.41559092]
    si.dp_dv = [0.14551054, 0.54917541, 0.39286475]
    si.n = ek.cross(si.dp_du, si.dp_dv)
    si.n /= ek.norm(si.n)
    si.t = 0

    si.compute_partials(r)

    # Positions reached via computed partials
    px1 = si.dp_du * si.duv_dx[0] + si.dp_dv * si.duv_dx[1]
    py1 = si.dp_du * si.duv_dy[0] + si.dp_dv * si.duv_dy[1]

    # Manually
    px2 = r.o_x + r.d_x * \
        ((ek.dot(si.n, si.p) - ek.dot(si.n, r.o_x)) / ek.dot(si.n, r.d_x))
    py2 = r.o_y + r.d_y * \
        ((ek.dot(si.n, si.p) - ek.dot(si.n, r.o_y)) / ek.dot(si.n, r.d_y))
    px2 -= si.p
    py2 -= si.p

    assert (ek.allclose(px1, px2))
    assert (ek.allclose(py1, py2))

    si.dp_du = [0, 0, 0]
    si.compute_partials(r)

    assert (ek.allclose(px1, px2))
    assert (ek.allclose(py1, py2))

    si.compute_partials(r)

    assert (ek.allclose(si.duv_dx, [0, 0]))
    assert (ek.allclose(si.duv_dy, [0, 0]))
示例#8
0
def test_sample_direction(variant_scalar_spectral, spectrum_key, it_pos,
                          wavelength_sample, cutoff_angle, lookat):
    # Check the correctness of the sample_direction() method

    import math
    from mitsuba.core import sample_shifted, Transform4f
    from mitsuba.render import SurfaceInteraction3f

    cutoff_angle_rad = math.radians(cutoff_angle)
    beam_width_rad = cutoff_angle_rad * 0.75
    inv_transition_width = 1 / (cutoff_angle_rad - beam_width_rad)
    emitter, spectrum = create_emitter_and_spectrum(lookat, cutoff_angle,
                                                    spectrum_key)
    eval_t = 0.3
    trafo = Transform4f(emitter.world_transform().eval(eval_t))

    # Create a surface iteration
    it = SurfaceInteraction3f.zero()
    it.p = it_pos
    it.time = eval_t

    # Sample a wavelength from spectrum
    wav, spec = spectrum.sample(it, sample_shifted(wavelength_sample))
    it.wavelengths = wav

    # Direction from the position to the point emitter
    d = -it.p + lookat["pos"]
    dist = ek.norm(d)
    d /= dist

    # Calculate angle between lookat direction and ray direction
    angle = ek.acos((trafo.inverse().transform_vector(-d))[2])
    angle = ek.select(
        ek.abs(angle - beam_width_rad) < 1e-3, beam_width_rad, angle)
    angle = ek.select(
        ek.abs(angle - cutoff_angle_rad) < 1e-3, cutoff_angle_rad, angle)

    # Sample a direction from the emitter
    ds, res = emitter.sample_direction(it, [0, 0])

    # Evalutate the spectrum
    spec = spectrum.eval(it)
    spec = ek.select(
        angle <= beam_width_rad, spec,
        spec * ((cutoff_angle_rad - angle) * inv_transition_width))
    spec = ek.select(angle <= cutoff_angle_rad, spec, 0)

    assert ds.time == it.time
    assert ds.pdf == 1.0
    assert ds.delta
    assert ek.allclose(ds.d, d)
    assert ek.allclose(res, spec / (dist**2))
def test_eval(variant_scalar_spectral, spectrum_key):
    # Check correctness of the eval() method
    from mitsuba.core import Vector3f
    from mitsuba.render import SurfaceInteraction3f

    direction = Vector3f([0, 0, -1])
    emitter = make_emitter(direction, spectrum_key)
    spectrum = make_spectrum(spectrum_key)

    # Incident direction in the illuminated direction
    wi = [0, 0, 1]
    it = SurfaceInteraction3f()
    it.p = [0, 0, 0]
    it.wi = wi
    assert ek.allclose(emitter.eval(it), 0.)

    # Incident direction off the illuminated direction
    wi = [0, 0, 1.1]
    it = SurfaceInteraction3f()
    it.p = [0, 0, 0]
    it.wi = wi
    assert ek.allclose(emitter.eval(it), 0.)
def test02_d65(variant_scalar_spectral):
    """d65: Spot check the model in a few places, the chi^2 test will ensure
    that sampling works."""

    from mitsuba.core.xml import load_string
    from mitsuba.render import PositionSample3f
    from mitsuba.render import SurfaceInteraction3f

    d65 = load_string("<spectrum version='2.0.0' type='d65'/>").expand()[0]
    ps = PositionSample3f()

    assert ek.allclose(
        d65.eval(SurfaceInteraction3f(ps, [350, 456, 700, 840])),
        ek.scalar.Vector4f([0, 117.49, 71.6091, 0]) / 10568.0)
def test03_blackbody(variant_scalar_spectral):
    """blackbody: Spot check the model in a few places, the chi^2 test will
    ensure that sampling works."""

    from mitsuba.core.xml import load_string
    from mitsuba.render import PositionSample3f
    from mitsuba.render import SurfaceInteraction3f

    bb = load_string("""<spectrum version='2.0.0' type='blackbody'>
        <float name='temperature' value='5000'/>
    </spectrum>""")
    ps = PositionSample3f()
    assert ek.allclose(bb.eval(SurfaceInteraction3f(ps, [350, 456, 700, 840])),
                       [0, 10997.9, 11812, 0])
def test05_sample_components(variant_scalar_rgb):
    from mitsuba.core import Frame3f
    from mitsuba.render import BSDFFlags, BSDFContext, SurfaceInteraction3f
    from mitsuba.core.xml import load_string
    from mitsuba.core.math import InvPi

    weight = 0.2

    bsdf = load_string("""<bsdf version="2.0.0" type="blendbsdf">
        <bsdf type="diffuse">
            <spectrum name="reflectance" value="0.0"/>
        </bsdf>
        <bsdf type="diffuse">
            <spectrum name="reflectance" value="1.0"/>
        </bsdf>
        <spectrum name="weight" value="{}"/>
    </bsdf>""".format(weight))

    si = SurfaceInteraction3f()
    si.t = 0.1
    si.p = [0, 0, 0]
    si.n = [0, 0, 1]
    si.sh_frame = Frame3f(si.n)
    si.wi = [0, 0, 1]

    ctx = BSDFContext()

    # Sample specific components separately using two different values of 'sample1'
    # and make sure the desired component is chosen always.

    ctx.component = 0

    expected_a = (1-weight)*0.0    # InvPi will cancel out with sampling pdf, but still need to apply weight
    bs_a, weight_a = bsdf.sample(ctx, si, 0.1, [0.5, 0.5])
    assert ek.allclose(weight_a, expected_a)

    expected_b = (1-weight)*0.0    # InvPi will cancel out with sampling pdf, but still need to apply weight
    bs_b, weight_b = bsdf.sample(ctx, si, 0.3, [0.5, 0.5])
    assert ek.allclose(weight_b, expected_b)

    ctx.component = 1

    expected_a = weight*1.0    # InvPi will cancel out with sampling pdf, but still need to apply weight
    bs_a, weight_a = bsdf.sample(ctx, si, 0.1, [0.5, 0.5])
    assert ek.allclose(weight_a, expected_a)

    expected_b = weight*1.0    # InvPi will cancel out with sampling pdf, but still need to apply weight
    bs_b, weight_b = bsdf.sample(ctx, si, 0.3, [0.5, 0.5])
    assert ek.allclose(weight_b, expected_b)
示例#13
0
    def sample_ray(
            self,
            time,
            sample1,  # wavelength
            sample2,  # pos
            sample3,  # dir
            active):
        wavelengths, spec_weight = self.m_intensity.sample(
            SurfaceInteraction3f(), ek.arange(sample1), active)
        trafo = self.m_world_transform.eval(ref.time)
        ray = Ray3f(trafo * Point3f(0), warp.square_to_uniform_sphere(sample3),
                    time, wavelengths)

        # print(spec_weight.class_().name())
        return (ray, spec_weight * 4.0 * Pi)
示例#14
0
def test02_eval(variant_packet_spectral, spectrum_key):
    # Check that eval() return the same values as the 'radiance' spectrum

    from mitsuba.render import SurfaceInteraction3f

    shape, spectrum = create_emitter_and_spectrum(spectrum_key)
    emitter = shape.emitter()

    it = SurfaceInteraction3f.zero(3)
    assert ek.allclose(emitter.eval(it), spectrum.eval(it))

    # Check that eval return 0.0 when direction points inside the shape

    it.wi = ek.normalize([0.2, 0.2, -0.5])
    assert ek.allclose(emitter.eval(it), 0.0)
def test05_direction_sample_construction_dynamic_and_slicing(
        variant_packet_rgb):
    from mitsuba.render import DirectionSample3f, SurfaceInteraction3f
    import numpy as np

    np.random.seed(12345)
    refs = np.array([[0.0, 0.5, 0.7], [1.0, 1.5, 0.2], [-1.3, 0.0, 99.1]])
    its = refs + np.random.uniform(size=refs.shape)
    directions = its - refs
    directions /= np.expand_dims(np.linalg.norm(directions, axis=1), 0).T

    pdfs = [0.99, 1.0, 0.05]

    records_batch = DirectionSample3f.zero(len(pdfs))
    records_batch.p = its
    records_batch.d = directions
    records_batch.pdf = pdfs

    records_individual = DirectionSample3f.zero(len(pdfs))

    # Switch back to scalar variant
    mitsuba.set_variant('scalar_rgb')
    from mitsuba.render import SurfaceInteraction3f, DirectionSample3f, Interaction3f

    for i in range(len(pdfs)):
        it = SurfaceInteraction3f()
        it.p = its[i, :]
        # Needs to be a "valid" (surface) interaction, otherwise interaction
        # will be assumed to have happened on an environment emitter.
        it.t = 0.1
        ref = Interaction3f.zero()
        ref.p = refs[i, :]

        r = DirectionSample3f(it, ref)
        r.pdf = pdfs[i]
        records_individual[i] = r

    assert ek.allclose(records_batch.p, its)
    assert ek.allclose(records_batch.p, records_individual.p)
    assert ek.allclose(records_batch.d, directions)
    assert ek.allclose(records_batch.d, records_individual.d, atol=1e-6)
    assert ek.allclose(records_batch.pdf, pdfs)
    assert ek.allclose(records_batch.pdf, records_individual.pdf)

    # Slicing: get a copy of one of the entries
    single = records_individual[2]
    assert (ek.allclose(single.d, directions[2])
            and ek.allclose(single.pdf, pdfs[2]))
示例#16
0
def test_sample_ray(variant_packet_spectral, spectrum_key, wavelength_sample,
                    pos_sample, cutoff_angle, lookat):
    # Check the correctness of the sample_ray() method

    import math
    from mitsuba.core import warp, sample_shifted, Transform4f
    from mitsuba.render import SurfaceInteraction3f

    cutoff_angle_rad = math.radians(cutoff_angle)
    cos_cutoff_angle_rad = math.cos(cutoff_angle_rad)
    beam_width_rad = cutoff_angle_rad * 0.75
    inv_transition_width = 1 / (cutoff_angle_rad - beam_width_rad)
    emitter, spectrum = create_emitter_and_spectrum(lookat, cutoff_angle,
                                                    spectrum_key)
    eval_t = 0.3
    trafo = Transform4f(emitter.world_transform().eval(eval_t))

    # Sample a local direction and calculate local angle
    dir_sample = pos_sample  # not being used anyway
    local_dir = warp.square_to_uniform_cone(pos_sample, cos_cutoff_angle_rad)
    angle = ek.acos(local_dir[2])
    angle = ek.select(
        ek.abs(angle - beam_width_rad) < 1e-3, beam_width_rad, angle)
    angle = ek.select(
        ek.abs(angle - cutoff_angle_rad) < 1e-3, cutoff_angle_rad, angle)

    # Sample a ray (position, direction, wavelengths) from the emitter
    ray, res = emitter.sample_ray(eval_t, wavelength_sample, pos_sample,
                                  dir_sample)

    # Sample wavelengths on the spectrum
    it = SurfaceInteraction3f.zero()
    wav, spec = spectrum.sample(it, sample_shifted(wavelength_sample))
    it.wavelengths = wav
    spec = spectrum.eval(it)
    spec = ek.select(
        angle <= beam_width_rad, spec,
        spec * ((cutoff_angle_rad - angle) * inv_transition_width))
    spec = ek.select(angle <= cutoff_angle_rad, spec, 0)

    assert ek.allclose(
        res, spec / warp.square_to_uniform_cone_pdf(
            trafo.inverse().transform_vector(ray.d), cos_cutoff_angle_rad))
    assert ek.allclose(ray.time, eval_t)
    assert ek.all(local_dir.z >= cos_cutoff_angle_rad)
    assert ek.allclose(ray.wavelengths, wav)
    assert ek.allclose(ray.d, trafo.transform_vector(local_dir))
    assert ek.allclose(ray.o, lookat["pos"])
示例#17
0
    def sample_ray(
            self,
            time,
            sample1,  # wavelength
            sample2,  # pos
            sample3,  # dir
            active):

        ps = self.m_shape.sample_position(time, sample2, active)
        local = warp.square_to_cosine_hemisphere(sample3)

        si = SurfaceInteraction3f(ps, 0)
        wavelengths, spec_weight = self.m_radiance.sample(
            si, ek.arange(sample1), active)

        ray = Ray3f(ps.p, Frame3f(ps.n).to_world(local), time, wavelengths)
        return (ray, spec_weight * self.m_area_times_pi)
示例#18
0
def test01_eval(variant_scalar_spectral, obj):
    from mitsuba.render import SurfaceInteraction3f

    si = SurfaceInteraction3f()

    values = [0, 1, 1.5, 2, .5, 0]
    for i in range(6):
        si.wavelengths = 450 + 50 * i
        assert ek.allclose(obj.eval(si), values[i])
        assert ek.allclose(obj.pdf_spectrum(si), values[i] / 212.5)

    with pytest.raises(RuntimeError) as excinfo:
        obj.eval_1(si)
    assert 'not implemented' in str(excinfo.value)

    with pytest.raises(RuntimeError) as excinfo:
        obj.eval_3(si)
    assert 'not implemented' in str(excinfo.value)
示例#19
0
    def sample_direction(self, ref, sample, active):
        # as the shape init happens after the emitter init
        if (not (hasattr(self, "m_shape"))):
            self.set_shape_area()

        ds = self.m_shape.sample_direction(ref, sample, active)

        active &= (ek.dot(ds.d, ds.n) < 0) & (ek.neq(ds.pdf, 0))

        si = SurfaceInteraction3f(ds, ref.wavelengths)
        # spatially varying
        cosTheta = -ek.dot(ds.d, ds.n)
        fall = self.fallof(cosTheta)

        spec = self.m_radiance.eval(si, active) * fall / ds.pdf

        ds.object = 0  # HACK

        return (ds, ek.select(active, spec, ek.zero(type(spec))))
def test_sample_ray(variant_scalar_spectral, direction, spectrum_key):
    from mitsuba.core import Vector2f, Vector3f, sample_shifted
    from mitsuba.render import SurfaceInteraction3f

    emitter = make_emitter(direction=direction, spectrum_key=spectrum_key)
    spectrum = make_spectrum(spectrum_key)
    direction = Vector3f(direction)

    time = 1.0

    for wavelength_sample, spatial_sample, directional_sample in zip(
        cycle([0.3, 0.7]),
        [
            [0.85, 0.13],
            [0.16, 0.50],
            [0.00, 1.00],
            [0.32, 0.87],
            [0.16, 0.44],
            [0.17, 0.44],
            [0.22, 0.81],
            [0.12, 0.82],
            [0.99, 0.42],
            [0.72, 0.40],
            [0.01, 0.61],
        ],
        cycle([[0.3, 0.2]])
    ):
        ray, _ = emitter.sample_ray(
            time, wavelength_sample, spatial_sample, directional_sample)

        # Check that ray direction is what is expected
        assert ek.allclose(ray.d, direction / ek.norm(direction))

        # Check that ray origin is outside of bounding sphere
        # Bounding sphere is centered at world origin and has radius 1 without scene
        assert ek.norm(ray.o) >= 1.

        # Check that passed irradiance spectrum is used for wavelength sampling
        it = SurfaceInteraction3f.zero()
        wav, spec = spectrum.sample_spectrum(
            it, sample_shifted(wavelength_sample))
        assert ek.allclose(ray.wavelengths, wav)
示例#21
0
    def sample_direction(self, ref, sample, active):
        trafo = self.m_world_transform.eval(ref.time, active)

        ds = DirectionSample3f()
        ds.p = trafo.matrix[3][:3]
        ds.n = 0
        ds.uv = 0
        ds.time = ref.time
        ds.pdf = 1
        ds.delta = True
        ds.d = ds.p - ref.p
        ds.dist = ek.norm(ds.d)
        inv_dist = ek.rcp(ds.dist)
        ds.d *= inv_dist

        si = SurfaceInteraction3f()
        si.wavelengths = ref.wavelengths

        spec = self.m_intensity.eval(si, active) * (inv_dist * inv_dist)
        return (ds, spec)
def test02_position_sample_construction_dynamic(variant_packet_rgb):
    from mitsuba.render import PositionSample3f, SurfaceInteraction3f

    n_records = 5

    records = PositionSample3f.zero(n_records)
    # Set properties for all records at once (SoA style)
    # records.n = np.zeros(shape=(n_records, 3))
    # records.pdf = np.zeros(shape=(n_records,))
    # records.uv = np.zeros(shape=(n_records, 2))
    # records.delta = np.zeros(shape=(n_records,), dtype=np.bool)
    records.p = np.array([[1.0, 1.0, 1.0], [0.9, 0.9, 0.9], [0.7, 0.7, 0.7],
                          [1.2, 1.5, 1.1], [1.5, 1.5, 1.5]])
    records.time = [0.0, 0.5, 0.7, 1.0, 1.5]
    assert str(records) == """PositionSample3fX[
  p = [[1, 1, 1],
       [0.9, 0.9, 0.9],
       [0.7, 0.7, 0.7],
       [1.2, 1.5, 1.1],
       [1.5, 1.5, 1.5]],
  n = [[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]],
  uv = [[0, 0],
        [0, 0],
        [0, 0],
        [0, 0],
        [0, 0]],
  time = [0, 0.5, 0.7, 1, 1.5],
  pdf = [0, 0, 0, 0, 0],
  delta = [0, 0, 0, 0, 0],
  object = [nullptr, nullptr, nullptr, nullptr, nullptr]
]"""

    # SurfaceInteraction constructor
    si = SurfaceInteraction3f.zero(n_records)
    si.time = [0.0, 0.5, 0.7, 1.0, 1.5]
    records = PositionSample3f(si)
    assert ek.all(records.time == si.time)
def test01_intersection_construction(variant_scalar_rgb):
    from mitsuba.core import Frame3f
    from mitsuba.render import SurfaceInteraction3f

    si = SurfaceInteraction3f()
    si.shape = None
    si.t = 1
    si.time = 2
    si.wavelengths = []
    si.p = [1, 2, 3]
    si.n = [4, 5, 6]
    si.uv = [7, 8]
    si.sh_frame = Frame3f([9, 10, 11], [12, 13, 14], [15, 16, 17])
    si.dp_du = [18, 19, 20]
    si.dp_dv = [21, 22, 23]
    si.duv_dx = [24, 25]
    si.duv_dy = [26, 27]
    si.wi = [31, 32, 33]
    si.prim_index = 34
    si.instance = None
    assert repr(si) == """SurfaceInteraction[
def test03_eval_components(variant_scalar_rgb):
    from mitsuba.core import Frame3f
    from mitsuba.render import BSDFFlags, BSDFContext, SurfaceInteraction3f
    from mitsuba.core.xml import load_string
    from mitsuba.core.math import InvPi

    weight = 0.2

    bsdf = load_string("""<bsdf version="2.0.0" type="blendbsdf">
        <bsdf type="diffuse">
            <spectrum name="reflectance" value="0.0"/>
        </bsdf>
        <bsdf type="diffuse">
            <spectrum name="reflectance" value="1.0"/>
        </bsdf>
        <spectrum name="weight" value="{}"/>
    </bsdf>""".format(weight))

    si = SurfaceInteraction3f()
    si.t = 0.1
    si.p = [0, 0, 0]
    si.n = [0, 0, 1]
    si.sh_frame = Frame3f(si.n)
    si.wi = [0, 0, 1]

    wo = [0, 0, 1]
    ctx = BSDFContext()

    # Evaluate the two components separately

    ctx.component = 0
    value0 = bsdf.eval(ctx, si, wo)
    expected0 = (1-weight) * 0.0*InvPi
    assert ek.allclose(value0, expected0)

    ctx.component = 1
    value1 = bsdf.eval(ctx, si, wo)
    expected1 = weight * 1.0*InvPi
    assert ek.allclose(value1, expected1)
示例#25
0
def get_bxdf_s(args, theta_i, phi_i):
    # Load desired BSDF plugin
    bsdf = load_string(args.material)

    # Create a (dummy) surface interaction to use for the evaluation
    si = SurfaceInteraction3f()

    # Specify an incident direction with 45 degrees elevation
    si.wi = sph_dir(theta_i, phi_i)

    # Create grid in spherical coordinates and map it onto the sphere
    d2r = ek.pi / 180
    theta_s, phi_s = ek.meshgrid(
        ek.linspace(Float, d2r * args.ts[0], d2r * args.ts[1], args.ts[2]),
        ek.linspace(Float, d2r * args.ps[0], d2r * args.ps[1], args.ps[2]))
    ws = sph_dir(theta_s, phi_s)

    # Evaluate the whole array (18000 directions) at once
    values = bsdf.eval(BSDFContext(), si, ws)
    values_r = np.array(values)[:, 0]
    values_r = values_r.reshape(args.ts[2], args.ps[2]).T
    return values_r
def test02_eval_pdf(variant_scalar_rgb):
    from mitsuba.core import Frame3f
    from mitsuba.render import BSDFContext, BSDFFlags, SurfaceInteraction3f
    from mitsuba.core.xml import load_string

    bsdf = load_string("<bsdf version='2.0.0' type='diffuse'></bsdf>")

    si    = SurfaceInteraction3f()
    si.p  = [0, 0, 0]
    si.n  = [0, 0, 1]
    si.wi = [0, 0, 1]
    si.sh_frame = Frame3f(si.n)

    ctx = BSDFContext()

    for i in range(20):
        theta = i / 19.0 * (ek.pi / 2)
        wo = [ek.sin(theta), 0, ek.cos(theta)]

        v_pdf  = bsdf.pdf(ctx, si, wo=wo)
        v_eval = bsdf.eval(ctx, si, wo=wo)[0]
        assert ek.allclose(v_pdf, wo[2] / ek.pi)
        assert ek.allclose(v_eval, 0.5 * wo[2] / ek.pi)
def test04_sample_all(variant_scalar_rgb):
    from mitsuba.core import Frame3f
    from mitsuba.render import BSDFFlags, BSDFContext, SurfaceInteraction3f
    from mitsuba.core.xml import load_string
    from mitsuba.core.math import InvPi

    weight = 0.2

    bsdf = load_string("""<bsdf version="2.0.0" type="blendbsdf">
        <bsdf type="diffuse">
            <spectrum name="reflectance" value="0.0"/>
        </bsdf>
        <bsdf type="diffuse">
            <spectrum name="reflectance" value="1.0"/>
        </bsdf>
        <spectrum name="weight" value="{}"/>
    </bsdf>""".format(weight))

    si = SurfaceInteraction3f()
    si.t = 0.1
    si.p = [0, 0, 0]
    si.n = [0, 0, 1]
    si.sh_frame = Frame3f(si.n)
    si.wi = [0, 0, 1]

    ctx = BSDFContext()

    # Sample using two different values of 'sample1' and make sure correct
    # components are chosen.

    expected_a = 1.0    # InvPi & weight will cancel out with sampling pdf
    bs_a, weight_a = bsdf.sample(ctx, si, 0.1, [0.5, 0.5])
    assert ek.allclose(weight_a, expected_a)

    expected_b = 0.0    # InvPi & weight will cancel out with sampling pdf
    bs_b, weight_b = bsdf.sample(ctx, si, 0.3, [0.5, 0.5])
    assert ek.allclose(weight_b, expected_b)
示例#28
0
 def pdf_functor(w, *args):
     plugin = instantiate(args)
     si = SurfaceInteraction3f.zero(ek.slices(w))
     si.wavelengths = w
     return plugin.pdf(si)[0]
示例#29
0
 def make_context(n):
     si = SurfaceInteraction3f.zero(n)
     si.wi = wi
     ek.set_slices(si.wi, n)
     si.wavelengths = []
     return (si, ctx)
示例#30
0
def render_sample(scene, sampler, rays, bdata, heightmap_pybind, bssrdf=None):
    """
    Sample RTE
    TODO: Support multi channel sampling

    Args:
        scene: Target scene object
        sampler: Sampler object for random number
        rays: Given rays for sampling
        bdata: BSSRDF Data object
        heightmap_pybind: Object for getting height map around incident position.
                          Refer src/librender/python/heightmap.cpp

    Returns:
        result: Sampling RTE result
        valid_rays: Mask data whether rays are valid or not
        scatter: Scatter components of Sampling RTE result
        non_scatter: Non scatter components of Sampling RTE result
        invalid_sample: Sampling RTE result with invalid sampled data by VAEBSSRDF
    """

    eta = Float(1.0)
    emission_weight = Float(1.0)
    throughput = Spectrum(1.0)
    result = Spectrum(0.0)
    scatter = Spectrum(0.0)
    non_scatter = Spectrum(0.0)
    invalid_sample = Spectrum(0.0)
    active = True
    is_bssrdf = False

    ##### First interaction #####
    si = scene.ray_intersect(rays, active)
    active = si.is_valid() & active
    valid_rays = si.is_valid()

    emitter = si.emitter(scene, active)

    depth = 0

    # Set channel
    # At and after evaluating BSSRDF, a ray consider only this one channel
    n_channels = 3
    channel = UInt32(
        ek.min(sampler.next_1d(active) * n_channels, n_channels - 1))

    d_out_local = Vector3f().zero()
    d_out_pdf = Float(0)

    sss = Mask(False)

    while (True):
        depth += 1
        if config.aovs and depth == 2:
            sss = is_bssrdf

        ##### Interaction with emitters #####
        emission_val = emission_weight * throughput * Emitter.eval_vec(
            emitter, si, active)

        result += ek.select(active, emission_val, Spectrum(0.0))
        invalid_sample += ek.select(active, emission_val, Spectrum(0.0))
        scatter += ek.select(active & sss, emission_val, Spectrum(0.0))
        non_scatter += ek.select(active & ~sss, emission_val, Spectrum(0.0))

        active = active & si.is_valid()

        # Process russian roulette
        if depth > config.rr_depth:
            q = ek.min(ek.hmax(throughput) * ek.sqr(eta), 0.95)
            active = active & (sampler.next_1d(active) < q)
            throughput *= ek.rcp(q)

        # Stop if the number of bouces exceeds the given limit bounce, or
        # all rays are invalid. latter check is done only when the limit
        # bounce is infinite
        if depth >= config.max_depth:
            break

        ##### Emitter sampling #####
        bsdf = si.bsdf(rays)
        ctx = BSDFContext()

        active_e = active & has_flag(BSDF.flags_vec(bsdf), BSDFFlags.Smooth)
        ds, emitter_val = scene.sample_emitter_direction(
            si, sampler.next_2d(active_e), True, active_e)
        active_e &= ek.neq(ds.pdf, 0.0)

        # Query the BSDF for that emitter-sampled direction
        wo = si.to_local(ds.d)
        bsdf_val = BSDF.eval_vec(bsdf, ctx, si, wo, active_e)
        # Determine density of sampling that same direction using BSDF sampling
        bsdf_pdf = BSDF.pdf_vec(bsdf, ctx, si, wo, active_e)

        mis = ek.select(ds.delta, Float(1), mis_weight(ds.pdf, bsdf_pdf))

        emission_val = mis * throughput * bsdf_val * emitter_val

        result += ek.select(active, emission_val, Spectrum(0.0))
        invalid_sample += ek.select(active, emission_val, Spectrum(0.0))
        scatter += ek.select(active & sss, emission_val, Spectrum(0.0))
        non_scatter += ek.select(active & ~sss, emission_val, Spectrum(0.0))

        ##### BSDF sampling #####
        bs, bsdf_val = BSDF.sample_vec(bsdf, ctx, si, sampler.next_1d(active),
                                       sampler.next_2d(active), active)

        ##### BSSRDF replacing #####
        if (config.enable_bssrdf):
            # Replace bsdf samples by ones of BSSRDF
            bs.wo = ek.select(is_bssrdf, d_out_local, bs.wo)
            bs.pdf = ek.select(is_bssrdf, d_out_pdf, bs.pdf)
            bs.sampled_component = ek.select(is_bssrdf, UInt32(1),
                                             bs.sampled_component)
            bs.sampled_type = ek.select(is_bssrdf,
                                        UInt32(+BSDFFlags.DeltaTransmission),
                                        bs.sampled_type)
        ############################

        throughput *= ek.select(is_bssrdf, Float(1.0), bsdf_val)
        active &= ek.any(ek.neq(throughput, 0))

        eta *= bs.eta

        # Intersect the BSDF ray against the scene geometry
        rays = RayDifferential3f(si.spawn_ray(si.to_world(bs.wo)))
        si_bsdf = scene.ray_intersect(rays, active)

        ##### Checking BSSRDF #####
        if (config.enable_bssrdf):
            # Whether the BSDF is BSS   RDF or not?
            is_bssrdf = (active
                         & has_flag(BSDF.flags_vec(bsdf), BSDFFlags.BSSRDF)
                         & (Frame3f.cos_theta(bs.wo) < Float(0.0))
                         & (Frame3f.cos_theta(si.wi) > Float(0.0)))

            # Decide whether we should use 0-scattering or multiple scattering
            is_zero_scatter = utils_render.check_zero_scatter(
                sampler, si_bsdf, bs, channel, is_bssrdf)
            is_bssrdf = is_bssrdf & ~is_zero_scatter

            throughput *= ek.select(is_bssrdf, ek.sqr(bs.eta), Float(1.0))
        ###########################

        ###### Process for BSSRDF ######
        if (config.enable_bssrdf and not ek.none(is_bssrdf)):
            # Get projected samples from BSSRDF
            projected_si, project_suc, abs_prob = bssrdf.sample_bssrdf(
                scene, bsdf, bs, si, bdata, heightmap_pybind, channel,
                is_bssrdf)

            if config.visualize_invalid_sample and (depth <= 1):
                active = active & (~is_bssrdf | project_suc)
                invalid_sample += ek.select((is_bssrdf & (~project_suc)),
                                            Spectrum([100, 0, 0]),
                                            Spectrum(0.0))

            # Sample outgoing direction from projected position
            d_out_local, d_out_pdf = utils_render.resample_wo(
                sampler, is_bssrdf)
            # Apply absorption probability
            throughput *= ek.select(is_bssrdf,
                                    Spectrum(1) - abs_prob, Spectrum(1))
            # Replace interactions by sampled ones from BSSRDF
            si_bsdf = SurfaceInteraction3f().masked_si(si_bsdf, projected_si,
                                                       is_bssrdf)
        ################################

        # Determine probability of having sampled that same
        # direction using emitter sampling
        emitter = si_bsdf.emitter(scene, active)
        ds = DirectionSample3f(si_bsdf, si)
        ds.object = emitter

        delta = has_flag(bs.sampled_type, BSDFFlags.Delta)
        emitter_pdf = ek.select(delta, Float(0.0),
                                scene.pdf_emitter_direction(si, ds))
        emission_weight = mis_weight(bs.pdf, emitter_pdf)

        si = si_bsdf

    return result, valid_rays, scatter, non_scatter, invalid_sample