|
shun-iwasawa |
a23340 |
#include "iwa_fractalnoisefx.h"
|
|
shun-iwasawa |
a23340 |
#include "iwa_noise1234.h"
|
|
shun-iwasawa |
a23340 |
#include "tparamuiconcept.h"
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
f9c294 |
#include <qvector3d></qvector3d>
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
a23340 |
namespace {
|
|
shun-iwasawa |
a23340 |
// convert sRGB color space to power space
|
|
shun-iwasawa |
a23340 |
template <typename t="double"></typename>
|
|
shun-iwasawa |
a23340 |
inline T to_linear_color_space(T nonlinear_color, T exposure, T gamma) {
|
|
shun-iwasawa |
a23340 |
// return -std::log(T(1) - std::pow(nonlinear_color, gamma)) / exposure;
|
|
shun-iwasawa |
481b59 |
if (nonlinear_color <= T(0)) return T(0);
|
|
shun-iwasawa |
a23340 |
return std::pow(nonlinear_color, gamma) / exposure;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
// convert power space to sRGB color space
|
|
shun-iwasawa |
a23340 |
template <typename t="double"></typename>
|
|
shun-iwasawa |
a23340 |
inline T to_nonlinear_color_space(T linear_color, T exposure, T gamma) {
|
|
shun-iwasawa |
a23340 |
// return std::pow(T(1) - std::exp(-exposure * linear_color), T(1) / gamma);
|
|
shun-iwasawa |
481b59 |
if (linear_color <= T(0)) return T(0);
|
|
shun-iwasawa |
a23340 |
return std::pow(exposure * linear_color, T(1) / gamma);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
inline double hardlight(const double *dn, const double *up) {
|
|
shun-iwasawa |
a23340 |
if ((*up) < 0.5)
|
|
shun-iwasawa |
a23340 |
return (*up) * (*dn) * 2.0;
|
|
shun-iwasawa |
a23340 |
else
|
|
shun-iwasawa |
a23340 |
return 1.0 - 2.0 * (1.0 - (*up)) * (1.0 - (*dn));
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
template <class t="double"></class>
|
|
shun-iwasawa |
a23340 |
inline const T &clamp(const T &v, const T &lo, const T &hi) {
|
|
shun-iwasawa |
a23340 |
assert(!(hi < lo));
|
|
shun-iwasawa |
a23340 |
return (v < lo) ? lo : (hi < v) ? hi : v;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
const double turbulentGamma = 2.2;
|
|
shun-iwasawa |
a23340 |
// magic number to offset evolution between generations
|
|
shun-iwasawa |
507240 |
const double evolutionOffsetStep = 19.82;
|
|
shun-iwasawa |
f9c294 |
const double evolutionOffsetStepW = 31.1;
|
|
shun-iwasawa |
a23340 |
} // namespace
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
Iwa_FractalNoiseFx::Iwa_FractalNoiseFx()
|
|
shun-iwasawa |
a23340 |
: m_fractalType(new TIntEnumParam(Basic, "Basic"))
|
|
shun-iwasawa |
a23340 |
, m_noiseType(new TIntEnumParam(Block, "Block"))
|
|
shun-iwasawa |
a23340 |
, m_invert(false)
|
|
shun-iwasawa |
a23340 |
, m_rotation(0.0)
|
|
shun-iwasawa |
a23340 |
, m_uniformScaling(true)
|
|
shun-iwasawa |
a23340 |
, m_scale(100.0)
|
|
shun-iwasawa |
a23340 |
, m_scaleW(100.0)
|
|
shun-iwasawa |
a23340 |
, m_scaleH(100.0)
|
|
shun-iwasawa |
a23340 |
, m_offsetTurbulence(TPointD(0.0, 0.0))
|
|
shun-iwasawa |
a23340 |
, m_perspectiveOffset(false)
|
|
shun-iwasawa |
a23340 |
, m_complexity(6.0)
|
|
shun-iwasawa |
a23340 |
, m_subInfluence(70.0)
|
|
shun-iwasawa |
a23340 |
, m_subScaling(56.0)
|
|
shun-iwasawa |
a23340 |
, m_subRotation(0.0)
|
|
shun-iwasawa |
a23340 |
, m_subOffset(TPointD(0.0, 0.0))
|
|
shun-iwasawa |
a23340 |
///, m_centerSubscale(false)
|
|
shun-iwasawa |
a23340 |
, m_evolution(0.0)
|
|
shun-iwasawa |
a23340 |
, m_cycleEvolution(false)
|
|
shun-iwasawa |
a23340 |
, m_cycleEvolutionRange(1.0)
|
|
shun-iwasawa |
a23340 |
///, m_randomSeed(0)
|
|
shun-iwasawa |
a23340 |
, m_dynamicIntensity(1.0)
|
|
shun-iwasawa |
f9c294 |
, m_alphaRendering(false)
|
|
shun-iwasawa |
507240 |
, m_doConical(false)
|
|
shun-iwasawa |
507240 |
, m_conicalEvolution(0.0)
|
|
shun-iwasawa |
507240 |
, m_conicalAngle(60.0)
|
|
shun-iwasawa |
507240 |
, m_cameraFov(60.0)
|
|
shun-iwasawa |
507240 |
, m_zScale(2.0) {
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(TurbulentSmooth, "Turbulent Smooth");
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(TurbulentBasic, "Turbulent Basic");
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(TurbulentSharp, "Turbulent Sharp");
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(Dynamic, "Dynamic");
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(DynamicTwist, "Dynamic Twist");
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(Max, "Max");
|
|
shun-iwasawa |
a23340 |
m_fractalType->addItem(Rocky, "Rocky");
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
m_noiseType->addItem(Smooth, "Smooth");
|
|
shun-iwasawa |
a23340 |
m_noiseType->setValue(Smooth);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
m_rotation->setMeasureName("angle");
|
|
shun-iwasawa |
a23340 |
m_rotation->setValueRange(-360.0, 360.0);
|
|
shun-iwasawa |
a23340 |
m_scale->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
m_scale->setValueRange(20.0, 600.0);
|
|
shun-iwasawa |
a23340 |
m_scaleW->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
m_scaleW->setValueRange(20.0, 600.0);
|
|
shun-iwasawa |
a23340 |
m_scaleH->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
m_scaleH->setValueRange(20.0, 600.0);
|
|
shun-iwasawa |
a23340 |
m_offsetTurbulence->getX()->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
m_offsetTurbulence->getY()->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
m_complexity->setValueRange(1.0, 10.0);
|
|
shun-iwasawa |
a23340 |
m_subInfluence->setValueRange(25.0, 100.0);
|
|
shun-iwasawa |
a23340 |
m_subScaling->setValueRange(25.0, 100.0);
|
|
shun-iwasawa |
a23340 |
m_subRotation->setMeasureName("angle");
|
|
shun-iwasawa |
a23340 |
m_subRotation->setValueRange(-360.0, 360.0);
|
|
shun-iwasawa |
a23340 |
m_subOffset->getX()->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
m_subOffset->getY()->setMeasureName("fxLength");
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
m_evolution->setValueRange(-100.0, 100.0);
|
|
shun-iwasawa |
a23340 |
m_cycleEvolutionRange->setValueRange(0.1, 30.0);
|
|
shun-iwasawa |
a23340 |
m_dynamicIntensity->setValueRange(-10.0, 10.0);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
f9c294 |
m_conicalEvolution->setValueRange(-100, 100.0);
|
|
shun-iwasawa |
f9c294 |
m_conicalAngle->setValueRange(0.0, 89.9);
|
|
shun-iwasawa |
f9c294 |
m_cameraFov->setValueRange(10.0, 170.0);
|
|
shun-iwasawa |
f9c294 |
m_zScale->setValueRange(0.0, 3.0);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
a23340 |
bindParam(this, "fractalType", m_fractalType);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "noiseType", m_noiseType);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "invert", m_invert);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "rotation", m_rotation);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "uniformScaling", m_uniformScaling);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "scale", m_scale);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "scaleW", m_scaleW);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "scaleH", m_scaleH);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "offsetTurbulence", m_offsetTurbulence);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "perspectiveOffset", m_perspectiveOffset);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "complexity", m_complexity);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "subInfluence", m_subInfluence);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "subScaling", m_subScaling);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "subRotation", m_subRotation);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "subOffset", m_subOffset);
|
|
shun-iwasawa |
a23340 |
/// bindParam(this, "centerSubscale", m_centerSubscale);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "evolution", m_evolution);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "cycleEvolution", m_cycleEvolution);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "cycleEvolutionRange", m_cycleEvolutionRange);
|
|
shun-iwasawa |
a23340 |
/// bindParam(this, "randomSeed", m_randomSeed);
|
|
shun-iwasawa |
a23340 |
bindParam(this, "dynamicIntensity", m_dynamicIntensity);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
f9c294 |
bindParam(this, "doConical", m_doConical);
|
|
shun-iwasawa |
f9c294 |
bindParam(this, "conicalEvolution", m_conicalEvolution);
|
|
shun-iwasawa |
f9c294 |
bindParam(this, "conicalAngle", m_conicalAngle);
|
|
shun-iwasawa |
f9c294 |
bindParam(this, "cameraFov", m_cameraFov);
|
|
shun-iwasawa |
f9c294 |
bindParam(this, "zScale", m_zScale);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
a23340 |
bindParam(this, "alphaRendering", m_alphaRendering);
|
|
shun-iwasawa |
481b59 |
|
|
shun-iwasawa |
481b59 |
enableComputeInFloat(true);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
bool Iwa_FractalNoiseFx::doGetBBox(double frame, TRectD &bBox,
|
|
shun-iwasawa |
a23340 |
const TRenderSettings &ri) {
|
|
shun-iwasawa |
a23340 |
bBox = TConsts::infiniteRectD;
|
|
shun-iwasawa |
a23340 |
return true;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::doCompute(TTile &tile, double frame,
|
|
shun-iwasawa |
a23340 |
const TRenderSettings &ri) {
|
|
shun-iwasawa |
a23340 |
// obtain current parameters
|
|
shun-iwasawa |
a23340 |
FNParam param;
|
|
shun-iwasawa |
a23340 |
obtainParams(param, frame, ri.m_affine);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
Noise1234 pn;
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
TDimension outDim = tile.getRaster()->getSize();
|
|
shun-iwasawa |
a23340 |
// allocate buffer for accumulating the noise patterns
|
|
shun-iwasawa |
a23340 |
TRasterGR8P out_buf_ras = TRasterGR8P(outDim.lx * sizeof(double), outDim.ly);
|
|
shun-iwasawa |
a23340 |
out_buf_ras->clear();
|
|
shun-iwasawa |
a23340 |
out_buf_ras->lock();
|
|
shun-iwasawa |
a23340 |
double *out_buf = (double *)out_buf_ras->getRawData();
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
// allocate buffer for storing the noise pattern of each generation
|
|
shun-iwasawa |
a23340 |
TRasterGR8P work_buf_ras = TRasterGR8P(outDim.lx * sizeof(double), outDim.ly);
|
|
shun-iwasawa |
a23340 |
work_buf_ras->lock();
|
|
shun-iwasawa |
a23340 |
double *work_buf = (double *)work_buf_ras->getRawData();
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
// affine transformations
|
|
shun-iwasawa |
507240 |
TAffine globalAff = TTranslation(-tile.m_pos) * ri.m_affine;
|
|
shun-iwasawa |
a23340 |
TAffine parentAff =
|
|
shun-iwasawa |
a23340 |
TScale(param.scale.lx, param.scale.ly) * TRotation(-param.rotation);
|
|
shun-iwasawa |
a23340 |
TAffine subAff = TTranslation(param.subOffset) * TScale(param.subScaling) *
|
|
shun-iwasawa |
a23340 |
TRotation(-param.subRotation);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
TAffine genAff;
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
// for cyclic evolution, rotate the sample position in ZW space instead of
|
|
shun-iwasawa |
a23340 |
// using the periodic noise in Z space so that it can cycle in arbitral
|
|
shun-iwasawa |
a23340 |
// period.
|
|
shun-iwasawa |
a23340 |
double evolution_z = param.evolution;
|
|
shun-iwasawa |
a23340 |
TPointD evolution_zw;
|
|
shun-iwasawa |
a23340 |
if (param.cycleEvolution) {
|
|
shun-iwasawa |
a23340 |
double theta = 2.0 * M_PI * param.evolution / param.cycleEvolutionRange;
|
|
shun-iwasawa |
a23340 |
double d = param.cycleEvolutionRange / (2.0 * M_PI);
|
|
shun-iwasawa |
a23340 |
evolution_zw.x = d * cos(theta);
|
|
shun-iwasawa |
a23340 |
evolution_zw.y = d * sin(theta);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
int genCount = (int)std::ceil(param.complexity);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
f9c294 |
if (!param.doConical) {
|
|
shun-iwasawa |
f9c294 |
TAffine parentOffsetAff = TTranslation(param.offsetTurbulence);
|
|
shun-iwasawa |
f9c294 |
// accumulate base noise pattern for each generation
|
|
shun-iwasawa |
f9c294 |
for (int gen = 0; gen < genCount; gen++) {
|
|
shun-iwasawa |
f9c294 |
// affine transformation for the current generation
|
|
shun-iwasawa |
f9c294 |
TAffine currentAff =
|
|
shun-iwasawa |
507240 |
(globalAff * parentOffsetAff * parentAff * genAff).inv();
|
|
shun-iwasawa |
f9c294 |
// scale of the current pattern ( used for the Dynamic / Dynamic Twist
|
|
shun-iwasawa |
f9c294 |
// offset )
|
|
shun-iwasawa |
f9c294 |
double scale = sqrt(std::abs(currentAff.det()));
|
|
shun-iwasawa |
f9c294 |
// for each pixel
|
|
shun-iwasawa |
507240 |
double *buf_p = work_buf;
|
|
shun-iwasawa |
f9c294 |
for (int y = 0; y < outDim.ly; y++) {
|
|
shun-iwasawa |
f9c294 |
for (int x = 0; x < outDim.lx; x++, buf_p++) {
|
|
shun-iwasawa |
f9c294 |
// obtain sampling position
|
|
shun-iwasawa |
f9c294 |
// For Dynamic and Dynamic Twist patterns, the position offsets using
|
|
shun-iwasawa |
f9c294 |
// gradient / rotation of the parent pattern
|
|
shun-iwasawa |
f9c294 |
TPointD samplePos =
|
|
shun-iwasawa |
507240 |
getSamplePos(x, y, outDim, out_buf, gen, scale, param);
|
|
shun-iwasawa |
f9c294 |
// multiply affine transformation
|
|
shun-iwasawa |
f9c294 |
samplePos = currentAff * samplePos;
|
|
shun-iwasawa |
f9c294 |
// adjust position for the block pattern
|
|
shun-iwasawa |
f9c294 |
if (param.noiseType == Block)
|
|
shun-iwasawa |
f9c294 |
samplePos = TPointD(std::floor(samplePos.x) + 0.5,
|
|
shun-iwasawa |
507240 |
std::floor(samplePos.y) + 0.5);
|
|
shun-iwasawa |
f9c294 |
// calculate the base noise
|
|
shun-iwasawa |
f9c294 |
if (param.cycleEvolution)
|
|
shun-iwasawa |
f9c294 |
*buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_zw.x,
|
|
shun-iwasawa |
507240 |
evolution_zw.y) +
|
|
shun-iwasawa |
507240 |
1.0) *
|
|
shun-iwasawa |
507240 |
0.5;
|
|
shun-iwasawa |
f9c294 |
else
|
|
shun-iwasawa |
f9c294 |
*buf_p =
|
|
shun-iwasawa |
507240 |
(pn.noise(samplePos.x, samplePos.y, evolution_z) + 1.0) * 0.5;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// convert the noise
|
|
shun-iwasawa |
f9c294 |
convert(buf_p, param);
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
f9c294 |
// just copy the values for the first generation
|
|
shun-iwasawa |
f9c294 |
if (gen == 0) {
|
|
shun-iwasawa |
f9c294 |
memcpy(out_buf, work_buf, outDim.lx * outDim.ly * sizeof(double));
|
|
shun-iwasawa |
507240 |
} else {
|
|
shun-iwasawa |
f9c294 |
// intensity of the last generation will take the fraction part of
|
|
shun-iwasawa |
f9c294 |
// complexity
|
|
shun-iwasawa |
f9c294 |
double genIntensity = std::min(1.0, param.complexity - (double)gen);
|
|
shun-iwasawa |
f9c294 |
// influence of the current generation
|
|
shun-iwasawa |
f9c294 |
double influence =
|
|
shun-iwasawa |
507240 |
genIntensity * std::pow(param.subInfluence, (double)gen);
|
|
shun-iwasawa |
f9c294 |
// composite the base noise pattern
|
|
shun-iwasawa |
507240 |
buf_p = work_buf;
|
|
shun-iwasawa |
507240 |
double *out_p = out_buf;
|
|
shun-iwasawa |
f9c294 |
for (int i = 0; i < outDim.lx * outDim.ly; i++, buf_p++, out_p++)
|
|
shun-iwasawa |
f9c294 |
composite(out_p, buf_p, influence, param);
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// update affine transformations (for the next generation loop)
|
|
shun-iwasawa |
f9c294 |
genAff *= subAff;
|
|
shun-iwasawa |
f9c294 |
// When the "Perspective Offset" option is ON, reduce the offset amount
|
|
shun-iwasawa |
f9c294 |
// according to the sub scale
|
|
shun-iwasawa |
f9c294 |
if (param.perspectiveOffset)
|
|
shun-iwasawa |
f9c294 |
parentOffsetAff = TScale(param.subScaling) *
|
|
shun-iwasawa |
507240 |
TRotation(-param.subRotation) * parentOffsetAff *
|
|
shun-iwasawa |
507240 |
TRotation(param.subRotation) *
|
|
shun-iwasawa |
507240 |
TScale(1 / param.subScaling);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
if (param.cycleEvolution)
|
|
shun-iwasawa |
f9c294 |
evolution_zw.x += evolutionOffsetStep;
|
|
shun-iwasawa |
f9c294 |
else
|
|
shun-iwasawa |
f9c294 |
evolution_z += evolutionOffsetStep;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// conical noise
|
|
shun-iwasawa |
f9c294 |
else {
|
|
shun-iwasawa |
f9c294 |
// angle of slope of the cone
|
|
shun-iwasawa |
f9c294 |
double theta_n = param.conicalAngle * M_PI_180;
|
|
shun-iwasawa |
f9c294 |
// half of the vertical fov
|
|
shun-iwasawa |
507240 |
double phi_2 = param.cameraFov * 0.5 * M_PI_180;
|
|
shun-iwasawa |
507240 |
double z_scale = std::pow(10.0, param.zScale);
|
|
shun-iwasawa |
f9c294 |
double evolution_w = param.conicalEvolution;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// pixel distance between camera and the screen
|
|
shun-iwasawa |
f9c294 |
double D = ri.m_cameraBox.getLy() * 0.5 / std::tan(phi_2);
|
|
shun-iwasawa |
f9c294 |
// the line on the slope : d = U * z + V
|
|
shun-iwasawa |
f9c294 |
double U = -1.0 / std::tan(theta_n);
|
|
shun-iwasawa |
f9c294 |
double V = ri.m_cameraBox.getLy() * 0.5;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
TPointD center = ri.m_affine * param.offsetTurbulence;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// accumulate base noise pattern for each generation
|
|
shun-iwasawa |
f9c294 |
for (int gen = 0; gen < genCount; gen++) {
|
|
shun-iwasawa |
f9c294 |
// affine transformation for the current generation
|
|
shun-iwasawa |
507240 |
TAffine currentAff = (globalAff * parentAff * genAff).inv();
|
|
shun-iwasawa |
f9c294 |
// scale of the current pattern ( used for the Dynamic / Dynamic Twist
|
|
shun-iwasawa |
f9c294 |
// offset )
|
|
shun-iwasawa |
f9c294 |
double scale = sqrt(std::abs(currentAff.det()));
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// for each pixel
|
|
shun-iwasawa |
507240 |
double *buf_p = work_buf;
|
|
shun-iwasawa |
f9c294 |
for (int y = 0; y < outDim.ly; y++) {
|
|
shun-iwasawa |
f9c294 |
for (int x = 0; x < outDim.lx; x++, buf_p++) {
|
|
shun-iwasawa |
f9c294 |
double dx, dy, dz;
|
|
shun-iwasawa |
f9c294 |
if (theta_n == 0.0) {
|
|
shun-iwasawa |
f9c294 |
dx = x;
|
|
shun-iwasawa |
f9c294 |
dy = y;
|
|
shun-iwasawa |
f9c294 |
dz = 0.0;
|
|
shun-iwasawa |
507240 |
} else {
|
|
shun-iwasawa |
f9c294 |
// conical, without offset
|
|
shun-iwasawa |
f9c294 |
if (center == TPointD()) {
|
|
shun-iwasawa |
f9c294 |
TPointD p = TTranslation(tile.m_pos) * TPointD(x, y);
|
|
shun-iwasawa |
f9c294 |
// pixel distance from the screen center
|
|
shun-iwasawa |
f9c294 |
double d = tdistance(p, TPointD());
|
|
shun-iwasawa |
f9c294 |
// line of sight : d = S * z + T
|
|
shun-iwasawa |
507240 |
double S = d / D;
|
|
shun-iwasawa |
507240 |
double T = d;
|
|
shun-iwasawa |
507240 |
dz = (V - T) / (S - U);
|
|
shun-iwasawa |
f9c294 |
double dp = S * dz + T;
|
|
shun-iwasawa |
f9c294 |
if (d != 0.0) {
|
|
shun-iwasawa |
f9c294 |
p.x *= dp / d;
|
|
shun-iwasawa |
f9c294 |
p.y *= dp / d;
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
p += center * (dp / V);
|
|
shun-iwasawa |
507240 |
p = TTranslation(tile.m_pos).inv() * p;
|
|
shun-iwasawa |
f9c294 |
dx = p.x;
|
|
shun-iwasawa |
f9c294 |
dy = p.y;
|
|
shun-iwasawa |
f9c294 |
dz /= z_scale;
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
// conical, with offset
|
|
shun-iwasawa |
f9c294 |
else {
|
|
shun-iwasawa |
507240 |
// compute the intersecting point between the "noise cone" and the
|
|
shun-iwasawa |
507240 |
// line of sight
|
|
shun-iwasawa |
f9c294 |
TPointD _p = TTranslation(tile.m_pos) * TPointD(x, y);
|
|
shun-iwasawa |
507240 |
// offset by combination of offsets of A) projection position and
|
|
luz paz |
657132 |
// B) eye position.
|
|
shun-iwasawa |
507240 |
//
|
|
shun-iwasawa |
507240 |
// A) 0.5 * projection position offset
|
|
shun-iwasawa |
507240 |
QVector3D p(_p.x - center.x * 0.5, _p.y - center.y * 0.5, 0.0);
|
|
shun-iwasawa |
f9c294 |
QVector3D cone_C(0.0, 0.0, V * std::tan(theta_n));
|
|
shun-iwasawa |
f9c294 |
QVector3D cone_a(0, 0, -1);
|
|
shun-iwasawa |
507240 |
// B) 0.5 * eye position offset
|
|
shun-iwasawa |
507240 |
double offsetAdj = 0.5 * (D + cone_C.z()) / cone_C.z();
|
|
shun-iwasawa |
507240 |
QVector3D eye_O(center.x * offsetAdj, center.y * offsetAdj, -D);
|
|
shun-iwasawa |
507240 |
QVector3D eye_d = (p - eye_O).normalized();
|
|
shun-iwasawa |
f9c294 |
double cos_ConeT = std::sin(theta_n);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
507240 |
float d_a = QVector3D::dotProduct(eye_d, cone_a);
|
|
shun-iwasawa |
507240 |
float Ca_Oa = QVector3D::dotProduct(cone_C, cone_a) -
|
|
shun-iwasawa |
507240 |
QVector3D::dotProduct(eye_O, cone_a);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// A * t^2 + B * t + C = 0
|
|
shun-iwasawa |
507240 |
float A =
|
|
shun-iwasawa |
507240 |
d_a * d_a - eye_d.lengthSquared() * cos_ConeT * cos_ConeT;
|
|
shun-iwasawa |
507240 |
float B = 2.0 *
|
|
shun-iwasawa |
507240 |
(QVector3D::dotProduct(eye_d, cone_C) -
|
|
shun-iwasawa |
507240 |
QVector3D::dotProduct(eye_d, eye_O)) *
|
|
shun-iwasawa |
507240 |
cos_ConeT * cos_ConeT -
|
|
shun-iwasawa |
507240 |
2.0 * Ca_Oa * d_a;
|
|
shun-iwasawa |
507240 |
float C = Ca_Oa * Ca_Oa -
|
|
shun-iwasawa |
507240 |
cos_ConeT * cos_ConeT *
|
|
shun-iwasawa |
507240 |
(cone_C.lengthSquared() -
|
|
shun-iwasawa |
507240 |
2.0 * QVector3D::dotProduct(eye_O, cone_C) +
|
|
shun-iwasawa |
507240 |
eye_O.lengthSquared());
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// obtain t
|
|
shun-iwasawa |
f9c294 |
double t1 = (-B + std::sqrt(B * B - 4.0 * A * C)) / (2.0 * A);
|
|
shun-iwasawa |
f9c294 |
double t2 = (-B - std::sqrt(B * B - 4.0 * A * C)) / (2.0 * A);
|
|
shun-iwasawa |
507240 |
if (t1 < 0)
|
|
shun-iwasawa |
507240 |
t1 = t2;
|
|
shun-iwasawa |
507240 |
else if (t2 < 0)
|
|
shun-iwasawa |
507240 |
t2 = t1;
|
|
shun-iwasawa |
f9c294 |
double t = std::min(t1, t2);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// intersecting point
|
|
shun-iwasawa |
f9c294 |
QVector3D sampleP = eye_O + eye_d * t;
|
|
shun-iwasawa |
507240 |
_p.x = sampleP.x();
|
|
shun-iwasawa |
507240 |
_p.y = sampleP.y();
|
|
shun-iwasawa |
507240 |
_p = TTranslation(tile.m_pos).inv() * _p;
|
|
shun-iwasawa |
507240 |
dx = _p.x;
|
|
shun-iwasawa |
507240 |
dy = _p.y;
|
|
shun-iwasawa |
507240 |
dz = sampleP.z() / z_scale;
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
if (param.cycleEvolution) {
|
|
shun-iwasawa |
507240 |
double cycle_theta =
|
|
shun-iwasawa |
507240 |
2.0 * M_PI * (param.evolution + param.conicalEvolution + dz) /
|
|
shun-iwasawa |
507240 |
param.cycleEvolutionRange;
|
|
shun-iwasawa |
f9c294 |
double cycle_d = param.cycleEvolutionRange / (2.0 * M_PI);
|
|
shun-iwasawa |
f9c294 |
evolution_zw.x = cycle_d * cos(cycle_theta);
|
|
shun-iwasawa |
f9c294 |
evolution_zw.y = cycle_d * sin(cycle_theta);
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
// obtain sampling position
|
|
shun-iwasawa |
f9c294 |
// For Dynamic and Dynamic Twist patterns, the position offsets using
|
|
shun-iwasawa |
f9c294 |
// gradient / rotation of the parent pattern
|
|
shun-iwasawa |
8a7fcb |
TPointD samplePosOffset =
|
|
shun-iwasawa |
8a7fcb |
getSamplePos(x, y, outDim, out_buf, gen, scale, param) -
|
|
shun-iwasawa |
8a7fcb |
TPointD(x, y);
|
|
shun-iwasawa |
f9c294 |
TPointD samplePos =
|
|
shun-iwasawa |
8a7fcb |
TPointD(dx, dy) + samplePosOffset * (D / (D + dz));
|
|
shun-iwasawa |
f9c294 |
// multiply affine transformation
|
|
shun-iwasawa |
f9c294 |
samplePos = currentAff * samplePos;
|
|
shun-iwasawa |
f9c294 |
// adjust position for the block pattern
|
|
shun-iwasawa |
f9c294 |
if (param.noiseType == Block)
|
|
shun-iwasawa |
f9c294 |
samplePos = TPointD(std::floor(samplePos.x) + 0.5,
|
|
shun-iwasawa |
507240 |
std::floor(samplePos.y) + 0.5);
|
|
shun-iwasawa |
f9c294 |
// calculate the base noise
|
|
shun-iwasawa |
f9c294 |
if (param.cycleEvolution)
|
|
shun-iwasawa |
f9c294 |
*buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_zw.x,
|
|
shun-iwasawa |
507240 |
evolution_zw.y) +
|
|
shun-iwasawa |
507240 |
1.0) *
|
|
shun-iwasawa |
507240 |
0.5;
|
|
shun-iwasawa |
f9c294 |
else
|
|
shun-iwasawa |
507240 |
*buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_z,
|
|
shun-iwasawa |
507240 |
evolution_w + dz) +
|
|
shun-iwasawa |
507240 |
1.0) *
|
|
shun-iwasawa |
507240 |
0.5;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// convert the noise
|
|
shun-iwasawa |
f9c294 |
convert(buf_p, param);
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
f9c294 |
// just copy the values for the first generation
|
|
shun-iwasawa |
f9c294 |
if (gen == 0) {
|
|
shun-iwasawa |
f9c294 |
memcpy(out_buf, work_buf, outDim.lx * outDim.ly * sizeof(double));
|
|
shun-iwasawa |
507240 |
} else {
|
|
shun-iwasawa |
f9c294 |
// intensity of the last generation will take the fraction part of
|
|
shun-iwasawa |
f9c294 |
// complexity
|
|
shun-iwasawa |
f9c294 |
double genIntensity = std::min(1.0, param.complexity - (double)gen);
|
|
shun-iwasawa |
f9c294 |
// influence of the current generation
|
|
shun-iwasawa |
f9c294 |
double influence =
|
|
shun-iwasawa |
507240 |
genIntensity * std::pow(param.subInfluence, (double)gen);
|
|
shun-iwasawa |
f9c294 |
// composite the base noise pattern
|
|
shun-iwasawa |
507240 |
buf_p = work_buf;
|
|
shun-iwasawa |
507240 |
double *out_p = out_buf;
|
|
shun-iwasawa |
f9c294 |
for (int i = 0; i < outDim.lx * outDim.ly; i++, buf_p++, out_p++)
|
|
shun-iwasawa |
f9c294 |
composite(out_p, buf_p, influence, param);
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
// update affine transformations (for the next generation loop)
|
|
shun-iwasawa |
f9c294 |
genAff *= subAff;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
if (param.cycleEvolution)
|
|
shun-iwasawa |
f9c294 |
evolution_zw.x += evolutionOffsetStep;
|
|
shun-iwasawa |
f9c294 |
else {
|
|
shun-iwasawa |
f9c294 |
evolution_z += evolutionOffsetStep;
|
|
shun-iwasawa |
f9c294 |
evolution_w += evolutionOffsetStepW;
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
f9c294 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
work_buf_ras->unlock();
|
|
shun-iwasawa |
a23340 |
|
|
luz paz |
67b4e9 |
// finalize pattern (converting the color space)
|
|
shun-iwasawa |
a23340 |
if (param.fractalType == TurbulentSmooth ||
|
|
shun-iwasawa |
a23340 |
param.fractalType == TurbulentBasic ||
|
|
shun-iwasawa |
a23340 |
param.fractalType == TurbulentSharp) {
|
|
shun-iwasawa |
a23340 |
double *out_p = out_buf;
|
|
shun-iwasawa |
a23340 |
for (int i = 0; i < outDim.lx * outDim.ly; i++, out_p++)
|
|
shun-iwasawa |
a23340 |
finalize(out_p, param);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
tile.getRaster()->clear();
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
// convert to RGB channel values
|
|
shun-iwasawa |
a23340 |
TRaster32P ras32 = (TRaster32P)tile.getRaster();
|
|
shun-iwasawa |
a23340 |
TRaster64P ras64 = (TRaster64P)tile.getRaster();
|
|
shun-iwasawa |
481b59 |
TRasterFP rasF = (TRasterFP)tile.getRaster();
|
|
shun-iwasawa |
a23340 |
if (ras32)
|
|
shun-iwasawa |
a23340 |
outputRaster<traster32p, tpixel32="">(ras32, out_buf, param);</traster32p,>
|
|
shun-iwasawa |
a23340 |
else if (ras64)
|
|
shun-iwasawa |
a23340 |
outputRaster<traster64p, tpixel64="">(ras64, out_buf, param);</traster64p,>
|
|
shun-iwasawa |
481b59 |
else if (rasF)
|
|
shun-iwasawa |
481b59 |
outputRaster<trasterfp, tpixelf="">(rasF, out_buf, param);</trasterfp,>
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
out_buf_ras->unlock();
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
// obtain current parameters
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::obtainParams(FNParam ¶m, const double frame,
|
|
shun-iwasawa |
a23340 |
const TAffine &aff) {
|
|
shun-iwasawa |
a23340 |
param.fractalType = (FractalType)m_fractalType->getValue();
|
|
shun-iwasawa |
a23340 |
param.noiseType = (NoiseType)m_noiseType->getValue();
|
|
shun-iwasawa |
a23340 |
param.invert = m_invert->getValue();
|
|
shun-iwasawa |
a23340 |
param.rotation = m_rotation->getValue(frame); // in degree, not radian
|
|
shun-iwasawa |
a23340 |
if (m_uniformScaling->getValue()) { // uniform case
|
|
shun-iwasawa |
a23340 |
double s = m_scale->getValue(frame);
|
|
shun-iwasawa |
a23340 |
param.scale = TDimensionD(s, s);
|
|
shun-iwasawa |
a23340 |
} else { // non-uniform case
|
|
shun-iwasawa |
a23340 |
param.scale.lx = m_scaleW->getValue(frame);
|
|
shun-iwasawa |
a23340 |
param.scale.ly = m_scaleH->getValue(frame);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
assert(param.scale.lx != 0.0 && param.scale.ly != 0.0);
|
|
shun-iwasawa |
a23340 |
if (param.scale.lx == 0.0) param.scale.lx = 1e-8;
|
|
shun-iwasawa |
a23340 |
if (param.scale.ly == 0.0) param.scale.ly = 1e-8;
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
param.offsetTurbulence = m_offsetTurbulence->getValue(frame);
|
|
shun-iwasawa |
a23340 |
param.perspectiveOffset = m_perspectiveOffset->getValue();
|
|
shun-iwasawa |
a23340 |
param.complexity = m_complexity->getValue(frame);
|
|
shun-iwasawa |
a23340 |
if (param.complexity < 1.0)
|
|
shun-iwasawa |
a23340 |
param.complexity =
|
|
shun-iwasawa |
a23340 |
1.0; // at least the first generation is rendered in full opacity
|
|
shun-iwasawa |
a23340 |
param.subInfluence =
|
|
shun-iwasawa |
a23340 |
m_subInfluence->getValue(frame) / 100.0; // normalize to 0 - 1
|
|
shun-iwasawa |
a23340 |
param.subScaling =
|
|
shun-iwasawa |
a23340 |
m_subScaling->getValue(frame) / 100.0; // normalize to 0 - 1
|
|
shun-iwasawa |
a23340 |
param.subRotation = m_subRotation->getValue(frame); // in degree, not radian
|
|
shun-iwasawa |
a23340 |
param.subOffset = m_subOffset->getValue(frame);
|
|
shun-iwasawa |
a23340 |
param.evolution = m_evolution->getValue(frame);
|
|
shun-iwasawa |
a23340 |
param.cycleEvolution = m_cycleEvolution->getValue();
|
|
shun-iwasawa |
a23340 |
param.cycleEvolutionRange = m_cycleEvolutionRange->getValue(frame);
|
|
shun-iwasawa |
a23340 |
param.dynamicIntensity = m_dynamicIntensity->getValue(frame) * 10.0;
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
507240 |
param.doConical = m_doConical->getValue();
|
|
shun-iwasawa |
f9c294 |
param.conicalEvolution = m_conicalEvolution->getValue(frame);
|
|
shun-iwasawa |
507240 |
param.conicalAngle = m_conicalAngle->getValue(frame);
|
|
shun-iwasawa |
507240 |
param.cameraFov = m_cameraFov->getValue(frame);
|
|
shun-iwasawa |
507240 |
param.zScale = m_zScale->getValue(frame);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
507240 |
param.alphaRendering = m_alphaRendering->getValue();
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
template <typename pixel="" raster,="" typename=""></typename>
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::outputRaster(const RASTER outRas, double *out_buf,
|
|
shun-iwasawa |
a23340 |
const FNParam ¶m) {
|
|
shun-iwasawa |
a23340 |
TDimension dim = outRas->getSize();
|
|
shun-iwasawa |
a23340 |
double *buf_p = out_buf;
|
|
shun-iwasawa |
481b59 |
bool doClamp = !(outRas->getPixelSize() == 16);
|
|
shun-iwasawa |
a23340 |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
a23340 |
PIXEL *pix = outRas->pixels(j);
|
|
shun-iwasawa |
a23340 |
for (int i = 0; i < dim.lx; i++, pix++, buf_p++) {
|
|
shun-iwasawa |
481b59 |
double val = (param.invert) ? 1.0 - (*buf_p) : (*buf_p);
|
|
shun-iwasawa |
481b59 |
if (doClamp) val = clamp(val, 0.0, 1.0);
|
|
shun-iwasawa |
a23340 |
typename PIXEL::Channel chan = static_cast<typename pixel::channel="">(</typename>
|
|
shun-iwasawa |
a23340 |
val * (double)PIXEL::maxChannelValue);
|
|
shun-iwasawa |
a23340 |
pix->r = chan;
|
|
shun-iwasawa |
a23340 |
pix->g = chan;
|
|
shun-iwasawa |
a23340 |
pix->b = chan;
|
|
shun-iwasawa |
a23340 |
pix->m = (param.alphaRendering) ? chan : PIXEL::maxChannelValue;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
|
|
shun-iwasawa |
a23340 |
concepts = new TParamUIConcept[length = 2];
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
concepts[0].m_type = TParamUIConcept::POINT;
|
|
shun-iwasawa |
a23340 |
concepts[0].m_label = "Offset Turbulence";
|
|
shun-iwasawa |
a23340 |
concepts[0].m_params.push_back(m_offsetTurbulence);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
concepts[1].m_type = TParamUIConcept::POINT;
|
|
shun-iwasawa |
a23340 |
concepts[1].m_label = "Sub Offset";
|
|
shun-iwasawa |
a23340 |
concepts[1].m_params.push_back(m_subOffset);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
// For Dynamic and Dynamic Twist patterns, the position offsets using gradient /
|
|
shun-iwasawa |
a23340 |
// rotation of the parent pattern
|
|
shun-iwasawa |
507240 |
TPointD Iwa_FractalNoiseFx::getSamplePos(double x, double y,
|
|
shun-iwasawa |
507240 |
const TDimension outDim,
|
|
shun-iwasawa |
a23340 |
const double *out_buf, const int gen,
|
|
shun-iwasawa |
a23340 |
const double scale,
|
|
shun-iwasawa |
a23340 |
const FNParam ¶m) {
|
|
shun-iwasawa |
a23340 |
// the position does not offset in the first generation
|
|
shun-iwasawa |
a23340 |
if (gen == 0 || param.dynamicIntensity == 0.0 ||
|
|
shun-iwasawa |
a23340 |
(param.fractalType != Dynamic && param.fractalType != DynamicTwist))
|
|
shun-iwasawa |
f9c294 |
return TPointD(x, y);
|
|
shun-iwasawa |
f9c294 |
|
|
shun-iwasawa |
f9c294 |
auto clampPos = [&](double x, double y) {
|
|
shun-iwasawa |
f9c294 |
if (x < 0.0)
|
|
shun-iwasawa |
f9c294 |
x = 0.0;
|
|
shun-iwasawa |
507240 |
else if (x > (double)(outDim.lx - 1))
|
|
shun-iwasawa |
f9c294 |
x = (double)(outDim.lx - 1);
|
|
shun-iwasawa |
f9c294 |
if (y < 0.0)
|
|
shun-iwasawa |
f9c294 |
y = 0.0;
|
|
shun-iwasawa |
507240 |
else if (y > (double)(outDim.ly - 1))
|
|
shun-iwasawa |
f9c294 |
y = (double)(outDim.ly - 1);
|
|
shun-iwasawa |
f9c294 |
return TPointD(x, y);
|
|
shun-iwasawa |
a23340 |
};
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
507240 |
auto val = [&](const TPoint &p) {
|
|
shun-iwasawa |
507240 |
return out_buf[std::min(p.y, outDim.ly - 1) * outDim.lx +
|
|
shun-iwasawa |
507240 |
std::min(p.x, outDim.lx - 1)];
|
|
shun-iwasawa |
f9c294 |
};
|
|
shun-iwasawa |
f9c294 |
auto lerp = [](double v0, double v1, double ratio) {
|
|
shun-iwasawa |
f9c294 |
return (1.0 - ratio) * v0 + ratio * v1;
|
|
shun-iwasawa |
f9c294 |
};
|
|
shun-iwasawa |
507240 |
auto lerpVal = [&](const TPointD &p) {
|
|
shun-iwasawa |
507240 |
int id_x = (int)std::floor(p.x);
|
|
shun-iwasawa |
f9c294 |
double ratio_x = p.x - (double)id_x;
|
|
shun-iwasawa |
507240 |
int id_y = (int)std::floor(p.y);
|
|
shun-iwasawa |
f9c294 |
double ratio_y = p.y - (double)id_y;
|
|
shun-iwasawa |
507240 |
return lerp(
|
|
shun-iwasawa |
507240 |
lerp(val(TPoint(id_x, id_y)), val(TPoint(id_x + 1, id_y)), ratio_x),
|
|
shun-iwasawa |
507240 |
lerp(val(TPoint(id_x, id_y + 1)), val(TPoint(id_x + 1, id_y + 1)),
|
|
shun-iwasawa |
507240 |
ratio_x),
|
|
shun-iwasawa |
507240 |
ratio_y);
|
|
shun-iwasawa |
f9c294 |
};
|
|
shun-iwasawa |
507240 |
int range = std::max(2, (int)(0.1 / scale));
|
|
shun-iwasawa |
507240 |
TPointD left = clampPos(x - range, y);
|
|
shun-iwasawa |
f9c294 |
TPointD right = clampPos(x + range, y);
|
|
shun-iwasawa |
f9c294 |
TPointD down = clampPos(x, y - range);
|
|
shun-iwasawa |
f9c294 |
TPointD up = clampPos(x, y + range);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
double dif_x = param.dynamicIntensity * (1 / scale) *
|
|
shun-iwasawa |
f9c294 |
(lerpVal(left) - lerpVal(right)) / (left.x - right.x);
|
|
shun-iwasawa |
507240 |
double dif_y = param.dynamicIntensity * (1 / scale) *
|
|
shun-iwasawa |
507240 |
(lerpVal(up) - lerpVal(down)) / (up.y - down.y);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
if (param.fractalType == Dynamic)
|
|
shun-iwasawa |
f9c294 |
return TPointD(x + dif_x, y + dif_y); // gradient
|
|
shun-iwasawa |
507240 |
else // Dynamic_twist
|
|
shun-iwasawa |
f9c294 |
return TPointD(x + dif_y, y - dif_x); // rotation
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
// convert the noise
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::convert(double *buf, const FNParam ¶m) {
|
|
shun-iwasawa |
a23340 |
if (param.fractalType == Basic || param.fractalType == Dynamic ||
|
|
shun-iwasawa |
a23340 |
param.fractalType == DynamicTwist)
|
|
shun-iwasawa |
a23340 |
return;
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
switch (param.fractalType) {
|
|
shun-iwasawa |
a23340 |
case TurbulentSmooth:
|
|
shun-iwasawa |
a23340 |
*buf = std::pow(std::abs(*buf - 0.5), 2.0) * 3.75;
|
|
shun-iwasawa |
a23340 |
*buf = to_linear_color_space(*buf, 1.0, turbulentGamma);
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
case TurbulentBasic:
|
|
shun-iwasawa |
a23340 |
*buf = std::pow(std::abs(*buf - 0.5), 1.62) * 4.454;
|
|
shun-iwasawa |
a23340 |
*buf = to_linear_color_space(*buf, 1.0, turbulentGamma);
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
case TurbulentSharp:
|
|
shun-iwasawa |
a23340 |
*buf = std::pow(std::abs(*buf - 0.5), 0.725) * 1.77;
|
|
shun-iwasawa |
a23340 |
*buf = to_linear_color_space(*buf, 1.0, turbulentGamma);
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
case Max:
|
|
shun-iwasawa |
a23340 |
*buf = std::abs(*buf - 0.5) * 1.96;
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
case Rocky:
|
|
luz paz |
67b4e9 |
// conversion LUT for the range from 0.43 to 0.57, every 0.01
|
|
shun-iwasawa |
a23340 |
static double table[15] = {
|
|
shun-iwasawa |
a23340 |
0.25, 0.256658635, 0.275550218, 0.30569519, 0.345275591,
|
|
shun-iwasawa |
a23340 |
0.392513494, 0.440512, 0.5, 0.555085147, 0.607486506,
|
|
shun-iwasawa |
a23340 |
0.654724409, 0.69430481, 0.724449782, 0.743341365, 0.75};
|
|
shun-iwasawa |
a23340 |
if (*buf <= 0.43)
|
|
shun-iwasawa |
a23340 |
*buf = 0.25;
|
|
shun-iwasawa |
a23340 |
else if (*buf >= 0.57)
|
|
shun-iwasawa |
a23340 |
*buf = 0.75;
|
|
shun-iwasawa |
a23340 |
else {
|
|
shun-iwasawa |
a23340 |
int id = (int)std::floor(*buf * 100.0) - 43;
|
|
shun-iwasawa |
a23340 |
double t = *buf * 100.0 - (double)(id + 43);
|
|
shun-iwasawa |
a23340 |
// linear interpolation the LUT values
|
|
shun-iwasawa |
a23340 |
*buf = (1 - t) * table[id] + t * table[id + 1];
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a23340 |
// composite the base noise pattern
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::composite(double *out, double *buf,
|
|
shun-iwasawa |
a23340 |
const double influence,
|
|
shun-iwasawa |
a23340 |
const FNParam ¶m) {
|
|
shun-iwasawa |
a23340 |
switch (param.fractalType) {
|
|
shun-iwasawa |
a23340 |
case Basic:
|
|
shun-iwasawa |
a23340 |
case Dynamic:
|
|
shun-iwasawa |
a23340 |
case DynamicTwist:
|
|
shun-iwasawa |
a23340 |
case Rocky: {
|
|
shun-iwasawa |
a23340 |
// hard light composition
|
|
shun-iwasawa |
a23340 |
double val = hardlight(out, buf);
|
|
shun-iwasawa |
a23340 |
*out = (1.0 - influence) * (*out) + influence * val;
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
case TurbulentSmooth:
|
|
shun-iwasawa |
a23340 |
case TurbulentBasic:
|
|
shun-iwasawa |
a23340 |
case TurbulentSharp:
|
|
shun-iwasawa |
a23340 |
// add composition in the linear color space
|
|
shun-iwasawa |
a23340 |
*out += (*buf) * influence;
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
case Max:
|
|
shun-iwasawa |
a23340 |
// max composition
|
|
shun-iwasawa |
a23340 |
*out = std::max(*out, influence * (*buf));
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
default: {
|
|
shun-iwasawa |
a23340 |
double val = hardlight(out, buf);
|
|
shun-iwasawa |
a23340 |
*out = (1.0 - influence) * (*out) + influence * val;
|
|
shun-iwasawa |
a23340 |
break;
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
//------------------------------------------------------------------
|
|
luz paz |
67b4e9 |
// finalize pattern (converting the color space)
|
|
shun-iwasawa |
a23340 |
void Iwa_FractalNoiseFx::finalize(double *out, const FNParam ¶m) {
|
|
shun-iwasawa |
a23340 |
assert(param.fractalType == TurbulentSmooth ||
|
|
shun-iwasawa |
a23340 |
param.fractalType == TurbulentBasic ||
|
|
shun-iwasawa |
a23340 |
param.fractalType == TurbulentSharp);
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
// TurbulentSmooth / TurbulentBasic / TurbulentSharp
|
|
shun-iwasawa |
a23340 |
*out = to_nonlinear_color_space(*out, 1.0, turbulentGamma);
|
|
shun-iwasawa |
a23340 |
}
|
|
shun-iwasawa |
a23340 |
|
|
shun-iwasawa |
a23340 |
FX_PLUGIN_IDENTIFIER(Iwa_FractalNoiseFx, "iwa_FractalNoiseFx");
|