150 lines
5 KiB
C++
150 lines
5 KiB
C++
#include "iwa_motionflowfx.h"
|
|
|
|
#include "tfxattributes.h"
|
|
|
|
#include "toonz/tstageobject.h"
|
|
|
|
#include "trop.h"
|
|
|
|
namespace {
|
|
double getSizePixelAmount(const double val, const TAffine affine) {
|
|
/*--- Convert to vector --- */
|
|
TPointD vect;
|
|
vect.x = val;
|
|
vect.y = 0.0;
|
|
/*--- Apply geometrical transformation ---*/
|
|
// For the following lines I referred to lines 586-592 of
|
|
// sources/stdfx/motionblurfx.cpp
|
|
TAffine aff(affine);
|
|
aff.a13 = aff.a23 = 0; /* ignore translation */
|
|
vect = aff * vect;
|
|
/*--- return the length of the vector ---*/
|
|
return std::sqrt(vect.x * vect.x + vect.y * vect.y);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
//------------------------------------------------------------
|
|
|
|
Iwa_MotionFlowFx::Iwa_MotionFlowFx()
|
|
: m_normalizeType(new TIntEnumParam(NORMALIZE_AUTO, "Auto"))
|
|
, m_normalizeRange(1.0) {
|
|
bindParam(this, "shutterLength", m_shutterLength);
|
|
bindParam(this, "motionObjectType", m_motionObjectType);
|
|
bindParam(this, "motionObjectIndex", m_motionObjectIndex);
|
|
bindParam(this, "normalizeType", m_normalizeType);
|
|
bindParam(this, "normalizeRange", m_normalizeRange);
|
|
|
|
m_normalizeType->addItem(NORMALIZE_MANUAL, "Manual");
|
|
m_normalizeRange->setMeasureName("fxLength");
|
|
m_normalizeRange->setValueRange(0.01, 1000.0);
|
|
|
|
getAttributes()->setIsSpeedAware(true);
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
|
|
void Iwa_MotionFlowFx::doCompute(TTile& tile, double frame,
|
|
const TRenderSettings& settings) {
|
|
/* Get parameters */
|
|
TAffine aff_Before, aff_After;
|
|
getAttributes()->getMotionAffines(aff_Before, aff_After);
|
|
|
|
TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy());
|
|
/* output */
|
|
TRasterGR8P out_ras(sizeof(double3) * dimOut.lx * dimOut.ly, 1);
|
|
out_ras->lock();
|
|
double3* out_ras_p = (double3*)out_ras->getRawData();
|
|
|
|
double3* out_p = out_ras_p;
|
|
|
|
double norm_range = 0.0;
|
|
|
|
for (int y = 0; y < dimOut.ly; y++) {
|
|
for (int x = 0; x < dimOut.lx; x++, out_p++) {
|
|
TPointD pos = TPointD((double)x, (double)y) + tile.m_pos;
|
|
TPointD vec = pos - (aff_Before * aff_After.inv() * pos);
|
|
out_p->z = std::sqrt(vec.x * vec.x + vec.y * vec.y);
|
|
if (out_p->z > 0.0) {
|
|
out_p->x = vec.x / out_p->z;
|
|
out_p->y = vec.y / out_p->z;
|
|
norm_range = std::max(norm_range, out_p->z);
|
|
} else {
|
|
out_p->x = 0.0;
|
|
out_p->y = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_normalizeType->getValue() == NORMALIZE_MANUAL)
|
|
norm_range = getSizePixelAmount(m_normalizeRange->getValue(frame),
|
|
settings.m_affine);
|
|
|
|
tile.getRaster()->clear();
|
|
TRaster32P outRas32 = (TRaster32P)tile.getRaster();
|
|
TRaster64P outRas64 = (TRaster64P)tile.getRaster();
|
|
if (outRas32)
|
|
setOutRas<TRaster32P, TPixel32>(outRas32, out_ras_p, norm_range);
|
|
else if (outRas64)
|
|
setOutRas<TRaster64P, TPixel64>(outRas64, out_ras_p, norm_range);
|
|
|
|
out_ras->unlock();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
|
|
template <typename RASTER, typename PIXEL>
|
|
void Iwa_MotionFlowFx::setOutRas(RASTER ras, double3* outBuf,
|
|
double norm_range) {
|
|
double3* buf_p = outBuf;
|
|
for (int j = 0; j < ras->getLy(); j++) {
|
|
PIXEL* pix = ras->pixels(j);
|
|
for (int i = 0; i < ras->getLx(); i++, pix++, buf_p++) {
|
|
double val = 0.5 + buf_p->x * 0.5;
|
|
pix->r = (typename PIXEL::Channel)(val * double(PIXEL::maxChannelValue));
|
|
val = 0.5 + buf_p->y * 0.5;
|
|
pix->g = (typename PIXEL::Channel)(val * double(PIXEL::maxChannelValue));
|
|
val = std::min(1.0, buf_p->z / norm_range);
|
|
pix->b = (typename PIXEL::Channel)(val * double(PIXEL::maxChannelValue));
|
|
pix->m = PIXEL::maxChannelValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
|
|
bool Iwa_MotionFlowFx::doGetBBox(double frame, TRectD& bBox,
|
|
const TRenderSettings& info) {
|
|
bBox = TConsts::infiniteRectD;
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
|
|
bool Iwa_MotionFlowFx::canHandle(const TRenderSettings& info, double frame) {
|
|
return true;
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
Since there is a possibility that the reference object is moving,
|
|
Change the alias every frame
|
|
------------------------------------------------------------*/
|
|
|
|
std::string Iwa_MotionFlowFx::getAlias(double frame,
|
|
const TRenderSettings& info) const {
|
|
std::string alias = getFxType();
|
|
alias += "[";
|
|
|
|
// alias of the effects related to the input ports separated by commas
|
|
// a port that is not connected to an alias blank (empty string)
|
|
|
|
std::string paramalias("");
|
|
for (int i = 0; i < getParams()->getParamCount(); i++) {
|
|
TParam* param = getParams()->getParam(i);
|
|
paramalias += param->getName() + "=" + param->getValueAlias(frame, 3);
|
|
}
|
|
unsigned long id = getIdentifier();
|
|
return alias + std::to_string(frame) + "," + std::to_string(id) + paramalias +
|
|
"]";
|
|
}
|
|
FX_PLUGIN_IDENTIFIER(Iwa_MotionFlowFx, "iwa_MotionFlowFx")
|