Pocket

cyberagent製のGPUImageFilterのシェーダは、java/kotlinの文字列で定義されています。

次は、GPUImageContrastFilter.java の CONTRAST_FRAGMENT_SHADERです。

    public static final String CONTRAST_FRAGMENT_SHADER = "" +
            "varying highp vec2 textureCoordinate;\n" +
            " \n" +
            " uniform sampler2D inputImageTexture;\n" +
            " uniform lowp float contrast;\n" +
            " \n" +
            " void main()\n" +
            " {\n" +
            "     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" +
            "     \n" +
            "     gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);\n" +
            " }";

文字列のまま編集するのは、面倒なんですね。行ごとに、ダブルクォートで囲んで、行末に「+」をつける必要があります。

別ファイルにしたいなと思って探したら、GPUImageFilterにloadShaderメソッドとconvertStreamToStringメソッドがありました。

(1)loadShaderメソッド

loadShaderメソッドは、assetsから読み込みます。次のように使います。

GPUImageGrayscaleFilterを機能はそのままで、シェーダー文字列をassetsに出して、MyGPUImageGrayscaleFilterを作ってみます。

まず、assets/gpuimage/my_grayscale.c を新規作成します。

precision highp float;

varying vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);

void main()
{
    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
    float luminance = dot(textureColor.rgb, W);

    gl_FragColor = vec4(vec3(luminance), textureColor.a);
}

次に、MyGPUImageGrayscaleFilter.javaを作ります。

public class MyGPUImageGrayscaleFilter extends GPUImageFilter {
    public static MyGPUImageGrayscaleFilter create(Context context) {
        String fragmentShader = GPUImageFilter.loadShader("gpuimage/my_grayscale.c", context);
        return new MyGPUImageGrayscaleFilter(fragmentShader);
    }

    public MyGPUImageGrayscaleFilter(String fragmentShader) {
        super(NO_FILTER_VERTEX_SHADER, fragmentShader);
    }
}

GPUImageFilterのインスタンスを作る箇所では、上で用意したcreateメソッドを使います。

GPUImageGrayscaleFilter filter = new GPUImageGrayscaleFilter();
↓
MyGPUImageGrayscaleFilter filter = MyGPUImageGrayscaleFilter.create(context);

または、次のように MyGPUImageGrayscaleFilter.javaを作っておき、

public class MyGPUImageGrayscaleFilter extends GPUImageFilter {
    public MyGPUImageGrayscaleFilter(String fragmentShader) {
        super(NO_FILTER_VERTEX_SHADER, fragmentShader);
    }
}

インスタンスを作る側で、assetsから読み込んでもいいと思います。

String fragmentShader = GPUImageFilter.loadShader("gpuimage/my_grayscale.c", context);
MyGPUImageGrayscaleFilter filter = new MyGPUImageGrayscaleFilter(fragmentShader);

(2) convertStreamToStringメソッド

convertStreamToStringメソッドは、RAWリソースのファイルから読み込みます。

res/raw/my_grayscale.txt を新規作成します。内容はさきほどの assets/gpuimage/my_grayscale.c と同じ内容です。

public class MyGPUImageGrayscaleFilter extends GPUImageFilter {
    public static MyGPUImageGrayscaleFilter create(Context context) {
        String fragmentShader = GPUImageFilter.convertStreamToString(context.getResources().openRawResource(R.raw.my_grayscale));
        return new MyGPUImageGrayscaleFilter(fragmentShader);
    }

    public MyGPUImageGrayscaleFilter(String fragmentShader) {
        super(NO_FILTER_VERTEX_SHADER, fragmentShader);
    }
}

GPUImageFilterのインスタンスを作る箇所では、上で用意したcreateメソッドを使います。

GPUImageGrayscaleFilter filter = new GPUImageGrayscaleFilter();
↓
MyGPUImageGrayscaleFilter filter = MyGPUImageGrayscaleFilter.create(context);

または、次のように MyGPUImageGrayscaleFilter.javaを作っておき、

public class MyGPUImageGrayscaleFilter extends GPUImageFilter {
    public MyGPUImageGrayscaleFilter(String fragmentShader) {
        super(NO_FILTER_VERTEX_SHADER, fragmentShader);
    }
}

インスタンスを作る側で、R.rawから読み込んでもいいと思います。

String fragmentShader = GPUImageFilter.convertStreamToString(context.getResources().openRawResource(R.raw.my_grayscale));
MyGPUImageGrayscaleFilter filter = new MyGPUImageGrayscaleFilter(fragmentShader);