inline void operator() (ustring name, Dual2<R> &result, const Dual2<S> &s, const Dual2<T> &t, ShaderGlobals *sg, const NoiseParams *opt) const { if (name == Strings::uperlin || name == Strings::noise) { Noise noise; noise(result, s, t); } else if (name == Strings::perlin || name == Strings::snoise) { SNoise snoise; snoise(result, s, t); } else if (name == Strings::simplexnoise || name == Strings::simplex) { SimplexNoise simplexnoise; simplexnoise(result, s, t); } else if (name == Strings::usimplexnoise || name == Strings::usimplex) { USimplexNoise usimplexnoise; usimplexnoise(result, s, t); } else if (name == Strings::cell) { CellNoise cellnoise; cellnoise(result.val(), s.val(), t.val()); result.clear_d(); } else if (name == Strings::gabor) { GaborNoise gnoise; gnoise (name, result, s, t, sg, opt); } else { ((ShadingContext *)sg->context)->error ("Unknown noise type \"%s\"", name.c_str()); } }
inline void operator() (ustring name, Dual2<R> &result, const Dual2<S> &s, const S &sp, ShaderGlobals *sg, const NoiseParams *opt) const { if (name == Strings::uperlin || name == Strings::noise) { PeriodicNoise noise; noise(result, s, sp); } else if (name == Strings::perlin || name == Strings::snoise) { PeriodicSNoise snoise; snoise(result, s, sp); } else if (name == Strings::cell) { PeriodicCellNoise cellnoise; cellnoise(result.val(), s.val(), sp); result.clear_d(); } else if (name == Strings::gabor) { GaborPNoise gnoise; gnoise (name, result, s, sp, sg, opt); } else { ((ShadingContext *)sg->context)->error ("Unknown noise type \"%s\"", name.c_str()); } }
inline Dual2<float> safe_fmod (const Dual2<float> &a, const Dual2<float> &b) { return Dual2<float> (safe_fmod (a.val(), b.val()), a.dx(), a.dy()); }
inline Dual2<float> fabsf (const Dual2<float> &x) { return x.val() >= 0 ? x : -x; }
// Helper function: per-component 'floor' of a Dual2<Vec3>. inline Vec3 floor (const Dual2<Vec3> &vd) { const Vec3 &v (vd.val()); return Vec3 (floorf(v[0]), floorf(v[1]), floorf(v[2])); }
// Evaluate the summed contribution of all gabor impulses within the // cell whose corner is c_i. x_c_i is vector from x (the point // we are trying to evaluate noise at) and c_i. Dual2<float> gabor_cell (GaborParams &gp, const Vec3 &c_i, const Dual2<Vec3> &x_c_i, int seed = 0) { fast_rng rng (gp.periodic ? Vec3(wrap(c_i,gp.period)) : c_i, seed); int n_impulses = rng.poisson (gp.lambda * gp.radius3); Dual2<float> sum = 0; for (int i = 0; i < n_impulses; i++) { // OLD code: Vec3 x_i_c (rng(), rng(), rng()); // Turned out that C++ spec says order of args are unspecified. // gcc appeared to do right-to-left, so to make sure our noise // function is locked down (and works identically for clang, // which evaluates left-to-right), we ask for the rng() calls // one at a time and match the way it looked before. float z_rng = rng(), y_rng = rng(), x_rng = rng(); Vec3 x_i_c (x_rng, y_rng, z_rng); Dual2<Vec3> x_k_i = gp.radius * (x_c_i - x_i_c); float phi_i; Vec3 omega_i; gabor_sample (gp, c_i, rng, omega_i, phi_i); if (x_k_i.val().length2() < gp.radius2) { if (! gp.do_filter) { // N.B. if determinant(gp.filter) is too small, we will // run into numerical problems. But the filtering isn't // needed in that case anyway, so just don't filter. // This seems to only come up when the filter region is // tiny. sum += gabor_kernel (gp.weight, omega_i, phi_i, gp.a, x_k_i); // 3D } else { // Transform the impulse's anisotropy into tangent space Vec3 omega_i_t; multMatrix (gp.local, omega_i, omega_i_t); // Slice to get a 2D kernel Dual2<float> d_i = -dot(gp.N, x_k_i); Dual2<float> w_i_t_s; Vec2 omega_i_t_s; Dual2<float> phi_i_t_s; slice_gabor_kernel_3d (d_i, gp.weight, gp.a, omega_i_t, phi_i, w_i_t_s, omega_i_t_s, phi_i_t_s); // Filter the 2D kernel Dual2<float> w_i_t_s_f; float a_i_t_s_f; Vec2 omega_i_t_s_f; Dual2<float> phi_i_t_s_f; filter_gabor_kernel_2d (gp.filter, w_i_t_s, gp.a, omega_i_t_s, phi_i_t_s, w_i_t_s_f, a_i_t_s_f, omega_i_t_s_f, phi_i_t_s_f); // Now evaluate the 2D filtered kernel Dual2<Vec3> xkit; multMatrix (gp.local, x_k_i, xkit); Dual2<Vec2> x_k_i_t = make_Vec2 (comp(xkit,0), comp(xkit,1)); Dual2<float> gk = gabor_kernel (w_i_t_s_f, omega_i_t_s_f, phi_i_t_s_f, a_i_t_s_f, x_k_i_t); // 2D if (! OIIO::isfinite(gk.val())) { // Numeric failure of the filtered version. Fall // back on the unfiltered. gk = gabor_kernel (gp.weight, omega_i, phi_i, gp.a, x_k_i); // 3D } sum += gk; } } } return sum; }