中級Shader教程16 水渲染


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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章