--User changes

-Add new Blur Cuve field which controls how blurring increases when moving from the center out.

--Bug fixes
 -Undo Y axis flipping from previous commit, it never worked and is not worth the effort.

--Code changes
 -The new field is a member of Ember and is called m_BlurCurve, and the corresponding xml field is called "blur_curve".
This commit is contained in:
Person 2020-01-18 22:29:08 -08:00
parent 8e6ba922af
commit 5f08e54bd4
20 changed files with 141 additions and 54 deletions

View File

@ -97,6 +97,10 @@ public:
m_PadCarLlY = T(carToRas.PadCarLlY());
m_PadCarUrX = T(carToRas.PadCarUrX());
m_PadCarUrY = T(carToRas.PadCarUrY());
m_CarHalfX = T(carToRas.CarHalfX());
m_CarHalfY = T(carToRas.CarHalfY());
m_CarCenterX = T(carToRas.CarCenterX());
m_CarCenterY = T(carToRas.CarCenterY());
return *this;
}
@ -126,12 +130,16 @@ public:
m_RasLlX = m_PixPerImageUnitW * carLlX;
m_PixPerImageUnitH = static_cast<T>(rasH) * invSizeH;
m_RasLlY = m_PixPerImageUnitH * carLlY;
m_OneRow = abs(m_CarUrY - m_CarLlY) / m_RasHeight;
m_OneCol = abs(m_CarUrX - m_CarLlX) / m_RasWidth;
m_OneRow = std::abs(m_CarUrY - m_CarLlY) / m_RasHeight;
m_OneCol = std::abs(m_CarUrX - m_CarLlX) / m_RasWidth;
m_PadCarLlX = m_CarLlX + m_OneCol;
m_PadCarUrX = m_CarUrX - m_OneCol;
m_PadCarLlY = m_CarLlY + m_OneRow;
m_PadCarUrY = m_CarUrY - m_OneRow;
m_CarHalfX = (m_CarUrX - m_CarLlX) / 2;
m_CarHalfY = (m_CarUrY - m_CarLlY) / 2;
m_CarCenterX = m_CarLlX + m_CarHalfX;
m_CarCenterY = m_CarLlY + m_CarHalfY;
}
/// <summary>
@ -227,6 +235,10 @@ public:
inline T PadCarLlY() const { return m_PadCarLlY; }
inline T PadCarUrX() const { return m_PadCarUrX; }
inline T PadCarUrY() const { return m_PadCarUrY; }
inline T CarHalfX() const { return m_CarHalfX; }
inline T CarHalfY() const { return m_CarHalfY; }
inline T CarCenterX() const { return m_CarCenterX; }
inline T CarCenterY() const { return m_CarCenterY; }
private:
size_t m_RasWidth, m_RasHeight;//The width and height of the raster image.
@ -238,5 +250,7 @@ private:
T m_RasLlY;//The lower left y of the raster image plane.
T m_CarLlX, m_CarLlY, m_CarUrX, m_CarUrY;//The bounds of the cartesian plane.
T m_PadCarLlX, m_PadCarLlY, m_PadCarUrX, m_PadCarUrY;//The bounds of the cartesian plane padded by one raster row and column on each side.
T m_CarHalfX, m_CarHalfY;//The distance from the center of the of the cartesian plane to the edges.
T m_CarCenterX, m_CarCenterY;//The center of the cartesian plane.
};
}

View File

@ -6,6 +6,8 @@
#include "SpatialFilter.h"
#include "TemporalFilter.h"
#include "EmberMotion.h"
#include "CarToRas.h"
#include "VarFuncs.h"
/// <summary>
/// Ember class.
@ -120,6 +122,7 @@ public:
m_CamYaw = T(ember.m_CamYaw);
m_CamPitch = T(ember.m_CamPitch);
m_CamDepthBlur = T(ember.m_CamDepthBlur);
m_BlurCurve = T(ember.m_BlurCurve);
m_CamMat = ember.m_CamMat;
m_CenterX = T(ember.m_CenterX);
m_CenterY = T(ember.m_CenterY);
@ -760,6 +763,7 @@ public:
InterpT<&Ember<T>::m_CamYaw>(embers, coefs, size);
InterpT<&Ember<T>::m_CamPitch>(embers, coefs, size);
InterpT<&Ember<T>::m_CamDepthBlur>(embers, coefs, size);
InterpT<&Ember<T>::m_BlurCurve>(embers, coefs, size);
InterpX<m3T, &Ember<T>::m_CamMat>(embers, coefs, size);
InterpT<&Ember<T>::m_CenterX>(embers, coefs, size);
InterpT<&Ember<T>::m_CenterY>(embers, coefs, size);
@ -1162,9 +1166,9 @@ public:
/// </summary>
/// <param name="point">The point to project</param>
/// <param name="rand">The Isaac object to pass to the projection functions</param>
inline void Proj(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
inline void Proj(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
(this->*m_ProjFunc)(point, rand);
(this->*m_ProjFunc)(point, rand, ctr);
}
/// <summary>
@ -1172,7 +1176,7 @@ public:
/// </summary>
/// <param name="point">Ignored</param>
/// <param name="rand">Ignored</param>
void ProjectNone(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
void ProjectNone(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
}
@ -1181,7 +1185,7 @@ public:
/// </summary>
/// <param name="point">The point to project</param>
/// <param name="rand">Ignored</param>
void ProjectZPerspective(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
void ProjectZPerspective(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
T zr = Zeps(1 - m_CamPerspective * (point.m_Z - m_CamZPos));
point.m_X /= zr;
@ -1194,7 +1198,7 @@ public:
/// </summary>
/// <param name="point">The point to project</param>
/// <param name="rand">Ignored</param>
void ProjectPitch(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
void ProjectPitch(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
T z = point.m_Z - m_CamZPos;
T y = m_CamMat[1][1] * point.m_Y + m_CamMat[2][1] * z;
@ -1209,7 +1213,7 @@ public:
/// </summary>
/// <param name="point">The point to project</param>
/// <param name="rand">Used for blurring</param>
void ProjectPitchDepthBlur(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
void ProjectPitchDepthBlur(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
T y, z, zr;
T dsin, dcos;
@ -1219,7 +1223,11 @@ public:
z = m_CamMat[1][2] * point.m_Y + m_CamMat[2][2] * z;
zr = Zeps(1 - m_CamPerspective * z);
sincos(t, &dsin, &dcos);
T dr = rand.Frand01<T>() * m_BlurCoef * z;
T prcx = (point.m_X - ctr.CarCenterX()) / ctr.CarHalfX();
T prcy = (y - ctr.CarCenterY()) / ctr.CarHalfY();
T dist = VarFuncs<T>::Hypot(prcx, prcy) * 10;
T scale = m_BlurCurve ? std::min<T>(T(1), Sqr(dist) / (4 * m_BlurCurve)) : T(1);
T dr = rand.Frand01<T>() * (m_BlurCoef * scale) * z;
point.m_X = (point.m_X + dr * dcos) / zr;
point.m_Y = (y + dr * dsin) / zr;
point.m_Z -= m_CamZPos;
@ -1230,7 +1238,7 @@ public:
/// </summary>
/// <param name="point">The point to project</param>
/// <param name="rand">Used for blurring</param>
void ProjectPitchYawDepthBlur(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
void ProjectPitchYawDepthBlur(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
T dsin, dcos;
T t = rand.Frand01<T>() * M_2PI;
@ -1239,7 +1247,11 @@ public:
T y = m_CamMat[0][1] * point.m_X + m_CamMat[1][1] * point.m_Y + m_CamMat[2][1] * z;
z = m_CamMat[0][2] * point.m_X + m_CamMat[1][2] * point.m_Y + m_CamMat[2][2] * z;
T zr = Zeps(1 - m_CamPerspective * z);
T dr = rand.Frand01<T>() * m_BlurCoef * z;
T prcx = (x - ctr.CarCenterX()) / ctr.CarHalfX();
T prcy = (y - ctr.CarCenterY()) / ctr.CarHalfY();
T dist = VarFuncs<T>::Hypot(prcx, prcy) * 10;
T scale = m_BlurCurve ? std::min<T>(T(1), Sqr(dist) / (4 * m_BlurCurve)) : T(1);
T dr = rand.Frand01<T>() * (m_BlurCoef * scale) * z;
sincos(t, &dsin, &dcos);
point.m_X = (x + dr * dcos) / zr;
point.m_Y = (y + dr * dsin) / zr;
@ -1251,7 +1263,7 @@ public:
/// </summary>
/// <param name="point">The point to project</param>
/// <param name="rand">Ignored</param>
void ProjectPitchYaw(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
void ProjectPitchYaw(Point<T>& point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, const CarToRas<T>& ctr)
{
T z = point.m_Z - m_CamZPos;
T x = m_CamMat[0][0] * point.m_X + m_CamMat[1][0] * point.m_Y;
@ -1356,6 +1368,10 @@ public:
APP_FMP(m_Vibrancy);
break;
case eEmberMotionParam::FLAME_MOTION_BLUR_CURVE:
APP_FMP(m_BlurCurve);
break;
case eEmberMotionParam::FLAME_MOTION_NONE:
default:
break;
@ -1403,6 +1419,7 @@ public:
m_CamYaw = 0;
m_CamPitch = 0;
m_CamDepthBlur = 0;
m_BlurCurve = 0;
m_BlurCoef = 0;
m_CamMat = m3T(0);
m_Quality = 1;
@ -1439,6 +1456,7 @@ public:
m_CamYaw = 999999;
m_CamPitch = 999999;
m_CamDepthBlur = 999999;
m_BlurCurve = 999999;
m_BlurCoef = 999999;
m_CamMat = m3T(999999);
m_Quality = -1;
@ -1502,6 +1520,7 @@ public:
<< "Perspective: " << m_CamPerspective << "\n"
<< "Yaw: " << m_CamYaw << "\n"
<< "Pitch: " << m_CamPitch << "\n"
<< "Blur Curve: " << m_BlurCurve << "\n"
<< "Depth Blur: " << m_CamDepthBlur << "\n"
<< "CenterX: " << m_CenterX << "\n"
<< "CenterY: " << m_CenterY << "\n"
@ -1613,7 +1632,7 @@ public:
//3D fields.
private:
typedef void (Ember<T>::*ProjFuncPtr)(Point<T>&, QTIsaac<ISAAC_SIZE, ISAAC_INT>&);
typedef void (Ember<T>::*ProjFuncPtr)(Point<T>&, QTIsaac<ISAAC_SIZE, ISAAC_INT>&, const CarToRas<T>&);
ProjFuncPtr m_ProjFunc;
public:
@ -1632,6 +1651,9 @@ public:
//Xml field: "cam_dof".
T m_CamDepthBlur = 0;
//Xml field: "blur_curve".
T m_BlurCurve = 0;//Used as p in the equation x^2/4p.
private:
T m_BlurCoef = 0;

View File

@ -169,7 +169,8 @@ enum class eEmberMotionParam : et//These must remain in this order forever.
FLAME_MOTION_BACKGROUND_R,
FLAME_MOTION_BACKGROUND_G,
FLAME_MOTION_BACKGROUND_B,
FLAME_MOTION_VIBRANCY
FLAME_MOTION_VIBRANCY,
FLAME_MOTION_BLUR_CURVE
};
/// <summary>

View File

@ -159,6 +159,7 @@ string EmberToXml<T>::ToString(Ember<T>& ember, const string& extraAttributes, s
os << " cam_yaw=\"" << ember.m_CamYaw << "\"";
os << " cam_pitch=\"" << ember.m_CamPitch << "\"";
os << " cam_dof=\"" << ember.m_CamDepthBlur << "\"";
os << " blur_curve=\"" << ember.m_BlurCurve << "\"";
if (ember.m_PaletteMode == ePaletteMode::PALETTE_STEP)
os << " palette_mode=\"step\"";

View File

@ -15,7 +15,7 @@ namespace EmberNs
using Iterator<T>::NextXformFromIndex; \
using Iterator<T>::DoFinalXform; \
using Iterator<T>::DoBadVals;
template <typename T>
struct IterParams
{
@ -69,12 +69,12 @@ public:
/// Virtual empty iteration function that will be overidden in derived iterator classes.
/// </summary>
/// <param name="ember">The ember whose xforms will be applied</param>
/// <param name="count">The number of iterations to do</param>
/// <param name="skip">The number of times to fuse</param>
/// <param name="params">Structure holding number of iterations to do, and the number to fuse. This is passed by value on purpose.</param>
/// <param name="ctr">The cartesian to raster conversion structure which is used in some 3D projections</param>
/// <param name="samples">The buffer to store the output points</param>
/// <param name="rand">The random context to use</param>
/// <returns>The number of bad values</returns>
virtual size_t Iterate(Ember<T>& ember, IterParams<T>& params, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) { return 0; }
virtual size_t Iterate(Ember<T>& ember, const IterParams<T> params, const CarToRas<T>& ctr, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) { return 0; }
/// <summary>
/// Initialize the xform selection vector by normalizing the weights of all xforms and
@ -292,12 +292,12 @@ public:
/// Overridden virtual function which iterates an ember a given number of times and does not use xaos.
/// </summary>
/// <param name="ember">The ember whose xforms will be applied</param>
/// <param name="count">The number of iterations to do</param>
/// <param name="skip">The number of times to fuse</param>
/// <param name="params">Structure holding number of iterations to do, and the number to fuse. This is passed by value on purpose.</param>
/// <param name="ctr">The cartesian to raster conversion structure which is used in some 3D projections</param>
/// <param name="samples">The buffer to store the output points</param>
/// <param name="rand">The random context to use</param>
/// <returns>The number of bad values</returns>
virtual size_t Iterate(Ember<T>& ember, IterParams<T>& params, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
virtual size_t Iterate(Ember<T>& ember, const IterParams<T> params, const CarToRas<T>& ctr, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
size_t i, badVals = 0;
Point<T> tempPoint, p1;
@ -316,7 +316,7 @@ public:
}
DoFinalXform(ember, p1, samples, rand);//Apply to last fuse point and store as the first element in samples.
ember.Proj(samples[0], rand);
ember.Proj(samples[0], rand, ctr);
for (i = 1; i < params.m_Count; i++)//Real loop.
{
@ -324,7 +324,7 @@ public:
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
DoFinalXform(ember, p1, samples + i, rand);
ember.Proj(samples[i], rand);
ember.Proj(samples[i], rand, ctr);
}
}
else//No xaos, 3D, no final.
@ -338,7 +338,7 @@ public:
}
samples[0] = p1;
ember.Proj(samples[0], rand);
ember.Proj(samples[0], rand, ctr);
for (i = 1; i < params.m_Count; i++)//Real loop.
{
@ -346,7 +346,7 @@ public:
DoBadVals(xforms, ember.m_RandPointRange, badVals, samples + i, rand);
p1 = samples[i];
ember.Proj(samples[i], rand);
ember.Proj(samples[i], rand, ctr);
}
}
}
@ -458,12 +458,12 @@ public:
/// Overridden virtual function which iterates an ember a given number of times and uses xaos.
/// </summary>
/// <param name="ember">The ember whose xforms will be applied</param>
/// <param name="count">The number of iterations to do</param>
/// <param name="skip">The number of times to fuse</param>
/// <param name="params">Structure holding number of iterations to do, and the number to fuse. This is passed by value on purpose.</param>
/// <param name="ctr">The cartesian to raster conversion structure which is used in some 3D projections</param>
/// <param name="samples">The buffer to store the output points</param>
/// <param name="rand">The random context to use</param>
/// <returns>The number of bad values</returns>
virtual size_t Iterate(Ember<T>& ember, IterParams<T>& params, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
virtual size_t Iterate(Ember<T>& ember, const IterParams<T> params, const CarToRas<T>& ctr, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
size_t i, xformIndex;
size_t lastXformUsed = 0;
@ -488,7 +488,7 @@ public:
}
DoFinalXform(ember, p1, samples, rand);//Apply to last fuse point and store as the first element in samples.
ember.Proj(samples[0], rand);
ember.Proj(samples[0], rand, ctr);
for (i = 1; i < params.m_Count; i++)//Real loop.
{
@ -498,7 +498,7 @@ public:
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
DoFinalXform(ember, p1, samples + i, rand);
ember.Proj(samples[i], rand);
ember.Proj(samples[i], rand, ctr);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}
}
@ -517,7 +517,7 @@ public:
}
samples[0] = p1;
ember.Proj(samples[0], rand);
ember.Proj(samples[0], rand, ctr);
for (i = 1; i < params.m_Count; i++)//Real loop.
{
@ -527,7 +527,7 @@ public:
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
samples[i] = p1;
ember.Proj(samples[i], rand);
ember.Proj(samples[i], rand, ctr);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}
}

View File

@ -1301,7 +1301,7 @@ EmberStats Renderer<T, bucketT>::Iterate(size_t iterCount, size_t temporalSample
//Finally, iterate.
//t.Tic();
//Iterating, loop 3.
m_BadVals[threadIndex] += m_Iterator->Iterate(m_ThreadEmbers[threadIndex], params, m_Samples[threadIndex].data(), m_Rand[threadIndex]);
m_BadVals[threadIndex] += m_Iterator->Iterate(m_ThreadEmbers[threadIndex], params, m_CarToRas, m_Samples[threadIndex].data(), m_Rand[threadIndex]);
//iterationTime += t.Toc();
if (m_LockAccum)

View File

@ -1253,9 +1253,10 @@ public:
m_Samples.resize(samples);
params.m_Count = samples;
params.m_Skip = 20;
auto& ctr = m_Renderer->CoordMap();
//params.m_OneColDiv2 = m_Renderer->CoordMap().OneCol() / 2;
//params.m_OneRowDiv2 = m_Renderer->CoordMap().OneRow() / 2;
size_t bv = m_Iterator->Iterate(ember, params, m_Samples.data(), m_Rand);//Use a special fuse of 20, all other calls to this will use 15, or 100.
size_t bv = m_Iterator->Iterate(ember, params, ctr, m_Samples.data(), m_Rand);//Use a special fuse of 20, all other calls to this will use 15, or 100.
if (bv / T(samples) > eps)
eps = 3 * bv / T(samples);

View File

@ -708,21 +708,21 @@ public:
<< "\t\tif (" << smoothStyle << " > 1)\n"
<< "\t\t znxy = 1 - (" << smoothStyle << " * (1 - ((exnze + wynze) / 2 * " << smoothStyle << ")));\n"
<< "\t\telse\n"
<< "\t\t znxy = 1 - (" << smoothStyle << " * (1 - ((exnze + wynze) * (real_t)(0.5))));\n";
<< "\t\t znxy = 1 - (" << smoothStyle << " * (1 - ((exnze + wynze) * (real_t)(0.5))));\n\n";
if (m_VarType == eVariationType::VARTYPE_PRE)
{
ss <<
"\t\tpx = vIn.x;\n"
"\t\tpy = vIn.y;\n"
"\t\tpz = vIn.z;\n";
"\t\tpz = vIn.z;\n\n";
}
else
{
ss <<
"\t\tpx = outPoint->m_X;\n"
"\t\tpy = outPoint->m_Y;\n"
"\t\tpz = outPoint->m_Z;\n";
"\t\tpz = outPoint->m_Z;\n\n";
}
ss <<

View File

@ -1605,6 +1605,7 @@ bool XmlToEmber<T>::ParseEmberElement(xmlNode* emberNode, Ember<T>& currentEmber
else if (ParseAndAssign(curAtt->name, attStr, "cam_yaw", currentEmber.m_CamYaw, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "cam_pitch", currentEmber.m_CamPitch, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "cam_dof", currentEmber.m_CamDepthBlur, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "blur_curve", currentEmber.m_BlurCurve, ret)) {}
//Parse simple int reads.
else if (ParseAndAssign(curAtt->name, attStr, "palette", currentEmber.m_Palette.m_Index, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "oversample", currentEmber.m_Supersample, ret)) {}

View File

@ -205,6 +205,7 @@ struct ALIGN EmberCL
T m_CamPerspective;
T m_CamYaw;
T m_CamPitch;
T m_BlurCurve;
T m_CamDepthBlur;
T m_BlurCoef;
m3T m_CamMat;
@ -225,6 +226,7 @@ static const char* EmberCLStructString =
" real_t m_CamPerspective;\n"
" real_t m_CamYaw;\n"
" real_t m_CamPitch;\n"
" real_t m_BlurCurve;\n"
" real_t m_CamDepthBlur;\n"
" real_t m_BlurCoef;\n"
" real_t m_C00;\n"
@ -254,6 +256,7 @@ struct ALIGN CarToRasCL
uint m_RasWidth;
T m_PixPerImageUnitH, m_RasLlY;
T m_CarLlX, m_CarUrX, m_CarUrY, m_CarLlY;
T m_CarHalfX, m_CarHalfY, m_CarCenterX, m_CarCenterY;
};
/// <summary>
@ -266,6 +269,7 @@ static const char* CarToRasCLStructString =
" uint m_RasWidth;\n"
" real_t m_PixPerImageUnitH, m_RasLlY;\n"
" real_t m_CarLlX, m_CarUrX, m_CarUrY, m_CarLlY;\n"
" real_t m_CarHalfX, m_CarHalfY, m_CarCenterX, m_CarCenterY;\n"
"} CarToRasCL;\n"
"\n";

View File

@ -940,7 +940,11 @@ string IterOpenCLKernelCreator<T>::CreateProjectionString(const Ember<T>& ember)
" z = fma(ember->m_C02, secondPoint.m_X, fma(ember->m_C12, secondPoint.m_Y, ember->m_C22 * z));\n"
"\n"
" real_t zr = Zeps(1 - ember->m_CamPerspective * z);\n"
" real_t dr = MwcNext01(&mwc) * ember->m_BlurCoef * z;\n"
" real_t prcx = (x - carToRas->m_CarCenterX) / carToRas->m_CarHalfX;\n"
" real_t prcy = (y - carToRas->m_CarCenterY) / carToRas->m_CarHalfY;\n"
" real_t dist = sqrt(SQR(prcx) + SQR(prcy)) * (real_t)(10.0);\n"
" real_t scale = ember->m_BlurCurve ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n"
" real_t dr = MwcNext01(&mwc) * (ember->m_BlurCoef * scale) * z;\n"
"\n"
" dsin = sin(t);\n"
" dcos = cos(t);\n"
@ -964,7 +968,11 @@ string IterOpenCLKernelCreator<T>::CreateProjectionString(const Ember<T>& ember)
" dsin = sin(t);\n"
" dcos = cos(t);\n"
"\n"
" real_t dr = MwcNext01(&mwc) * ember->m_BlurCoef * z;\n"
" real_t prcx = (secondPoint.m_X - carToRas->m_CarCenterX) / carToRas->m_CarHalfX;\n"
" real_t prcy = (y - carToRas->m_CarCenterY) / carToRas->m_CarHalfY;\n"
" real_t dist = sqrt(SQR(prcx) + SQR(prcy)) * (real_t)(10.0);\n"
" real_t scale = ember->m_BlurCurve ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n"
" real_t dr = MwcNext01(&mwc) * (ember->m_BlurCoef * scale) * z;\n"
"\n"
" secondPoint.m_X = fma(dr, dcos, secondPoint.m_X) / zr;\n"
" secondPoint.m_Y = fma(dr, dsin, y) / zr;\n"

View File

@ -1778,6 +1778,7 @@ void RendererCL<T, bucketT>::ConvertEmber(Ember<T>& ember, EmberCL<T>& emberCL,
emberCL.m_CamPerspective = ember.m_CamPerspective;
emberCL.m_CamYaw = ember.m_CamYaw;
emberCL.m_CamPitch = ember.m_CamPitch;
emberCL.m_BlurCurve = ember.m_BlurCurve;
emberCL.m_CamDepthBlur = ember.m_CamDepthBlur;
emberCL.m_BlurCoef = ember.BlurCoef();
emberCL.m_CamMat = ember.m_CamMat;
@ -1829,6 +1830,10 @@ void RendererCL<T, bucketT>::ConvertCarToRas(const CarToRas<T>& carToRas)
m_CarToRasCL.m_CarLlY = carToRas.CarLlY();
m_CarToRasCL.m_CarUrX = carToRas.CarUrX();
m_CarToRasCL.m_CarUrY = carToRas.CarUrY();
m_CarToRasCL.m_CarHalfX = carToRas.CarHalfX();
m_CarToRasCL.m_CarHalfY = carToRas.CarHalfY();
m_CarToRasCL.m_CarCenterX = carToRas.CarCenterX();
m_CarToRasCL.m_CarCenterY = carToRas.CarCenterY();
}
/// <summary>

View File

@ -995,6 +995,7 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, m_PitchSpin);
w = SetTabOrder(this, w, m_YawSpin);
w = SetTabOrder(this, w, m_DepthBlurSpin);
w = SetTabOrder(this, w, m_BlurCurveSpin);
w = SetTabOrder(this, w, m_SpatialFilterWidthSpin);//Flame filter.
w = SetTabOrder(this, w, m_SpatialFilterTypeCombo);
w = SetTabOrder(this, w, m_DEFilterMinRadiusSpin);

View File

@ -230,6 +230,7 @@ public slots:
void OnPitchChanged(double d);
void OnYawChanged(double d);
void OnDepthBlurChanged(double d);
void OnBlurCurveChanged(double d);
void OnSpatialFilterWidthChanged(double d);//Filter.
void OnSpatialFilterTypeComboCurrentIndexChanged(const QString& text);
void OnTemporalFilterWidthChanged(double d);
@ -487,6 +488,7 @@ private:
DoubleSpinBox* m_PitchSpin;
DoubleSpinBox* m_YawSpin;
DoubleSpinBox* m_DepthBlurSpin;
DoubleSpinBox* m_BlurCurveSpin;
DoubleSpinBox* m_SpatialFilterWidthSpin;//Filter.
StealthComboBox* m_SpatialFilterTypeCombo;
DoubleSpinBox* m_TemporalFilterWidthSpin;

View File

@ -713,13 +713,13 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>266</height>
<height>288</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>266</height>
<height>288</height>
</size>
</property>
<property name="focusPolicy">
@ -866,6 +866,11 @@
<string>Depth Blur</string>
</property>
</row>
<row>
<property name="text">
<string>Blur Curve</string>
</property>
</row>
<column>
<property name="text">
<string>Field</string>
@ -1032,6 +1037,19 @@
<string>0</string>
</property>
</item>
<item row="12" column="0">
<property name="text">
<string>Blur Curve (3D)</string>
</property>
<property name="toolTip">
<string>Curve parameter to adjust how blurry points are as they move away from 0,0. Use 0 to make bluriness uniform.</string>
</property>
</item>
<item row="12" column="1">
<property name="text">
<string>0</string>
</property>
</item>
</widget>
</item>
<item row="9" column="0">
@ -3194,7 +3212,7 @@
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Duplicate selected xforms.&lt;/p&gt;&lt;p&gt;If xaos is present in the flame, the new xforms will be added with existing xaos preserved, else they'll just be added normally.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Duplicate selected xforms.&lt;/p&gt;&lt;p&gt;If xaos is present in the flame, the duplicated xforms will be added with existing xaos preserved, else they'll just be added normally.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>

View File

@ -165,6 +165,7 @@ public:
virtual void PitchChanged(double d) { }
virtual void YawChanged(double d) { }
virtual void DepthBlurChanged(double d) { }
virtual void BlurCurveChanged(double d) { }
virtual void SpatialFilterWidthChanged(double d) { }
virtual void SpatialFilterTypeChanged(const QString& text) { }
virtual void TemporalFilterWidthChanged(double d) { }
@ -453,6 +454,7 @@ public:
virtual void PitchChanged(double d) override;
virtual void YawChanged(double d) override;
virtual void DepthBlurChanged(double d) override;
virtual void BlurCurveChanged(double d) override;
virtual void SpatialFilterWidthChanged(double d) override;
virtual void SpatialFilterTypeChanged(const QString& text) override;
virtual void TemporalFilterWidthChanged(double d) override;

View File

@ -188,10 +188,10 @@ void Fractorium::UpdateHistogramBounds()
if (auto r = m_Controller->Renderer())
{
ul.sprintf("UL: %3.3f, %3.3f", r->LowerLeftX(), m_Settings->YAxisUp() ? r->UpperRightY() : r->LowerLeftY());//These bounds include gutter padding.
ur.sprintf("UR: %3.3f, %3.3f", r->UpperRightX(), m_Settings->YAxisUp() ? r->UpperRightY() : r->LowerLeftY());
lr.sprintf("LR: %3.3f, %3.3f", r->UpperRightX(), m_Settings->YAxisUp() ? r->LowerLeftY() : r->UpperRightY());
ll.sprintf("LL: %3.3f, %3.3f", r->LowerLeftX(), m_Settings->YAxisUp() ? r->LowerLeftY() : r->UpperRightY());
ul.sprintf("UL: %3.3f, %3.3f", r->LowerLeftX(), r->UpperRightY());//These bounds include gutter padding.
ur.sprintf("UR: %3.3f, %3.3f", r->UpperRightX(), r->UpperRightY());
lr.sprintf("LR: %3.3f, %3.3f", r->UpperRightX(), r->LowerLeftY());
ll.sprintf("LL: %3.3f, %3.3f", r->LowerLeftX(), r->LowerLeftY());
wh.sprintf("W x H: %4u x %4u", r->SuperRasW(), r->SuperRasH());
g.sprintf("%u", (uint)r->GutterWidth());
ui.InfoBoundsLabelUL->setText(ul);

View File

@ -59,11 +59,12 @@ void Fractorium::InitParamsUI()
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ZoomSpin, spinHeight, 0, 25, 0.2, SIGNAL(valueChanged(double)), SLOT(OnZoomChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_RotateSpin, spinHeight, -180, 180, 10, SIGNAL(valueChanged(double)), SLOT(OnRotateChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ZPosSpin, spinHeight, -1000, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnZPosChanged(double)), true, 0, 1, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ZPosSpin, spinHeight, -1000, 1000, 0.1, SIGNAL(valueChanged(double)), SLOT(OnZPosChanged(double)), true, 0, 1, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_PerspectiveSpin, spinHeight, -500, 500, 0.01, SIGNAL(valueChanged(double)), SLOT(OnPerspectiveChanged(double)), true, 0, 1, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_PitchSpin, spinHeight, -dmax, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnPitchChanged(double)), true, 0, 45, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_YawSpin, spinHeight, -dmax, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnYawChanged(double)), true, 0, 45, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_DepthBlurSpin, spinHeight, -dmax, dmax, 0.01, SIGNAL(valueChanged(double)), SLOT(OnDepthBlurChanged(double)), true, 0, 1, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_BlurCurveSpin, spinHeight, 0, dmax, 0.1, SIGNAL(valueChanged(double)), SLOT(OnBlurCurveChanged(double)), true, 0, 1, 0);
m_WidthSpin->m_DoubleClickNonZeroEvent = [&](SpinBox * sb, int val)
{
m_Controller->ResizeAndScale(val, m_HeightSpin->DoubleClickNonZero(), eScaleType::SCALE_WIDTH);
@ -467,6 +468,15 @@ template <typename T> void FractoriumEmberController<T>::DepthBlurChanged(double
}
void Fractorium::OnDepthBlurChanged(double d) { m_Controller->DepthBlurChanged(d); }
template <typename T> void FractoriumEmberController<T>::BlurCurveChanged(double d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_BlurCurve = d;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
}
void Fractorium::OnBlurCurveChanged(double d) { m_Controller->BlurCurveChanged(d); }
/// <summary>
/// Filter.
/// </summary>
@ -797,6 +807,7 @@ void FractoriumEmberController<T>::FillParamTablesAndPalette()
m_Fractorium->m_PitchSpin->SetValueStealth(m_Ember.m_CamPitch * RAD_2_DEG_T);
m_Fractorium->m_YawSpin->SetValueStealth(m_Ember.m_CamYaw * RAD_2_DEG_T);
m_Fractorium->m_DepthBlurSpin->SetValueStealth(m_Ember.m_CamDepthBlur);
m_Fractorium->m_BlurCurveSpin->SetValueStealth(m_Ember.m_BlurCurve);
m_Fractorium->m_SpatialFilterWidthSpin->SetValueStealth(m_Ember.m_SpatialFilterRadius);//Filter.
m_Fractorium->m_SpatialFilterTypeCombo->SetCurrentIndexStealth(int(m_Ember.m_SpatialFilterType));
m_Fractorium->m_TemporalFilterWidthSpin->SetValueStealth(m_Ember.m_TemporalFilterWidth);
@ -871,6 +882,7 @@ void FractoriumEmberController<T>::ParamsToEmberPrivate(Ember<U>& ember, bool im
ember.m_CamPitch = m_Fractorium->m_PitchSpin->value() * DEG_2_RAD_T;
ember.m_CamYaw = m_Fractorium->m_YawSpin->value() * DEG_2_RAD_T;
ember.m_CamDepthBlur = m_Fractorium->m_DepthBlurSpin->value();
ember.m_BlurCurve = m_Fractorium->m_BlurCurveSpin->value();
ember.m_SubBatchSize = m_Fractorium->m_SbsSpin->value();
ember.m_FuseCount = m_Fractorium->m_FuseSpin->value();
ember.m_RandPointRange = m_Fractorium->m_RandRangeSpin->value();

View File

@ -208,7 +208,7 @@ void Fractorium::OnAddLinkedXformButtonClicked(bool checked) { m_Controller->Add
/// <summary>
/// Duplicate the specified xforms in the current ember, and set the last one as the current xform.
/// If xaos is present in the ember, the new xforms will be added with xaos preserved, else they'll just be added normally.
/// If xaos is present in the ember, the duplicated xforms will be added with xaos preserved, else they'll just be added normally.
/// Called when the duplicate xform button is clicked.
/// Resets the rendering process.
/// </summary>

View File

@ -549,12 +549,7 @@ void GLWidget::paintGL()
#else
m_Program->bind();
m_ProjMatrix.setToIdentity();
if (!controller->Renderer()->YAxisUp())
m_ProjMatrix.ortho(-unitX, unitX, unitY, -unitY, -1, 1);//Projection matrix: OpenGL camera is always centered, just move the ember internally inside the renderer.
else
m_ProjMatrix.ortho(-unitX, unitX, -unitY, unitY, -1, 1);
m_ProjMatrix.ortho(-unitX, unitX, -unitY, unitY, -1, 1);//Projection matrix: OpenGL camera is always centered, just move the ember internally inside the renderer.
m_ModelViewMatrix.setToIdentity();
//this->DrawUnitSquare();
controller->GLController()->DrawAffines(pre, post);