1.前置知識鏈接
1.Noise和FBM請參考這篇文章中給出的鏈接
2.ranymarching 框架
2.分析
1.基本形狀構造
這裏利用了Noise本身隨機的同時也連續的特性來模擬水面的變動
1.使用FBM來實現水面的基本形狀
2.水的動態是通過在Noise中使用time作爲一個維度,來實現水的擾動
2.着色
1.水渲染需要考慮的有diffuse,specular,reflect,refract,fresnel這幾種不同的效應
3.實現
1.波浪
1.使用FBM 來模擬水的波動 (利用的是其隨機性和連續性)
2.在Noise中使用time作爲其中的一維度來模擬水的動態
float WaterMap( fixed3 pos ) {
return FBM( fixed3( pos.xz, ftime )) * 1;
}
float3 WaterNormal(float3 pos,float rz){
//注意這裏的小技巧 法線隨着距離而變化幅度小的,
//不會造成因ray採樣少而導致的噪音波動
float EPSILON = 0.003*rz*rz;
float3 dx = float3( EPSILON, 0.,0. );
float3 dz = float3( 0.,0., EPSILON );
float3 normal = float3( 0., 1., 0. );
float bumpfactor = 0.4 * pow(1.-clamp((rz)/1000.,0.,1.),6.);//根據距離所見減少Bump幅度
normal.x = -bumpfactor * (WaterMap(pos + dx) - WaterMap(pos-dx) ) / (2. * EPSILON);
normal.z = -bumpfactor * (WaterMap(pos + dz) - WaterMap(pos-dz) ) / (2. * EPSILON);
return normalize( normal );
}
1.折射反射效果模擬
1.反射
1.反射是根據入射rd以及法線nor,計算反射rdrfl
2.通過反射rdrfl和入射點p 重新發射一條新的ray 進行raymarching
2.折射
1.在進行raymarching 的過程中先忽略水面的檢測這樣可以直接獲得碰撞點p
2.計算p到水面的距離 來融合水的顏色和背景色,模擬折射效果
這裏使用了取巧的方式只是改變了p的法線來模擬水面的擾動,正確的應該根據水面法線重新raymarching,
float4 ProcessRayMarch(float2 uv,float3 ro,float3 rd,inout float sceneDep,float4 sceneCol){
float maxT = 10000;
float minT = 0.1;
float3 col = float3 (0.,0.,0.);
float waterT = maxT;
//直接模擬水平面 求交ray和平面的交點
if(rd.y <-0.01){
float t = -(ro.y - waterHeight)/rd.y;
waterT = min(waterT,t);
}
float sundot = clamp(dot(rd,_LightDir),0.0,1.0);
float rz = RaycastTerrain(ro,rd);
float firstInsertRZ = min(rz,waterT);
float fresnel = 0;
float3 refractCol = float3(0.,0.,0.);
bool reflected = false;
// hit the water
if(rz >= waterT && rd.y < -0.01){
float3 waterPos = ro + rd * waterT;
float3 nor = WaterNormal(waterPos,waterT);
float ndotr = dot(nor,-rd);
fresnel = pow(1.0-abs(ndotr),6.);//
float3 diff = pow(dot(nor,_LightDir) * 0.4 + 0.6,3.);
// 基本水顏色
float3 waterCol = _BaseWaterColor + diff * _LightWaterColor * 0.12;
// 根據pos距離水面的高度調整透明程度
float transPer = pow(1.0-clamp( rz - waterT,0,waterTranDeep)/waterTranDeep,3.);
// 獲取折射後顏色
float3 bgCol = RenderMountain(ro,rd + nor* clamp(1.-dot(rd,-nor),0.,1.),rz);
refractCol = lerp(waterCol,bgCol,transPer);
//計算髮射ro,rd,重新發射ray 進行 raymarching
ro = waterPos;
rd = reflect( rd, nor);
rz = RaycastTerrain(ro,rd);
reflected = true;
col = refractCol;
}
//渲染背景
if(rz >= maxT){
col = Sky( ro, rd,_LightDir);
}else{
col = RenderMountain(ro,rd,rz);
}
// 融合折射和反射效果
if( reflected == true ) {
col = lerp(refractCol,col,fresnel);
float spec= pow(max(dot(rd,_LightDir),0.0),128.) * 3.;
col += float3(spec,spec,spec);
}
MergeUnityIntoRayMarching(firstInsertRZ,col,sceneDep,sceneCol);
sceneCol.xyz = col;
return sceneCol;
}