A high-performance Swift library for GPU-accelerated image filtering, featuring a powerful wave distortion filter built on top of GPUImage3. Create stunning ripple and wave effects with circular geometry correction and configurable parameters.
- π GPU-Accelerated: Metal-powered image processing for maximum performance
- π Advanced Wave Filter: Circular wave distortions with aspect ratio correction
- ποΈ Configurable Parameters: Fully customizable amplitude, frequency, and phase
- π± Cross-Platform: Native support for iOS and macOS
- π Real-time Animation: Smooth animated wave effects
- π» Example App: Complete demo application with live preview
The WaveFilter creates realistic ripple and wave distortion effects that maintain perfect circular geometry on images of any aspect ratio. The filter simulates water ripples radiating from the center of the image using a sophisticated Metal shader pipeline.
- Circular Wave Geometry: Automatic aspect ratio correction ensures circular waves on any image
- Parameter Validation: Automatic clamping prevents invalid values and ensures stable output
- Thread-Safe Processing: Semaphore-protected texture processing for concurrent usage
- Custom Metal Pipeline: Direct Metal shader implementation bypassing standard GPUImage3 pipeline
- Resource Discovery: Intelligent Swift package resource loading with fallback mechanisms
- GPU Optimized: Full Metal shader implementation for maximum performance






Add MonstraImageFilters to your project in Xcode:
- Go to File β Add Package Dependencies
- Enter the repository URL:
https://github.com/yangchenlarkin/MonstraImageFilters.git
- Select the version and add to your target
Or add to your Package.swift
:
dependencies: [
.package(url: "https://github.com/yangchenlarkin/MonstraImageFilters.git", from: "1.0.0")
]
import MonstraImageFilters
// Create a wave filter
let waveFilter = WaveFilter()
// Configure parameters
waveFilter.normalizedPhase = 0.5 // Animation phase (0.0 - 1.0)
waveFilter.amplitude = 0.05 // Wave strength (0.0 - 0.5, auto-clamped)
waveFilter.frequency = 15.0 // Wave rings (1.0 - 20.0, auto-clamped)
// Apply to UIImage/NSImage using GPUImage3
let filteredImage = originalImage.filterWithOperation(waveFilter)
import MonstraImageFilters
let waveFilter = WaveFilter()
waveFilter.amplitude = 0.03
waveFilter.frequency = 8.0
// Animate by updating the normalized phase
var phase: Float = 0.0
Timer.scheduledTimer(withTimeInterval: 1.0/60.0, repeats: true) { _ in
phase += 0.02 // Adjust speed by changing increment
waveFilter.normalizedPhase = phase.truncatingRemainder(dividingBy: 1.0)
let animatedImage = originalImage.filterWithOperation(waveFilter)
// Update your image view
}
let waveFilter = WaveFilter()
// Subtle ripple effect (many small waves)
waveFilter.amplitude = 0.02
waveFilter.frequency = 18.0
waveFilter.normalizedPhase = 0.3
// Strong wave distortion (fewer large waves)
waveFilter.amplitude = 0.25
waveFilter.frequency = 4.0
waveFilter.normalizedPhase = 0.7
let result = originalImage.filterWithOperation(waveFilter)
The included example app demonstrates all WaveFilter capabilities with a live preview interface.
-
Clone the repository:
git clone https://github.com/yangchenlarkin/MonstraImageFilters.git cd MonstraImageFilters
-
Open the workspace:
open MonstraImageFilters.xcworkspace
-
Select the Example scheme in Xcode and run the project
-
View WaveFilter Effects:
- Launch the app to see a grid of sample images
- Tap the "waveFilter" button at the top to apply the wave effect
- Tap any image to view it full-screen with the applied filter
To modify the default WaveFilter settings in the example app:
-
Open
Example/Example/AllFilters.swift
-
Locate lines 55-57 in the
new()
method:case .waveFilter: let filter = WaveFilter() filter.normalizedPhase = 0.5 // Animation phase (0.0 - 1.0) filter.amplitude = 0.1 // Wave strength (0.0 - 1.0) filter.frequency = 10 // Wave cycles (1.0 - 50.0) return filter
-
Modify the values:
normalizedPhase
: Controls animation timing (0.0 - 1.0)amplitude
: Wave intensity - higher values create stronger distortionfrequency
: Number of wave cycles - higher values create more ripples
-
Rebuild and run to see your changes
// Gentle water ripples (realistic)
filter.normalizedPhase = 0.3
filter.amplitude = 0.03
filter.frequency = 12.0
// Strong wave distortion (dramatic)
filter.normalizedPhase = 0.7
filter.amplitude = 0.2
filter.frequency = 5.0
// Tight ripple pattern (detailed)
filter.normalizedPhase = 0.0
filter.amplitude = 0.06
filter.frequency = 16.0
// Core parameters with automatic validation
public var normalizedPhase: Float // Animation phase (0.0 - 1.0, default: 0.0)
public var amplitude: Float // Wave strength (0.0 - 0.5, default: 0.05, auto-clamped)
public var frequency: Float // Wave rings (1.0 - 20.0, default: 15.0, auto-clamped)
let waveFilter = WaveFilter()
// normalizedPhase: Controls wave animation (0.0 - 1.0)
waveFilter.normalizedPhase = 0.0 // Wave at initial phase
waveFilter.normalizedPhase = 0.5 // Wave at half cycle
waveFilter.normalizedPhase = 1.0 // Wave at full cycle
// amplitude: Wave displacement strength (0.0 - 0.5, auto-clamped)
waveFilter.amplitude = 0.0 // No wave effect
waveFilter.amplitude = 0.05 // Subtle waves (default)
waveFilter.amplitude = 0.2 // Strong waves
waveFilter.amplitude = 0.5 // Maximum wave effect
// frequency: Number of wave rings (1.0 - 20.0, auto-clamped)
waveFilter.frequency = 1.0 // Single large wave ring
waveFilter.frequency = 8.0 // Multiple rings (good for animation)
waveFilter.frequency = 20.0 // Many tight rings (ripple effect)
// Values automatically clamped to valid ranges
waveFilter.amplitude = 2.0 // Automatically clamped to 0.5
waveFilter.frequency = 100.0 // Automatically clamped to 20.0
// Thread-safe concurrent processing
DispatchQueue.concurrentPerform(iterations: 10) { index in
let phase = Float(index) / 10.0
waveFilter.normalizedPhase = phase
let result = originalImage.filterWithOperation(waveFilter)
// Process result...
}
The WaveFilter implements a sophisticated Metal rendering pipeline:
- Direct Metal Integration: Implements
ImageProcessingOperation
directly, bypassing standard GPUImage3 filter pipeline - Custom Shader Pipeline: Loads Metal library from Swift package resources with intelligent bundle discovery
- Thread-Safe Processing: Uses
DispatchSemaphore
to ensure safe concurrent texture processing - Aspect Ratio Correction: Calculates and passes aspect ratio to shader for perfect circular geometry
- Custom Fragment Shader:
waveFragment
function with configurable uniforms - Vertex Buffer Management: Manual creation of position and texture coordinate buffers
- Uniform Buffer: Passes
WaveUniforms
struct (phase, amplitude, frequency, aspectRatio) to GPU - Triangle Strip Rendering: Efficient full-screen quad rendering with 4 vertices
- GPU-Only Processing: All calculations performed on Metal GPU, zero CPU image processing
- Resource Reuse: Efficient buffer management with minimal allocations
- Pipeline State Caching: Render pipeline state created once and reused
- Memory Management: Proper texture lifecycle management with GPUImage3 integration
- GPU Processing: All filtering happens on Metal-compatible devices
- Memory Efficient: Processes images without intermediate CPU copies
- Real-time: Capable of 60fps processing on modern devices
- Scalable: Performance scales with GPU capability
- iOS: 13.0 or later
- macOS: 10.15 (Catalina) or later
- Xcode: 12.0 or later
- Swift: 5.9 or later
- Metal: Required for GPU acceleration
Contributions are welcome! Please read our Contributing Guide for details.
- Fork and clone the repository
- Open
MonstraImageFilters.xcworkspace
- Make your changes
- Run tests:
β+U
in Xcode - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on the powerful GPUImage3 framework
- Inspired by classic ripple and wave distortion effects
- Metal shader optimizations for circular wave geometry
Made with β€οΈ for the Swift community