问题
I'm trying to build a Vibrance filter for GPUImage based on this Javascript:
/**
* @filter Vibrance
* @description Modifies the saturation of desaturated colors, leaving saturated colors unmodified.
* @param amount -1 to 1 (-1 is minimum vibrance, 0 is no change, and 1 is maximum vibrance)
*/
function vibrance(amount) {
gl.vibrance = gl.vibrance || new Shader(null, '\
uniform sampler2D texture;\
uniform float amount;\
varying vec2 texCoord;\
void main() {\
vec4 color = texture2D(texture, texCoord);\
float average = (color.r + color.g + color.b) / 3.0;\
float mx = max(color.r, max(color.g, color.b));\
float amt = (mx - average) * (-amount * 3.0);\
color.rgb = mix(color.rgb, vec3(mx), amt);\
gl_FragColor = color;\
}\
');
simpleShader.call(this, gl.vibrance, {
amount: clamp(-1, amount, 1)
});
return this;
}
One would think I should be able to more/less copy paste the shader block:
GPUImageVibranceFilter.h
@interface GPUImageVibranceFilter : GPUImageFilter
{
GLint vibranceUniform;
}
// Modifies the saturation of desaturated colors, leaving saturated colors unmodified.
// Value -1 to 1 (-1 is minimum vibrance, 0 is no change, and 1 is maximum vibrance)
@property (readwrite, nonatomic) CGFloat vibrance;
@end
GPUImageVibranceFilter.m
#import "GPUImageVibranceFilter.h"
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const kGPUImageVibranceFragmentShaderString = SHADER_STRING
(
uniform sampler2D inputImageTexture;
uniform float vibrance;
varying highp vec2 textureCoordinate;
void main() {
vec4 color = texture2D(inputImageTexture, textureCoordinate);
float average = (color.r + color.g + color.b) / 3.0;
float mx = max(color.r, max(color.g, color.b));
float amt = (mx - average) * (-vibrance * 3.0);
color.rgb = mix(color.rgb, vec3(mx), amt);
gl_FragColor = color;
}
);
#else
NSString *const kGPUImageVibranceFragmentShaderString = SHADER_STRING
(
uniform sampler2D inputImageTexture;
uniform float vibrance;
varying vec2 textureCoordinate;
void main() {
vec4 color = texture2D(inputImageTexture, textureCoordinate);
float average = (color.r + color.g + color.b) / 3.0;
float mx = max(color.r, max(color.g, color.b));
float amt = (mx - average) * (-vibrance * 3.0);
color.rgb = mix(color.rgb, vec3(mx), amt);
gl_FragColor = color;
}
);
#endif
@implementation GPUImageVibranceFilter
@synthesize vibrance = _vibrance;
#pragma mark -
#pragma mark Initialization and teardown
- (id)init;
{
if (!(self = [super initWithFragmentShaderFromString:kGPUImageVibranceFragmentShaderString]))
{
return nil;
}
vibranceUniform = [filterProgram uniformIndex:@"vibrance"];
self.vibrance = 0.0;
return self;
}
#pragma mark -
#pragma mark Accessors
- (void)setVibrance:(CGFloat)vibrance;
{
_vibrance = vibrance;
[self setFloat:_vibrance forUniform:vibranceUniform program:filterProgram];
}
@end
But that doesn't compile, crashing with:
Failed to compile fragment shader
Program link log: ERROR: One or more attached shaders not successfully compiled
Fragment shader compile log: (null)
Vertex shader compile log: (null)
The error is certainly clear, but being inexperienced with OpenGL ES shaders, I have no idea what the problem actually is.
回答1:
One would think I should be able to more/less copy paste the shader block.
This might be the case in desktop GLSL, but in OpenGL ES you cannot declare a float
variable (this includes types derived from float
such as vec2
or mat4
as well) without first setting the precision - there is no pre-defined default precision for float
in the fragment shader.
Implementations guarantee support for mediump
and lowp
floating-point precision in the fragment shader. You will have to check before setting highp
as the default, however.
This whole problem screams "missing precision" to me, but why the compiler is not telling you this in the compile log I really do not know.
Brush up on 4.5.3 Default Precision Qualifiers (pp. 35-36)
Side-note regarding your use of CGFloat
:
Be careful using CGFloat
.
Depending on your compile target (whether the host machine is 32-bit or 64-bit), that type will either be single-precision or double-precision. If you are passing something declared CGFloat
to GL, stop that =P
Use GLfloat
instead, because that will always be single-precision as GL requires.
See a related answer I wrote for more details.
来源:https://stackoverflow.com/questions/31997762/gpuimage-shader-crashing-with-error-one-or-more-attached-shaders-not-successfu