Help us understand the problem. What is going on with this article?

GPUImageでフラグメントシェーダに配列を渡す方法

More than 3 years have passed since last update.

2016-11-14 NSArray用のも追加

たぶん当たり前すぎて誰も書いてないんでしょうけど、GPUImageではじめてシェーダ触る僕が苦労したのでまとめました。
なんかもっと良い方法あったら教えてください。

GPUImageFilterを継承したクラス

GPUImageArrayTestFilter.h
#import <GPUImage/GPUImage.h>

@interface GPUImageArrayTestFilter : GPUImageFilter
{
  //配列のユニフォーム
  GLint testUniform;
  //長さのユニフォーム
  GLint sizeUniform;
}

//配列データを受け取るプロパティ
@property(readwrite, nonatomic) GLfloat *test;

//配列の長さも同時に指定するセッタ
-(void)setTest:(GLfloat *)test withSize:(GLsizei)size;

@end
GPUImageArrayTestFilter.m
#import "GPUImageArrayTestFilter.h"

//シェーダーをNSStringの文字列として用意する
NSString *const kGPUImageArrayTestShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;

//固定長しかダメ?
 uniform highp float test[256];
//実際に使う配列の長さ
 uniform highp int size;

 void main()
 {
  //基本は黒
   lowp vec3 color = vec3(0.0, 0.0, 0.0);

   //配列内で指定された矩形だけ赤くする
   for(int i = 0 ; i < size; i+=4){
     if(test[i] < textureCoordinate.x
        && textureCoordinate.x < test[i] + test[i + 2]
        && test[i+1] < textureCoordinate.y
        && textureCoordinate.y < test[i+1] + test[i+3]
        ){
       color = vec3(1.0, 0.0, 0.0);
       break;
     }
   }
   gl_FragColor = vec4(color, 1);
 }
 );

@implementation GPUImageArrayTestFilter

- (id)init{
  if (!(self = [super initWithFragmentShaderFromString:kGPUImageArrayTestShaderString]))
  {
    return nil;
  }
  //配列のuniformIndexを登録
  testUniform = [filterProgram uniformIndex:@"test"];
  //長さのuniformIndexを登録
  sizeUniform = [filterProgram uniformIndex:@"size"];

  return self;
}

//C言語の配列とその長さも同時に指定するセッタ
-(void)setTestCArr:(GLfloat *)test withSize:(GLsizei)size{
  _test = test;
  //配列のポインタをセット
  [self setFloatArray:_test length:size forUniform:testUniform program:filterProgram];
  //実際のデータのサイズをセット
  [self setInteger:size forUniform:_sizeUniform program:filterProgram];
}

//NSArrayを代入するセッタ
-(void)setTestNSArr:(NSArray*)test{
  float *cArr = (float*)malloc(sizeof(float*)*test.size);
  for(int i = 0 ; i < test.size ; i++){
   cArr[i] = [test[i] floatValue];
  }
  [self setTestCArr:cArr withSize:test.size];
  free(cArr);
}

//デフォルトのセッタは配列の長さを0としておく
-(void)setTest:(GLfloat *)test{
  [self setTest:test withSize:0];
}

@end

使い方

test.m
  //矩形表示用のテストデータ
  float test[8] = {
    //x,y,width,heightの順で入れている
    0.2, 0.2, 0.1, 0.1
    ,0.6, 0.2, 0.1, 0.1
  };

  GPUImageArrayTestFilter *filter = [GPUImageArrayTestFilter new];

  [filter setTestCArr:test withSize:8];

//あとはGPUImageのフィルタとして実行

実行結果

こんな画像が出来ます。
IMG_0868.PNG

最後

これで検出した顔情報ごとに何か処理をやるみたいなこともできますね

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした