就職氷河期
M2 が二人売れ残ってます。他の二人がさっさと決めてくれたので意外と調子いいなと思ってたんですが、残る二人がなかなか決まりません。うち一人は早くから研究成果を出していた人なので悔しいです。それに就職活動が長引いたせいで、せっかく積み上げてきた成果がしなびてしまいそうです。なんとかならんかな。
似非 SSS (Subsurface Scattering)
先日 SSAO のサンプルを作っているときに久保尋之氏からメッセージを頂いたのをきっかけに、久保氏のご研究をヒントに、もしかしたらこういう方法でも SSS (Subsurface Scattering, 表面下散乱) っぽい表現ができるかも、と考えてやってみました。この方法は理論的な裏付けもサーベイもしてませんし、速くもなければ品質が良い訳でもないのですが、SSAO のプログラムをわずかにいじるだけで実現できます。いじったのは下記のところです。
- サンプル点の密度を均一にした。
- サンプル点の散布範囲を大きくした。
- 遮蔽されないサンプル点数と環境光の反射係数との関係を調整した。
- 拡散反射係数・鏡面反射係数などのマテリアルを微調整した。
- 光源強度・環境光強度を微調整した。
- 背景・地面を描かないようにした。
- 環境マッピング・屈折マッピングを取り除いた。
サンプルプログラムは SSAO のものとほとんど変わりませんが、一応まとめました。SSAO との差分も用意しています。
サンプル点の散布方法
SSAO の場合はサンプル点を密度が距離の二乗に反比例するように散布していましたが、これを均一にしました。密度が距離の二乗に反比例していると照射点に近い部分の影響が強くなりすぎて、表面に近いところだけが明るくなってしまいます。密度が均一ということは、照射点の周囲の空間の体積を計測することになります。また、透過光がオブジェクト全体に行き渡る? ように、サンプル点の散布範囲をオブジェクトのサイズに対して大きめに設定します。
/*
** 深度のサンプリングに使う点群
*/
#define MAXSAMPLES 256 // サンプル点の最大数
#define SAMPLERADIUS 0.3f // サンプル点の散布半径
static GLfloat pointbuf[MAXSAMPLES][4]; // サンプル点の位置
static GLint point; // サンプル点の uniform 変数
...
/*
** 初期化
*/
static void init(void)
{
...
/*
** 露出度を算出するのに使う球状の点群
*/
// サンプル点の生成
for (int i = 0; i < MAXSAMPLES; ++i) {
float r = SAMPLERADIUS * pow((float)rand() / (float)RAND_MAX, 1.0f / 3.0f);
float t = 6.2831853f * (float)rand() / ((float)RAND_MAX + 1.0f);
float cp = 2.0f * (float)rand() / (float)RAND_MAX - 1.0f;
float sp = sqrt(1.0f - cp * cp);
float ct = cos(t), st = sin(t);
pointbuf[i][0] = r * sp * ct;
pointbuf[i][1] = r * sp * st;
pointbuf[i][2] = r * cp;
pointbuf[i][3] = 0.0f;
}
}
環境光の反射係数
サンプル点とデプスバッファを比較して可視のものの数を求めるところは同じですが、この場合は照射点の周囲の空間の体積を求めます。これがサンプル点数の 2 分の 1 を超えたら、超えた分に比例して環境光の反射係数を大きくします。これは自己発光強度を上げたことになります。
// 遮蔽されないポイントの数から周辺のボリュームを求め、露出度に換算する
float a = clamp(float(count) * SAMPLING_RATIO / float(SAMPLES), 1.0, SAMPLING_RATIO);
// 環境光の反射光 (unit[1]) に露出度を適用
vec4 color = diffspec + texture2D(unit[1], texcoord) * a;
そのほか
材質や光源は SSS っぽく見えるようにトライアンドエラーでアドホックに設定しています。
