中級Shader教程17 海洋渲染


1.前置知識鏈接

1.Noise和FBM請參考這篇文章中給出的鏈接
2.ranymarching 框架

2.海浪型狀的構造

1.基本形狀構造

1.基本周期函數
2.擴散方向
3.Noise擾動

2.性能分析

1.還是和地形渲染一樣,我們這裏採用多種分辨率的地形函數
2.性能關鍵
.基本周期函數
.Nolise函數的實現

3.實現

0.基本框架

1.基本raymarching
#define Waves(pos,NUM)\
    float2 uv = pos.xz;\
    ....//不同的實現


float2 TerrainL(float3 pos){ 
    Waves(pos,5.);
} 
float2 TerrainM(float3 pos){
    Waves(pos,9.);
} 
float2 TerrainH(float3 pos){
    Waves(pos,24.);
} 

float RaycastTerrain(float3 ro, float3 rd) { 
    _MRCRO_RAY_CAST(ro,rd,10000.,TerrainL);  
}
float3 NormalTerrian( in float3 pos, float rz ){
    _MACRO_CALC_NORMAL(pos,rz,TerrainH); 
}

float SoftShadow(in float3 ro, in float3 rd,float tmax){    
    _MACRO_SOFT_SHADOW(ro,rd,tmax,TerrainM);  
}  
2.水渲染

海水渲染需要考慮的有diffuse,specular,reflect,refract,fresnel這集中不同的效應

//基本渲染
float3 RenderSea(float3 pos, float3 rd,float rz, float3 nor, float3 lightDir) {  
    float fresnel = clamp(1.0 - dot(nor,-rd), 0.0, 1.0);
    fresnel = pow(fresnel,3.0) * 0.65;

    float3 reflected = Sky(pos,reflect(rd,nor),lightDir);    
    float3 diff = pow(dot(nor,lightDir) * 0.4 + 0.6,3.);
    float3 refracted = _SeaBaseColor + diff * _SeaWaterColor * 0.12;
    float3 col = lerp(refracted,reflected,fresnel);

    float spec=  pow(max(dot(reflect(rd,nor),lightDir),0.0),60.) * 3.;
    col += float3(spec,spec,spec);

    return col;
}
3.海天的處理

在海水和天空之間過渡

float4 ProcessRayMarch(float2 uv,float3 ro,float3 rd,inout float sceneDep,float4 sceneCol){ 
    float rz = RaycastTerrain(ro,rd).x; 
    float3 pos = ro + rd *rz;
    float3 nor = NormalTerrian(pos,rz);

    // color
    float3 skyCol = Sky(pos,rd,_LightDir);
    float3 seaCol = RenderSea(pos,rd,rz,nor,_LightDir);
    //讓海水和天空的過渡平和點
    float3 col = lerp(skyCol,seaCol,pow(smoothstep(0.0,-0.05,rd.y),0.3));
    col = pow( col, float3(0.4545,0.4545,0.4545) );
    sceneCol.xyz = col;
    return sceneCol; 
}

這裏介紹兩種方式來夠着波浪:
1.使用多個發射點(圓形)發射不同頻率,振幅的波來合成最終效果
2.使用多個放射方向(直線)發射不同頻率,振幅的波來合成最終效果

1.圓形波
#define Waves(pos,NUM)\
    float2 uv = pos.xz;\
    float w = 0.0,sw = 0.0;\
    float iter = 0.0, ww = 1.0;\
    uv += ftime * 0.5;\
    // 類FBM 波合成
    for(int i=0;i<NUM;i++){\
        w += ww * Wave(uv * 0.06 , float2(sin(iter), cos(iter)) * 10.0, 2.0 + iter * 0.08, 2.0 + iter * 3.0);\
        sw += ww;\
        ww = lerp(ww, 0.0115, 0.4);\
        iter += 2.39996;\
    }\
    return float2(pos.y- w / sw*_SeaWaveHeight,1.);\


float Wave(float2 uv, float2 emitter, float speed, float phase){ 
    //uv += Noise(uv);// 是否使用noise 來扭曲採樣點
    float dst = distance(uv, emitter);//圓形擴散 極座標
    return pow((0.5 + 0.5 * sin(dst * phase - ftime * speed)), 5.0);
}

兩個sin波疊加的效果

多個sin波疊加的效果

最終效果

1.方向波
#define Waves(pos,_LOOP_NUM)\
    float2 uv = pos.xz;\
    //float2x2(0.8,0.6,-0.6,0.8) * 2.0
    float2x2 octave_m = float2x2(1.6,1.2,-1.2,1.6);\
    float freq = _SeaFreq;\
    float amp = _SeaWaveHeight;\
    float choppy = _SeaChoppy;\
    uv.x *= 0.75;\
    float d, h = 0.0;   \
    //類FBM效果  
    for(int i = 0; i < _LOOP_NUM; i++) {        \
        //讓波浪相交
        d = Wave((uv+SEA_TIME)*freq,choppy);\
        d += Wave((uv-SEA_TIME)*freq,choppy);\
        h += d * amp;  \
        uv = mul(octave_m,uv); freq *= 1.9; amp *= 0.22;\
        choppy = lerp(choppy,1.0,0.2);\
    }\
    return float2(pos.y - h,1.0);


// sea
float Wave(float2 uv, float choppy) {
    uv += Noise(uv);   // 是否使用noise 來扭曲採樣點
    float2 wv = 1.0-abs(sin(uv));//讓波尖銳
    float2 swv = abs(cos(uv));   //方型
    wv = lerp(wv,swv,wv);
    return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}

兩個方向波的效果

多個方向波的效果

#### 2.隨機化
c
float Wave(float2 uv, float choppy) {
uv += Noise(uv); // 是否使用noise 來扭曲採樣點
...
}

添加Noise來增加波浪的隨機行爲


最終效果


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