ボリュームデータの法線の求め方

基本的な考え方

normal.png
ふつうは面の法線を求める。
面という概念のないボリュームデータの場合はどうする?
等値面で光が反射していると考える。
なので等値面に対して垂直なベクトルが法線になる。

この図の場合、オレンジ色の線が法線になる。
つまりは、隣とのデータ値の差で重み付けした方向に法線が向くように計算できるのだ。

ソースコード

レイキャスティング法でレンダリングする場合は、
フラグメントシェーダで法線を計算する。
頂点シェーダだと、立方体の端っこだけになってしまうから。

#define DELTA (0.01)
#define THRESHOLD (0.1)
half4 main(half3 uvw : TEXCOORD0,
float3 position : TEXCOORD1,
uniform float3 lightPosition,
uniform float3 eyePosition,
uniform sampler3D texture,
uniform sampler1D transfer_function) : COLOR{
half sample = tex3D(texture,uvw).x;
half4 result = tex1D(transfer_function,sample);
if(result.a>THRESHOLD){
float3 sample1,sample2,alpha1,slpah2,
//six texture samples for gradient
sample1.x=tex3D(texture,uvw-half3(DELTA,0.0,0.0)).x;
sample2.x=tex3D(texture,uvw+half3(DELTA,0.0,0.0)).x;
sample1.y=tex3D(texture,uvw-half3(0.0,DELTA,0.0)).x;
sample2.y=tex3D(texture,uvw+half3(0.0,DELTA,0.0)).x;
sample1.z=tex3D(texture,uvw-half3(0.0,0.0,DELTA)).x;
sample2.z=tex3D(texture,uvw+half3(0.0,0.0,DELTA)).x;
//six texture samples for the transfer function
alpha1.x=tex1D(transfer_function,sample1.x).a;
alpha2.x=tex1D(transfer_function,sample2.x).a;
alpha1.y=tex1D(transfer_function,sample1.y).a;
alpha2.y=tex1D(transfer_function,sample2.y).a;
alpha1.z=tex1D(transfer_function,sample1.z).a;
alpha2.z=tex1D(transfer_function,sample2.z).a;
//central difference and normalization
float3 N=normalize(alpha2-alpha1);
//calculate light-and viewing direction
float3 L = normalize(lightPosition-position);
float3 V = normalize(eyePosition-position);
//add local illumination
result.rgb+=shading(N,V,L);
}
return result;
}
サポートサイト Wikidot.com shader