Chango的數學Shader世界(十八)RayTrace三維分形(三)—— 完善,距離場軟陰影

目的:

移植Inigo Quilez的可視化三維Julia的算法到ue4。

本篇注重完善造型後模型表面的光照,軟陰影。

 

參考:

1.Inigo Quilez在ShaderToy上的Julia,網址後綴MsfGRr

2.之前我討論簡單的Fresnel:Chango的數學Shader世界(七)

 

觀察:

將上節的基本造型和Inigo Quilez的Julia對比(麥芽糖好想喫哇...)

我認爲最影響畫面效果的基本元素有3:

1.抗鋸齒

2.軟陰影

3.Blin-Phong光照模型

 

分析:

1.SSAA抗鋸齒

仿照原shader,直接上無腦SSAA。因爲Julia形狀的特殊性,用SSAA沒太大毛病,就是太耗。

for( int j=0; j<AA; j++ )
    for( int i=0; i<AA; i++ )
    {
        float2 pos = -1.0 + 2.0 * (uv+float2(i/Size.x,j/Size.y)/AA);
        rd = 獲得Ray(pos);
        ...
        col += render( ro, rd, ...);
    }

col /= AA*AA;

 2.基於距離場的RayTrace軟陰影

float sha = softshadow( pos, lightDir, 0.001, shadowLight, c );
///////////////////////
float softshadow( float3 ro, float3 rd, float mint, float k, float4 c )
{
    float res = 1.0;
    float t = mint;
    for( int i=0; i<64; i++ )
    {
        float h = map(ro + rd*t, c);
        res = min( res, k*h/t );
        if( res<0.001 ) break;
        t += clamp( h, 0.01, 0.5 );
    }
    return clamp(res,0.0,1.0);
}

softshadow裏面就是我們原來慢慢Ray到Julia表面的那個操作,只是起點ro是當前位置,方向沿着lightDir。

那爲什麼這個操作能告訴關於軟陰影的信息?

顯然,即使是完全光照的地方,光sha=hk/t,sha永遠不能達到1,所以乘上一個大數k,使得hk大到一定距離就溢出1,之後clamp。

還有,爲什麼不直接k*res,還要除以t呢?考慮一下那些十分貼近光源又不被遮擋的點。

 3.Blin-Phong光照模型

float3 pos = ro + t*rd;
float3 nor = calcNormal( pos, c );
float sha = softshadow( pos, lightDir, 0.001, shadowLight, c );
//shadow*diff+ambient
re = sha*clamp(dot(nor,lightDir),0,1)*baseColor+ambientColor;

float3 hal = normalize( -rd+lightDir );
float spe = pow(clamp(dot(hal,nor), 0.0, 1.0 ), specularPower );
float fre = 0.04 + 0.96*pow(1.0-clamp(dot(-rd,nor),0,1),5.0);
re += specularMulti*fre*sha*spe*specularColor;

對高光加一個fresnel,自然些?因爲我們這個材質像塑料?。注意現實中大多數不透明絕緣體材質也有明顯的fresnel。

無fresnel

有fresnel

 

步驟

1.主Custom函數修改

float3 col = float3(0,0,0);
float3 rd;
for( int j=0; j<AA; j++ )

	for( int i=0; i<AA; i++ )
	{
		float2 pos = -1.0 + 2.0 * (uv+float2(i/Size.x,j/Size.y)/AA);
		rd = normalize(float3(pos.x, -pos.y*Size.y/Size.x, 1));
		rd = mul(rd, (MaterialFloat3x3)(ResolvedView.CameraViewToTranslatedWorld));
		rd = normalize(rd);
		col += render( ro, rd, c, lightDir, baseColor, shadowLight, specularColor, specularPower , specularMulti, ambientColor);
	}

col /= AA*AA;
return col;

2. usf修改部分

float softshadow( float3 ro, float3 rd, float mint, float k, float4 c )
{
    float res = 1.0;
    float t = mint;
    for( int i=0; i<64; i++ )
    {
        float h = map(ro + rd*t, c);
        res = min( res, k*h/t );
        if( res<0.001 ) break;
        t += clamp( h, 0.01, 0.5 );
    }
    return clamp(res,0.0,1.0);
}

float3 render(float3 ro,float3 rd,float4 c,float3 lightDir,float3 baseColor,float shadowLight,float3 specularColor,float specularPower,float specularMulti, float3 ambientColor)
{
	float3 re=float3(0,0,0); 
	float t= intersectJulia(ro,rd,c);
	if(t<0)
	{
	//not julia face
	}
	else
	{
	float3 pos = ro + t*rd;
	float3 nor = calcNormal( pos, c );
	float sha = softshadow( pos, lightDir, 0.001, shadowLight, c );
	//shadow*diff+ambient
	re = sha*clamp(dot(nor,lightDir),0,1)*baseColor+ambientColor;
	
	float3 hal = normalize( -rd+lightDir );
	float spe = pow(clamp(dot(hal,nor), 0.0, 1.0 ), specularPower );
	float co = clamp( dot(hal,lightDir), 0.0, 1.0 );
	float fre = 0.04 + 0.96*pow(1.0-clamp(dot(-rd,nor),0,1),5.0);
	re += specularMulti*fre*sha*spe*specularColor;
	}
	return re;

3.調參

令c=0,0,0,0。回憶上篇動圖,c=0時2維是單位圓,那麼咱三維就是單位球。然後像看材質球一樣調參。

 



結語

很可惜受限於機器無法在實時渲染中無限放大分形的細節。

我感覺到分形是有限走向無限的一條路。

分形藝術連接了最感性的藝術和最理性的科學,將兩個“極端”連成一個環,告訴我們二位一體,我喜歡這樣的東西。

它太美了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章