diff --git a/Source/Ember/CarToRas.h b/Source/Ember/CarToRas.h index 5750161..53205e4 100644 --- a/Source/Ember/CarToRas.h +++ b/Source/Ember/CarToRas.h @@ -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(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; } /// @@ -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. }; } diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h index 1b9addd..1ae42a4 100644 --- a/Source/Ember/Ember.h +++ b/Source/Ember/Ember.h @@ -6,6 +6,8 @@ #include "SpatialFilter.h" #include "TemporalFilter.h" #include "EmberMotion.h" +#include "CarToRas.h" +#include "VarFuncs.h" /// /// 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::m_CamYaw>(embers, coefs, size); InterpT<&Ember::m_CamPitch>(embers, coefs, size); InterpT<&Ember::m_CamDepthBlur>(embers, coefs, size); + InterpT<&Ember::m_BlurCurve>(embers, coefs, size); InterpX::m_CamMat>(embers, coefs, size); InterpT<&Ember::m_CenterX>(embers, coefs, size); InterpT<&Ember::m_CenterY>(embers, coefs, size); @@ -1162,9 +1166,9 @@ public: /// /// The point to project /// The Isaac object to pass to the projection functions - inline void Proj(Point& point, QTIsaac& rand) + inline void Proj(Point& point, QTIsaac& rand, const CarToRas& ctr) { - (this->*m_ProjFunc)(point, rand); + (this->*m_ProjFunc)(point, rand, ctr); } /// @@ -1172,7 +1176,7 @@ public: /// /// Ignored /// Ignored - void ProjectNone(Point& point, QTIsaac& rand) + void ProjectNone(Point& point, QTIsaac& rand, const CarToRas& ctr) { } @@ -1181,7 +1185,7 @@ public: /// /// The point to project /// Ignored - void ProjectZPerspective(Point& point, QTIsaac& rand) + void ProjectZPerspective(Point& point, QTIsaac& rand, const CarToRas& ctr) { T zr = Zeps(1 - m_CamPerspective * (point.m_Z - m_CamZPos)); point.m_X /= zr; @@ -1194,7 +1198,7 @@ public: /// /// The point to project /// Ignored - void ProjectPitch(Point& point, QTIsaac& rand) + void ProjectPitch(Point& point, QTIsaac& rand, const CarToRas& 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: /// /// The point to project /// Used for blurring - void ProjectPitchDepthBlur(Point& point, QTIsaac& rand) + void ProjectPitchDepthBlur(Point& point, QTIsaac& rand, const CarToRas& 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() * m_BlurCoef * z; + T prcx = (point.m_X - ctr.CarCenterX()) / ctr.CarHalfX(); + T prcy = (y - ctr.CarCenterY()) / ctr.CarHalfY(); + T dist = VarFuncs::Hypot(prcx, prcy) * 10; + T scale = m_BlurCurve ? std::min(T(1), Sqr(dist) / (4 * m_BlurCurve)) : T(1); + T dr = rand.Frand01() * (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: /// /// The point to project /// Used for blurring - void ProjectPitchYawDepthBlur(Point& point, QTIsaac& rand) + void ProjectPitchYawDepthBlur(Point& point, QTIsaac& rand, const CarToRas& ctr) { T dsin, dcos; T t = rand.Frand01() * 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() * m_BlurCoef * z; + T prcx = (x - ctr.CarCenterX()) / ctr.CarHalfX(); + T prcy = (y - ctr.CarCenterY()) / ctr.CarHalfY(); + T dist = VarFuncs::Hypot(prcx, prcy) * 10; + T scale = m_BlurCurve ? std::min(T(1), Sqr(dist) / (4 * m_BlurCurve)) : T(1); + T dr = rand.Frand01() * (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: /// /// The point to project /// Ignored - void ProjectPitchYaw(Point& point, QTIsaac& rand) + void ProjectPitchYaw(Point& point, QTIsaac& rand, const CarToRas& 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::*ProjFuncPtr)(Point&, QTIsaac&); + typedef void (Ember::*ProjFuncPtr)(Point&, QTIsaac&, const CarToRas&); 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; diff --git a/Source/Ember/EmberDefines.h b/Source/Ember/EmberDefines.h index 06f450f..6f7a037 100644 --- a/Source/Ember/EmberDefines.h +++ b/Source/Ember/EmberDefines.h @@ -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 }; /// diff --git a/Source/Ember/EmberToXml.cpp b/Source/Ember/EmberToXml.cpp index 22ffc28..4950c6d 100644 --- a/Source/Ember/EmberToXml.cpp +++ b/Source/Ember/EmberToXml.cpp @@ -159,6 +159,7 @@ string EmberToXml::ToString(Ember& 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\""; diff --git a/Source/Ember/Iterator.h b/Source/Ember/Iterator.h index afd4264..b136ab4 100644 --- a/Source/Ember/Iterator.h +++ b/Source/Ember/Iterator.h @@ -15,7 +15,7 @@ namespace EmberNs using Iterator::NextXformFromIndex; \ using Iterator::DoFinalXform; \ using Iterator::DoBadVals; - + template struct IterParams { @@ -69,12 +69,12 @@ public: /// Virtual empty iteration function that will be overidden in derived iterator classes. /// /// The ember whose xforms will be applied - /// The number of iterations to do - /// The number of times to fuse + /// Structure holding number of iterations to do, and the number to fuse. This is passed by value on purpose. + /// The cartesian to raster conversion structure which is used in some 3D projections /// The buffer to store the output points /// The random context to use /// The number of bad values - virtual size_t Iterate(Ember& ember, IterParams& params, Point* samples, QTIsaac& rand) { return 0; } + virtual size_t Iterate(Ember& ember, const IterParams params, const CarToRas& ctr, Point* samples, QTIsaac& rand) { return 0; } /// /// 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. /// /// The ember whose xforms will be applied - /// The number of iterations to do - /// The number of times to fuse + /// Structure holding number of iterations to do, and the number to fuse. This is passed by value on purpose. + /// The cartesian to raster conversion structure which is used in some 3D projections /// The buffer to store the output points /// The random context to use /// The number of bad values - virtual size_t Iterate(Ember& ember, IterParams& params, Point* samples, QTIsaac& rand) override + virtual size_t Iterate(Ember& ember, const IterParams params, const CarToRas& ctr, Point* samples, QTIsaac& rand) override { size_t i, badVals = 0; Point 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. /// /// The ember whose xforms will be applied - /// The number of iterations to do - /// The number of times to fuse + /// Structure holding number of iterations to do, and the number to fuse. This is passed by value on purpose. + /// The cartesian to raster conversion structure which is used in some 3D projections /// The buffer to store the output points /// The random context to use /// The number of bad values - virtual size_t Iterate(Ember& ember, IterParams& params, Point* samples, QTIsaac& rand) override + virtual size_t Iterate(Ember& ember, const IterParams params, const CarToRas& ctr, Point* samples, QTIsaac& 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. } } diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index a446496..eeb9387 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -1301,7 +1301,7 @@ EmberStats Renderer::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) diff --git a/Source/Ember/SheepTools.h b/Source/Ember/SheepTools.h index a33c645..c87f196 100644 --- a/Source/Ember/SheepTools.h +++ b/Source/Ember/SheepTools.h @@ -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); diff --git a/Source/Ember/Variations05.h b/Source/Ember/Variations05.h index ea46508..f7df6f0 100644 --- a/Source/Ember/Variations05.h +++ b/Source/Ember/Variations05.h @@ -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 << diff --git a/Source/Ember/XmlToEmber.cpp b/Source/Ember/XmlToEmber.cpp index a2d3d84..eba3c40 100644 --- a/Source/Ember/XmlToEmber.cpp +++ b/Source/Ember/XmlToEmber.cpp @@ -1605,6 +1605,7 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& 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)) {} diff --git a/Source/EmberCL/EmberCLStructs.h b/Source/EmberCL/EmberCLStructs.h index 6427214..5c1f7c3 100644 --- a/Source/EmberCL/EmberCLStructs.h +++ b/Source/EmberCL/EmberCLStructs.h @@ -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; }; /// @@ -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"; diff --git a/Source/EmberCL/IterOpenCLKernelCreator.cpp b/Source/EmberCL/IterOpenCLKernelCreator.cpp index 24d25cc..9c7059f 100644 --- a/Source/EmberCL/IterOpenCLKernelCreator.cpp +++ b/Source/EmberCL/IterOpenCLKernelCreator.cpp @@ -940,7 +940,11 @@ string IterOpenCLKernelCreator::CreateProjectionString(const Ember& 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::CreateProjectionString(const Ember& 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" diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp index c2dd7e5..a5b8ad4 100644 --- a/Source/EmberCL/RendererCL.cpp +++ b/Source/EmberCL/RendererCL.cpp @@ -1778,6 +1778,7 @@ void RendererCL::ConvertEmber(Ember& ember, EmberCL& 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::ConvertCarToRas(const CarToRas& 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(); } /// diff --git a/Source/Fractorium/Fractorium.cpp b/Source/Fractorium/Fractorium.cpp index b62c954..7f8419b 100644 --- a/Source/Fractorium/Fractorium.cpp +++ b/Source/Fractorium/Fractorium.cpp @@ -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); diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h index 2e5a919..1116193 100644 --- a/Source/Fractorium/Fractorium.h +++ b/Source/Fractorium/Fractorium.h @@ -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; diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui index 90771ed..cf2c070 100644 --- a/Source/Fractorium/Fractorium.ui +++ b/Source/Fractorium/Fractorium.ui @@ -713,13 +713,13 @@ 0 - 266 + 288 16777215 - 266 + 288 @@ -866,6 +866,11 @@ Depth Blur + + + Blur Curve + + Field @@ -1032,6 +1037,19 @@ 0 + + + Blur Curve (3D) + + + Curve parameter to adjust how blurry points are as they move away from 0,0. Use 0 to make bluriness uniform. + + + + + 0 + + @@ -3194,7 +3212,7 @@ - <html><head/><body><p>Duplicate selected xforms.</p><p>If xaos is present in the flame, the new xforms will be added with existing xaos preserved, else they'll just be added normally.</p></body></html> + <html><head/><body><p>Duplicate selected xforms.</p><p>If xaos is present in the flame, the duplicated xforms will be added with existing xaos preserved, else they'll just be added normally.</p></body></html> diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index 748853b..591cda8 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -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; diff --git a/Source/Fractorium/FractoriumInfo.cpp b/Source/Fractorium/FractoriumInfo.cpp index a079cfb..53722f6 100644 --- a/Source/Fractorium/FractoriumInfo.cpp +++ b/Source/Fractorium/FractoriumInfo.cpp @@ -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); diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp index 64c2388..fe538e0 100644 --- a/Source/Fractorium/FractoriumParams.cpp +++ b/Source/Fractorium/FractoriumParams.cpp @@ -59,11 +59,12 @@ void Fractorium::InitParamsUI() SetupSpinner(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240); SetupSpinner(table, this, row, 1, m_ZoomSpin, spinHeight, 0, 25, 0.2, SIGNAL(valueChanged(double)), SLOT(OnZoomChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_RotateSpin, spinHeight, -180, 180, 10, SIGNAL(valueChanged(double)), SLOT(OnRotateChanged(double)), true, 0, 0, 0); - SetupSpinner(table, this, row, 1, m_ZPosSpin, spinHeight, -1000, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnZPosChanged(double)), true, 0, 1, 0); + SetupSpinner(table, this, row, 1, m_ZPosSpin, spinHeight, -1000, 1000, 0.1, SIGNAL(valueChanged(double)), SLOT(OnZPosChanged(double)), true, 0, 1, 0); SetupSpinner(table, this, row, 1, m_PerspectiveSpin, spinHeight, -500, 500, 0.01, SIGNAL(valueChanged(double)), SLOT(OnPerspectiveChanged(double)), true, 0, 1, 0); SetupSpinner(table, this, row, 1, m_PitchSpin, spinHeight, -dmax, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnPitchChanged(double)), true, 0, 45, 0); SetupSpinner(table, this, row, 1, m_YawSpin, spinHeight, -dmax, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnYawChanged(double)), true, 0, 45, 0); SetupSpinner(table, this, row, 1, m_DepthBlurSpin, spinHeight, -dmax, dmax, 0.01, SIGNAL(valueChanged(double)), SLOT(OnDepthBlurChanged(double)), true, 0, 1, 0); + SetupSpinner(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 void FractoriumEmberController::DepthBlurChanged(double } void Fractorium::OnDepthBlurChanged(double d) { m_Controller->DepthBlurChanged(d); } +template void FractoriumEmberController::BlurCurveChanged(double d) +{ + UpdateAll([&](Ember& ember, bool isMain) + { + ember.m_BlurCurve = d; + }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); +} +void Fractorium::OnBlurCurveChanged(double d) { m_Controller->BlurCurveChanged(d); } + /// /// Filter. /// @@ -797,6 +807,7 @@ void FractoriumEmberController::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::ParamsToEmberPrivate(Ember& 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(); diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp index 38fb49b..dd47b9c 100644 --- a/Source/Fractorium/FractoriumXforms.cpp +++ b/Source/Fractorium/FractoriumXforms.cpp @@ -208,7 +208,7 @@ void Fractorium::OnAddLinkedXformButtonClicked(bool checked) { m_Controller->Add /// /// 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. /// diff --git a/Source/Fractorium/GLWidget.cpp b/Source/Fractorium/GLWidget.cpp index 7b647db..34a2d22 100644 --- a/Source/Fractorium/GLWidget.cpp +++ b/Source/Fractorium/GLWidget.cpp @@ -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);