水面下を描く - 集光効果の習作(2020.06.26)

はじめに

 ここでは集光効果の説明と、その表現を目指した以下の作品についての説明を行います。

集光効果 = caustics

 集光効果もしくは集光模様のことをコンピュータグラフィックスではコースティクス (caustics)と呼ばれています。

コースティクスは光の反射・屈折等により、光がある部分に集中することで発生します。 以下の図はバークレイのフォトンマッピングの授業のページに掲載されているものです ( https://people.eecs.berkeley.edu/~sequin/CS184/TOPICS/GlobalIllumination/Gill_b.html )。

causticsの説明図

フォトンマッピングとは Henrik Wann Jensen が開発したレンダリングアルゴリズムで、 コースティクスなどの表現まで対応します。

Jensen さんは CG 界の有名人なのですが、私はなぜか秋葉原のメイド喫茶に Jensen さんを含めた皆さんと一緒に行くという、 自分でもちょっと何を言っているのかよく分からない状況になったことがあります (懐かしい)。

と、それはさておき、光が集る部分は明るくなるので、 水面が作る模様も集光効果のひとつです。

causticsの例

FreeImages.com/Tatyana Postovyk

https://jp.freeimages.com/photo/sunlignt-effect-on-sea-water-1532485

ソースコード(清書版)

size(500,500)
blendMode(ADD)
surfaceHeight=[
  [noise(i*.005,j*.005) for i in range(500)] for j in range(500)
]
noStroke();
fill(2)
background(50,80,150)
for y in range(499):
    for x in range(499):
        dx=surfaceHeight[y  ][x+1]-surfaceHeight[y][x]
        dy=surfaceHeight[y+1][x  ]-surfaceHeight[y][x]
        circle(x+dx*6000,y+dy*6000,4)

プログラムの解説

 この作品では、光が沢山集まっている所を白く光らせる必要があるため、 加色混合モードを利用します(blendMode(ADD))。

後は、水面により屈折した光のビーム(面積を持った光の集合)を描けば コースティクスが浮かび上がってくることとなります。

しかし、これを真面目に計算するのは大変です (なので、フォトンマッピングという技術が開発された訳です。 もちろん、フォトンマッピングはビームではなくあくまでも ポイントサンプリングをベースとする技術なので、 面積を持ったビームを取り扱っているわけではないのですが、 まあ、それはそれとして)。

 この作品の目的は、集光効果もしくは集光効果らしきものを つぶやき Processing で 表現することにあります。 そのため、処理を大幅に簡略化する必要があります。

 まず、水面の表現ですが、ここでは単純にノイズ関数を用いています。 ノイズ関数により水面の高さを計算し、それを配列 surfaceHeight に格納しています。

 水面による光の屈折は光の侵入角度により定まります。 ここでは、光は真上からやってくるものとして、 あとは水面の傾きにより適当に方向を変える、という処理をしています。

なので、屈折については全く考慮していません。 この段階で、この作品は疑似的な集光効果の表現にならざるを得なくなっています。

 水面の傾きは、現在注目している位置 (x,y) の隣の位置との差分により計算しています。 ここも丁寧に処理する場合、異なった方法がありますが、 とにかく文字数を減らす必要があるため、 この作品では、水平方向は右隣と、垂直方向はひとつ下の値との差分を用いて 水面の傾斜 (dx,dy) として取り扱っています。

 傾きが得られたので、それを用いて円を描く部分を定めています (circle(x+dx*6000,y+dy*6000,4))。 6000 という値や円の半径 4 という値に根拠はありません。 生成される画像を見ながら調整した値です。

 この方法は単に円の描画される位置を変位させているだけです。 それでもこのような集光効果による模様を得ることができています。

まとめ

 このページでは冒頭に挙げた作品をベースとして、 集光効果の説明と簡易な集光効果の実装例(習作)について説明しました。

 コースティクスについて、ビームを用いて真面目に考えると、 ビームの境界領域毎に屈折の度合いが異なるし、 また、水面から水の底への距離によっては、 ビームの面積が小さくなったり・大きくなったりするはずです。

ビームが持つエネルギーは一定ですので、 面積が小さくなればその領域はより明るくなり、 面積が大きくなれば暗くなります。

 今回のプログラムではそこまでの処理は入っていません。 しかし、この程度の処理でも集光効果らしき模様が現れています。 ただ、微妙なリップルも現れており、アーティファクトとなってしまっています。

この辺りが解決できれば、さらに完成度が高くなると思うのですが、 なかなか良い方法が見つかっていません。