前回の続き。SMAAの実装の紹介。
ソースは最新のこっちにした。
https://github.com/iryoku/smaa
SMAAで3回分のシェーダが必要なんだけど、shader3つも作るのはナンセンスだから1つにまとめてみた。でも、これだと1passはrgチャンネルしか使わないのでbit数の最適化ができてない。まぁいいか・・・。
バーテックスシェーダ
#include "../common/version.glsl"
/* uStep
* 0:Edge Detection
* 1:Weight Calculation
* 2:BlendingWeight
*/
uniform int uStep=0;
layout(binding=0) uniform sampler2D uInpTex;
vec2 texSize = vec2(textureSize(uInpTex, 0));
#define SMAA_RT_METRICS vec4(1.0/texSize,texSize)
#define SMAA_INCLUDE_PS 0
#define SMAA_GLSL_4 1
#define SMAA_PRESET_ULTRA 1
#include "SMAA.hlsl"
noperspective out vec2 texcoord;
noperspective out vec2 pixcoord;
noperspective out vec4 offset[3];
layout(location=0) in vec3 position;
void main(){
texcoord = position.xy * 0.5 + 0.5;
if(uStep==2){
SMAANeighborhoodBlendingVS(texcoord, offset[0]);
}else if(uStep==1){
SMAABlendingWeightCalculationVS(texcoord, pixcoord, offset);
}else{
SMAAEdgeDetectionVS(texcoord, offset);
}
gl_Position = vec4(position.xy, 0.0, 1.0);
}
ピクセルシェーダ
#include "../common/version.glsl"
/* uStep
* 0:Edge Detection
* 1:Weight Calculation
* 2:BlendingWeight
*/
uniform int uStep=0;
layout(binding=0) uniform sampler2D uInpTex;
layout(binding=1) uniform sampler2D uInpTex2;
layout(binding=2) uniform sampler2D uInpTex3;
vec2 texSize = vec2(textureSize(uInpTex, 0));
#define SMAA_RT_METRICS vec4(1.0/texSize,texSize)
#define SMAA_INCLUDE_VS 0
#define SMAA_GLSL_4 1
#define SMAA_PRESET_ULTRA 1
#include "SMAA.hlsl"
noperspective in vec2 texcoord;
noperspective in vec2 pixcoord;
noperspective in vec4 offset[3];
layout(location = 0) out vec4 fOut;
void main(){
if(uStep==2){
fOut = SMAANeighborhoodBlendingPS(texcoord, offset[0], uInpTex, uInpTex2);
}else if(uStep==1){
fOut = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, uInpTex, uInpTex2, uInpTex3, ivec4(0));
}else{
fOut = vec4(SMAAColorEdgeDetectionPS(texcoord, offset, uInpTex),0.0,0.0);
}
}
多分こんな感じ。GLSLは410以降が必要。
作業用のFBOはアルファチャンネルも使うのでRGBAが必要。あと、テクスチャ用のヘッダファイルがあるのでofTextureとして登録。
ofFbo::Settings defaultSetting;
defaultSetting.numSamples=0;
defaultSetting.textureTarget=GL_TEXTURE_2D;
defaultSetting.height=768;
defaultSetting.internalformat=GL_RGBA;
defaultSetting.useDepth=false;
defaultSetting.useStencil=false;
defaultSetting.width=1024;
defaultSetting.wrapModeHorizontal=GL_CLAMP_TO_EDGE;
defaultSetting.wrapModeVertical=GL_CLAMP_TO_EDGE;
defaultSetting.numSamples=false;
fboRender_.allocate(defaultSetting); //入力用
fboAA_.allocate(defaultSetting); // AA結果表示用
fboSmaaWk_.allocate(defaultSetting); //作業用
//SMAAテクスチャ
texSmaaArea_.allocate(AREATEX_WIDTH,AREATEX_HEIGHT,GL_RG8,false);
texSmaaArea_.loadData(areaTexBytes,AREATEX_WIDTH,AREATEX_HEIGHT,GL_RG);
texSmaaArea_.setTextureMinMagFilter(GL_LINEAR,GL_LINEAR);
texSmaaSearch_.allocate(SEARCHTEX_WIDTH,SEARCHTEX_HEIGHT,GL_R8,false);
texSmaaSearch_.loadData(searchTexBytes,SEARCHTEX_WIDTH,SEARCHTEX_HEIGHT,GL_RED);
texSmaaSearch_.setTextureMinMagFilter(GL_NEAREST,GL_NEAREST);
処理はこんな感じ。blendモードとかちゃんときっておかないと動かない。
glDisable(GL_BLEND);
glClearColor(0,0,0,0);
shaderSmaa_.begin();
fboAA_.begin(false);
glColorMask(GL_TRUE,GL_TRUE,GL_FALSE,GL_FALSE);
glClear(GL_COLOR_BUFFER_BIT);
shaderSmaa_.setUniform1i("uStep",0);
shaderSmaa_.setUniformTexture("uInpTex",fboRender_,0);
ssObj.draw();
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
fboAA_.end();
fboSmaaWk_.begin(false);
glClear(GL_COLOR_BUFFER_BIT);
shaderSmaa_.setUniform1i("uStep",1);
shaderSmaa_.setUniformTexture("uInpTex",fboAA_,0);
shaderSmaa_.setUniformTexture("uInpTex2",texSmaaArea_,1);
shaderSmaa_.setUniformTexture("uInpTex3",texSmaaSearch_,2);
ssObj.draw();
fboSmaaWk_.end();
fboAA_.begin(false);
shaderSmaa_.setUniform1i("uStep",2);
shaderSmaa_.setUniformTexture("uInpTex",fboRender_,0);
shaderSmaa_.setUniformTexture("uInpTex2",fboSmaaWk_,1);
ssObj.draw();
fboAA_.end();
shaderSmaa_.end();
Openframeworksのサンプルコードはこちら(vs2012のみー)
ちなみにこのなかのofShaderHelperは、#includeとか使うために適当に作ったやつだから信用できないwGLSL4系だと結構モジュール化とかやりやすくなってるから需要あると思うので、ちゃんとしたやつをofShaderの中で強化してもらえるといいなぁ。
サンプルではFBOへの出力を単純にポストプロセスでAAかけてて、汎用的に使えると思う。最適かどうかはおいておいて、FXAA,SMAAを比較することで、メリット、デメリットが見えてくるう。SMAAは画質重視で重い。FXAAはディテールの破壊があるが高速。カメラワーク、オブジェクトの動きが激しいシーンではFXAAにスイッチするとかして使い分けるのもいいかもしれない。てかDofとか入れるとほとんどAA不要な気がする。
ところでSMAAなんだけど、MacbookAir(Intel HD 4000)でどうしてもうまく動いてくれないのだ。なんでだろー。わからーん。