1 /*------------------------------------
2 Iwa_DirectionalBlurFx
3 ボケ足の伸ばし方を選択でき、参照画像を追加した DirectionalBlur
4 //------------------------------------*/
5
6 #include "iwa_directionalblurfx.h"
7
8 #include "tparamuiconcept.h"
9
10 enum FILTER_TYPE { Linear = 0, Gaussian, Flat };
11
12 /*------------------------------------------------------------
13 参照画像の輝度を0〜1に正規化してホストメモリに読み込む
14 ------------------------------------------------------------*/
15
16 template <typename RASTER, typename PIXEL>
setReferenceRaster(const RASTER srcRas,float * dstMem,TDimensionI dim)17 void Iwa_DirectionalBlurFx::setReferenceRaster(const RASTER srcRas,
18 float *dstMem, TDimensionI dim) {
19 float *dst_p = dstMem;
20
21 for (int j = 0; j < dim.ly; j++) {
22 PIXEL *pix = srcRas->pixels(j);
23 for (int i = 0; i < dim.lx; i++, pix++, dst_p++) {
24 (*dst_p) = ((float)pix->r * 0.3f + (float)pix->g * 0.59f +
25 (float)pix->b * 0.11f) /
26 (float)PIXEL::maxChannelValue;
27 }
28 }
29 }
30
31 /*------------------------------------------------------------
32 ソース画像を0〜1に正規化してホストメモリに読み込む
33 ------------------------------------------------------------*/
34
35 template <typename RASTER, typename PIXEL>
setSourceRaster(const RASTER srcRas,float4 * dstMem,TDimensionI dim)36 void Iwa_DirectionalBlurFx::setSourceRaster(const RASTER srcRas, float4 *dstMem,
37 TDimensionI dim) {
38 float4 *chann_p = dstMem;
39
40 for (int j = 0; j < dim.ly; j++) {
41 PIXEL *pix = srcRas->pixels(j);
42 for (int i = 0; i < dim.lx; i++, pix++, chann_p++) {
43 (*chann_p).x = (float)pix->r / (float)PIXEL::maxChannelValue;
44 (*chann_p).y = (float)pix->g / (float)PIXEL::maxChannelValue;
45 (*chann_p).z = (float)pix->b / (float)PIXEL::maxChannelValue;
46 (*chann_p).w = (float)pix->m / (float)PIXEL::maxChannelValue;
47 }
48 }
49 }
50
51 /*------------------------------------------------------------
52 出力結果をChannel値に変換してタイルに格納
53 ------------------------------------------------------------*/
54 template <typename RASTER, typename PIXEL>
setOutputRaster(float4 * srcMem,const RASTER dstRas,TDimensionI dim,int2 margin)55 void Iwa_DirectionalBlurFx::setOutputRaster(float4 *srcMem, const RASTER dstRas,
56 TDimensionI dim, int2 margin) {
57 int out_j = 0;
58 for (int j = margin.y; j < dstRas->getLy() + margin.y; j++, out_j++) {
59 PIXEL *pix = dstRas->pixels(out_j);
60 float4 *chan_p = srcMem;
61 chan_p += j * dim.lx + margin.x;
62 for (int i = 0; i < dstRas->getLx(); i++, pix++, chan_p++) {
63 float val;
64 val = (*chan_p).x * (float)PIXEL::maxChannelValue + 0.5f;
65 pix->r = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
66 ? (float)PIXEL::maxChannelValue
67 : val);
68 val = (*chan_p).y * (float)PIXEL::maxChannelValue + 0.5f;
69 pix->g = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
70 ? (float)PIXEL::maxChannelValue
71 : val);
72 val = (*chan_p).z * (float)PIXEL::maxChannelValue + 0.5f;
73 pix->b = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
74 ? (float)PIXEL::maxChannelValue
75 : val);
76 val = (*chan_p).w * (float)PIXEL::maxChannelValue + 0.5f;
77 pix->m = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
78 ? (float)PIXEL::maxChannelValue
79 : val);
80 }
81 }
82 }
83
84 //------------------------------------
85
Iwa_DirectionalBlurFx()86 Iwa_DirectionalBlurFx::Iwa_DirectionalBlurFx()
87 : m_angle(0.0)
88 , m_intensity(10.0)
89 , m_bidirectional(false)
90 , m_filterType(new TIntEnumParam(Linear, "Linear")) {
91 m_intensity->setMeasureName("fxLength");
92 m_angle->setMeasureName("angle");
93
94 bindParam(this, "angle", m_angle);
95 bindParam(this, "intensity", m_intensity);
96 bindParam(this, "bidirectional", m_bidirectional);
97 bindParam(this, "filterType", m_filterType);
98
99 addInputPort("Source", m_input);
100 addInputPort("Reference", m_reference);
101 m_intensity->setValueRange(0, (std::numeric_limits<double>::max)());
102
103 m_filterType->addItem(Gaussian, "Gaussian");
104 m_filterType->addItem(Flat, "Flat");
105 }
106
107 //------------------------------------
108
doCompute(TTile & tile,double frame,const TRenderSettings & settings)109 void Iwa_DirectionalBlurFx::doCompute(TTile &tile, double frame,
110 const TRenderSettings &settings) {
111 /*- 接続していない場合は処理しない -*/
112 if (!m_input.isConnected()) {
113 tile.getRaster()->clear();
114 return;
115 }
116
117 TPointD blurVector;
118 double angle = m_angle->getValue(frame) * M_PI_180;
119 double intensity = m_intensity->getValue(frame);
120 bool bidirectional = m_bidirectional->getValue();
121
122 blurVector.x = intensity * cos(angle);
123 blurVector.y = intensity * sin(angle);
124
125 double shrink = (settings.m_shrinkX + settings.m_shrinkY) / 2.0;
126
127 /*- 平行移動成分を消したアフィン変換をかけ、ボケベクトルを変形 -*/
128 TAffine aff = settings.m_affine;
129 aff.a13 = aff.a23 = 0;
130 TPointD blur = (1.0 / shrink) * (aff * blurVector);
131
132 /*- ボケの実際の長さを求める -*/
133 double blurValue = norm(blur);
134 /*- ボケの実際の長さがほぼ0なら入力画像をそのまま return -*/
135 if (areAlmostEqual(blurValue, 0, 1e-3)) {
136 m_input->compute(tile, frame, settings);
137 return;
138 }
139
140 /*- 表示の範囲を得る -*/
141 TRectD bBox =
142 TRectD(tile.m_pos /*- Render画像上(Pixel単位)の位置 -*/
143 ,
144 TDimensionD(/*- Render画像上(Pixel単位)のサイズ -*/
145 tile.getRaster()->getLx(), tile.getRaster()->getLy()));
146 /*- 上下左右のマージンを得る -*/
147 double minX, maxX, minY, maxY;
148 if (blur.x > 0.0) /*- X成分が正の場合 -*/
149 {
150 maxX = blur.x;
151 minX = (bidirectional) ? -blur.x : 0.0;
152 } else /*- X成分が負の場合 -*/
153 {
154 maxX = (bidirectional) ? -blur.x : 0.0;
155 minX = blur.x;
156 }
157 if (blur.y > 0.0) /*- Y成分が正の場合 -*/
158 {
159 maxY = blur.y;
160 minY = (bidirectional) ? -blur.y : 0.0;
161 } else /*- Y成分が負の場合 -*/
162 {
163 maxY = (bidirectional) ? -blur.y : 0.0;
164 minY = blur.y;
165 }
166 int marginLeft = (int)ceil(std::abs(minX));
167 int marginRight = (int)ceil(std::abs(maxX));
168 int marginTop = (int)ceil(std::abs(maxY));
169 int marginBottom = (int)ceil(std::abs(minY));
170
171 /*- マージンは、フィルタの上下左右を反転した寸法になる -*/
172 TRectD enlargedBBox(bBox.x0 - (double)marginRight,
173 bBox.y0 - (double)marginTop, bBox.x1 + (double)marginLeft,
174 bBox.y1 + (double)marginBottom);
175
176 std::cout << "Margin Left:" << marginLeft << " Right:" << marginRight
177 << " Bottom:" << marginBottom << " Top:" << marginTop << std::endl;
178
179 TDimensionI enlargedDimIn(/*- Pixel単位に四捨五入 -*/
180 (int)(enlargedBBox.getLx() + 0.5),
181 (int)(enlargedBBox.getLy() + 0.5));
182
183 TTile enlarge_tile;
184 m_input->allocateAndCompute(enlarge_tile, enlargedBBox.getP00(),
185 enlargedDimIn, tile.getRaster(), frame, settings);
186
187 /*- 参照画像が有ったら、メモリに取り込む -*/
188 float *reference_host = 0;
189 TRasterGR8P reference_host_ras;
190 if (m_reference.isConnected()) {
191 TTile reference_tile;
192 m_reference->allocateAndCompute(reference_tile, enlargedBBox.getP00(),
193 enlargedDimIn, tile.getRaster(), frame,
194 settings);
195 /*- ホストのメモリ確保 -*/
196 reference_host_ras =
197 TRasterGR8P(sizeof(float) * enlargedDimIn.lx, enlargedDimIn.ly);
198 reference_host_ras->lock();
199 reference_host = (float *)reference_host_ras->getRawData();
200 /*- 参照画像の輝度を0〜1に正規化してホストメモリに読み込む -*/
201 TRaster32P ras32 = (TRaster32P)reference_tile.getRaster();
202 TRaster64P ras64 = (TRaster64P)reference_tile.getRaster();
203 if (ras32)
204 setReferenceRaster<TRaster32P, TPixel32>(ras32, reference_host,
205 enlargedDimIn);
206 else if (ras64)
207 setReferenceRaster<TRaster64P, TPixel64>(ras64, reference_host,
208 enlargedDimIn);
209 }
210
211 //-------------------------------------------------------
212 /*- 計算範囲 -*/
213 TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy());
214 TDimensionI filterDim(marginLeft + marginRight + 1,
215 marginTop + marginBottom + 1);
216
217 doCompute_CPU(tile, frame, settings, blur, bidirectional, marginLeft,
218 marginRight, marginTop, marginBottom, enlargedDimIn,
219 enlarge_tile, dimOut, filterDim, reference_host);
220
221 /*- 参照画像が刺さっている場合、メモリを解放する -*/
222 if (reference_host) {
223 reference_host_ras->unlock();
224 reference_host = 0;
225 }
226 }
227
228 //------------------------------------
229
doCompute_CPU(TTile & tile,double frame,const TRenderSettings & settings,TPointD & blur,bool bidirectional,int marginLeft,int marginRight,int marginTop,int marginBottom,TDimensionI & enlargedDimIn,TTile & enlarge_tile,TDimensionI & dimOut,TDimensionI & filterDim,float * reference_host)230 void Iwa_DirectionalBlurFx::doCompute_CPU(
231 TTile &tile, double frame, const TRenderSettings &settings, TPointD &blur,
232 bool bidirectional, int marginLeft, int marginRight, int marginTop,
233 int marginBottom, TDimensionI &enlargedDimIn, TTile &enlarge_tile,
234 TDimensionI &dimOut, TDimensionI &filterDim, float *reference_host) {
235 /*- メモリ確保 -*/
236 TRasterGR8P in_ras(sizeof(float4) * enlargedDimIn.lx, enlargedDimIn.ly);
237 in_ras->lock();
238 float4 *in = (float4 *)in_ras->getRawData();
239
240 TRasterGR8P out_ras(sizeof(float4) * enlargedDimIn.lx, enlargedDimIn.ly);
241 out_ras->lock();
242 float4 *out = (float4 *)out_ras->getRawData();
243
244 TRasterGR8P filter_ras(sizeof(float) * filterDim.lx, filterDim.ly);
245 filter_ras->lock();
246 float *filter = (float *)filter_ras->getRawData();
247
248 /*- ソース画像を0〜1に正規化してホストメモリに読み込む -*/
249 TRaster32P ras32 = (TRaster32P)enlarge_tile.getRaster();
250 TRaster64P ras64 = (TRaster64P)enlarge_tile.getRaster();
251 if (ras32)
252 setSourceRaster<TRaster32P, TPixel32>(ras32, in, enlargedDimIn);
253 else if (ras64)
254 setSourceRaster<TRaster64P, TPixel64>(ras64, in, enlargedDimIn);
255
256 /*- フィルタ作る -*/
257 makeDirectionalBlurFilter_CPU(filter, blur, bidirectional, marginLeft,
258 marginRight, marginTop, marginBottom,
259 filterDim);
260
261 if (reference_host) /*- 参照画像がある場合 -*/
262 {
263 float4 *out_p = out + marginTop * enlargedDimIn.lx;
264 float *ref_p = reference_host + marginTop * enlargedDimIn.lx;
265 /*- フィルタリング -*/
266 for (int y = marginTop; y < dimOut.ly + marginTop; y++) {
267 out_p += marginRight;
268 ref_p += marginRight;
269 for (int x = marginRight; x < dimOut.lx + marginRight;
270 x++, out_p++, ref_p++) {
271 /*- 参照画像が黒ならソースをそのまま返す -*/
272 if ((*ref_p) == 0.0f) {
273 (*out_p) = in[y * enlargedDimIn.lx + x];
274 continue;
275 }
276
277 /*- 値を積算する入れ物を用意 -*/
278 float4 value = {0.0f, 0.0f, 0.0f, 0.0f};
279
280 float *filter_p = filter;
281
282 if ((*ref_p) == 1.0f) {
283 /*- フィルタのサイズでループ
284 ただし、フィルタはサンプル点の画像を収集するように
285 用いるため、上下左右反転してサンプルする -*/
286 for (int fily = -marginBottom; fily < filterDim.ly - marginBottom;
287 fily++) {
288 /*- サンプル座標 と インデックス の このスキャンラインのうしろ -*/
289 int2 samplePos = {x + marginLeft, y - fily};
290 int sampleIndex = samplePos.y * enlargedDimIn.lx + samplePos.x;
291
292 for (int filx = -marginLeft; filx < filterDim.lx - marginLeft;
293 filx++, filter_p++, sampleIndex--) {
294 /*- フィルター値が0またはサンプルピクセルが透明ならcontinue -*/
295 if ((*filter_p) == 0.0f || in[sampleIndex].w == 0.0f) continue;
296 /*- サンプル点の値にフィルタ値を掛けて積算する -*/
297 value.x += in[sampleIndex].x * (*filter_p);
298 value.y += in[sampleIndex].y * (*filter_p);
299 value.z += in[sampleIndex].z * (*filter_p);
300 value.w += in[sampleIndex].w * (*filter_p);
301 }
302 }
303 } else {
304 for (int fily = -marginBottom; fily < filterDim.ly - marginBottom;
305 fily++) {
306 for (int filx = -marginLeft; filx < filterDim.lx - marginLeft;
307 filx++, filter_p++) {
308 /*- フィルター値が0ならcontinue -*/
309 if ((*filter_p) == 0.0f) continue;
310 /*- サンプル座標 -*/
311 int2 samplePos = {tround((float)x - (float)filx * (*ref_p)),
312 tround((float)y - (float)fily * (*ref_p))};
313 int sampleIndex = samplePos.y * enlargedDimIn.lx + samplePos.x;
314
315 /*- サンプルピクセルが透明ならcontinue -*/
316 if (in[sampleIndex].w == 0.0f) continue;
317
318 /*- サンプル点の値にフィルタ値を掛けて積算する -*/
319 value.x += in[sampleIndex].x * (*filter_p);
320 value.y += in[sampleIndex].y * (*filter_p);
321 value.z += in[sampleIndex].z * (*filter_p);
322 value.w += in[sampleIndex].w * (*filter_p);
323 }
324 }
325 }
326
327 /*- 値を格納 -*/
328 (*out_p) = value;
329 }
330 out_p += marginLeft;
331 ref_p += marginLeft;
332 }
333
334 } else /*- 参照画像が無い場合 -*/
335 {
336 float4 *out_p = out + marginTop * enlargedDimIn.lx;
337 /*- フィルタリング -*/
338 for (int y = marginTop; y < dimOut.ly + marginTop; y++) {
339 out_p += marginRight;
340 for (int x = marginRight; x < dimOut.lx + marginRight; x++, out_p++) {
341 /*- 値を積算する入れ物を用意 -*/
342 float4 value = {0.0f, 0.0f, 0.0f, 0.0f};
343 /*- フィルタのサイズでループ
344 ただし、フィルタはサンプル点の画像を収集するように
345 用いるため、上下左右反転してサンプルする -*/
346 int filterIndex = 0;
347 for (int fily = -marginBottom; fily < filterDim.ly - marginBottom;
348 fily++) {
349 /*- サンプル座標 と インデックス の このスキャンラインのうしろ -*/
350 int2 samplePos = {x + marginLeft, y - fily};
351 int sampleIndex = samplePos.y * enlargedDimIn.lx + samplePos.x;
352
353 for (int filx = -marginLeft; filx < filterDim.lx - marginLeft;
354 filx++, filterIndex++, sampleIndex--) {
355 /*- フィルター値が0またはサンプルピクセルが透明ならcontinue -*/
356 if (filter[filterIndex] == 0.0f || in[sampleIndex].w == 0.0f)
357 continue;
358 /*- サンプル点の値にフィルタ値を掛けて積算する -*/
359 value.x += in[sampleIndex].x * filter[filterIndex];
360 value.y += in[sampleIndex].y * filter[filterIndex];
361 value.z += in[sampleIndex].z * filter[filterIndex];
362 value.w += in[sampleIndex].w * filter[filterIndex];
363 }
364 }
365
366 /*- 値を格納 -*/
367 (*out_p) = value;
368 }
369 out_p += marginLeft;
370 }
371 }
372
373 in_ras->unlock();
374 filter_ras->unlock();
375
376 /*- ラスタのクリア -*/
377 tile.getRaster()->clear();
378 TRaster32P outRas32 = (TRaster32P)tile.getRaster();
379 TRaster64P outRas64 = (TRaster64P)tile.getRaster();
380 int2 margin = {marginRight, marginTop};
381 if (outRas32)
382 setOutputRaster<TRaster32P, TPixel32>(out, outRas32, enlargedDimIn, margin);
383 else if (outRas64)
384 setOutputRaster<TRaster64P, TPixel64>(out, outRas64, enlargedDimIn, margin);
385
386 out_ras->unlock();
387 }
388
389 //------------------------------------
390
makeDirectionalBlurFilter_CPU(float * filter,TPointD & blur,bool bidirectional,int marginLeft,int marginRight,int marginTop,int marginBottom,TDimensionI & filterDim)391 void Iwa_DirectionalBlurFx::makeDirectionalBlurFilter_CPU(
392 float *filter, TPointD &blur, bool bidirectional, int marginLeft,
393 int marginRight, int marginTop, int marginBottom, TDimensionI &filterDim) {
394 /*- 必要なら、ガウスフィルタを前計算 -*/
395 FILTER_TYPE filterType = (FILTER_TYPE)m_filterType->getValue();
396 std::vector<float> gaussian;
397 if (filterType == Gaussian) {
398 gaussian.reserve(101);
399 for (int g = 0; g < 101; g++) {
400 float x = (float)g / 100.0f;
401 // sigma == 0.25
402 gaussian.push_back(exp(-x * x / 0.125f));
403 }
404 }
405
406 /*- フィルタを作る -*/
407 TPointD p0 =
408 (bidirectional) ? TPointD(-blur.x, -blur.y) : TPointD(0.0f, 0.0f);
409 TPointD p1 = blur;
410 float2 vec_p0_p1 = {static_cast<float>(p1.x - p0.x),
411 static_cast<float>(p1.y - p0.y)};
412
413 float *fil_p = filter;
414 float intensity_sum = 0.0f;
415
416 for (int fy = -marginBottom; fy <= marginTop; fy++) {
417 for (int fx = -marginLeft; fx <= marginRight; fx++, fil_p++) {
418 /*- 現在の座標とブラー直線の距離を求める -*/
419 /*- P0->サンプル点とP0->P1の内積を求める -*/
420 float2 vec_p0_sample = {static_cast<float>(fx - p0.x),
421 static_cast<float>(fy - p0.y)};
422 float dot = vec_p0_sample.x * vec_p0_p1.x + vec_p0_sample.y * vec_p0_p1.y;
423 /*- 軌跡ベクトルの長さの2乗を計算する -*/
424 float length2 = vec_p0_p1.x * vec_p0_p1.x + vec_p0_p1.y * vec_p0_p1.y;
425
426 /*- 距離の2乗を求める -*/
427 float dist2;
428 float framePosRatio;
429 /*- P0より手前にある場合 -*/
430 if (dot <= 0.0f) {
431 dist2 = vec_p0_sample.x * vec_p0_sample.x +
432 vec_p0_sample.y * vec_p0_sample.y;
433 framePosRatio = 0.0f;
434 } else {
435 /*- P0〜P1間にある場合 -*/
436 if (dot < length2) {
437 float p0_sample_dist2 = vec_p0_sample.x * vec_p0_sample.x +
438 vec_p0_sample.y * vec_p0_sample.y;
439 dist2 = p0_sample_dist2 - dot * dot / length2;
440 framePosRatio = dot / length2;
441 }
442 /*- P1より先にある場合 -*/
443 else {
444 float2 vec_p1_sample = {static_cast<float>(fx - p1.x),
445 static_cast<float>(fy - p1.y)};
446 dist2 = vec_p1_sample.x * vec_p1_sample.x +
447 vec_p1_sample.y * vec_p1_sample.y;
448 framePosRatio = 1.0f;
449 }
450 }
451 /*- 距離が(√2 + 1)/2より遠かったらreturn dist2との比較だから2乗している
452 * -*/
453 if (dist2 > 1.4571f) {
454 (*fil_p) = 0.0f;
455 continue;
456 }
457
458 /*-
459 現在のピクセルのサブピクセル(16*16)が、近傍ベクトルからの距離0.5の範囲にどれだけ
460 含まれているかをカウントする -*/
461 int count = 0;
462
463 for (int yy = 0; yy < 16; yy++) {
464 /*- サブピクセルのY座標 -*/
465 float subPosY = (float)fy + ((float)yy - 7.5f) / 16.0f;
466 for (int xx = 0; xx < 16; xx++) {
467 /*- サブピクセルのX座標 -*/
468 float subPosX = (float)fx + ((float)xx - 7.5f) / 16.0f;
469
470 float2 vec_p0_sub = {static_cast<float>(subPosX - p0.x),
471 static_cast<float>(subPosY - p0.y)};
472 float sub_dot =
473 vec_p0_sub.x * vec_p0_p1.x + vec_p0_sub.y * vec_p0_p1.y;
474 /*- 距離の2乗を求める -*/
475 float dist2;
476 /*- P0より手前にある場合 -*/
477 if (sub_dot <= 0.0f)
478 dist2 = vec_p0_sub.x * vec_p0_sub.x + vec_p0_sub.y * vec_p0_sub.y;
479 else {
480 /*- P0〜P1間にある場合 -*/
481 if (sub_dot < length2) {
482 float p0_sub_dist2 =
483 vec_p0_sub.x * vec_p0_sub.x + vec_p0_sub.y * vec_p0_sub.y;
484 dist2 = p0_sub_dist2 - sub_dot * sub_dot / length2;
485 }
486 /*- P1より先にある場合 -*/
487 else {
488 float2 vec_p1_sub = {static_cast<float>(subPosX - p1.x),
489 static_cast<float>(subPosY - p1.y)};
490 dist2 = vec_p1_sub.x * vec_p1_sub.x + vec_p1_sub.y * vec_p1_sub.y;
491 }
492 }
493 /*- 距離の2乗が0.25より近ければカウントをインクリメント -*/
494 if (dist2 <= 0.25f) count++;
495 }
496 }
497 /*- 保険 カウントが0の場合はフィールド値0でreturn -*/
498 if (count == 0) {
499 (*fil_p) = 0.0f;
500 continue;
501 }
502 /*- countは Max256 -*/
503 float countRatio = (float)count / 256.0f;
504
505 /*- オフセット値を求める -*/
506 float offset =
507 (bidirectional) ? std::abs(framePosRatio * 2.0 - 1.0) : framePosRatio;
508
509 /*- フィルタごとに分ける -*/
510 float bokeAsiVal;
511 switch (filterType) {
512 case Linear:
513 bokeAsiVal = 1.0f - offset;
514 break;
515 case Gaussian: {
516 int index = (int)floor(offset * 100.0f);
517 float ratio = offset * 100.0f - (float)index;
518 bokeAsiVal =
519 gaussian[index] * (1.0f - ratio) + gaussian[index + 1] * ratio;
520 } break;
521 case Flat:
522 bokeAsiVal = 1.0f;
523 break;
524 default:
525 bokeAsiVal = 1.0f - offset;
526 break;
527 }
528
529 /*- フィールド値の格納 -*/
530 (*fil_p) = bokeAsiVal * countRatio;
531 intensity_sum += (*fil_p);
532 }
533 }
534
535 /*- 正規化 -*/
536 fil_p = filter;
537 for (int f = 0; f < filterDim.lx * filterDim.ly; f++, fil_p++) {
538 if ((*fil_p) == 0.0f) continue;
539 (*fil_p) /= intensity_sum;
540 }
541 }
542
543 //------------------------------------
544
doGetBBox(double frame,TRectD & bBox,const TRenderSettings & info)545 bool Iwa_DirectionalBlurFx::doGetBBox(double frame, TRectD &bBox,
546 const TRenderSettings &info) {
547 if (false == this->m_input.isConnected()) {
548 bBox = TRectD();
549 return false;
550 }
551
552 bool ret = m_input->doGetBBox(frame, bBox, info);
553
554 if (bBox == TConsts::infiniteRectD) return ret;
555
556 TPointD blur;
557 double angle = m_angle->getValue(frame) * M_PI_180;
558 double intensity = m_intensity->getValue(frame);
559 bool bidirectional = m_bidirectional->getValue();
560
561 blur.x = intensity * cos(angle);
562 blur.y = intensity * sin(angle);
563
564 /*- 上下左右のマージンを得る -*/
565 double minX, maxX, minY, maxY;
566 if (blur.x > 0.0) /*- X成分が正の場合 -*/
567 {
568 maxX = blur.x;
569 minX = (bidirectional) ? -blur.x : 0.0;
570 } else /*- X成分が負の場合 -*/
571 {
572 maxX = (bidirectional) ? -blur.x : 0.0;
573 minX = blur.x;
574 }
575 if (blur.y > 0.0) /*- Y成分が正の場合 -*/
576 {
577 maxY = blur.y;
578 minY = (bidirectional) ? -blur.y : 0.0;
579 } else /*- Y成分が負の場合 -*/
580 {
581 maxY = (bidirectional) ? -blur.y : 0.0;
582 minY = blur.y;
583 }
584 int marginLeft = (int)ceil(std::abs(minX));
585 int marginRight = (int)ceil(std::abs(maxX));
586 int marginTop = (int)ceil(std::abs(maxY));
587 int marginBottom = (int)ceil(std::abs(minY));
588
589 TRectD enlargedBBox(
590 bBox.x0 - (double)marginLeft, bBox.y0 - (double)marginBottom,
591 bBox.x1 + (double)marginRight, bBox.y1 + (double)marginTop);
592
593 bBox = enlargedBBox;
594
595 return ret;
596 }
597
598 //------------------------------------
599
canHandle(const TRenderSettings & info,double frame)600 bool Iwa_DirectionalBlurFx::canHandle(const TRenderSettings &info,
601 double frame) {
602 return isAlmostIsotropic(info.m_affine) || m_intensity->getValue(frame) == 0;
603 }
604
605 //------------------------------------
606
getParamUIs(TParamUIConcept * & concepts,int & length)607 void Iwa_DirectionalBlurFx::getParamUIs(TParamUIConcept *&concepts,
608 int &length) {
609 concepts = new TParamUIConcept[length = 1];
610
611 concepts[0].m_type = TParamUIConcept::POLAR;
612 concepts[0].m_label = "Angle and Intensity";
613 concepts[0].m_params.push_back(m_angle);
614 concepts[0].m_params.push_back(m_intensity);
615 }
616
617 //------------------------------------
618
619 FX_PLUGIN_IDENTIFIER(Iwa_DirectionalBlurFx, "iwa_DirectionalBlurFx")
620