Example #1
0
def weight_measurements(spec,
                        D,
                        sigma,
                        theta_i,
                        phi_i,
                        theta_o,
                        phi_o,
                        active=None):
    from mitsuba.core import MarginalContinuous2D0, Vector2f
    m_ndf = MarginalContinuous2D0(D, normalize=False)
    m_sigma = MarginalContinuous2D0(sigma, normalize=False)
    scaled = np.zeros(spec.shape)
    n_phi = spec.shape[-2]
    n_theta = spec.shape[-1]

    for i in range(phi_i.size):
        for j in range(theta_i.size):
            # Incient direction
            wi = spherical2cartesian(theta_i[j], phi_i[i])
            u_wi = Vector2f(theta2u(theta_i[j]), phi2u(phi_i[i]))
            # Outgoing direction
            wo = spherical2cartesian(theta_o[i, j].flatten(),
                                     phi_o[i, j].flatten())
            # Phase direction
            m = ek.normalize(wi + wo)
            theta_m, phi_m = cartesian2spherical(wo)
            u_m = Vector2f(theta2u(theta_m), phi2u(phi_m))
            # Scale by inverse jacobian
            jacobian = m_ndf.eval(u_m) / (4 * m_sigma.eval(u_wi))
            scaled[i, j] = spec[i, j] / np.reshape(jacobian, (n_phi, n_theta))
    if not active is None:
        n_wavelenths = spec.shape[2]
        for i in range(n_wavelenths):
            scaled[:, :, i][~active] = 0
    return scaled
Example #2
0
def visible_ndf(D, sigma, theta_i, phi_i, isotropic):
    from mitsuba.core import MarginalContinuous2D0, Vector2f

    # Construct projected surface area interpolant data structure
    m_sigma = MarginalContinuous2D0(sigma, normalize=False)

    # Create uniform samples and warp by G2 mapping
    if isotropic:
        n_theta = n_phi = D.shape[1]
    else:
        n_phi = D.shape[0]
        n_theta = D.shape[1]

    # Check dimensions of micro-facet model
    Dvis = np.zeros((phi_i.size, theta_i.size, n_phi, n_theta))

    theta = u2theta(np.linspace(0, 1, n_theta))
    phi = u2phi(np.linspace(0, 1, n_phi))

    # Calculate projected area of micro-facets
    for i in range(Dvis.shape[0]):  # incident elevation
        for j in range(Dvis.shape[1]):  # incident azimuth
            # Postion for sigma samples
            sample = Vector2f(theta2u(theta_i[j]), phi2u(phi_i[i]))
            sigma_i = m_sigma.eval(sample)

            # Incident direction
            omega_i = spherical2cartesian(theta_i[j], phi_i[i])
            #print(np.degrees(theta_i[j]), np.degrees(phi_i[i]))

            for k in range(Dvis.shape[2]):  # observation azimuth
                # Observation direction
                omega = spherical2cartesian(theta, phi[k])
                sample = Vector2f(theta2u(theta), phi2u(phi[k]))

                # NDF at observation directions
                if isotropic:
                    D_m = D[0]
                else:
                    D_m = D[k]
                # Bidirectional NDF
                Dvis[i, j,
                     k] = ek.max(0, ek.dot(omega, omega_i)) * D_m / sigma_i
    return Dvis
Example #3
0
def normalize_2D(F, isotropic=True):
    # Normalize function so that integral = 1
    from mitsuba.core import MarginalContinuous2D0, Vector2f
    F_norm = np.zeros(F.shape)
    # Construct projected surface area interpolant data structure
    m_F_norm = MarginalContinuous2D0(F, normalize=True)

    # Create uniform samples
    u_1 = np.linspace(0, 1, F_norm.shape[1])
    u_2 = np.linspace(0, 1, F_norm.shape[0])

    # Sample normalized mapping
    if isotropic:
        sample = Vector2f(u_1, u_2[0])
        F_norm[0] = m_F_norm.eval(sample)
        F_norm[1] = F_norm[0]
    else:
        for k in range(F_norm.shape[0]):
            sample = Vector2f(u_1, u_2[k])
            F_norm[k] = m_F_norm.eval(sample)
            print(sample, m_F_norm.eval(sample))
    return F_norm
Example #4
0
def eval_md(n_theta, n_phi, D_in, isotropic):
    from mitsuba.render import MarginalContinuous2D0, Vector2f
    m_D = MarginalContinuous2D0(D_in, normalize=False)
    u = np.meshgrid(np.linspace(0, 1, n_theta), np.linspace(0, 1, n_phi))
    u_0 = u[0].flatten()
    u_1 = u[1].flatten()
    samples = Vector2f(u_0, u_1)
    D = m_D.eval(samples)
    if isotropic:
        D = np.vstack((D, D))
    else:
        D = np.reshape(D, (n_phi, n_theta))
    return D
Example #5
0
def incident_elevation(n, sigma):
    from mitsuba.core import Float, Vector2f
    from mitsuba.core import MarginalContinuous2D0

    # Construct projected surface area interpolant data structure
    sigma_sampler = ndf_intp2sample(sigma)
    m_sigma = MarginalContinuous2D0(sigma_sampler, normalize=False)

    # Warp samples by projected area
    samples = Vector2f(np.linspace(0, 1, n), 0.5)
    u_m, _ = m_sigma.sample(samples)

    # Map samples to sphere
    theta_i = u2theta(u_m[0])  #(np.pi - u_m[0] * np.pi) / 2
    return theta_i
Example #6
0
def normalize_4D(F, theta_i, phi_i):
    # Normalize function so that integral = 1
    from mitsuba.core import MarginalContinuous2D2, Vector2f
    F_norm = np.zeros(F.shape)
    params = [phi_i.tolist(), theta_i.tolist()]
    # Construct projected surface area interpolant data structure
    m_F_norm = MarginalContinuous2D2(F, params, normalize=True)

    # Create uniform samples
    u_1 = np.linspace(0, 1, F_norm.shape[3])
    u_2 = np.linspace(0, 1, F_norm.shape[2])

    # Sample normalized mapping
    for i in range(F_norm.shape[0]):
        for j in range(F_norm.shape[1]):
            for k in range(F_norm.shape[2]):
                sample = Vector2f(u_1, u_2[k])
                F_norm[i, j, k] = m_F_norm.eval(sample, [phi_i[i], theta_i[j]])
    return F_norm
Example #7
0
def normalize_2D2(func, theta_i, phi_i):
    from mitsuba.core import MarginalContinuous2D2, Vector2f
    params = [phi_i.tolist(), theta_i.tolist()]
    m_func = MarginalContinuous2D2(func, params, normalize=True)

    n_phi_o = func.shape[2]
    n_theta_o = func.shape[3]

    normalized = np.zeros(func.shape)
    # Create uniform samples
    u_0 = np.linspace(0, 1, n_theta_o)
    u_1 = np.linspace(0, 1, n_phi_o)
    samples = Vector2f(np.tile(u_0, n_phi_o), np.repeat(u_1, n_theta_o))

    for i in range(phi_i.size):
        for j in range(theta_i.size):
            # Warp uniform samples by VNDF distribution (G1 mapping)
            normalized[i, j] = np.reshape(
                m_func.eval(samples, [phi_i[i], theta_i[j]]),
                (n_phi_o, n_theta_o))
    return normalized
Example #8
0
def brdf_samples(vndf, theta_i, phi_i, n_theta, n_phi):
    from mitsuba.core import MarginalContinuous2D2
    # Construct projected surface area interpolant data structure
    params = [phi_i.tolist(), theta_i.tolist()]
    m_vndf = MarginalContinuous2D2(vndf, params, normalize=False)

    u_m = np.meshgrid(np.linspace(0, 1, n_theta), np.linspace(0, 1, n_phi))
    u_0 = u_m[0].flatten()
    u_1 = u_m[1].flatten()
    samples = Vector2f(u_0, u_1)

    # Check dimensions of micro-facet model
    theta_o = phi_o = np.zeros((phi_i.size, theta_i.size, n_phi * n_theta))

    # Warp sample grid to VNDF
    for i in range(vndf.shape[0]):
        for j in range(vndf.shape[1]):
            val = m_vndf.eval(samples, [theta_i[j], phi_i[i]])
            m = m_vndf.sample(samples, [theta_i[j], phi_i[i]])
            # Map samples to spere
            theta_o[i, j] = u2theta(m[0])
            phi_o[i, j] = u2phi(m[1])
    return theta_o, phi_o
Example #9
0
def outgoing_direction(n_phi,
                       n_theta,
                       Dvis_sampler,
                       theta_i,
                       phi_i,
                       isotropic,
                       theta_max=np.pi / 2,
                       all=False):
    from mitsuba.core import Vector2f, Frame3f
    from mitsuba.core import MarginalContinuous2D2

    print("Max theta angle is %f deg." % np.degrees(theta_max))

    phi_o = np.zeros((phi_i.size, theta_i.size, n_phi, n_theta))
    theta_o = np.zeros((phi_i.size, theta_i.size, n_phi, n_theta))
    invalid = np.ones((phi_i.size, theta_i.size, n_phi, n_theta), dtype='bool')
    active = np.ones((phi_i.size, theta_i.size, n_phi, n_theta), dtype='bool')

    # Create uniform samples
    u_0 = np.linspace(0, 1, n_theta)
    u_1 = np.linspace(0, 1, n_phi)
    samples = Vector2f(np.tile(u_0, n_phi), np.repeat(u_1, n_theta))

    # Construct projected surface area interpolant data structure
    params = [phi_i.tolist(), theta_i.tolist()]
    m_vndf = MarginalContinuous2D2(Dvis_sampler, params, normalize=True)

    for i in range(phi_i.size):
        for j in range(theta_i.size):
            # Warp uniform samples by VNDF distribution (G1 mapping)
            u_m, ndf_pdf = m_vndf.sample(samples, [phi_i[i], theta_i[j]])
            # Convert samples to radians (G2 mapping)
            theta_m = u2theta(u_m.x)  # [0, 1] -> [0, pi]
            phi_m = u2phi(u_m.y)  # [0, 1] -> [0, 2pi]
            if isotropic:
                phi_m += phi_i[i]
            # Phase vector
            m = spherical2cartesian(theta_m, phi_m)
            # Incident direction
            wi = spherical2cartesian(theta_i[j], phi_i[i])
            # Outgoing direction (reflection over phase vector)
            wo = ek.fmsub(m, 2.0 * ek.dot(m, wi), wi)
            tmp1, tmp2 = cartesian2spherical(wo)
            # Remove invalid directions
            act = u_m.y > 0  # covered twice [-pi = pi]
            inv = Frame3f.cos_theta(wo) < 0  # below surface plane
            act &= np.invert(inv)  # above surface plane
            act &= tmp1 <= (theta_max + EPSILON)  # further angular restriction
            if isotropic:
                act &= tmp2 >= 0
            if not all:
                tmp1[~act] = 0
                tmp2[~act] = 0
            else:
                tmp1[inv] = 0
                tmp2[inv] = 0

            # Fit to datashape
            act = np.reshape(act, (n_phi, n_theta))
            inv = np.reshape(inv, (n_phi, n_theta))
            tmp1 = np.reshape(tmp1, (n_phi, n_theta))
            tmp2 = np.reshape(tmp2, (n_phi, n_theta))

            # Append
            active[i, j] = act
            invalid[i, j] = inv
            theta_o[i, j] = tmp1
            phi_o[i, j] = tmp2
    return [theta_o, phi_o, active, invalid]
Example #10
0
def projected_area(D, isotropic, projected=True):
    from mitsuba.core import MarginalContinuous2D0, Vector2f, Vector3f

    # Check dimensions of micro-facet model
    sigma = np.zeros(D.shape)

    # Construct projected surface area interpolant data structure
    m_D = MarginalContinuous2D0(D, normalize=False)

    # Create uniform samples and warp by G2 mapping
    if isotropic:
        n_theta = n_phi = D.shape[1]
    else:
        n_phi = D.shape[0]
        n_theta = D.shape[1]
    theta = u2theta(np.linspace(0, 1, n_theta))
    phi = u2phi(np.linspace(0, 1, n_phi))

    # Temporary values for surface area calculation
    theta_mean = np.zeros(n_theta + 1)
    for i in range(n_theta - 1):
        theta_mean[i + 1] = (theta[i + 1] - theta[i]) / 2. + theta[i]
    theta_mean[-1] = theta[-1]
    theta_mean[0] = theta[0]
    """
    Surface area portion of unit sphere.
    Conditioning better for non vectorized approach.
    a  = sphere_surface_patch(1, theta_next, Vector2f(phi[0], phi[1]))
    """
    a = np.zeros(n_theta)
    for i in range(n_theta):
        a[i] = sphere_surface_patch(1, theta_mean[i:i + 2], phi[-3:-1])

    # Calculate constants for integration
    for j in range(n_phi):
        # Interpolation points
        o = spherical2cartesian(theta, phi[j])
        # Postion for NDF samples
        u0 = theta2u(theta)
        u1 = np.ones(n_theta) * phi2u(phi[j])
        if j == 0:
            omega = o
            u_0 = u0
            u_1 = u1
            area = a / 2
        else:
            omega = np.concatenate((omega, o))
            u_0 = np.concatenate((u_0, u0))
            u_1 = np.concatenate((u_1, u1))
            if j == n_phi - 1:
                area = np.concatenate((area, a / 2))
            else:
                area = np.concatenate((area, a))
    sample = Vector2f(u_0, u_1)
    D_s = m_D.eval(sample)
    omega = Vector3f(omega)

    P = 1.
    # Calculate projected area of micro-facets
    for i in range(sigma.shape[0] - 1):
        for j in range(sigma.shape[1]):
            # Get projection factor from incident and outgoind direction
            if projected:
                # Incident direction
                omega_i = spherical2cartesian(theta[j], phi[i])
                P = ek.max(0, ek.dot(omega, omega_i))

            # Integrate over sphere
            F = P * D_s
            sigma[i, j] = np.dot(F, area)

        if projected:
            # Normalise
            sigma[i] = sigma[i] / sigma[i, 0]

    # TODO: Check for anisotropic case
    if isotropic:
        sigma[1] = sigma[0]

    return sigma