def quat_to_euler(q): name = _ek.detail.array_name('Array', q.Type, [3], q.IsScalar) module = _modules.get(q.__module__) Array3f = getattr(module, name) sinp = 2 * _ek.fmsub(q.w, q.y, q.z * q.x) gimbal_lock = _ek.abs(sinp) > (1.0 - 5e-8) # roll (x-axis rotation) q_y_2 = _ek.sqr(q.y) sinr_cosp = 2 * _ek.fmadd(q.w, q.x, q.y * q.z) cosr_cosp = _ek.fnmadd(2, _ek.fmadd(q.x, q.x, q_y_2), 1) roll = _ek.select(gimbal_lock, 2 * _ek.atan2(q.x, q.w), _ek.atan2(sinr_cosp, cosr_cosp)) # pitch (y-axis rotation) pitch = _ek.select(gimbal_lock, _ek.copysign(0.5 * _ek.Pi, sinp), _ek.asin(sinp)) # yaw (z-axis rotation) siny_cosp = 2 * _ek.fmadd(q.w, q.z, q.x * q.y) cosy_cosp = _ek.fnmadd(2, _ek.fmadd(q.z, q.z, q_y_2), 1) yaw = _ek.select(gimbal_lock, 0, _ek.atan2(siny_cosp, cosy_cosp)) return Array3f(roll, pitch, yaw)
def test05_scalar(t): if not ek.is_array_v(t) or ek.array_size_v(t) == 0: return get_class(t.__module__) if ek.is_mask_v(t): assert ek.all_nested(t(True)) assert ek.any_nested(t(True)) assert ek.none_nested(t(False)) assert ek.all_nested(t(False) ^ t(True)) assert ek.all_nested(ek.eq(t(False), t(False))) assert ek.none_nested(ek.eq(t(True), t(False))) if ek.is_arithmetic_v(t): assert t(1) + t(1) == t(2) assert t(3) - t(1) == t(2) assert t(2) * t(2) == t(4) assert ek.min(t(2), t(3)) == t(2) assert ek.max(t(2), t(3)) == t(3) if ek.is_signed_v(t): assert t(2) * t(-2) == t(-4) assert ek.abs(t(-2)) == t(2) if ek.is_integral_v(t): assert t(6) // t(2) == t(3) assert t(7) % t(2) == t(1) assert t(7) >> 1 == t(3) assert t(7) << 1 == t(14) assert t(1) | t(2) == t(3) assert t(1) ^ t(3) == t(2) assert t(1) & t(3) == t(1) else: assert t(6) / t(2) == t(3) assert ek.sqrt(t(4)) == t(2) assert ek.fmadd(t(1), t(2), t(3)) == t(5) assert ek.fmsub(t(1), t(2), t(3)) == t(-1) assert ek.fnmadd(t(1), t(2), t(3)) == t(1) assert ek.fnmsub(t(1), t(2), t(3)) == t(-5) assert (t(1) & True) == t(1) assert (t(1) & False) == t(0) assert (t(1) | False) == t(1) assert ek.all_nested(t(3) > t(2)) assert ek.all_nested(ek.eq(t(2), t(2))) assert ek.all_nested(ek.neq(t(3), t(2))) assert ek.all_nested(t(1) >= t(1)) assert ek.all_nested(t(2) < t(3)) assert ek.all_nested(t(1) <= t(1)) assert ek.select(ek.eq(t(2), t(2)), t(4), t(5)) == t(4) assert ek.select(ek.eq(t(3), t(2)), t(4), t(5)) == t(5) t2 = t(2) assert ek.hsum(t2) == t.Value(2 * len(t2)) assert ek.dot(t2, t2) == t.Value(4 * len(t2)) assert ek.dot_async(t2, t2) == t(4 * len(t2)) value = t(1) value[ek.eq(value, t(1))] = t(2) value[ek.eq(value, t(3))] = t(5) assert value == t(2)
def det(m): if not _ek.is_matrix_v(m): raise Exception("Unsupported target type!") if m.Size == 1: return m[0, 0] elif m.Size == 2: return _ek.fmsub(m[0, 0], m[1, 1], m[0, 1] * m[1, 0]) elif m.Size == 3: return _ek.dot(m[0], _ek.cross(m[1], m[2])) elif m.Size == 4: col0, col1, col2, col3 = m col1 = _ek.shuffle((2, 3, 0, 1), col1) col3 = _ek.shuffle((2, 3, 0, 1), col3) temp = _ek.shuffle((1, 0, 3, 2), col2 * col3) row0 = col1 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fmsub(col1, temp, row0) temp = _ek.shuffle((1, 0, 3, 2), col1 * col2) row0 = _ek.fmadd(col3, temp, row0) temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col3, temp, row0) col1 = _ek.shuffle((2, 3, 0, 1), col1) col2 = _ek.shuffle((2, 3, 0, 1), col2) temp = _ek.shuffle((1, 0, 3, 2), col1 * col3) row0 = _ek.fmadd(col2, temp, row0) temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col2, temp, row0) return _ek.dot(col0, row0) else: raise Exception('Unsupported array size!')
def test04_operators(): I3 = ek.scalar.Array3i F3 = ek.scalar.Array3f assert (I3(1, 2, 3) + I3(0, 1, 0) == I3(1, 3, 3)) assert (I3(1, 2, 3) - I3(0, 1, 0) == I3(1, 1, 3)) assert (I3(1, 2, 3) * I3(0, 1, 0) == I3(0, 2, 0)) assert (I3(1, 2, 3) // I3(2, 2, 2) == I3(0, 1, 1)) assert (I3(1, 2, 3) % I3(2, 2, 2) == I3(1, 0, 1)) assert (I3(1, 2, 3) << 1 == I3(2, 4, 6)) assert (I3(1, 2, 3) >> 1 == I3(0, 1, 1)) assert (I3(1, 2, 3) & 1 == I3(1, 0, 1)) assert (I3(1, 2, 3) | 1 == I3(1, 3, 3)) assert (I3(1, 2, 3) ^ 1 == I3(0, 3, 2)) assert (-I3(1, 2, 3) == I3(-1, -2, -3)) assert (~I3(1, 2, 3) == I3(-2, -3, -4)) assert (ek.abs(I3(1, -2, 3)) == I3(1, 2, 3)) assert (abs(I3(1, -2, 3)) == I3(1, 2, 3)) assert (ek.abs(I3(1, -2, 3)) == I3(1, 2, 3)) assert (ek.fmadd(F3(1, 2, 3), F3(2, 3, 1), F3(1, 1, 1)) == F3(3, 7, 4)) assert (ek.fmsub(F3(1, 2, 3), F3(2, 3, 1), F3(1, 1, 1)) == F3(1, 5, 2)) assert (ek.fnmadd(F3(1, 2, 3), F3(2, 3, 1), F3(1, 1, 1)) == F3(-1, -5, -2)) assert (ek.fnmsub(F3(1, 2, 3), F3(2, 3, 1), F3(1, 1, 1)) == F3(-3, -7, -4))
def mul_(a0, a1): if not a0.IsArithmetic: raise Exception("mul(): requires arithmetic operands!") if _ek.array_depth_v(a1) < _ek.array_depth_v(a0): # Avoid type promotion in scalars multiplication, which would # be costly for special types (matrices, quaternions, etc.) sr = len(a0) ar = a0.empty_(sr if a0.Size == Dynamic else 0) for i in range(len(a0)): ar[i] = a0[i] * a1 return ar ar, sr = _check2(a0, a1) if not a0.IsSpecial: for i in range(sr): ar[i] = a0[i] * a1[i] elif a0.IsComplex: ar.real = _ek.fmsub(a0.real, a1.real, a0.imag * a1.imag) ar.imag = _ek.fmadd(a0.real, a1.imag, a0.imag * a1.real) elif a0.IsQuaternion: tbl = (4, 3, -2, 1, -3, 4, 1, 2, 2, -1, 4, 3, -1, -2, -3, 4) for i in range(4): accum = 0 for j in range(4): idx = tbl[i * 4 + j] value = a1[abs(idx) - 1] accum = _ek.fmadd(a0[j], value if idx > 0 else -value, accum) ar[i] = accum elif a0.IsMatrix: raise Exception( "mul(): please use the matrix multiplication operator '@' instead." ) else: raise Exception("mul(): unsupported array type!") return ar
def quat_to_euler(q): q_y_2 = _ek.sqr(q.y) sinr_cosp = 2 * _ek.fmadd(q.w, q.x, q.y * q.z) cosr_cosp = _ek.fnmadd(2, _ek.fmadd(q.x, q.x, q_y_2), 1) roll = _ek.atan2(sinr_cosp, cosr_cosp) # pitch (y-axis rotation) sinp = 2 * _ek.fmsub(q.w, q.y, q.z * q.x) if (_ek.abs(sinp) >= 1.0): pitch = _ek.copysign(0.5 * _ek.Pi, sinp) else: pitch = _ek.asin(sinp) # yaw (z-axis rotation) siny_cosp = 2 * _ek.fmadd(q.w, q.z, q.x * q.y) cosy_cosp = _ek.fnmadd(2, _ek.fmadd(q.z, q.z, q_y_2), 1) yaw = _ek.atan2(siny_cosp, cosy_cosp) name = _ek.detail.array_name('Array', q.Type, [3], q.IsScalar) module = _modules.get(q.__module__) Array3f = getattr(module, name) return Array3f(roll, pitch, yaw)
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]
def inverse_transpose(m): if not _ek.is_matrix_v(m): raise Exception("Unsupported target type!") t = type(m) if m.Size == 1: return t(_ek.rcp(m[0, 0])) elif m.Size == 2: inv_det = _ek.rcp(_ek.fmsub(m[0, 0], m[1, 1], m[0, 1] * m[1, 0])) return t(m[1, 1] * inv_det, -m[1, 0] * inv_det, -m[0, 1] * inv_det, m[0, 0] * inv_det) elif m.Size == 3: col0, col1, col2 = m row0 = _ek.cross(col1, col2) row1 = _ek.cross(col2, col0) row2 = _ek.cross(col0, col1) inv_det = _ek.rcp(_ek.dot(col0, row0)) return t(row0 * inv_det, row1 * inv_det, row2 * inv_det) elif m.Size == 4: col0, col1, col2, col3 = m col1 = _ek.shuffle((2, 3, 0, 1), col1) col3 = _ek.shuffle((2, 3, 0, 1), col3) temp = _ek.shuffle((1, 0, 3, 2), col2 * col3) row0 = col1 * temp row1 = col0 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fmsub(col1, temp, row0) row1 = _ek.shuffle((2, 3, 0, 1), _ek.fmsub(col0, temp, row1)) temp = _ek.shuffle((1, 0, 3, 2), col1 * col2) row0 = _ek.fmadd(col3, temp, row0) row3 = col0 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col3, temp, row0) row3 = _ek.shuffle((2, 3, 0, 1), _ek.fmsub(col0, temp, row3)) temp = _ek.shuffle((1, 0, 3, 2), _ek.shuffle((2, 3, 0, 1), col1) * col3) col2 = _ek.shuffle((2, 3, 0, 1), col2) row0 = _ek.fmadd(col2, temp, row0) row2 = col0 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col2, temp, row0) row2 = _ek.shuffle((2, 3, 0, 1), _ek.fmsub(col0, temp, row2)) temp = _ek.shuffle((1, 0, 3, 2), col0 * col1) row2 = _ek.fmadd(col3, temp, row2) row3 = _ek.fmsub(col2, temp, row3) temp = _ek.shuffle((2, 3, 0, 1), temp) row2 = _ek.fmsub(col3, temp, row2) row3 = _ek.fnmadd(col2, temp, row3) temp = _ek.shuffle((1, 0, 3, 2), col0 * col3) row1 = _ek.fnmadd(col2, temp, row1) row2 = _ek.fmadd(col1, temp, row2) temp = _ek.shuffle((2, 3, 0, 1), temp) row1 = _ek.fmadd(col2, temp, row1) row2 = _ek.fnmadd(col1, temp, row2) temp = _ek.shuffle((1, 0, 3, 2), col0 * col2) row1 = _ek.fmadd(col3, temp, row1) row3 = _ek.fnmadd(col1, temp, row3) temp = _ek.shuffle((2, 3, 0, 1), temp) row1 = _ek.fnmadd(col3, temp, row1) row3 = _ek.fmadd(col1, temp, row3) inv_det = _ek.rcp(_ek.dot(col0, row0)) return t(row0 * inv_det, row1 * inv_det, row2 * inv_det, row3 * inv_det) else: raise Exception('Unsupported array size!')