diff --git a/stuff/config/current.txt b/stuff/config/current.txt
index 97020a9..9810bda 100644
--- a/stuff/config/current.txt
+++ b/stuff/config/current.txt
@@ -1160,10 +1160,14 @@
- "STD_inoRadialBlurFx.center" "Center"
- "STD_inoRadialBlurFx.radius" "Radius"
- "STD_inoRadialBlurFx.blur" "Blur"
+ - "STD_inoRadialBlurFx.type" "Type"
- "STD_inoRadialBlurFx.twist" "Twist"
- "STD_inoRadialBlurFx.alpha_rendering" "Alpha Rendering"
- "STD_inoRadialBlurFx.anti_alias" "Anti Alias"
- "STD_inoRadialBlurFx.reference" "Reference"
+ - "STD_inoRadialBlurFx.ellipse_aspect_ratio" "Ellipse Aspect Ratio"
+ - "STD_inoRadialBlurFx.ellipse_angle" "Ellipse Angle"
+ - "STD_inoRadialBlurFx.intensity_correlation_with_ellipse" "Intensity Correlation"
- "STD_inoSpinBlurFx" "Spin Blur Ino"
- "STD_inoSpinBlurFx.center" "Center"
- "STD_inoSpinBlurFx.radius" "Radius"
diff --git a/stuff/profiles/layouts/fxs/STD_inoRadialBlurFx.xml b/stuff/profiles/layouts/fxs/STD_inoRadialBlurFx.xml
index eace9eb..162ea51 100644
--- a/stuff/profiles/layouts/fxs/STD_inoRadialBlurFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoRadialBlurFx.xml
@@ -3,8 +3,13 @@
center
radius
blur
+ type
twist
alpha_rendering
+
+ ellipse_aspect_ratio
+ ellipse_angle
+ intensity_correlation_with_ellipse
anti_alias
reference
diff --git a/stuff/profiles/layouts/fxs/STD_inoSpinBlurFx.xml b/stuff/profiles/layouts/fxs/STD_inoSpinBlurFx.xml
index 6f215c4..ea2d4da 100644
--- a/stuff/profiles/layouts/fxs/STD_inoSpinBlurFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoSpinBlurFx.xml
@@ -5,8 +5,9 @@
blur
type
alpha_rendering
- ellipse_aspect_ratio
- ellipse_angle
+
+ ellipse_aspect_ratio
+ ellipse_angle
anti_alias
reference
diff --git a/toonz/sources/include/tools/tool.h b/toonz/sources/include/tools/tool.h
index 5ccf7e7..ab30f5a 100644
--- a/toonz/sources/include/tools/tool.h
+++ b/toonz/sources/include/tools/tool.h
@@ -677,6 +677,7 @@ public:
/*-- Toolで画面の内外を判断するため --*/
virtual TRectD getGeometry() const = 0;
+ virtual TRectD getCameraRect() const { return TRectD(); }
virtual void bindFBO() {}
virtual void releaseFBO() {}
diff --git a/toonz/sources/include/tparamuiconcept.h b/toonz/sources/include/tparamuiconcept.h
index dfc6419..167008e 100644
--- a/toonz/sources/include/tparamuiconcept.h
+++ b/toonz/sources/include/tparamuiconcept.h
@@ -70,7 +70,7 @@ public:
RAINBOW_WIDTH,
- ELLIPSE, // used in spin blur ino
+ ELLIPSE, // used in spin blur ino and radial blur ino
TYPESCOUNT
};
diff --git a/toonz/sources/stdfx/igs_radial_blur.cpp b/toonz/sources/stdfx/igs_radial_blur.cpp
index 35f5d73..5a5d63d 100644
--- a/toonz/sources/stdfx/igs_radial_blur.cpp
+++ b/toonz/sources/stdfx/igs_radial_blur.cpp
@@ -4,1000 +4,444 @@
#include // std::domain_error()
#include "igs_ifx_common.h"
#include "igs_radial_blur.h"
+
+#include
+#include
+
namespace {
//------------------------------------------------------------------
-template
+enum Type { Accelerator = 0, Uniform_Length };
+
class radial_ {
+ const float* in_top_;
+ const int hh_;
+ const int ww_;
+ const int cc_;
+ const TPointD center_;
+ const bool antialias_sw_;
+ const bool alpha_rendering_sw_;
+ const double intensity_;
+ const double blur_radius_;
+ const double twist_radian_;
+ const double pivot_radius_;
+ const int type_;
+ const double ellipse_aspect_ratio_;
+ const double ellipse_angle_;
+ const double intensity_correlation_with_ellipse_;
+ QTransform tr_, tr_inv_;
+
public:
- radial_(const T *in_top, const int height, const int width,
- const int channels, const double xc, const double yc,
- const double sub_size, const int imax, const double dmax,
- const double intensity /* 平均値ぼかし強度 */
- ,
- const double radius /* 平均値ぼかしの始まる半径 */
- )
+ radial_(const float* in_top, const int height, const int width,
+ const int channels, const TPointD center, const bool antialias_sw,
+ const bool alpha_rendering_sw,
+ const double intensity, /* 平均値ぼかし強度 */
+ const double blur_radius, /* 平均値ぼかしの始まる半径 */
+ const double twist_radian, const double pivot_radius, const int type,
+ const double ellipse_aspect_ratio, const double ellipse_angle,
+ const double intensity_correlation_with_ellipse)
: in_top_(in_top)
, hh_(height)
, ww_(width)
, cc_(channels)
- , xc_(xc)
- , yc_(yc)
- , sub_size_(sub_size)
- , imax_(imax)
- , dmax_(dmax)
+ , center_(center)
+ , antialias_sw_(antialias_sw)
+ , alpha_rendering_sw_(alpha_rendering_sw)
, intensity_(intensity)
- , radius_(radius) {}
- void pixel_value(const T *in_current_pixel, const int xx, const int yy,
- const int z1, const int z2, const double ref_increase_val,
- const double ref_decrease_val,
- const double each_pixel_blur_ratio, T *result_pixel) {
- /* Pixel位置(0.5 1.5 2.5 ...) */
- const double xp = static_cast(xx) + 0.5;
- const double yp = static_cast(yy) + 0.5;
-
- /* 中心からPixel位置へのベクトルと長さ */
- const double xv = xp - this->xc_;
- const double yv = yp - this->yc_;
- const double dist = sqrt(xv * xv + yv * yv);
-
- /* 指定半径の範囲内なら何もしない */
- if (dist <= this->radius_) {
- for (int zz = z1; zz <= z2; ++zz) {
- result_pixel[zz] = in_current_pixel[zz];
- }
- return;
- }
-
- /* 中心からPixel位置への単位ベクトル */
- const double cosval = xv / dist;
- const double sinval = yv / dist;
-
- /* Radial方向のSamplingの開始位置と終了位置 */
- double scale = this->intensity_;
- if (0.0 <= each_pixel_blur_ratio) {
- scale *= each_pixel_blur_ratio;
- }
- const double length = (dist - this->radius_) * scale;
- const double count_half = floor(length / 2.0 / this->sub_size_);
- const double sub_sta = -this->sub_size_ * count_half;
- const double sub_end = this->sub_size_ * count_half;
-
- /* 積算値と積算回数 */
- std::vector accum_val(this->cc_);
- int accum_counter = 0;
-
- /* 円周接線方向Samplingの相対位置 */
- for (double ss = this->sub_size_ / 2.0 - 0.5; ss < 0.5;
- ss += this->sub_size_) {
- /* 円周接線方向Sampling位置 */
- const double xps = xp + ss * sinval;
- const double yps = yp + ss * cosval;
-
- /* 中心からSampling位置へのベクトルと長さ */
- const double xvs = xps - this->xc_;
- const double yvs = yps - this->yc_;
- const double dists = sqrt(xvs * xvs + yvs * yvs);
-
- /* 中心からSampling位置への単位ベクトル */
- const double cosvals = xvs / dists;
- const double sinvals = yvs / dists;
-
- /* Radial方向のSampling */
- for (double tt = sub_sta; tt <= sub_end; tt += this->sub_size_) {
- /* Sampling位置からPixel位置を得る */
- int xi = static_cast(xps + tt * cosvals);
- int yi = static_cast(yps + tt * sinvals);
-
- /* clamp */
- xi = (xi < 0) ? 0 : ((this->ww_ <= xi) ? this->ww_ - 1 : xi);
- yi = (yi < 0) ? 0 : ((this->hh_ <= yi) ? this->hh_ - 1 : yi);
-
- /* 画像のPixel位置 */
- const T *in_current =
- this->in_top_ + this->cc_ * this->ww_ * yi + this->cc_ * xi;
-
- /* 積算 */
- for (int zz = z1; zz <= z2; ++zz) {
- accum_val[zz] += static_cast(in_current[zz]);
- }
- ++accum_counter;
- }
- }
- /* 積算しなかったとき(念のためのCheck) */
- if (accum_counter <= 0) {
- for (int zz = z1; zz <= z2; ++zz) {
- result_pixel[zz] = in_current_pixel[zz];
- }
- return;
+ , blur_radius_(blur_radius)
+ , twist_radian_(twist_radian)
+ , pivot_radius_(pivot_radius)
+ , type_(type)
+ , ellipse_aspect_ratio_(ellipse_aspect_ratio)
+ , ellipse_angle_(ellipse_angle)
+ , intensity_correlation_with_ellipse_(
+ intensity_correlation_with_ellipse) {
+ if (ellipse_aspect_ratio_ != 1.0) {
+ double axis_x =
+ 2.0 * ellipse_aspect_ratio_ / (ellipse_aspect_ratio_ + 1.0);
+ double axis_y = axis_x / ellipse_aspect_ratio_;
+ tr_ = QTransform()
+ .rotateRadians(this->ellipse_angle_)
+ .scale(axis_x, axis_y);
+ tr_inv_ = QTransform(tr_).inverted();
}
- /* ここで画像Pixelに保存 */
- for (int zz = z1; zz <= z2; ++zz) {
- accum_val[zz] /= static_cast(accum_counter);
-
- if ((0 <= ref_increase_val) && (in_current_pixel[zz] < accum_val[zz])) {
- /* 増分のみMask! */
- accum_val[zz] =
- static_cast(in_current_pixel[zz]) +
- (accum_val[zz] - in_current_pixel[zz]) * ref_increase_val;
- } else if ((0 <= ref_decrease_val) &&
- (accum_val[zz] < in_current_pixel[zz])) {
- /* 減分のみMask! */
- accum_val[zz] =
- static_cast(in_current_pixel[zz]) +
- (accum_val[zz] - in_current_pixel[zz]) * ref_decrease_val;
+ }
+ void pixel_value(const float* in_current_pixel, const int xx, const int yy,
+ const bool isRGB, const double refVal, float* result_pixel) {
+ auto in_pixel = [&](int x, int y) {
+ /* clamp */
+ x = (x < 0) ? 0 : ((this->ww_ <= x) ? this->ww_ - 1 : x);
+ y = (y < 0) ? 0 : ((this->hh_ <= y) ? this->hh_ - 1 : y);
+ return this->in_top_ + this->cc_ * y * this->ww_ + this->cc_ * x;
+ };
+ auto interp = [&](float v1, float v2, float r) {
+ return v1 * (1.f - r) + v2 * r;
+ };
+ auto accum_interp_in_values = [&](QPointF pos, std::vector& accumP,
+ int z1, int z2, float weight) {
+ int xId = (int)std::floor(pos.x());
+ float rx = pos.x() - (float)xId;
+ int yId = (int)std::floor(pos.y());
+ float ry = pos.y() - (float)yId;
+ const float* p00 = in_pixel(xId, yId);
+ const float* p01 = in_pixel(xId + 1, yId);
+ const float* p10 = in_pixel(xId, yId + 1);
+ const float* p11 = in_pixel(xId + 1, yId + 1);
+ for (int zz = z1; zz <= z2; zz++) {
+ accumP[zz] += weight * interp(interp(p00[zz], p01[zz], rx),
+ interp(p10[zz], p11[zz], rx), ry);
}
-
- accum_val[zz] += 0.5; /* 誤差対策 */
- if (this->dmax_ < accum_val[zz]) {
- result_pixel[zz] = static_cast(this->imax_);
- } else if (accum_val[zz] < 0) {
- result_pixel[zz] = 0;
- } else {
- result_pixel[zz] = static_cast(accum_val[zz]);
+ };
+ auto accum_in_values = [&](QPointF pos, std::vector& accumP, int z1,
+ int z2, float weight) {
+ int xId = (int)std::round(pos.x());
+ int yId = (int)std::round(pos.y());
+ const float* p = in_pixel(xId, yId);
+ for (int zz = z1; zz <= z2; zz++) {
+ accumP[zz] += weight * p[zz];
}
- }
- }
-
-private:
- radial_() {}
-
- const T *in_top_;
- const int hh_;
- const int ww_;
- const int cc_;
- const double xc_;
- const double yc_;
- const double sub_size_;
- const int imax_;
- const double dmax_;
- const double intensity_;
- const double radius_;
-
- /* copy constructorを無効化 */
- radial_(const radial_ &);
-
- /* 代入演算子を無効化 */
- radial_ &operator=(const radial_ &);
-};
-template
-void radial_convert_template_(
- const IT *in, const int margin /* 参照画像(in)がもつ余白 */
-
- ,
- const RT *ref /* 求める画像(out)と同じ高さ、幅、チャンネル数 */
- ,
- const int ref_bits, const int ref_mode // R,G,B,A,luminance
-
- ,
- IT *out, const int hh /* 求める画像(out)の高さ */
- ,
- const int ww /* 求める画像(out)の幅 */
- ,
- const int cc, const double xc, const double yc,
- const double intensity /* 強度。ゼロより大きく2以下 */
- /* radius円境界での平均値ぼかしゼロとするためintensityは2より小さい */
- ,
- const double radius /* 平均値ぼかしの始まる半径 */
- ,
- const int sub_div /* 1ならJaggy、2以上はAntialias */
- ,
- const bool alpha_rendering_sw) {
- ref_bits; // for warning
-
- /* 強度のないとき、または、サブ分割がないとき、なにもしない */
- if (intensity <= 0.0 || sub_div <= 0) {
- return;
- }
-
- radial_ cl_ra(
- in, hh + margin * 2, ww + margin * 2, cc, xc + margin, yc + margin,
- 1.0 / sub_div, std::numeric_limits::max() /* サンプリング値 */
- ,
- static_cast(std::numeric_limits::max()), intensity, radius);
+ };
+ int c1, c2;
+ if (isRGB) {
#if defined RGBA_ORDER_OF_TOONZ6
- const int z1 = igs::image::rgba::blu;
- const int z2 = igs::image::rgba::red;
+ c1 = igs::image::rgba::blu;
+ c2 = igs::image::rgba::red;
#elif defined RGBA_ORDER_OF_OPENGL
- const int z1 = igs::image::rgba::red;
- const int z2 = igs::image::rgba::blu;
+ c1 = igs::image::rgba::red;
+ c2 = igs::image::rgba::blu;
#else
- Must be define / DRGBA_ORDER_OF_TOONZ6 or
- / DRGBA_ORDER_OF_OPENGL
+ Must be define / DRGBA_ORDER_OF_TOONZ6 or / DRGBA_ORDER_OF_OPENGL
#endif
- const IT *p_in = in + margin * (ww + margin * 2) * cc + margin * cc;
- IT *pout = out;
-
- if (0 == ref) { /* 参照なし */
- if (igs::image::rgba::siz == cc) {
- using namespace igs::image::rgba;
- if (alpha_rendering_sw) { /* Alphaも処理する */
- for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) {
- for (int xx = margin; xx < ww + margin;
- ++xx, p_in += cc, pout += cc) {
- cl_ra.pixel_value(p_in, xx, yy, alp, alp, -1.0, -1.0, -1.0, pout);
- if (0 == pout[alp]) {
- pout[red] = p_in[red];
- pout[gre] = p_in[gre];
- pout[blu] = p_in[blu];
- continue;
- }
- cl_ra.pixel_value(p_in, xx, yy, z1, z2, -1.0, -1.0, -1.0, pout);
- }
- }
- } else { /* Alpha処理しない、RGB増分をAlphaでMaskする */
- const unsigned int val_max = std::numeric_limits::max();
- for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) {
- for (int xx = margin; xx < ww + margin;
- ++xx, p_in += cc, pout += cc) {
- pout[alp] = p_in[alp];
- if (0 == pout[alp]) {
- pout[red] = p_in[red];
- pout[gre] = p_in[gre];
- pout[blu] = p_in[blu];
- continue;
- }
- /* Alpha値あるならRGB増分のみAlphaでMaskする */
- cl_ra.pixel_value(p_in, xx, yy, z1, z2,
- static_cast(p_in[alp]) / val_max, -1.0,
- -1.0, pout);
- }
- }
- }
- } else { /* Alphaがない, RGB/Grayscale... */
- for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) {
- for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) {
- cl_ra.pixel_value(p_in, xx, yy, 0, cc - 1, -1.0, -1.0, -1.0, pout);
- }
- }
+ } else {
+ c1 = igs::image::rgba::alp;
+ c2 = igs::image::rgba::alp;
}
- } else { /* 参照あり */
- const RT *refe = ref;
- const int r_max = std::numeric_limits