目的:
移植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維是單位圓,那麼咱三維就是單位球。然後像看材質球一樣調參。
結語
很可惜受限於機器無法在實時渲染中無限放大分形的細節。
我感覺到分形是有限走向無限的一條路。
分形藝術連接了最感性的藝術和最理性的科學,將兩個“極端”連成一個環,告訴我們二位一體,我喜歡這樣的東西。
它太美了。