【Shader特效10】体积雾特效的使用

说在开始

这里主要讲解一下体积雾的算法和相关的知识。在许多大型游戏中都可以看到体积雾的身影,体积雾是飘动的,实现的效果也是距离摄像机越远雾的浓度也就越大。这里介绍一套数学模型相对比较简单的体积雾,可以有一个简单的认识。

作者:憨豆酒(YinDou),联系我[email protected],熟悉图形学,图像处理领域,本章的源代码可在此仓库中找到: https://github.com/douysu/person-summary 如果对您有帮助还请帮忙点一个star。如果大家发现错误以及不合理之处,还希望多多指出。

  • 我的Github
  • 我的CSDN
参考内容:
  • 《OpenGL ES 3.X 游戏开发 下卷》

运行效果

原理部分

【Shader特效10】体积雾特效的使用_第1张图片
这里涉及到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

这里主要的方法就是tjFogCal方法了,该方法计算了雾的浓度因子,计算时,使用的是射线和平面的参数方程。可以查看我的另一篇博客。还有就是,雾的动态的,为了实现动态的效果,还是用了正弦函数,具体可以参考http://blog.csdn.net/modestbean/article/details/79139315 这篇博客中的内容。

最后

如果本节对您有帮助,还希望点一个star,本人的知识有限,如果本节内容有错误和不合理之处,还请朋友们多多指出,我会虚心接受每一个建议。

你可能感兴趣的:(着色器特效)