Improve stripe size range, remove accidental quantization of 2D shapes

pull/322/head
Anthony Hall 2025-09-07 14:33:39 -07:00
rodzic 29a7ddf93b
commit 82f10238fb
1 zmienionych plików z 52 dodań i 43 usunięć

Wyświetl plik

@ -5,48 +5,57 @@
// Inspired by xenontesla122 // Inspired by xenontesla122
class PolygonBitCrushEffect : public osci::EffectApplication { class PolygonBitCrushEffect : public osci::EffectApplication {
public: public:
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>> &values, double sampleRate) override { osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>> &values, double sampleRate) override {
const double pi = juce::MathConstants<double>::pi; const double pi = juce::MathConstants<double>::pi;
const double twoPi = juce::MathConstants<double>::twoPi; const double twoPi = juce::MathConstants<double>::twoPi;
double effectScale = juce::jlimit(0.0, 1.0, values[0].load()); double effectScale = juce::jlimit(0.0, 1.0, values[0].load());
double nSides = juce::jmax(2.0, values[1].load()); double nSides = juce::jmax(2.0, values[1].load());
double stripeSize = juce::jmax(1e-4, values[2].load()); double stripeSize = juce::jmax(1e-4, values[2].load());
double thetaOffset = values[3] * twoPi; stripeSize = std::pow(stripeSize, 1.5); // Bias slightly toward smaller values
double rOffset = values[4]; double thetaOffset = values[3] * twoPi;
double rOffset = values[4];
osci::Point output(0); osci::Point output(0);
if (input.x != 0 || input.y != 0) { if (input.x != 0 || input.y != 0) {
// Note 90 degree rotation: Theta is treated relative to -Y rather than +X // Note 90 degree rotation: Theta is treated relative to +Y rather than +X
double r = std::hypot(input.x, input.y); double r = std::hypot(input.x, input.y);
double theta = std::atan2(-input.x, input.y) - thetaOffset; double theta = std::atan2(-input.x, input.y) - thetaOffset;
theta = MathUtil::wrapAngle(theta + pi) - pi; // Move branch cut to +/-pi after thetaOffset is applied theta = MathUtil::wrapAngle(theta + pi) - pi; // Move branch cut to +/-pi after thetaOffset is applied
double regionTheta = std::round(theta * nSides / twoPi) / nSides * twoPi; double regionCenterTheta = std::round(theta * nSides / twoPi) / nSides * twoPi;
double localTheta = theta - regionTheta; double localTheta = theta - regionCenterTheta;
double dist = r * std::cos(localTheta); double dist = r * std::cos(localTheta);
double newDist = juce::jmax(0.0, (std::round(dist / stripeSize - rOffset) + rOffset) * stripeSize); double newDist = juce::jmax(0.0, (std::round(dist / stripeSize - rOffset) + rOffset) * stripeSize);
double scale = newDist / dist; double scale = newDist / dist;
output.x = scale * input.x; output.x = scale * input.x;
output.y = scale * input.y; output.y = scale * input.y;
} }
// Apply the same stripe quantization to abs(z) // Apply the same stripe quantization to abs(z) if the input is 3D
if (input.z != 0) { double absZ = std::abs(input.z);
double signZ = input.z > 0 ? 1 : -1; if (absZ > 0.0001) {
output.z = signZ * juce::jmax(0.0, (std::round(std::abs(input.z) / stripeSize - rOffset) + rOffset) * stripeSize); double signZ = input.z > 0 ? 1 : -1;
} output.z = signZ * juce::jmax(0.0, (std::round(absZ / stripeSize - rOffset) + rOffset) * stripeSize);
return (1 - effectScale) * input + effectScale * output; }
} return (1 - effectScale) * input + effectScale * output;
}
std::shared_ptr<osci::Effect> build() const override { std::shared_ptr<osci::Effect> build() const override {
auto eff = std::make_shared<osci::Effect>( auto eff = std::make_shared<osci::Effect>(
std::make_shared<PolygonBitCrushEffect>(), std::make_shared<PolygonBitCrushEffect>(),
std::vector<osci::EffectParameter*>{ std::vector<osci::EffectParameter*>{
new osci::EffectParameter("Polygon Bit Crush", "Constrains points to a polygon pattern.", "polygonBitCrushEnable", VERSION_HINT, 1.0, 0.0, 1.0), new osci::EffectParameter("Polygon Bit Crush",
new osci::EffectParameter("Sides", "Controls the number of sides of the polygon pattern.", "polygonSides", VERSION_HINT, 5.0, 3.0, 8.0), "Constrains points to a polygon pattern.",
new osci::EffectParameter("Stripe Size", "Controls the spacing between the stripes of the polygon pattern.", "polygonBandSize", VERSION_HINT, 0.15, 0.0, 0.5), "polygonBitCrushEnable", VERSION_HINT, 1.0, 0.0, 1.0),
new osci::EffectParameter("Angle Offset", "Rotates the polygon pattern.", "polygonAngleOffset", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001, osci::LfoType::Sawtooth, 0.1), new osci::EffectParameter("Sides", "Controls the number of sides of the polygon pattern.",
new osci::EffectParameter("Radial Offset", "Offsets the stripes of the polygon pattern.", "polygonROffset", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001, osci::LfoType::Sawtooth, 2.0) "polygonSides", VERSION_HINT, 5.0, 3.0, 8.0),
}); new osci::EffectParameter("Stripe Size",
eff->setIcon(BinaryData::diamond_svg); "Controls the spacing between the stripes of the polygon pattern.",
return eff; "polygonBandSize", VERSION_HINT, 0.15, 0.0, 0.5),
} new osci::EffectParameter("Angle Offset", "Rotates the polygon pattern.",
}; "polygonAngleOffset", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001, osci::LfoType::Sawtooth, 0.1),
new osci::EffectParameter("Radial Offset", "Offsets the stripes of the polygon pattern.",
"polygonROffset", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001, osci::LfoType::Sawtooth, 2.0)
});
eff->setIcon(BinaryData::diamond_svg);
return eff;
}
};