2011冬コミ備忘録

2011冬コミ、三日間参加してずっとコス写真撮ってきました。
今回、枚数は277枚で思ってたより少ない結果となりました。
原因はどう考えても混雑。ということでそこらへんを今度のコミケのために立ち回りとかについて書いておく!
to me!


今回のコスプレ広場はひどかった!第一会場は日を追うごとに狭く、移動しづらくなっていって・・・特にひどかったのが最終日。寿司詰め。
今まで会場だった場所が意味不明に通路になっていたり、今まで出口だった場所がただのDEAD ENDになってて誰も係員が居ないから混乱するわ。


第二会場の屋上広場も三日目は寿司詰め。屋上広場なんて通りかかった人もとりあえず入ってくるからもうとんでもないことに・・・。
イベント会場と内部で合体してるとかいう意味わからん構造のおかげで二度三度入り口と出口が現れては消え、現れては消えで大混乱。


逆に1・2日目の第二会場である駐車場のほうが今までより広さが二倍位になっていてすごい良かった。あれは継続すべき!


ということで今年のテンションは1日目がピークでどんどん落ちていく形に。とりあえず来年はまず広場の予定をちゃんと確認しよう。
特に屋上広場がどうなるかはまじで気をつけたほうがいい。あと来年は第一広場行かない!ずっと駐車場にいく!
そんで屋上広場がまたちょっとだめそうなら、となコスも吝かではない。


あ、あと写真の撮り方もメモ。


自分の写真の基本信念は「ボカしたい」なんだけど、今回は晴天なのできつかった。
晴天逆光だとボカしながらフラッシュ焚くには、ハイスピードシンクロない今の機材じゃ無理、、、
しかしどうしても絞りは開放で行きたい、、、今年はかなり失敗写真ばかりだけど、来年はそうならないように
ハイスピードシンクロのストロボ買うか、妥協して絞って撮るべし。


ふう、文脈も考えず殴り書きしてしまった。次のコミケの直前の俺、ちゃんとこの記事見るんだよ!



あ、あけましておめでとうございます。

モノトーンフィルター

ちょっと故あって基本的な事からちゃんと埋めて行こう、って自分の中でなったので今日はモノトーンフィルターについて調べました。

ベリーダンスのモーション落としてきたので今日はこんな画像をモノクロにしてみましょう。

とりあえず思いついたものが、RGBの平均値を出力すればいいんじゃないの?って。それが以下

//=============================================================================
// ピクセルシェーダ
// (頂点シェーダは入力をそのまま出力)
//=============================================================================
float4 PS(
  float2 Tex: TEXCOORD0
  ) : COLOR 
{
  float4 Color = tex2D( ScnSamp, Tex);
  float4 AVE = float4( 0.3333333f, 0.3333333f, 0.3333333f, 0.0f );
  float RGB_AVE = dot( Color, AVE );
  return float4( RGB_AVE, RGB_AVE, RGB_AVE, 1.0f);
}

結果画像。


まあ、そうだよねっていう画像が出てきたのですが、一応調べてみるとどうやら普通はYIQとかに変換してモノクロを作成するみたい。

色空間 - Wikipedia - http://ja.wikipedia.org/wiki/%E8%89%B2%E7%A9%BA%E9%96%93

ここ見ると詳しく書いてあるけど、たとえばYIQってのは放送用だったりする。つまり、テレビとか画像で見てる「モノクロ」ってのはこっちのことをさすみたい。ちなみにYIQでモノクロを作成すると以下のようになる。

//=============================================================================
// ピクセルシェーダ
// (頂点シェーダは入力をそのまま出力)
//=============================================================================
float4 PS(
  float2 Tex: TEXCOORD0
  ) : COLOR 
{
  float4 Color = tex2D( ScnSamp, Tex);
  float4 YIQ_Y_AXIS = float4( 0.299f, 0.587f, 0.114f, 0.0f );
  float Y = dot(Color,YIQ_Y_AXIS);
  return float4( Y, Y, Y, 1.0f);
}

結果画像。


よくわかんないので比較用のシェーダ書いて画像出してみた。左がRGB、右がYIQ。


そんなに違いはないんだけど、水着の青い部分がちょこっと黒味がかってる?というかRGB平均と比べたら、YIQのは重みが違うだけだからそんなに違いないのは当たり前か!式から見ると青が弱めで緑が強いのか。弱いって事は0.0fに近いって事だから黒く写る、って事で確かに画像と一致してますね。

なるほどー。今日はこんなところで。

最近はRubyしてます

夜中に突然ブログのデザインを編集したくなっちゃって3時だよ・・・。更新もして無いのにアホちゃうか…。一応このデザインに変えたのは理由があって、ソースが見やすいからです。あと前のピアノデザインは横幅が狭すぎたってのも。


さてさて最近はずっとRubyにかまけててMMEとかやってなかったわけで。ずっと会社でバッシュばっかりやってて、ウヒョーシェルタノシー状態が続いてたんだけど、ある日Ruby触ってみたらやりたいことが結構楽に出来ることに気がついて少し続けてるっていう状態です。さすがに高級言語だけあって、やりたいことを主軸にしたら強いなあとか思った。


まあ俺のやりたい事(プログラムで自動化したい事)って画像掲示板の自動巡回とかTodoリストとかそういうちっちゃいプログラムなんですがね…。砂時計をずっと見てられる自分としてはそういうのを走らせて自動でがりがりやってるのをずっと見てるのが好き。どう考えても手動のほうが効率いいです本当にありがとうございました。


それとは別に同期が貼ったストッキングエフェクトが秀逸すぎて、自分がやりたいことを思い出した感もあるのでまた少しMMEも弄ってみようかなと思ってるところだったり。ハーフランバートが面白そう。やりたいことにpushしておいた。他にもゲームプログラミングの基本の流れを習得したいのでクソゲー量産も考えてて、やりたいことは山積みだけど時間が足りない状態ですね。とりあえずは帰ってからの作業の効率化と残業しないで帰れるスキルを磨きますw

スクリプトでパスを複数回繰り返す

あらすじ:ラジアルブラーを複数回かけたいけど、パスを手動で書くのよりいいのがあるんじゃないのか?と模索する

描画の制御が出来るスクリプトってものがMMEにはあります。MME落としたらREFERENCEがついてくるのでそれを参照!そのなかに、スクリプトのループ系の命令がいくつかありました。

  • LoopByCount=(パラメータ名)
  • LoopEnd=
  • LoopGetIndex=(パラメータ名)

適当に int Count = 3 とか作っておいて、LoopByCount=Countとか置いてやると、それ以降でLoopEnd=までをCount分だけ繰り返してくれるようだ。しかもLoopGetIndex=パラメータとか置いてあげると、そのパラメータに値を受け渡すことが出来るみたい。
ということは、ラジアルブラーのパワーを変えつつ複数回描画するには別に手動で似たようなパスを複数作る必要ないんじゃないか?と思い、作成したのが以下のスクリプト

float COUNT = 3.0f;

//-------------------------------------
// ラジアル3回描画
//-------------------------------------
technique Radial <
  string Script = 
    "RenderColorTarget0=ScnMap;"
    "RenderDepthStencilTarget=DepthBuffer;"
      "ClearSetColor=ClearColor;"
      "ClearSetDepth=ClearDepth;"
      "Clear=Color;"
      "Clear=Depth;"
    "ScriptExternal=Color;"
    "LoopByCount=COUNT;"
    "LoopGetIndex=blur_power;"
      "RenderColorTarget0=;"
        "RenderDepthStencilTarget=;"
        "ClearSetColor=ClearColor;"
        "ClearSetDepth=ClearDepth;"
        "Clear=Color;"
        "Clear=Depth;"
        "Pass=Radial;"
    "LoopEnd=;"
    ;
> {
    pass Radial < string Script= "Draw=Buffer;"; > {
        AlphaBlendEnable = FALSE;
        VertexShader = compile vs_3_0 VS();
        PixelShader  = compile ps_3_0 PS_Radial();
    } 
}
      "RenderColorTarget0=;"
        "RenderDepthStencilTarget=;"
        "ClearSetColor=ClearColor;"
        "ClearSetDepth=ClearDepth;"
        "Clear=Color;"
        "Clear=Depth;"
        "Pass=Radial;"

を三回描画して、COUNTの値をradial_powerに受け渡してみた。内部でradial_pwoerを*20.0fとかしておけば、ラジアルパワー20.0f,40.0f,60.0fで描画できてるはず!
しかし結果は…。


だめじゃんorz

何故かわわかりませんが・・・。
比較の為に次はラジアルを複数パス作ってやってみます。今日はここまで…。

スクリプトの理解は深まったのでよしとしよう…!

ラジアルブラー!

あらすじ:ラジアルブラーのソース載せます

さーて、仕事が2年目に突入して少しだけ時間に余裕が出来る様になりました。ここぞとばかりにMMEやりましょうかね。

ラジアルブラーについて。

説明は要らないかもしれないけど自分の為にちょい説明を。ラジアルってのは放射状っていう意味で、ラジアルブラーって言うのは放射状にブラー(ぼかし)をかける手法のこと。どうやって放射状にするかというと、ある中心点Cを決めて現在の座標PとのベクトルPCを方向ベクトルにします。この方向ベクトル上で色を拾ってボカシをかけてあげるとラジアルブラーの出来上がり。

他に注意する点は

  • パラメータは方向ベクトルを伸ばしたり縮めたりするPower
  • 自分に近い色の要素を強く拾ってくるように重みをかける
    • 合計が1にならないと色が減ったり増えたりしちゃうので注意
    • ガウシアンブラーの重みをつかうのがベター

位ですかね。

ソース

//===================================================================
// ラジアルブラー
//===================================================================

//===================================================================
// 定数・定義
//===================================================================

//-------------------------------------
// パラメータ:ブラーパワー
// 個人的に弱20.0f,中30.0f,強50.0f
//-------------------------------------
float blur_power = 20.0f;


//-------------------------------------
//-------------------------------------
float Script : STANDARDSGLOBAL <
    string ScriptOutput = "color";
    string ScriptClass = "scene";
    string ScriptOrder = "postprocess";
> = 0.8;

//-------------------------------------
// スクリーンサイズ
//-------------------------------------
float2 ViewportSize : VIEWPORTPIXELSIZE;
static float2 ViewportOffset = (float2(0.5,0.5)/ViewportSize);
//-------------------------------------
// レンダリングターゲットのクリア値
//-------------------------------------
float4 ClearColor = {1,1,1,1};
float ClearDepth  = 1.0;


//-------------------------------------------------------------------
// レンダーターゲット・テクスチャ
//-------------------------------------------------------------------

//-------------------------------------
// オリジナルの描画結果を記録するためのレンダーターゲット
//-------------------------------------
texture2D ScnMap : RENDERCOLORTARGET <
    float2 ViewPortRatio = {1.0,1.0};
    int MipLevels = 1;
    string Format = "A8R8G8B8" ;
>;
sampler2D ScnSamp = sampler_state {
    texture = <ScnMap>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU  = CLAMP;
    AddressV = CLAMP;
};


//-------------------------------------
// デプスバッファー
//-------------------------------------
texture2D DepthBuffer : RENDERDEPTHSTENCILTARGET <
    float2 ViewPortRatio = {1.0,1.0};
    string Format = "D24S8";
>;

//===================================================================
// 構造体
//===================================================================

//-------------------------------------
// VS->PS
//-------------------------------------
struct VS_OUTPUT {
    float4 Pos      : POSITION;
  float2 Tex      : TEXCOORD0;
};

//===================================================================
// 頂点シェーダ
//===================================================================
VS_OUTPUT VS( float4 Pos : POSITION, float4 Tex : TEXCOORD0 ) {
    VS_OUTPUT Out = (VS_OUTPUT)0; 

    Out.Pos = Pos;
    Out.Tex = Tex + float2(0, ViewportOffset.y);
    return Out;
}


//===================================================================
// ピクセルシェーダ
//===================================================================

//-------------------------------------
// ラジアルフィルタ
//-------------------------------------
float4 PS_Radial(
  float2 Tex: TEXCOORD0
  ) : COLOR 
{

  float4 color[10];
  float2 center = float2( 0.5f, 0.5f );
  float2 dir = center - Tex;
  float len = length( dir );
  float2 offset = normalize( dir ) * ViewportOffset;
  offset *= ( blur_power * len );

  // ( シーンのテクスチャ,座標+オフセット )*ガウシアンウェイト
  color[0] = tex2D( ScnSamp, Tex                 ) * 0.19f;
  color[1] = tex2D( ScnSamp, Tex + offset        ) * 0.17f;
  color[2] = tex2D( ScnSamp, Tex + offset * 2.0f ) * 0.15f;
  color[3] = tex2D( ScnSamp, Tex + offset * 3.0f ) * 0.13f;
  color[4] = tex2D( ScnSamp, Tex + offset * 4.0f ) * 0.11f;
  color[5] = tex2D( ScnSamp, Tex + offset * 5.0f ) * 0.09f;
  color[6] = tex2D( ScnSamp, Tex + offset * 6.0f ) * 0.07f;
  color[7] = tex2D( ScnSamp, Tex + offset * 7.0f ) * 0.05f;
  color[8] = tex2D( ScnSamp, Tex + offset * 8.0f ) * 0.03f;
  color[9] = tex2D( ScnSamp, Tex + offset * 9.0f ) * 0.01f;

  float4 Color = float4( 0.0f, 0.0f, 0.0f, 0.0f );
  Color = (  color[0] + color[1] + color[2] + color[3] + color[4]
           + color[5] + color[6] + color[7] + color[8] + color[9] );
  return Color;
}

//===================================================================
// テクニック指定
//===================================================================

//-------------------------------------
// ガウシアン1回描画
//-------------------------------------
technique Radial <
  string Script = 

    "RenderColorTarget0=ScnMap;"
    "RenderDepthStencilTarget=DepthBuffer;"
      "ClearSetColor=ClearColor;"
      "ClearSetDepth=ClearDepth;"
      "Clear=Color;"
      "Clear=Depth;"
    
    "ScriptExternal=Color;"
    
    "RenderColorTarget0=;"
      "RenderDepthStencilTarget=;"
      "ClearSetColor=ClearColor;"
      "ClearSetDepth=ClearDepth;"
      "Clear=Color;"
      "Clear=Depth;"
      "Pass=Radial;"

    ;
> {
    pass Radial < string Script= "Draw=Buffer;"; > {
        AlphaBlendEnable = FALSE;
        VertexShader = compile vs_3_0 VS();
        PixelShader  = compile ps_3_0 PS_Radial();
    } 
}

//==============================[EOF]==============================//

複数回かける?

そもそも、方向ベクトルに沿って離散的に色を拾うので、ガビガビになります。ガビガビにならないようにするには離散的にならないように方向ベクトルを縮めると考えますが、それだと本当にただボケただけになります。
広い範囲でボカしつつガビガビにならないようにするには同じ事を数回やってガビガビ自体をボカしつつ広範囲に影響が行くようにします。経験的に、ブラーPowerを毎回変えてかけると綺麗になります。
上記のソースのPowerだけをかえたラジアルブラーに名前をつけて複数回かけてみたりしたのが以下です。

ブラーなし

ブラー1回(Power=20.0f)

ブラー2回(Power=20.0f,30.0f)

ブラー3回(Power=20.0f,30.0f,50.0f)

アクセサリで複数回読み込むだけでokです。

今後の展開

  • 最初っから複数回かけたラジアルブラーを作成する
  • ゲームみたいにうにょん!って発生させる
  • ラジアルブラー卒業してSSAOやる

まあ、複数回かけたソースあげろよって話だけど、まだソースが汚いのでこれまた今度w
MMDには使う用途がないかもしれないですが、動的なラジアルブラーが見たいんですよ。ゲームで使ってるような。今のラジアルだと静的なんですよね。ちょうどクリックに反応するものがあったので、押してからカウンタを進める作りにすれば多分ゲームみたいに発生させることが出来るんじゃないかと画策中!

SSAOはやり方が若干まだわかってない…。
そもそもデプステクスチャがあってフェッチ出来ることが自分の中での前提だったのでちょっと悩み中。デプス計算するの自体は簡単なんだけど、そのテクスチャを他の演算にもってこれるのか?という悩みです。一回シーンを書きつつデプスをテクスチャに保存してそれからフィルター処理すればいいのはわかってるんだが、MMEでそれをどうやれば出来るのかがわかってないのです。。。まあリファレンス嫁って話ですね^p^

ただ、このソース(サンプルのガウンシアンブラーが元になってる)に、

//-------------------------------------
// デプスバッファー
//-------------------------------------
texture2D DepthBuffer : RENDERDEPTHSTENCILTARGET <
    float2 ViewPortRatio = {1.0,1.0};
    string Format = "D24S8";
>;
とか記述があって、あれ?もしかして?状態なのは内緒。

まあ、気まぐれなので何からアップするかは気分しだいって事で!
それではまたの機会をお待ちください!

ラジアルブラー?

あらすじ:そうか、何回もかけるものなのか


いきなり久しぶりです。ちょっと間が空いちゃいました。


前回の日記で、上記のラジアルブラー的な物を作ってみて
周りから「えこれラジアルブラー?」的な反応を頂き、不安で枕をぬらす日々でした。
あれから、会社でラジアルブラーを見たりPhotoshopでのラジアルブラーを見てみたりしてようやくフィルターの事が少しだけわかるようになってきました。
結果を先に書いておくと、一回だけでは前回のような画像になって問題ないようです。そもそも何回もかけるもののようです。
自分の脳内では一回かけるとあのような綺麗なブラーになる予定ではあったのですが、そう甘くはないようです。ためしに、アクセサリとしてラジアルブラーを二重に読んでみたら、それっぽい絵になりました。ブラーの強さを変えて読み込むとさらにそれっぽい絵に!段々強くなるようにかけると格段にそれっぽくなりますね。

ラジアルブラーおわったらSSAOでもいくかな!軽いやつと重いやつ両方考えてます。

今日はとりあえず報告だけー。次は画像とソースあげますー。

MikuMikuEffectエラーメモ


数ヶ月前に、MikuMikuEffectなるものを発見しました。調度そのとき仕事でシェーダを触らせてもらえてたから、これはいいと思ってダウンロード。しかしサンプルすらエラーが出る始末でしばらく放置してたのですが、なんかいきなり動くようになりました。忘れないようにメモ。


エフェクトファイルの読み込みに失敗しました:
Error:some techniques cannot run on this hawdware: MainTec

みたいなエラーが表示されるのですが、いかんせん初心者だったので何がどうダメなのか全くわからず。ぐぐって見ても、MikuMikuEffect落としなおしてみなよくらいしか記述がなく困っていました。いろいろコメントアウトしてすこしづつ復活させてもほとんどがだめで、諦めてました。ハードウェアって事でグラボ変えてみたりとかもしたけど全く変わらず。んで、わかった結果が下。


グラボちゃんと詰んでるのに描画がエラーになる場合は、テクニック指定時にシェーダのバージョンを3.0以降にしてみる。

// 変更前 オブジェクト描画用テクニック
technique MainTec < string MMDPass = "object"; > {
    pass DrawObject
    {
        VertexShader = compile vs_2_0 Basic_VS();
        PixelShader  = compile ps_2_0 Basic_PS();
    }
}

//変更後 オブジェクト描画用テクニック
technique MainTec < string MMDPass = "object"; > {
    pass DrawObject
    {
        VertexShader = compile vs_3_0 Basic_VS();
        PixelShader  = compile ps_3_0 Basic_PS();
    }
}

仕事でシェーダを何個か書いてたので、本日再挑戦してみた。#if 0 で削って、段々戻していったら、動かないものの共通点はTEXCOORD[n]のセマンティクスを使っている部分だということまでわかった。関係ねえかーとか思いつつシェーダのバージョン指定を2.0から3.0にしたら直った・・・。2.0はTEXCOORDセマンティクスは複数個使えないの・・・?そんなことはなかったと思うのだが・・・。何故動くかまでは現在の知識では見当もつかないのです…。

あとはポストエフェクト系はアクセサリとして読むこと!これは超個人的な備忘録ですw


ようやくシェーダかけるところまで行ったので、ガウシアンぼかしのサンプルを改造してラジアルブラー作ってみました。まだちょっと調整が要りますが、最低限の部分は問題なく動きますね。これからいろんなエフェクト作るぞ!!