Henry Greensteinの位相関数

本物のページはこちら→henry-greenstein-phase-function

Included page "henry-greenstein-phase-function" does not exist (create it now)

Henry-Greenstein位相関数

異方性が各サンプル点の透明度に比例する
より具体的に言うと、
雲の後ろから光が当たった場合は雲の縁が光る。
雲の手前から光が当たった場合は、雲の縁は黒っぽくなる
といった具合。
縁の領域は、高くピークになった位相関数になっている。

逆に、雲の真ん中らへんは
等方性(isotropic)な位相関数になっている。

(1)
\begin{align} G(\theta,g)=\frac{1-g^2}{4\pi (1+g^2-2gcos\theta)^{1.5'}} \end{align}
g
異方性を表すパラメータ。0ならば等方性、すべて同じ方向に散乱する。負の場合はback-scatteringになる。多分光の波長を表しているんだと思う。0.0-1.0の範囲の値
θ
Phase angle 位相角。 光源ベクトルと視線ベクトルのなす角

Henry-Greenstein関数はθ=0のときに最大値になる。
たぶん$cos 0=1$だからかな?

最正規化する

gが正の値の場合

(2)
\begin{align} G'(\theta,g)=\frac{G(\theta,g)}{G(0,g)} \end{align}

gが負の値の場合

(3)
\begin{align} G'(\theta,g)=\frac{G(\theta,g)}{G(180,g)} \end{align}

θ=0のときはgが0以上であれば、どんな値だろうと常に$G'(0,g)=1$である。
この数式はどんなかんじになるのか?
画像として出力してみた 
縦軸がg(光の波長)で横軸がθ
値は高いほど白い。
henry_greenstein.png
Henry GreenSteinの位相関数の画像を生成するためのソースコードはこちら

# coding: UTF-8
from PIL import Image
import math#piに使う
 
im=Image.new( 'L', ( 360, 200 ));
maxvalue=0;
 
for y in range(0,200):
    g=y*0.01-1.0;#g=-1.0-1.0
    if(g>0):
        maxdenom=(math.pow((4*math.pi)*(1+g*g-2*g),1.5));
    else:
        maxdenom=(math.pow((4*math.pi)*(1+g*g+2*g),1.5));
    if(maxdenom!=0):
        maxval=(1-g*g)/maxdenom;
    else:
        maxval=1;
    if(maxval==0):
        maxval=1;
    for x in range(0,360):
 
        theta=x* math.pi / 180.0;
 
        denom=math.pow((4*math.pi)*(1+g*g-2*g*math.cos(theta)),1.5);
        if(denom!=0):
            val=(1-g*g)/denom;
        else:
            val=0;
        val=val/maxval;#normalize
        if(val>maxvalue):
            maxvalue=val;
 
        val*=255;    
 
        im.putpixel((x,y),val);
im.save( "pil.png");
print("maxval="+str(maxvalue));

シェーダに直接書いて実装する方法

最終的には位相関数を2Dテクスチャにしてキャッシュしたほうがはやいが、とりあえず実験するためシェーダに直接書いてみる。

vec3 lightvec = normalize(gl_LightSource[0].position.xyz  - uvw);
            vec3 viewvec = normalize(v_cam_local - uvw);
            //位相関数の実装
            //float g=((src.x-THRESHOLD)/0.45)*2.0-1.0;
            float g=((0.65-src.x)/0.45)*2.0-1.0;//±1.0に正規化 gには1-alphaを入れたい
            float maxdenom=1.0;
            if(g>0.0){
                maxdenom=(pow((4.0*M_PI)*(1.0+g*g-2.0*g),1.5));
            }
            else{
                maxdenom=(pow((4.0*M_PI)*(1.0+g*g+2.0*g),1.5));
            }
            float maxval=1.0;
            if(maxdenom!=0){
                maxval=(1.0-g*g)/maxdenom;
            }
            if(maxval==0){maxval=1.0;}
            float theta=(dot(lightvec,viewvec)+1.0)*0.5*2.0*M_PI;//dotの結果は±1.0なので0.0-1.0の範囲になるように正規化する
            float denom=pow((4*M_PI)*(1.0+g*g-2.0*g*cos(theta)),1.5);
            float phase=0.0;
            if(denom!=0){
                phase=(1.0-g*g)/denom;}
            else{
                phase=0;}
            phase=phase/maxval;
            phase=1.0-phase;

サポートサイト Wikidot.com