diff --git a/stuff/config/current.txt b/stuff/config/current.txt
index 671fc5b..d37503f 100644
--- a/stuff/config/current.txt
+++ b/stuff/config/current.txt
@@ -1450,6 +1450,11 @@
- "STD_iwa_FractalNoiseFx.cycleEvolution" "Cycle Evolution"
- "STD_iwa_FractalNoiseFx.cycleEvolutionRange" "Cycle (in Evolution)"
- "STD_iwa_FractalNoiseFx.dynamicIntensity" "Dynamic Intensity"
+ - "STD_iwa_FractalNoiseFx.doConical" "Do Conical Transform"
+ - "STD_iwa_FractalNoiseFx.conicalAngle" "Conical Angle"
+ - "STD_iwa_FractalNoiseFx.cameraFov" "Camera FoV"
+ - "STD_iwa_FractalNoiseFx.zScale" "Scale Depth"
+ - "STD_iwa_FractalNoiseFx.conicalEvolution" "Conical Evolution"
- "STD_iwa_FractalNoiseFx.alphaRendering" "Alpha Rendering"
- "STD_iwa_BloomFx" "Bloom Iwa"
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_FractalNoiseFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_FractalNoiseFx.xml
index 6ce9310..c0cf15e 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_FractalNoiseFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_FractalNoiseFx.xml
@@ -29,10 +29,22 @@
cycleEvolutionRange
-
dynamicIntensity
+
+ doConical
+
+ conicalAngle
+ cameraFov
+ zScale
+ conicalEvolution
+
+
alphaRendering
+
+ doConical
+ perspectiveOffset
+
diff --git a/toonz/sources/stdfx/iwa_fractalnoisefx.cpp b/toonz/sources/stdfx/iwa_fractalnoisefx.cpp
index e04817a..63cdb79 100644
--- a/toonz/sources/stdfx/iwa_fractalnoisefx.cpp
+++ b/toonz/sources/stdfx/iwa_fractalnoisefx.cpp
@@ -2,6 +2,8 @@
#include "iwa_noise1234.h"
#include "tparamuiconcept.h"
+#include
+
namespace {
// convert sRGB color space to power space
template
@@ -32,6 +34,7 @@ inline const T &clamp(const T &v, const T &lo, const T &hi) {
const double turbulentGamma = 2.2;
// magic number to offset evolution between generations
const double evolutionOffsetStep = 19.82;
+const double evolutionOffsetStepW = 31.1;
} // namespace
//------------------------------------------------------------------
@@ -57,7 +60,12 @@ Iwa_FractalNoiseFx::Iwa_FractalNoiseFx()
, m_cycleEvolutionRange(1.0)
///, m_randomSeed(0)
, m_dynamicIntensity(1.0)
- , m_alphaRendering(false) {
+ , m_alphaRendering(false)
+, m_doConical(false)
+, m_conicalEvolution(0.0)
+, m_conicalAngle(60.0)
+, m_cameraFov(60.0)
+, m_zScale(2.0) {
m_fractalType->addItem(TurbulentSmooth, "Turbulent Smooth");
m_fractalType->addItem(TurbulentBasic, "Turbulent Basic");
m_fractalType->addItem(TurbulentSharp, "Turbulent Sharp");
@@ -92,6 +100,11 @@ Iwa_FractalNoiseFx::Iwa_FractalNoiseFx()
m_cycleEvolutionRange->setValueRange(0.1, 30.0);
m_dynamicIntensity->setValueRange(-10.0, 10.0);
+ m_conicalEvolution->setValueRange(-100, 100.0);
+ m_conicalAngle->setValueRange(0.0, 89.9);
+ m_cameraFov->setValueRange(10.0, 170.0);
+ m_zScale->setValueRange(0.0, 3.0);
+
bindParam(this, "fractalType", m_fractalType);
bindParam(this, "noiseType", m_noiseType);
bindParam(this, "invert", m_invert);
@@ -114,6 +127,12 @@ Iwa_FractalNoiseFx::Iwa_FractalNoiseFx()
/// bindParam(this, "randomSeed", m_randomSeed);
bindParam(this, "dynamicIntensity", m_dynamicIntensity);
+ bindParam(this, "doConical", m_doConical);
+ bindParam(this, "conicalEvolution", m_conicalEvolution);
+ bindParam(this, "conicalAngle", m_conicalAngle);
+ bindParam(this, "cameraFov", m_cameraFov);
+ bindParam(this, "zScale", m_zScale);
+
bindParam(this, "alphaRendering", m_alphaRendering);
}
@@ -149,7 +168,6 @@ void Iwa_FractalNoiseFx::doCompute(TTile &tile, double frame,
// affine transformations
TAffine globalAff = TTranslation(-tile.m_pos) * ri.m_affine;
- TAffine parentOffsetAff = TTranslation(param.offsetTurbulence);
TAffine parentAff =
TScale(param.scale.lx, param.scale.ly) * TRotation(-param.rotation);
TAffine subAff = TTranslation(param.subOffset) * TScale(param.subScaling) *
@@ -171,78 +189,240 @@ void Iwa_FractalNoiseFx::doCompute(TTile &tile, double frame,
int genCount = (int)std::ceil(param.complexity);
- // accumulate base noise pattern for each generation
- for (int gen = 0; gen < genCount; gen++) {
- // affine transformation for the current generation
- TAffine currentAff =
+ if (!param.doConical) {
+ TAffine parentOffsetAff = TTranslation(param.offsetTurbulence);
+ // accumulate base noise pattern for each generation
+ for (int gen = 0; gen < genCount; gen++) {
+ // affine transformation for the current generation
+ TAffine currentAff =
(globalAff * parentOffsetAff * parentAff * genAff).inv();
- // scale of the current pattern ( used for the Dynamic / Dynamic Twist
- // offset )
- double scale = sqrt(std::abs(currentAff.det()));
-
- // for each pixel
- double *buf_p = work_buf;
- for (int y = 0; y < outDim.ly; y++) {
- for (int x = 0; x < outDim.lx; x++, buf_p++) {
- // obtain sampling position
- // For Dynamic and Dynamic Twist patterns, the position offsets using
- // gradient / rotation of the parent pattern
- TPointD samplePos =
+ // scale of the current pattern ( used for the Dynamic / Dynamic Twist
+ // offset )
+ double scale = sqrt(std::abs(currentAff.det()));
+ // for each pixel
+ double* buf_p = work_buf;
+ for (int y = 0; y < outDim.ly; y++) {
+ for (int x = 0; x < outDim.lx; x++, buf_p++) {
+ // obtain sampling position
+ // For Dynamic and Dynamic Twist patterns, the position offsets using
+ // gradient / rotation of the parent pattern
+ TPointD samplePos =
getSamplePos(x, y, outDim, out_buf, gen, scale, param);
- // multiply affine transformation
- samplePos = currentAff * samplePos;
- // adjust position for the block pattern
- if (param.noiseType == Block)
- samplePos = TPointD(std::floor(samplePos.x) + 0.5,
- std::floor(samplePos.y) + 0.5);
- // calculate the base noise
- if (param.cycleEvolution)
- *buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_zw.x,
- evolution_zw.y) +
- 1.0) *
- 0.5;
- else
- *buf_p =
- (pn.noise(samplePos.x, samplePos.y, evolution_z) + 1.0) * 0.5;
-
- // convert the noise
- convert(buf_p, param);
+ // multiply affine transformation
+ samplePos = currentAff * samplePos;
+ // adjust position for the block pattern
+ if (param.noiseType == Block)
+ samplePos = TPointD(std::floor(samplePos.x) + 0.5,
+ std::floor(samplePos.y) + 0.5);
+ // calculate the base noise
+ if (param.cycleEvolution)
+ *buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_zw.x,
+ evolution_zw.y) +
+ 1.0) *
+ 0.5;
+ else
+ *buf_p =
+ (pn.noise(samplePos.x, samplePos.y, evolution_z) + 1.0) * 0.5;
+
+ // convert the noise
+ convert(buf_p, param);
+ }
}
- }
- // just copy the values for the first generation
- if (gen == 0) {
- memcpy(out_buf, work_buf, outDim.lx * outDim.ly * sizeof(double));
- } else {
- // intensity of the last generation will take the fraction part of
- // complexity
- double genIntensity = std::min(1.0, param.complexity - (double)gen);
- // influence of the current generation
- double influence =
+ // just copy the values for the first generation
+ if (gen == 0) {
+ memcpy(out_buf, work_buf, outDim.lx * outDim.ly * sizeof(double));
+ }
+ else {
+ // intensity of the last generation will take the fraction part of
+ // complexity
+ double genIntensity = std::min(1.0, param.complexity - (double)gen);
+ // influence of the current generation
+ double influence =
genIntensity * std::pow(param.subInfluence, (double)gen);
- // composite the base noise pattern
- buf_p = work_buf;
- double *out_p = out_buf;
- for (int i = 0; i < outDim.lx * outDim.ly; i++, buf_p++, out_p++)
- composite(out_p, buf_p, influence, param);
+ // composite the base noise pattern
+ buf_p = work_buf;
+ double* out_p = out_buf;
+ for (int i = 0; i < outDim.lx * outDim.ly; i++, buf_p++, out_p++)
+ composite(out_p, buf_p, influence, param);
+ }
+
+ // update affine transformations (for the next generation loop)
+ genAff *= subAff;
+ // When the "Perspective Offset" option is ON, reduce the offset amount
+ // according to the sub scale
+ if (param.perspectiveOffset)
+ parentOffsetAff = TScale(param.subScaling) *
+ TRotation(-param.subRotation) * parentOffsetAff *
+ TRotation(param.subRotation) *
+ TScale(1 / param.subScaling);
+
+ if (param.cycleEvolution)
+ evolution_zw.x += evolutionOffsetStep;
+ else
+ evolution_z += evolutionOffsetStep;
}
+ }
+
+ // conical noise
+ else {
+ // angle of slope of the cone
+ double theta_n = param.conicalAngle * M_PI_180;
+ // half of the vertical fov
+ double phi_2 = param.cameraFov * 0.5 * M_PI_180;
+ double z_scale = std::pow(10.0, param.zScale);
+ double evolution_w = param.conicalEvolution;
+
+ // pixel distance between camera and the screen
+ double D = ri.m_cameraBox.getLy() * 0.5 / std::tan(phi_2);
+ // the line on the slope : d = U * z + V
+ double U = -1.0 / std::tan(theta_n);
+ double V = ri.m_cameraBox.getLy() * 0.5;
+
+ TPointD center = ri.m_affine * param.offsetTurbulence;
+
+ // accumulate base noise pattern for each generation
+ for (int gen = 0; gen < genCount; gen++) {
+ // affine transformation for the current generation
+ TAffine currentAff =
+ (globalAff * parentAff * genAff).inv();
+ // scale of the current pattern ( used for the Dynamic / Dynamic Twist
+ // offset )
+ double scale = sqrt(std::abs(currentAff.det()));
+
+ // for each pixel
+ double* buf_p = work_buf;
+ for (int y = 0; y < outDim.ly; y++) {
+ for (int x = 0; x < outDim.lx; x++, buf_p++) {
+
+ double dx, dy, dz;
+ if (theta_n == 0.0) {
+ dx = x;
+ dy = y;
+ dz = 0.0;
+ }
+ else {
+ // conical, without offset
+ if (center == TPointD()) {
+ TPointD p = TTranslation(tile.m_pos) * TPointD(x, y);
+ // pixel distance from the screen center
+ double d = tdistance(p, TPointD());
+ // line of sight : d = S * z + T
+ double S = d / D;
+ double T = d;
+ dz = (V - T) / (S - U);
+ double dp = S * dz + T;
+ if (d != 0.0) {
+ p.x *= dp / d;
+ p.y *= dp / d;
+ }
+ p += center * (dp / V);
+ p = TTranslation(tile.m_pos).inv() * p;
+ dx = p.x;
+ dy = p.y;
+ dz /= z_scale;
+ }
+ // conical, with offset
+ else {
+ // compute the intersecting point between the "noise cone" and the line of sight
+ TPointD _p = TTranslation(tile.m_pos) * TPointD(x, y);
+ QVector3D p(_p.x, _p.y, 0.0);
+ QVector3D eye_O(center.x, center.y, -D);
+ QVector3D eye_d = (p - eye_O).normalized();
+ QVector3D cone_C(0.0, 0.0, V * std::tan(theta_n));
+ QVector3D cone_a(0, 0, -1);
+ double cos_ConeT = std::sin(theta_n);
+
+ float d_a = QVector3D::dotProduct(eye_d, cone_a);
+ float Ca_Oa = QVector3D::dotProduct(cone_C, cone_a) - QVector3D::dotProduct(eye_O, cone_a);
+
+ // A * t^2 + B * t + C = 0
+ float A = d_a * d_a - eye_d.lengthSquared() * cos_ConeT;
+ float B = 2.0 * (QVector3D::dotProduct(eye_d, cone_C) - QVector3D::dotProduct(eye_d, eye_O)) * cos_ConeT * cos_ConeT
+ - 2.0 * Ca_Oa * d_a;
+ float C = Ca_Oa * Ca_Oa
+ - cos_ConeT * cos_ConeT * (cone_C.lengthSquared() - 2.0 * QVector3D::dotProduct(eye_O, cone_C) + eye_O.lengthSquared());
+
+ // obtain t
+ double t1 = (-B + std::sqrt(B * B - 4.0 * A * C)) / (2.0 * A);
+ double t2 = (-B - std::sqrt(B * B - 4.0 * A * C)) / (2.0 * A);
+ if (t1 < 0) t1 = t2;
+ else if (t2 < 0) t2 = t1;
+ double t = std::min(t1, t2);
+
+ // intersecting point
+ QVector3D sampleP = eye_O + eye_d * t;
+ _p.x = sampleP.x();
+ _p.y = sampleP.y();
+ _p = TTranslation(tile.m_pos).inv() * _p;
+ dx = _p.x;
+ dy = _p.y;
+ dz = sampleP.z() / z_scale;
+ }
+ if (param.cycleEvolution) {
+ double cycle_theta = 2.0 * M_PI * (param.evolution + param.conicalEvolution + dz) / param.cycleEvolutionRange;
+ double cycle_d = param.cycleEvolutionRange / (2.0 * M_PI);
+ evolution_zw.x = cycle_d * cos(cycle_theta);
+ evolution_zw.y = cycle_d * sin(cycle_theta);
+ }
+ }
+ // obtain sampling position
+ // For Dynamic and Dynamic Twist patterns, the position offsets using
+ // gradient / rotation of the parent pattern
+ TPointD samplePos =
+ getSamplePos(dx, dy, outDim, out_buf, gen, scale, param);
+ // multiply affine transformation
+ samplePos = currentAff * samplePos;
+ // adjust position for the block pattern
+ if (param.noiseType == Block)
+ samplePos = TPointD(std::floor(samplePos.x) + 0.5,
+ std::floor(samplePos.y) + 0.5);
+ // calculate the base noise
+ if (param.cycleEvolution)
+ *buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_zw.x,
+ evolution_zw.y) +
+ 1.0) *
+ 0.5;
+ else
+ *buf_p =
+ (pn.noise(samplePos.x, samplePos.y, evolution_z, evolution_w + dz) + 1.0) * 0.5;
+
+ // convert the noise
+ convert(buf_p, param);
+ }
+ }
- // update affine transformations (for the next generation loop)
- genAff *= subAff;
- // When the "Perspective Offset" option is ON, reduce the offset amount
- // according to the sub scale
- if (param.perspectiveOffset)
- parentOffsetAff = TScale(param.subScaling) *
- TRotation(-param.subRotation) * parentOffsetAff *
- TRotation(param.subRotation) *
- TScale(1 / param.subScaling);
-
- if (param.cycleEvolution)
- evolution_zw.x += evolutionOffsetStep;
- else
- evolution_z += evolutionOffsetStep;
+ // just copy the values for the first generation
+ if (gen == 0) {
+ memcpy(out_buf, work_buf, outDim.lx * outDim.ly * sizeof(double));
+ }
+ else {
+ // intensity of the last generation will take the fraction part of
+ // complexity
+ double genIntensity = std::min(1.0, param.complexity - (double)gen);
+ // influence of the current generation
+ double influence =
+ genIntensity * std::pow(param.subInfluence, (double)gen);
+ // composite the base noise pattern
+ buf_p = work_buf;
+ double* out_p = out_buf;
+ for (int i = 0; i < outDim.lx * outDim.ly; i++, buf_p++, out_p++)
+ composite(out_p, buf_p, influence, param);
+ }
+
+ // update affine transformations (for the next generation loop)
+ genAff *= subAff;
+
+ if (param.cycleEvolution)
+ evolution_zw.x += evolutionOffsetStep;
+ else {
+ evolution_z += evolutionOffsetStep;
+ evolution_w += evolutionOffsetStepW;
+ }
+ }
}
+
work_buf_ras->unlock();
// finalize pattern (coverting the color space)
@@ -302,6 +482,13 @@ void Iwa_FractalNoiseFx::obtainParams(FNParam ¶m, const double frame,
param.cycleEvolution = m_cycleEvolution->getValue();
param.cycleEvolutionRange = m_cycleEvolutionRange->getValue(frame);
param.dynamicIntensity = m_dynamicIntensity->getValue(frame) * 10.0;
+
+ param.doConical = m_doConical->getValue();
+ param.conicalEvolution = m_conicalEvolution->getValue(frame);
+ param.conicalAngle = m_conicalAngle->getValue(frame);
+ param.cameraFov = m_cameraFov->getValue(frame);
+ param.zScale = m_zScale->getValue(frame);
+
param.alphaRendering = m_alphaRendering->getValue();
}
@@ -342,43 +529,56 @@ void Iwa_FractalNoiseFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
//------------------------------------------------------------------
// For Dynamic and Dynamic Twist patterns, the position offsets using gradient /
// rotation of the parent pattern
-TPointD Iwa_FractalNoiseFx::getSamplePos(int x, int y, const TDimension outDim,
+TPointD Iwa_FractalNoiseFx::getSamplePos(double x, double y, const TDimension outDim,
const double *out_buf, const int gen,
const double scale,
const FNParam ¶m) {
// the position does not offset in the first generation
if (gen == 0 || param.dynamicIntensity == 0.0 ||
(param.fractalType != Dynamic && param.fractalType != DynamicTwist))
- return TPointD((double)x, (double)y);
-
- auto clampPos = [&](int x, int y) {
- if (x < 0)
- x = 0;
- else if (x >= outDim.lx)
- x = outDim.lx - 1;
- if (y < 0)
- y = 0;
- else if (y >= outDim.ly)
- y = outDim.ly - 1;
- return TPoint(x, y);
+ return TPointD(x, y);
+
+ auto clampPos = [&](double x, double y) {
+ if (x < 0.0)
+ x = 0.0;
+ else if (x > (double)(outDim.lx-1))
+ x = (double)(outDim.lx - 1);
+ if (y < 0.0)
+ y = 0.0;
+ else if (y > (double)(outDim.ly-1))
+ y = (double)(outDim.ly - 1);
+ return TPointD(x, y);
};
- auto val = [&](const TPoint &p) { return out_buf[p.y * outDim.lx + p.x]; };
+ auto val = [&](const TPoint& p) {
+ return out_buf[std::min(p.y, outDim.ly - 1) * outDim.lx + std::min(p.x, outDim.lx - 1)];
+ };
+ auto lerp = [](double v0, double v1, double ratio) {
+ return (1.0 - ratio) * v0 + ratio * v1;
+ };
+ auto lerpVal = [&](const TPointD &p) {
+ int id_x = (int)std::floor(p.x);
+ double ratio_x = p.x - (double)id_x;
+ int id_y = (int)std::floor(p.y);
+ double ratio_y = p.y - (double)id_y;
+ return lerp ( lerp(val(TPoint(id_x, id_y)), val(TPoint(id_x+1, id_y)), ratio_x),
+ lerp(val(TPoint(id_x, id_y+1)), val(TPoint(id_x + 1, id_y+1)), ratio_x), ratio_y);
+ };
int range = std::max(2, (int)(0.1 / scale));
- TPoint left = clampPos(x - range, y);
- TPoint right = clampPos(x + range, y);
- TPoint down = clampPos(x, y - range);
- TPoint up = clampPos(x, y + range);
+ TPointD left = clampPos(x - range, y);
+ TPointD right = clampPos(x + range, y);
+ TPointD down = clampPos(x, y - range);
+ TPointD up = clampPos(x, y + range);
double dif_x = param.dynamicIntensity * (1 / scale) *
- (val(left) - val(right)) / (left.x - right.x);
- double dif_y = param.dynamicIntensity * (1 / scale) * (val(up) - val(down)) /
+ (lerpVal(left) - lerpVal(right)) / (left.x - right.x);
+ double dif_y = param.dynamicIntensity * (1 / scale) * (lerpVal(up) - lerpVal(down)) /
(up.y - down.y);
if (param.fractalType == Dynamic)
- return TPointD((double)x + dif_x, (double)y + dif_y); // gradient
+ return TPointD(x + dif_x, y + dif_y); // gradient
else // Dynamic_twist
- return TPointD((double)x + dif_y, (double)y - dif_x); // rotation
+ return TPointD(x + dif_y, y - dif_x); // rotation
}
//------------------------------------------------------------------
diff --git a/toonz/sources/stdfx/iwa_fractalnoisefx.h b/toonz/sources/stdfx/iwa_fractalnoisefx.h
index d0b2642..652fa18 100644
--- a/toonz/sources/stdfx/iwa_fractalnoisefx.h
+++ b/toonz/sources/stdfx/iwa_fractalnoisefx.h
@@ -46,6 +46,13 @@ class Iwa_FractalNoiseFx final : public TStandardZeraryFx {
bool cycleEvolution;
double cycleEvolutionRange;
double dynamicIntensity;
+
+ bool doConical;
+ double conicalEvolution;
+ double conicalAngle;
+ double cameraFov;
+ double zScale;
+
bool alphaRendering;
};
@@ -106,6 +113,13 @@ protected:
// �_�C�i�~�b�N�̓x����
TDoubleParamP m_dynamicIntensity;
+ //- - - Conical Noise - - -
+ TBoolParamP m_doConical;
+ TDoubleParamP m_conicalEvolution;
+ TDoubleParamP m_conicalAngle;
+ TDoubleParamP m_cameraFov;
+ TDoubleParamP m_zScale;
+
// - - - additional parameters - - -
TBoolParamP m_alphaRendering;
@@ -127,7 +141,7 @@ public:
// For Dynamic and Dynamic Twist patterns, the position offsets using gradient
// / rotation of the parent pattern
- TPointD getSamplePos(int x, int y, const TDimension outDim,
+ TPointD getSamplePos(double x, double y, const TDimension outDim,
const double *out_buf, const int gen, const double scale,
const FNParam ¶m);
// convert the noise