2015-08-14 2 views
0

Работая на другой фильтр OpenGL ES изображений на основе this:GPUImage пользовательских OpenGL ES шейдеры приводят к черному изображению

uniform sampler2D texture; 
uniform float amount; 
uniform vec2 texSize; 
varying vec2 texCoord; 
void main() { 
    vec4 color = texture2D(texture, texCoord); 
    vec4 orig = color; 

    /* High pass filter */ 
    vec4 highpass = color * 5.0; 

    float dx = 1.0/texSize.x; 
    float dy = 1.0/texSize.y; 
    highpass += texture2D(texture, texCoord + vec2(-dx, -dy)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(dx, -dy)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(dx, dy)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(-dx, dy)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(-dx * 2.0, -dy * 2.0)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(dx * 2.0, -dy * 2.0)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(dx * 2.0, dy * 2.0)) * -0.625; 
    highpass += texture2D(texture, texCoord + vec2(-dx * 2.0, dy * 2.0)) * -0.625; 
    highpass.a = 1.0; 

    /* Overlay blend */ 
    vec3 overlay = vec3(1.0); 
    if (highpass.r <= 0.5) { 
     overlay.r = 2.0 * color.r * highpass.r; 
    } else { 
     overlay.r = 1.0 - 2.0 * (1.0 - color.r) * (1.0 - highpass.r); 
    } 
    if (highpass.g <= 0.5) { 
     overlay.g = 2.0 * color.g * highpass.g; 
    } else { 
     overlay.g = 1.0 - 2.0 * (1.0 - color.g) * (1.0 - highpass.g); 
    } 
    if (highpass.b <= 0.5) { 
     overlay.b = 2.0 * color.b * highpass.b; 
    } else { 
     overlay.b = 1.0 - 2.0 * (1.0 - color.b) * (1.0 - highpass.b); 
    } 
    color.rgb = (overlay * 0.8) + (orig.rgb * 0.2); 

    /* Desaturated hard light */ 
    vec3 desaturated = vec3(orig.r + orig.g + orig.b/3.0); 
    if (desaturated.r <= 0.5) { 
     color.rgb = 2.0 * color.rgb * desaturated; 
    } else { 
     color.rgb = vec3(1.0) - vec3(2.0) * (vec3(1.0) - color.rgb) * (vec3(1.0) - desaturated); 
    } 
    color = (orig * 0.6) + (color * 0.4); 

    /* Add back some color */ 
    float average = (color.r + color.g + color.b)/3.0; 
    color.rgb += (average - color.rgb) * (1.0 - 1.0/(1.001 - 0.45)); 

    gl_FragColor = (color * amount) + (orig * (1.0 - amount)); 
} 

За мой question yesterday, я знал, что для назначения точности для каждого поплавка и VEC. На этот раз он скомпилировался отлично, однако, когда я иду на применение фильтра в GPUImage (например, установив значение clarity на 0.8), изображение становится черным. Моя кишка говорит мне, что это связано с размером текстуры, но, не зная, как GPUImage справляется с этим, я немного застрял.

Вот моя реализация в Objective-C:

.h

#import <GPUImage/GPUImage.h> 

@interface GPUImageClarityFilter : GPUImageFilter 
{ 
    GLint clarityUniform; 
} 

// Gives the image a gritty, surreal contrasty effect 
// Value 0 to 1 
@property (readwrite, nonatomic) GLfloat clarity; 

@end 

.m

#import "GPUImageClarityFilter.h" 

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE 
NSString *const kGPUImageClarityFragmentShaderString = SHADER_STRING 
(
uniform sampler2D inputImageTexture; 
uniform lowp float clarity; 
uniform highp vec2 textureSize; 
varying highp vec2 textureCoordinate; 
void main() { 
    highp vec4 color = texture2D(inputImageTexture, textureCoordinate); 
    highp vec4 orig = color; 

    /* High pass filter */ 
    highp vec4 highpass = color * 5.0; 

    highp float dx = 1.0/textureSize.x; 
    highp float dy = 1.0/textureSize.y; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx, -dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx, -dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx, dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx, dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx * 2.0, -dy * 2.0)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx * 2.0, -dy * 2.0)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx * 2.0, dy * 2.0)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx * 2.0, dy * 2.0)) * -0.625; 
    highpass.a = 1.0; 

    /* Overlay blend */ 
    highp vec3 overlay = vec3(1.0); 
    if (highpass.r <= 0.5) { 
     overlay.r = 2.0 * color.r * highpass.r; 
    } else { 
     overlay.r = 1.0 - 2.0 * (1.0 - color.r) * (1.0 - highpass.r); 
    } 
    if (highpass.g <= 0.5) { 
     overlay.g = 2.0 * color.g * highpass.g; 
    } else { 
     overlay.g = 1.0 - 2.0 * (1.0 - color.g) * (1.0 - highpass.g); 
    } 
    if (highpass.b <= 0.5) { 
     overlay.b = 2.0 * color.b * highpass.b; 
    } else { 
     overlay.b = 1.0 - 2.0 * (1.0 - color.b) * (1.0 - highpass.b); 
    } 
    color.rgb = (overlay * 0.8) + (orig.rgb * 0.2); 

    /* Desaturated hard light */ 
    highp vec3 desaturated = vec3(orig.r + orig.g + orig.b/3.0); 
    if (desaturated.r <= 0.5) { 
     color.rgb = 2.0 * color.rgb * desaturated; 
    } else { 
     color.rgb = vec3(1.0) - vec3(2.0) * (vec3(1.0) - color.rgb) * (vec3(1.0) - desaturated); 
    } 
    color = (orig * 0.6) + (color * 0.4); 

    /* Add back some color */ 
    highp float average = (color.r + color.g + color.b)/3.0; 
    color.rgb += (average - color.rgb) * (1.0 - 1.0/(1.001 - 0.45)); 

    gl_FragColor = (color * clarity) + (orig * (1.0 - clarity)); 
} 
); 
#else 
NSString *const kGPUImageClarityFragmentShaderString = SHADER_STRING 
(
uniform sampler2D inputImageTexture; 
uniform float clarity; 
uniform vec2 textureSize; 
varying vec2 textureCoordinate; 
void main() { 
    vec4 color = texture2D(inputImageTexture, textureCoordinate); 
    vec4 orig = color; 

    /* High pass filter */ 
    vec4 highpass = color * 5.0; 

    float dx = 1.0/textureSize.x; 
    float dy = 1.0/textureSize.y; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx, -dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx, -dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx, dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx, dy)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx * 2.0, -dy * 2.0)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx * 2.0, -dy * 2.0)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(dx * 2.0, dy * 2.0)) * -0.625; 
    highpass += texture2D(inputImageTexture, textureCoordinate + vec2(-dx * 2.0, dy * 2.0)) * -0.625; 
    highpass.a = 1.0; 

    /* Overlay blend */ 
    vec3 overlay = vec3(1.0); 
    if (highpass.r <= 0.5) { 
     overlay.r = 2.0 * color.r * highpass.r; 
    } else { 
     overlay.r = 1.0 - 2.0 * (1.0 - color.r) * (1.0 - highpass.r); 
    } 
    if (highpass.g <= 0.5) { 
     overlay.g = 2.0 * color.g * highpass.g; 
    } else { 
     overlay.g = 1.0 - 2.0 * (1.0 - color.g) * (1.0 - highpass.g); 
    } 
    if (highpass.b <= 0.5) { 
     overlay.b = 2.0 * color.b * highpass.b; 
    } else { 
     overlay.b = 1.0 - 2.0 * (1.0 - color.b) * (1.0 - highpass.b); 
    } 
    color.rgb = (overlay * 0.8) + (orig.rgb * 0.2); 

    /* Desaturated hard light */ 
    vec3 desaturated = vec3(orig.r + orig.g + orig.b/3.0); 
    if (desaturated.r <= 0.5) { 
     color.rgb = 2.0 * color.rgb * desaturated; 
    } else { 
     color.rgb = vec3(1.0) - vec3(2.0) * (vec3(1.0) - color.rgb) * (vec3(1.0) - desaturated); 
    } 
    color = (orig * 0.6) + (color * 0.4); 

    /* Add back some color */ 
    float average = (color.r + color.g + color.b)/3.0; 
    color.rgb += (average - color.rgb) * (1.0 - 1.0/(1.001 - 0.45)); 

    gl_FragColor = (color * clarity) + (orig * (1.0 - clarity)); 
} 
); 
#endif 

@implementation GPUImageClarityFilter 

@synthesize clarity = _clarity; 

#pragma mark - 
#pragma mark Initialization and teardown 

- (id)init; 
{ 
    if (!(self = [super initWithFragmentShaderFromString:kGPUImageClarityFragmentShaderString])) 
    { 
     return nil; 
    } 

    clarityUniform = [filterProgram uniformIndex:@"clarity"]; 
    self.clarity = 0.0; 

    return self; 
} 

#pragma mark - 
#pragma mark Accessors 

- (void)setClarity:(GLfloat)clarity; 
{ 
    _clarity = clarity; 

    [self setFloat:_clarity forUniform:clarityUniform program:filterProgram]; 
} 

@end 

Еще одна вещь, которую я думал, что делать применяет встроенную GPUImage в в фильтрах нижних частот и высоких частот, но у меня возникает ощущение, что в итоге получится довольно неуклюжий olution.

ответ

1

Это, вероятно, связано с тем, что textureSize не является стандартной формой, которая предоставляется вам как часть GPUImageFilter. inputImageTexture и textureCoordinate - стандартная униформа, предоставляемая одним из этих фильтров, и похоже, что вы предоставляете форму clarity.

С textureSize не установлен, он по умолчанию будет 0.0. Затем ваш расчет 1.0/textureSize.x делит на ноль, что приводит к появлению черных кадров в шейдере фрагментов iOS.

Вы можете либо вычислить, либо предоставить эту единицу, либо вместо этого взглянуть на исходный фильтр на GPUImage3x3TextureSamplingFilter. Этот базовый класс фильтра проходит в результате 1.0/textureSize.x как формата texelWidth (и соответствие texelHeight для вертикального компонента). Вам не нужно это вычислять. Фактически, он также вычисляет координаты текстуры окружающих 8 пикселей, поэтому вы можете вырезать четыре из вышеперечисленных вычислений и преобразовать их в не зависящие от текстуры. Вам просто нужно вычислить четыре текстовых показания на основе 2 * texelWidth и 2 * texelHeight, чтобы завершить оставшиеся четыре чтения.

Возможно, вы сможете разбить эту операцию на несколько проходов, чтобы экономить на вычислениях, делая небольшое размытие ящика, затем накладываемую смесь, а затем последнюю ступень этого фильтра. Это может ускорить это.

+0

Спасибо, Брэд, я сделаю снимок. – brandonscript

+0

Провел некоторое время, играя с ним, но, к сожалению, я недостаточно знаком с написанием шейдеров, чтобы выяснить, как интегрировать 3x3TextureSamplingFilter. Вместо этого я просто играл с некоторыми жестко закодированными значениями для текстуры и приземлялся на «320.0», придавая мне отличный эффект. – brandonscript

+0

Черт, и, конечно, это работает только в том случае, если входное изображение имеет конкретное измерение. – brandonscript

0

Таким образом, вы можете переопределить

(void)setupFilterForSize:(CGSize)filterFrameSize 

Метод для установки коэффициента ширины & высоты, как GPUImageSharpenFilter.