Skip to content

Commit

Permalink
Expanded Gaussian shader generator to support kernels beyond the limi…
Browse files Browse the repository at this point in the history
…t of OpenGL ES varyings, using dependent texture reads after that.
  • Loading branch information
BradLarson committed Oct 18, 2013
1 parent 6272c28 commit 4fc4cfa
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@ - (void)setupFilter;
self.filterSettingsSlider.hidden = NO;

[self.filterSettingsSlider setMinimumValue:1.0];
[self.filterSettingsSlider setMaximumValue:7.0];
[self.filterSettingsSlider setMaximumValue:14.0];
[self.filterSettingsSlider setValue:2.0];

filter = [[GPUImageGaussianBlurFilter alloc] init];
Expand Down Expand Up @@ -1589,7 +1589,7 @@ - (IBAction)updateFilterFromSlider:(id)sender;
case GPUIMAGE_PERLINNOISE: [(GPUImagePerlinNoiseFilter *)filter setScale:[(UISlider *)sender value]]; break;
case GPUIMAGE_MOSAIC: [(GPUImageMosaicFilter *)filter setDisplayTileSize:CGSizeMake([(UISlider *)sender value], [(UISlider *)sender value])]; break;
case GPUIMAGE_VIGNETTE: [(GPUImageVignetteFilter *)filter setVignetteEnd:[(UISlider *)sender value]]; break;
case GPUIMAGE_GAUSSIAN: [(GPUImageGaussianBlurFilter *)filter setBlurRadiusInPixels:round([(UISlider*)sender value])]; break;
case GPUIMAGE_GAUSSIAN: [(GPUImageGaussianBlurFilter *)filter setBlurRadiusInPixels:[(UISlider*)sender value]]; break;
// case GPUIMAGE_GAUSSIAN: [(GPUImageGaussianBlurFilter *)filter setBlurPasses:round([(UISlider*)sender value])]; break;
// case GPUIMAGE_BILATERAL: [(GPUImageBilateralFilter *)filter setBlurSize:[(UISlider*)sender value]]; break;
case GPUIMAGE_BILATERAL: [(GPUImageBilateralFilter *)filter setDistanceNormalizationFactor:[(UISlider*)sender value]]; break;
Expand Down
34 changes: 27 additions & 7 deletions framework/Source/GPUImageGaussianBlurFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ @implementation GPUImageGaussianBlurFilter
- (id) initWithFirstStageVertexShaderFromString:(NSString *)firstStageVertexShaderString
firstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString
secondStageVertexShaderFromString:(NSString *)secondStageVertexShaderString
secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString {
secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString
{

// NSString *currentGaussianBlurVertexShader = [GPUImageGaussianBlurFilter vertexShaderForStandardGaussianOfRadius:4 sigma:2.0];
// NSString *currentGaussianBlurFragmentShader = [GPUImageGaussianBlurFilter fragmentShaderForStandardGaussianOfRadius:4 sigma:2.0];
Expand All @@ -32,9 +33,6 @@ - (id) initWithFirstStageVertexShaderFromString:(NSString *)firstStageVertexShad
_blurRadiusInPixels = 2.0;
shouldResizeBlurRadiusWithImageSize = NO;

// NSLog(@"Calculated vertex shader: \n%@", currentGaussianBlurVertexShader);
// NSLog(@"Calculated fragment shader: \n%@", currentGaussianBlurFragmentShader);

// NSLog(@"Optimized vertex shader: \n%@", [GPUImageGaussianBlurFilter vertexShaderForOptimizedGaussianOfRadius:4 sigma:1.833333]);
// NSLog(@"Optimized fragment shader: \n%@", [GPUImageGaussianBlurFilter fragmentShaderForOptimizedGaussianOfRadius:4 sigma:1.833333]);
return self;
Expand Down Expand Up @@ -286,6 +284,8 @@ + (NSString *)fragmentShaderForOptimizedGaussianOfRadius:(NSUInteger)blurRadius
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
[shaderString appendFormat:@"\
uniform sampler2D inputImageTexture;\n\
uniform highp float texelWidthOffset;\n\
uniform highp float texelHeightOffset;\n\
\n\
varying highp vec2 blurCoordinates[%d];\n\
\n\
Expand All @@ -295,13 +295,16 @@ void main()\n\
#else
[shaderString appendFormat:@"\
uniform sampler2D inputImageTexture;\n\
uniform float texelWidthOffset;\n\
uniform float texelHeightOffset;\n\
\n\
varying vec2 blurCoordinates[%d];\n\
\n\
void main()\n\
{\n\
vec4 sum = vec4(0.0);\n", 1 + (numberOfOptimizedOffsets * 2) ];
#endif

// Inner texture loop
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0]) * %f;\n", standardGaussianWeights[0]];

Expand All @@ -315,9 +318,22 @@ void main()\n\
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%d]) * %f;\n", (currentBlurCoordinateIndex * 2) + 2, optimizedWeight];
}

// If the number of required samples exceeds the amount we can pass in via varyings, we have to do dependent texture reads in the fragment shader
if (trueNumberOfOptimizedOffsets > numberOfOptimizedOffsets)
{
// Do the overflow dependent texture reads
[shaderString appendString:@"highp vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n"];

for (NSUInteger currentOverlowTextureRead = numberOfOptimizedOffsets; currentOverlowTextureRead < trueNumberOfOptimizedOffsets; currentOverlowTextureRead++)
{
GLfloat firstWeight = standardGaussianWeights[currentOverlowTextureRead * 2 + 1];
GLfloat secondWeight = standardGaussianWeights[currentOverlowTextureRead * 2 + 2];

GLfloat optimizedWeight = firstWeight + secondWeight;
GLfloat optimizedOffset = (firstWeight * (currentOverlowTextureRead * 2 + 1) + secondWeight * (currentOverlowTextureRead * 2 + 2)) / optimizedWeight;

[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0] + singleStepOffset * %f) * %f;\n", optimizedOffset, optimizedWeight];
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0] - singleStepOffset * %f) * %f;\n", optimizedOffset, optimizedWeight];
}
}

// Footer
Expand Down Expand Up @@ -379,6 +395,8 @@ - (void)switchToVertexShader:(NSString *)newVertexShader fragmentShader:(NSStrin
filterPositionAttribute = [filterProgram attributeIndex:@"position"];
filterTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate"];
filterInputTextureUniform = [filterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader
verticalPassTexelWidthOffsetUniform = [filterProgram uniformIndex:@"texelWidthOffset"];
verticalPassTexelHeightOffsetUniform = [filterProgram uniformIndex:@"texelHeightOffset"];
[GPUImageContext setActiveShaderProgram:filterProgram];

glEnableVertexAttribArray(filterPositionAttribute);
Expand Down Expand Up @@ -407,10 +425,14 @@ - (void)switchToVertexShader:(NSString *)newVertexShader fragmentShader:(NSStrin
secondFilterTextureCoordinateAttribute = [secondFilterProgram attributeIndex:@"inputTextureCoordinate"];
secondFilterInputTextureUniform = [secondFilterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader
secondFilterInputTextureUniform2 = [secondFilterProgram uniformIndex:@"inputImageTexture2"]; // This does assume a name of "inputImageTexture2" for second input texture in the fragment shader
horizontalPassTexelWidthOffsetUniform = [secondFilterProgram uniformIndex:@"texelWidthOffset"];
horizontalPassTexelHeightOffsetUniform = [secondFilterProgram uniformIndex:@"texelHeightOffset"];
[GPUImageContext setActiveShaderProgram:secondFilterProgram];

glEnableVertexAttribArray(secondFilterPositionAttribute);
glEnableVertexAttribArray(secondFilterTextureCoordinateAttribute);

[self setupFilterForSize:[self sizeOfFBO]];
});

}
Expand Down Expand Up @@ -438,8 +460,6 @@ - (void)setBlurRadiusInPixels:(CGFloat)newValue;
_blurRadiusInPixels = round(newValue); // For now, only do even blur sizes (based on a multiple of two of the sigma)
// _blurRadiusInPixels = (round(newValue * 2.0)) / 2.0; // Only take this in half-pixel steps to minimize shader creation, yet provide single pixel blur resolution

// NSString *newGaussianBlurVertexShader = [GPUImageGaussianBlurFilter vertexShaderForStandardGaussianOfRadius:(_blurRadiusInPixels * 2) sigma:_blurRadiusInPixels];
// NSString *newGaussianBlurFragmentShader = [GPUImageGaussianBlurFilter fragmentShaderForStandardGaussianOfRadius:(_blurRadiusInPixels * 2) sigma:_blurRadiusInPixels];
NSString *newGaussianBlurVertexShader = [GPUImageGaussianBlurFilter vertexShaderForOptimizedGaussianOfRadius:(_blurRadiusInPixels * 2) sigma:_blurRadiusInPixels];
NSString *newGaussianBlurFragmentShader = [GPUImageGaussianBlurFilter fragmentShaderForOptimizedGaussianOfRadius:(_blurRadiusInPixels * 2) sigma:_blurRadiusInPixels];
// NSString *newGaussianBlurVertexShader = [GPUImageGaussianBlurFilter vertexShaderForOptimizedGaussianOfRadius:round(_blurRadiusInPixels * 2)/2 sigma:_blurRadiusInPixels];
Expand Down

0 comments on commit 4fc4cfa

Please sign in to comment.