【Shader特效10】體積霧特效的使用

說在開始

這裏主要講解一下體積霧的算法和相關的知識。在許多大型遊戲中都可以看到體積霧的身影,體積霧是飄動的,實現的效果也是距離攝像機越遠霧的濃度也就越大。這裏介紹一套數學模型相對比較簡單的體積霧,可以有一個簡單的認識。

作者:憨豆酒(YinDou),聯繫我[email protected],熟悉圖形學,圖像處理領域,本章的源代碼可在此倉庫中找到: https://github.com/douysu/person-summary 如果對您有幫助還請幫忙點一個star。如果大家發現錯誤以及不合理之處,還希望多多指出。

參考內容:
  • 《OpenGL ES 3.X 遊戲開發 下卷》

運行效果

這裏寫圖片描述

原理部分

這裏寫圖片描述
這裏涉及到3D數學的一些知識。

  • 首先計算當前片元與攝像機機之間形成的射線,然後計算攝像與霧平面的交點。
  • 如果霧平面與射線存才交點,那麼計算霧平面交點與當前片元的距離。通過求出的距離計算一個因子,距離越大因子越大,因子影響的霧的濃度。
    關於射線與平面交點的計算可以參考另一篇博客:http://blog.csdn.net/modestbean/article/details/7924917
    這一個簡單的數學模型就可以達到距離越遠霧的濃度越大了。

代碼部分

這裏是片元着色器的代碼:

#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (std140,set = 0, binding = 0) uniform bufferVals { //一致塊
    vec4 uCamaraLocation;//攝像機位置
    float startAngle;//正弦函數起始角度
} myBufferVals;
layout (binding = 1) uniform sampler2D tCaodi;//傳入的草地紋理
layout (binding = 2) uniform sampler2D tXued;//傳入的雪地紋理
layout (location = 0) in vec2 inTexCoor;//傳入的紋理座標
layout (location = 1) in float landHeight;//傳入的當前頂點的高度(物體座標系)
layout (location = 2) in vec4 pLocation;//當如的當前頂點位置(世界座標系)
layout (location = 0) out vec4 outColor;//傳給渲染管線的最終片元顏色值
const float slabY=60.0f;//霧平面的高度
const float QFheight=5.0f;//霧平面起伏高度
const float WAngleSpan=12*3.1415926f;//霧的總角度跨度
float tjFogCal(vec4 pLocation){//計算體積霧濃度因子的方法
   float xAngle=pLocation.x/960.0f*WAngleSpan;//計算出頂點X座標折算出的角度
   float zAngle=pLocation.z/960.0f*WAngleSpan;//計算出頂點Z座標折算出的角度
   float slabYFactor=sin(xAngle+zAngle+myBufferVals.startAngle)*QFheight;//聯合起始角計算出角度和的正弦值
   //求從攝像機到待處理片元的射線參數方程Pc+(Pp-Pc)t與霧平面交點的t值
   float t=(slabY+slabYFactor-myBufferVals.uCamaraLocation.y)/(pLocation.y-myBufferVals.uCamaraLocation.y);
   //有效的t的範圍應該在0~1的範圍內,若不存在範圍內表示待處理片元不在霧平面以下
   if(t>0.0&&t<1.0){//若在有效範圍內則
      //求出射線與霧平面的交點座標
	  float xJD=myBufferVals.uCamaraLocation.x+(pLocation.x-myBufferVals.uCamaraLocation.x)*t;
	  float zJD=myBufferVals.uCamaraLocation.z+(pLocation.z-myBufferVals.uCamaraLocation.z)*t;
	  vec3 locationJD=vec3(xJD,slabY,zJD);
	  float L=distance(locationJD,pLocation.xyz);//求出交點到待處理片元位置的距離
	  float L0=20.0;
	  return L0/(L+L0);//計算體積霧的霧濃度因子
   }else{
      return 1.0f;//若待處理片元不在霧平面以下,則此片元不受霧影響
   }
}
void main() {
    float height1=90;//混合紋理起始高度
    float height2=180;//混合紋理結束高度
    vec4  colorCaodi=textureLod(tCaodi, inTexCoor, 0.0);//採樣出草地顏色
    vec4 colorSand=textureLod(tXued, inTexCoor, 0.0);//採樣出雪地顏色
    if(landHeight<height1){//繪製草地
    outColor=colorCaodi;
    }else if(landHeight<height2){//繪製混合顏色
    float radio=(landHeight-height1)/(height2-height1);
    outColor=mix(colorSand,colorCaodi,1-radio);
    }else{//繪製雪地
    outColor=colorSand;
    }
    float fogFactor=tjFogCal(pLocation);//計算霧濃度因子
    outColor=fogFactor*outColor+ (1.0-fogFactor)*vec4(0.9765,0.7490,0.0549,0.0); //給此片元最終顏色值
}

這裏主要的方法就是tjFogCal方法了,該方法計算了霧的濃度因子,計算時,使用的是射線和平面的參數方程。可以查看我的另一篇博客。還有就是,霧的動態的,爲了實現動態的效果,還是用了正弦函數,具體可以參考http://blog.csdn.net/modestbean/article/details/79139315 這篇博客中的內容。

最後

如果本節對您有幫助,還希望點一個star,本人的知識有限,如果本節內容有錯誤和不合理之處,還請朋友們多多指出,我會虛心接受每一個建議。

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