diff --git a/stuff/config/current.txt b/stuff/config/current.txt index d88e4b1..7855ea9 100644 --- a/stuff/config/current.txt +++ b/stuff/config/current.txt @@ -821,6 +821,8 @@ "STD_particlesFx.source_gradation" "Use Control Image Gradation" "STD_particlesFx.pick_color_for_every_frame" "Pick Control Image's Color for Every Frame" "STD_particlesFx.perspective_distribution" "Perspective Distribution" + "STD_particlesFx.motion_blur" "Motion Blur" + "STD_particlesFx.motion_blur_gamma" "Gamma" diff --git a/stuff/doc/español/particlesFx.html b/stuff/doc/español/particlesFx.html index 770602d..3d12c3b 100644 --- a/stuff/doc/español/particlesFx.html +++ b/stuff/doc/español/particlesFx.html @@ -599,25 +599,6 @@ rt ○ - -   - Trail - Trail - Muestra una estela para cada partícula, que se desvanecerá a lo largo de la cantidad de fotogramas especificados en el parámetro Trail. - ― - - -   -   - Step - Permite definir cuántas imágenes se mostrarán en la estela. Cada estela estará compuesta por (Trail/Step) imágenes. - ― -   Lifetime @@ -855,6 +836,43 @@ rt ― + +   + Trail + Trail + Muestra una estela para cada partícula, que se desvanecerá a lo largo de la cantidad de fotogramas especificados en el parámetro Trail. + ― + + +   +   + Step + Permite definir cuántas imágenes se mostrarán en la estela. Cada estela estará compuesta por (Trail/Step) imágenes. + ― + + +   +   + Motion Blur + When turned ON, particles will be rendered with motion blur according to its movement. + ― + + +   +   + Gamma + Film gamma value used for the motion blur. + ― +   ○ - -   - Trail - Trail - Display a trail for each particle, that fades out over the number of frames specified in the Trail parameter. - ― - - -   -   - Step - The particle trail will be displayed every Step value. That is, there will be (Trail/Step) images displayed in the trail. - ― -   Lifetime @@ -849,7 +830,44 @@ rt Trail Opacity When a trail is defined in Birth Params → Trail, it specifies the minimum / maximum values for the opacity of the particles in the trail. + width:356pt'>When a trail is defined in Animation → Trail, it specifies the minimum / maximum values for the opacity of the particles in the trail. + ― + + +   + Trail + Trail + Display a trail for each particle, that fades out over the number of frames specified in the Trail parameter. + ― + + +   +   + Step + The particle trail will be displayed every Step value. That is, there will be (Trail/Step) images displayed in the trail. + ― + + +   +   + Motion Blur + When turned ON, particles will be rendered with motion blur according to its movement. + ― + + +   +   + Gamma + Film gamma value used for the motion blur. ― diff --git a/stuff/doc/日本語/particlesFx.html b/stuff/doc/日本語/particlesFx.html index 28ddffd..15efa83 100644 --- a/stuff/doc/日本語/particlesFx.html +++ b/stuff/doc/日本語/particlesFx.html @@ -599,25 +599,6 @@ rt �� - - �@ - Trail - Trail - �O�Ղ�\��������BTrail�Ŏw�肵���t���[���������ăt�F�[�h�A�E�g����B - �\ - - - �@ - �@ - Step - �O�Ղ�Step�l�����ɕ\������B���Ȃ킿�A�O�Ղ̉摜�́iTrail�j/(Frame)���\������邱�ƂɂȂ�B - �\ - �@ Lifetime @@ -855,7 +836,44 @@ rt Trail Opacity BirthParam��Trail��Trail���w�肵���Ƃ��A���̋O�Ղ̃p�[�e�B�N���̕s�����x�̍ŏ�/�ő�l�����߂�B + width:356pt'>Animation��Trail��Trail���w�肵���Ƃ��A���̋O�Ղ̃p�[�e�B�N���̕s�����x�̍ŏ�/�ő�l�����߂�B + �\ + + + �@ + Trail + Trail + �O�Ղ�\��������BTrail�Ŏw�肵���t���[���������ăt�F�[�h�A�E�g����B + �\ + + + �@ + �@ + Step + �O�Ղ�Step�l�����ɕ\������B���Ȃ킿�A�O�Ղ̉摜�́iTrail�j/(Frame)���\������邱�ƂɂȂ�B + �\ + + + �@ + �@ + Motion Blur + When turned ON, particles will be rendered with motion blur according to its movement. + �\ + + + �@ + �@ + Gamma + Film gamma value used for the motion blur. �\ diff --git a/stuff/profiles/layouts/fxs/STD_particlesFx.xml b/stuff/profiles/layouts/fxs/STD_particlesFx.xml index 01972ba..88b295f 100644 --- a/stuff/profiles/layouts/fxs/STD_particlesFx.xml +++ b/stuff/profiles/layouts/fxs/STD_particlesFx.xml @@ -56,9 +56,6 @@ mass rot rot_ctrl - - trail - trail_step lifetime lifetime_ctrl @@ -119,6 +116,14 @@ fade_out trail_opacity + + trail + trail_step + + + motion_blur + motion_blur_gamma + scale_step scale_step_ctrl diff --git a/toonz/sources/stdfx/particles.cpp b/toonz/sources/stdfx/particles.cpp index d7ef492..046411d 100644 --- a/toonz/sources/stdfx/particles.cpp +++ b/toonz/sources/stdfx/particles.cpp @@ -174,10 +174,12 @@ Particle::Particle(int g_lifetime, int seed, std::map porttiles, trail = (int)(values.trail_val.first + (ranges.trail_range) * random.getFloat()); - vx = random_speed * sin(random_s_a_range); - vy = -random_speed * cos(random_s_a_range); - oldx = 0; - oldy = 0; + vx = random_speed * sin(random_s_a_range); + vy = -random_speed * cos(random_s_a_range); + for (int i = 0; i < 3; i++) { + oldx[i] = 0.; + oldy[i] = 0.; + } mass = values.mass_val.first + (ranges.mass_range) * random.getFloat(); if (values.scale_ctrl_val && (porttiles.find(values.scale_ctrl_val) != porttiles.end())) { @@ -670,8 +672,13 @@ void Particle::move(std::map porttiles, if (values.scalestep_ctrl_val) scalestepreference = imagereferences[values.scalestep_ctrl_val]; lifetime--; - oldx = x; - oldy = y; + // slide the old positions + for (int i = 2; i >= 1; i--) { + oldx[i] = oldx[i - 1]; + oldy[i] = oldy[i - 1]; + } + oldx[0] = x; + oldy[0] = y; // time=genlifetime-lifetime-1; // if(time<0) time=0; if (values.gravity_ctrl_val && diff --git a/toonz/sources/stdfx/particles.h b/toonz/sources/stdfx/particles.h index da353f4..8b2ed5d 100644 --- a/toonz/sources/stdfx/particles.h +++ b/toonz/sources/stdfx/particles.h @@ -56,8 +56,6 @@ struct particles_values { bool scale_ctrl_all_val; DoublePair rot_val; int rot_ctrl_val; - DoublePair trail_val; - double trailstep_val; int rotswingmode_val; double rotspeed_val; DoublePair rotsca_val; @@ -66,7 +64,8 @@ struct particles_values { DoublePair opacity_val; int opacity_ctrl_val; DoublePair trailopacity_val; - double mblur_val; + DoublePair trail_val; + double trailstep_val; DoublePair scalestep_val; int scalestep_ctrl_val; double fadein_val; @@ -93,6 +92,8 @@ struct particles_values { bool reset_random_for_every_frame_val; bool pick_color_for_every_frame_val; bool perspective_distribution_val; + bool motion_blur_val; + double motion_blur_gamma_val; }; //------------------------------------------------------------------------------ @@ -133,8 +134,8 @@ class Particle { public: double x; double y; - double oldx; - double oldy; + double oldx[3]; + double oldy[3]; double vx; /*sono le velox iniziali*/ double vy; /*sono le velox iniziali*/ double mass; diff --git a/toonz/sources/stdfx/particlesengine.cpp b/toonz/sources/stdfx/particlesengine.cpp index bf1ecc9..9f6ab2a 100644 --- a/toonz/sources/stdfx/particlesengine.cpp +++ b/toonz/sources/stdfx/particlesengine.cpp @@ -27,6 +27,9 @@ #include +#include +#include + /*-----------------------------------------------------------------*/ Particles_Engine::Particles_Engine(ParticlesFx *parent, double frame) @@ -135,6 +138,9 @@ void Particles_Engine::fill_value_struct(struct particles_values &myvalues, m_parent->pick_color_for_every_frame_val->getValue(); myvalues.perspective_distribution_val = m_parent->perspective_distribution_val->getValue(); + myvalues.motion_blur_val = m_parent->motion_blur_val->getValue(); + myvalues.motion_blur_gamma_val = + m_parent->motion_blur_gamma_val->getValue(frame); } /*-----------------------------------------------------------------*/ @@ -411,7 +417,6 @@ void Particles_Engine::normalize_values(struct particles_values &values, (values.opacity_val.second) = (values.opacity_val.second) * 0.01; (values.trailopacity_val.first) = (values.trailopacity_val.first) * 0.01; (values.trailopacity_val.second) = (values.trailopacity_val.second) * 0.01; - (values.mblur_val) = (values.mblur_val) * 0.01; (values.friction_val) = -(values.friction_val) * 0.01; (values.windangle_val) = (values.windangle_val) * M_PI_180; (values.g_angle_val) = (values.g_angle_val + 180) * M_PI_180; @@ -855,6 +860,14 @@ void Particles_Engine::do_render( // Particles parameters M = ri.m_affine * M * TScale(1.0 / partScale); + // render with motion blur + if (values.motion_blur_val) { + if (do_render_motion_blur(part, tile, tileRas, rfinalpart, M, bbox, + values.trailopacity_val, + values.motion_blur_gamma_val, ri)) + return; + } + // Then, retrieve the particle position in current reference. TPointD pos(part->x, part->y); pos = ri.m_affine * pos; @@ -874,6 +887,376 @@ void Particles_Engine::do_render( /*-----------------------------------------------------------------*/ +bool Particles_Engine::do_render_motion_blur( + Particle *part, TTile *tile, TRasterP tileRas, TRaster32P rfinalpart, + TAffine &M, const TRectD &bbox, const DoublePair &trailOpacity, + const double gamma, const TRenderSettings &ri) { + QList points; + QList lengths; + + // do not render new-born particles as it has no trace + if (part->genlifetime - part->lifetime == 0) return true; + + TRectD partBBoxD = + M * TTranslation(bbox.getP00()) * convert(rfinalpart->getBounds()); + partBBoxD = partBBoxD.enlarge(1.0); + + TRect partBBox = convert(partBBoxD); + + TRaster32P partRas(partBBox.getSize()); + TRop::over( + partRas, rfinalpart, + TTranslation(-partBBoxD.getP00()) * M * TTranslation(bbox.getP00())); + + // create trace vertices list + // render straight trace in the first 4 frames + if (part->genlifetime - part->lifetime < 3) { + TPointD p0(part->x, part->y); + TPointD p1(part->oldx[0], part->oldy[0]); + p0 = ri.m_affine * p0; + p1 = ri.m_affine * p1; + points.append(TPointD(0, 0)); + points.append(p1 - p0); + } + // Cubic spline interpolation + else { + // divide into 8 lines (= 9 segments) + int pointAmount = 9; + TPointD keyP[4] = {TPointD(part->x, part->y), + TPointD(part->oldx[0], part->oldy[0]), + TPointD(part->oldx[1], part->oldy[1]), + TPointD(part->oldx[2], part->oldy[2])}; + for (int i = 0; i < 4; i++) { + keyP[i] = ri.m_affine * keyP[i]; + if (i > 0) { + keyP[i] -= keyP[0]; + } + } + keyP[0] = TPointD(0, 0); + + double u[4]; + u[0] = 0.; + u[1] = u[0] + norm(keyP[1] - keyP[0]); + u[2] = u[1] + norm(keyP[2] - keyP[1]); + u[3] = u[2] + norm(keyP[3] - keyP[2]); + + QMatrix4x4 mat(u[0] * u[0] * u[0], u[0] * u[0], u[0], 1., + u[1] * u[1] * u[1], u[1] * u[1], u[1], 1., + u[2] * u[2] * u[2], u[2] * u[2], u[2], 1., + u[3] * u[3] * u[3], u[3] * u[3], u[3], 1.); + + bool ok; + mat = mat.inverted(&ok); + if (!ok) return false; + + QPointF coeff[4]; + for (int i = 0; i < 4; i++) { + coeff[i] = mat(i, 0) * QPointF(keyP[0].x, keyP[0].y) + + mat(i, 1) * QPointF(keyP[1].x, keyP[1].y) + + mat(i, 2) * QPointF(keyP[2].x, keyP[2].y) + + mat(i, 3) * QPointF(keyP[3].x, keyP[3].y); + } + + for (int p = 0; p <= pointAmount; p++) { + double ratio = (double)p / (double)pointAmount; + double cur_u = u[0] * ratio + u[1] * (1 - ratio); + + points.append(TPointD( + cur_u * cur_u * cur_u * coeff[0].x() + cur_u * cur_u * coeff[1].x() + + cur_u * coeff[2].x() + coeff[3].x(), + cur_u * cur_u * cur_u * coeff[0].y() + cur_u * cur_u * coeff[1].y() + + cur_u * coeff[2].y() + coeff[3].y())); + } + } + + // compute lengths + for (int p = 0; p < points.size() - 1; p++) { + TPointD vec = points[p + 1] - points[p]; + lengths.append(norm(vec)); + } + + /* Get upper, lower, left and right margin */ + double minX = 0.0; + double maxX = 0.0; + double minY = 0.0; + double maxY = 0.0; + for (int p = 0; p < points.size(); p++) { + if (points.at(p).x > maxX) maxX = points.at(p).x; + if (points.at(p).x < minX) minX = points.at(p).x; + if (points.at(p).y > maxY) maxY = points.at(p).y; + if (points.at(p).y < minY) minY = points.at(p).y; + } + int marginLeft = (int)std::ceil(std::abs(minX)); + int marginRight = (int)std::ceil(std::abs(maxX)); + int marginTop = (int)std::ceil(std::abs(maxY)); + int marginBottom = (int)std::ceil(std::abs(minY)); + if (marginLeft == 0 && marginRight == 0 && marginTop == 0 && + marginBottom == 0) + return false; + + // end opacity is computed so that the trace will be connected smoothly in the + // trail + float end_opacity = + trailOpacity.second + + (trailOpacity.first - trailOpacity.second) / std::max(1, part->trail); + + // create the blur filter + TDimensionI filterDim(marginLeft + marginRight + 1, + marginTop + marginBottom + 1); + TRasterGR8P filter_ras(sizeof(float) * filterDim.lx, filterDim.ly); + filter_ras->lock(); + float *filter_p = (float *)filter_ras->getRawData(); + /* Variable for adding filter value*/ + float fil_val_sum = 0.0f; + /* The current filter position to be looped in the 'for' statement */ + float *current_fil_p = filter_p; + /* For each coordinate in the filter */ + for (int fily = 0; fily < filterDim.ly; fily++) { + for (int filx = 0; filx < filterDim.lx; filx++, current_fil_p++) { + /* Get filter coordinates */ + TPointD pos(static_cast(filx - marginLeft), + static_cast(fily - marginBottom)); + /* Value to be updated */ + float nearestDist2 = 100.0f; + int nearestIndex = -1; + float nearestFramePosRatio = 0.0f; + + /* Find the nearest point for each pair of sample points */ + for (int v = 0; v < points.count() - 1; v++) { + TPointD p0 = points[v]; + TPointD p1 = points[v + 1]; + + /* If it is not within the range, continue */ + if (pos.x < std::min(p0.x, p1.x) - 1.0f || + pos.x > std::max(p0.x, p1.x) + 1.0f || + pos.y < std::min(p0.y, p1.y) - 1.0f || + pos.y > std::max(p0.y, p1.y) + 1.0f) + continue; + + /* Since it is within the range, obtain the distance between the line + * segment and the point. */ + /* Calculate the inner product of 'p0'->sampling point and 'p0'->'p1' */ + TPointD vec_p0_sample(static_cast(pos.x - p0.x), + static_cast(pos.y - p0.y)); + TPointD vec_p0_p1(static_cast(p1.x - p0.x), + static_cast(p1.y - p0.y)); + float dot = + vec_p0_sample.x * vec_p0_p1.x + vec_p0_sample.y * vec_p0_p1.y; + /* Calculate the square of distance */ + float dist2; + float framePosRatio; + /* If it is before 'p0' */ + if (dot <= 0.0f) { + dist2 = vec_p0_sample.x * vec_p0_sample.x + + vec_p0_sample.y * vec_p0_sample.y; + framePosRatio = 0.0f; + } else { + /* Calculate the square of the length of the trajectory vector */ + float length2 = lengths[v] * lengths[v]; + + /* If it is between 'p0' and 'p1' + * If the trajectory at p is a point, + * 'length2' becomes 0, so it will never fall into this condition. + * So, there should not be worry of becoming ZeroDivide. */ + if (dot < length2) { + float p0_sample_dist2 = vec_p0_sample.x * vec_p0_sample.x + + vec_p0_sample.y * vec_p0_sample.y; + dist2 = p0_sample_dist2 - dot * dot / length2; + framePosRatio = dot / length2; + } + /* If it is before 'p1' */ + else { + TPointD vec_p1_sample = pos - p1; + dist2 = vec_p1_sample.x * vec_p1_sample.x + + vec_p1_sample.y * vec_p1_sample.y; + framePosRatio = 1.0f; + } + } + /* If the distance is farther than (√ 2 + 1) / 2, continue + * Because it is a comparison with dist2, the value is squared */ + if (dist2 > 1.4571f) continue; + + /* Update if distance is closer */ + if (dist2 < nearestDist2) { + nearestDist2 = dist2; + nearestIndex = v; + nearestFramePosRatio = framePosRatio; + } + } + + /* If neighborhood vector of the current pixel can not be found, + * set the filter value to 0 and return */ + if (nearestIndex == -1) { + *current_fil_p = 0.0f; + continue; + } + + /* Count how many subpixels (16 * 16) of the current pixel + * are in the range 0.5 from the neighborhood vector. + */ + int count = 0; + TPointD np0 = points[nearestIndex]; + TPointD np1 = points[nearestIndex + 1]; + for (int yy = 0; yy < 16; yy++) { + /* Y coordinate of the subpixel */ + float subPosY = pos.y + ((float)yy - 7.5f) / 16.0f; + for (int xx = 0; xx < 16; xx++) { + /* X coordinate of the subpixel */ + float subPosX = pos.x + ((float)xx - 7.5f) / 16.0f; + + TPointD vec_np0_sub = TPointD(subPosX, subPosY) - np0; + TPointD vec_np0_np1 = np1 - np0; + float dot = + vec_np0_sub.x * vec_np0_np1.x + vec_np0_sub.y * vec_np0_np1.y; + /* Calculate the square of the distance */ + float dist2; + /* If it is before 'p0' */ + if (dot <= 0.0f) + dist2 = + vec_np0_sub.x * vec_np0_sub.x + vec_np0_sub.y * vec_np0_sub.y; + else { + /* Compute the square of the length of the trajectory vector */ + float length2 = lengths[nearestIndex] * lengths[nearestIndex]; + /* If it is between 'p0' and 'p1' */ + if (dot < length2) { + float np0_sub_dist2 = + vec_np0_sub.x * vec_np0_sub.x + vec_np0_sub.y * vec_np0_sub.y; + dist2 = np0_sub_dist2 - dot * dot / length2; + } + /* if it is before 'p1' */ + else { + TPointD vec_np1_sub = TPointD(subPosX, subPosY) - np1; + dist2 = + vec_np1_sub.x * vec_np1_sub.x + vec_np1_sub.y * vec_np1_sub.y; + } + } + /* Increment count if squared distance is less than 0.25 */ + if (dist2 <= 0.25f) count++; + } + } + /* 'safeguard' - If the count is 0, set the field value to 0 and return. + */ + if (count == 0) { + *current_fil_p = 0.0f; + continue; + } + + /* Count is 256 at a maximum */ + float countRatio = (float)count / 256.0f; + + /* The brightness of the filter value is inversely proportional + * to the area of ​​the line of width 1 made by the vector. + * + * Since there are semicircular caps with radius 0.5 + * before and after the vector, it will never be 0-divide + * even if the length of vector is 0. + */ + + /* Area of the neighborhood vector when width = 1 */ + float vecMenseki = 0.25f * 3.14159265f + lengths[nearestIndex]; + + float opacity = 1.0f; + if (end_opacity < 1.0f) { + float ratio = ((float)nearestIndex + nearestFramePosRatio) / + (float)(points.size() - 1); + opacity = ratio + end_opacity * (1.f - ratio); + } + /* Store field value */ + *current_fil_p = opacity * countRatio / vecMenseki; + fil_val_sum += *current_fil_p; + } + } + + /* Normalization */ + current_fil_p = filter_p; + for (int f = 0; f < filterDim.lx * filterDim.ly; f++, current_fil_p++) { + *current_fil_p /= fil_val_sum; + } + + // apply the filter + TDimension blurredSize = + partRas->getSize() + + TDimension(marginLeft + marginRight, marginTop + marginBottom); + float4 *blurred_p; + TRasterGR8P blurred_ras(sizeof(float4) * blurredSize.lx, blurredSize.ly); + blurred_ras->lock(); + blurred_ras->clear(); + blurred_p = (float4 *)blurred_ras->getRawData(); + // for each texture pixels, + // distribute to all pixels in the filter + for (int ty = 0; ty < partRas->getLy(); ty++) { + TPixel32 *t_p = partRas->pixels(ty); + for (int tx = 0; tx < partRas->getLx(); tx++, t_p++) { + if (t_p->m == 0) continue; + + float4 tex = {(float)t_p->r / (float)(TPixel32::maxChannelValue), + (float)t_p->g / (float)(TPixel32::maxChannelValue), + (float)t_p->b / (float)(TPixel32::maxChannelValue), + (float)t_p->m / (float)(TPixel32::maxChannelValue)}; + if (gamma > 1.f) { + tex.x = std::pow(tex.x / tex.w, gamma) * tex.w; + tex.y = std::pow(tex.y / tex.w, gamma) * tex.w; + tex.z = std::pow(tex.z / tex.w, gamma) * tex.w; + } + + current_fil_p = filter_p; + for (int outy = ty; outy < ty + filterDim.ly; outy++) { + for (int outx = tx; outx < tx + filterDim.lx; outx++, current_fil_p++) { + if (*current_fil_p == 0.f) continue; + int outIndex = outy * blurredSize.lx + outx; + blurred_p[outIndex].x += *current_fil_p * tex.x; + blurred_p[outIndex].y += *current_fil_p * tex.y; + blurred_p[outIndex].z += *current_fil_p * tex.z; + blurred_p[outIndex].w += *current_fil_p * tex.w; + } + } + } + } + + filter_ras->unlock(); + + float4 *b_p = blurred_p; + TRaster32P blurred(blurredSize); + for (int by = 0; by < blurredSize.ly; by++) { + TPixel32 *b_ras_p = blurred->pixels(by); + for (int bx = 0; bx < blurredSize.lx; bx++, b_ras_p++, b_p++) { + if (gamma > 1.f && (*b_p).w > 0.f) { + (*b_p).x = std::pow((*b_p).x / (*b_p).w, 1.f / gamma) * (*b_p).w; + (*b_p).y = std::pow((*b_p).y / (*b_p).w, 1.f / gamma) * (*b_p).w; + (*b_p).z = std::pow((*b_p).z / (*b_p).w, 1.f / gamma) * (*b_p).w; + } + + b_ras_p->r = (TPixel32::Channel)std::round( + (*b_p).x * (float)(TPixel32::maxChannelValue)); + b_ras_p->g = (TPixel32::Channel)std::round( + (*b_p).y * (float)(TPixel32::maxChannelValue)); + b_ras_p->b = (TPixel32::Channel)std::round( + (*b_p).z * (float)(TPixel32::maxChannelValue)); + b_ras_p->m = (TPixel32::Channel)std::round( + (*b_p).w * (float)(TPixel32::maxChannelValue)); + } + } + + blurred_ras->unlock(); + + // composite particle + TPointD pos(part->x, part->y); + pos = ri.m_affine * pos; + M = TTranslation(pos - tile->m_pos) * + TTranslation(-TPointD(marginLeft, marginBottom) + partBBoxD.getP00()); + + if (TRaster32P myras32 = tileRas) + TRop::over(tileRas, blurred, M); + else if (TRaster64P myras64 = tileRas) + TRop::over(tileRas, blurred, M); + else + throw TException("ParticlesFx: unsupported Pixel Type"); + + return true; +} + +/*-----------------------------------------------------------------*/ + void Particles_Engine::fill_array(TTile *ctrl1, int ®ioncount, std::vector &myarray, std::vector &lista, diff --git a/toonz/sources/stdfx/particlesengine.h b/toonz/sources/stdfx/particlesengine.h index 645ae65..9ad865e 100644 --- a/toonz/sources/stdfx/particlesengine.h +++ b/toonz/sources/stdfx/particlesengine.h @@ -7,6 +7,9 @@ #include "particles.h" #include "particlesfx.h" +struct float4 { + float x, y, z, w; +}; class Particle; class Particles_Engine { @@ -51,6 +54,11 @@ public: int curr_frame, std::map, double> &partScales); + bool do_render_motion_blur(Particle *part, TTile *tile, TRasterP tileRas, + TRaster32P rfinalpart, TAffine &M, + const TRectD &bbox, const DoublePair &trailOpacity, + const double gamma, const TRenderSettings &ri); + bool port_is_used(int i, struct particles_values &values); bool port_is_used_for_value(int i, struct particles_values &values); bool port_is_used_for_gradient(int i, struct particles_values &values); diff --git a/toonz/sources/stdfx/particlesfx.cpp b/toonz/sources/stdfx/particlesfx.cpp index 3cb9d98..39db057 100644 --- a/toonz/sources/stdfx/particlesfx.cpp +++ b/toonz/sources/stdfx/particlesfx.cpp @@ -98,7 +98,9 @@ ParticlesFx::ParticlesFx() , foutfadecol_val(0.0) , source_gradation_val(false) , pick_color_for_every_frame_val(false) - , perspective_distribution_val(false) { + , perspective_distribution_val(false) + , motion_blur_val(false) + , motion_blur_gamma_val(2.2) { addInputPort("Texture1", new TRasterFxPort, 0); addInputPort("Control1", new TRasterFxPort, 1); @@ -264,6 +266,9 @@ ParticlesFx::ParticlesFx() bindParam(this, "source_gradation", source_gradation_val); bindParam(this, "pick_color_for_every_frame", pick_color_for_every_frame_val); bindParam(this, "perspective_distribution", perspective_distribution_val); + bindParam(this, "motion_blur", motion_blur_val); + bindParam(this, "motion_blur_gamma", motion_blur_gamma_val); + motion_blur_gamma_val->setValueRange(1.0, 5.0); } //------------------------------------------------------------------ diff --git a/toonz/sources/stdfx/particlesfx.h b/toonz/sources/stdfx/particlesfx.h index fd34e07..eaac440 100644 --- a/toonz/sources/stdfx/particlesfx.h +++ b/toonz/sources/stdfx/particlesfx.h @@ -56,8 +56,6 @@ public: TBoolParamP scale_ctrl_all_val; TRangeParamP rot_val; TIntParamP rot_ctrl_val; - TRangeParamP trail_val; - TDoubleParamP trailstep_val; TIntEnumParamP rotswingmode_val; TDoubleParamP rotspeed_val; TRangeParamP rotsca_val; @@ -66,6 +64,8 @@ public: TRangeParamP opacity_val; TIntParamP opacity_ctrl_val; TRangeParamP trailopacity_val; + TRangeParamP trail_val; + TDoubleParamP trailstep_val; TRangeParamP scalestep_val; TIntParamP scalestep_ctrl_val; TDoubleParamP fadein_val; @@ -90,6 +90,8 @@ public: TBoolParamP source_gradation_val; TBoolParamP pick_color_for_every_frame_val; TBoolParamP perspective_distribution_val; + TBoolParamP motion_blur_val; + TDoubleParamP motion_blur_gamma_val; public: enum { UNIT_SMALL_INCH, UNIT_INCH };