webgl-混合与雾

519 阅读4分钟

1. 前言

到目前为止,案例中的物体都不是透明的,这在很多情况下能够满足需求。但现实世界中还有很多半透明的物体,如果希望在场景中真实再现此类物体,最常用的技术就是混合。

2. 混合技术

顾名思义,混合技术就是将两个面片调和,主要通过各项测试将准备进入帧缓冲的片元与帧缓冲中的原有片元按照设定的比例加权计算出最终片元的颜色值。也就是说在启用混合技术的情况下,新片源将不再直接覆盖缓冲区中的源片源。

        gl.enable(gl.BLEND);//开启混合
        gl.blendFunc(gl.SRC_COLOR,gl.ONE_MINUS_SRC_COLOR);//设置混合因子
        ms.pushMatrix();//保护现场
        ms.translate(rex, rey, 25);//移动滤光镜
        ms.scale(3.0, 3.0, 3.0);//进行缩放
        tex.drawSelf(ms,earthTex);//绘制滤光镜

image.png

        gl.enable(gl.BLEND);
        gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);//设置混合因子
        cloud.drawSelfcloud(ms,cloudTex);//绘制云层
        gl.disable(gl.BLEND);//关闭混合

image.png

从前面的介绍已经知道,混合前需要首先设定加权比例。WebGL中是通过设置混合因子来指定两个片元的加权比例的,每次都需要给出两个混合因子,具体如下所示。 第一个是源因子,用于确定进入帧缓冲中的片源在最中的片元在最终片元中的比例。 第二个是目标因子,用于确定原帧缓冲中的片元在最终片元中的比例。

3. 地月系云层效果

本节将为地月系场景中的地球添加云层。 先看下贴图有哪几张:

earth.png

earthn.png cloud.jpg

通过这三张图实现相对真实的地球场景。

下图是没有融合的效果

无云.gif

这个是开启融合的效果

云.gif

4. 雾

前面给出不少真实场景的案例,这些案例中的物体无论远近看起来都一样清晰。虽然这样也不错,但并不完全符合现实世界的情况。现实世界中由于有大气、灰尘、雾等的影响,随着距离的加大物体将越来越不清晰,最终融入背景中。

雾的原理

有很多数学模型可以实现雾效果。首先介绍最为简单的线性模型,此模型的计算公式如下:

f = max(min((end - dist)/(end - start),1.0),0.0)
  • f为雾化因子,取值范围为0.0~1.0.当雾化因子的值为0时表示雾很浓,至看见雾,看不见物体。反之当雾化因子的值为1时,表示雾淡的已经看不见了,这时可以清晰地看到物体。
  • dist为当前要绘制的片元离摄像机的距离。
  • end表示一个特定的距离值,当片元距离摄像机的距离超过end时,雾化因子为0。
  • start也表示一个特定的距离值,当片元距离摄像机的距离小于start时,雾化因子为1.

上面的公式在start至end之间的变化是线性的,但现实世界中的雾不完全是线性变化的,希望模拟出更真实的雾,可以采用如下非线性的计算公式。

f = 1.0 - smoothstep(start,end,dist)  //smoothstep返回一个光滑的曲线

顶点着色器

//计算雾因子的方法
float computeFogFactor(){
   float tmpFactor;
   float fogDistance = length(uCamera-(uMMatrix*vec4(aPosition,1)).xyz);//顶点到摄像机的距离
   const float end = 490.0;//雾结束位置
   const float start = 350.0;//雾开始位置
   tmpFactor = 1.0-smoothstep(start,end,fogDistance);//计算雾因子
   return tmpFactor;
}
void main()
{
   gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
   finalLight = pointLight(normalize(aNormal),uLightLocation,
   vec4(0.4,0.4,0.4,1.0),vec4(0.7,0.7,0.7,1.0),vec4(0.3,0.3,0.3,1.0));
   //计算雾因子
   vFogFactor = computeFogFactor();
}

面片着色器

#version 300 es
precision mediump float;
in vec4 finalLight;//接受顶点着色器传过来的最终光照强度
in float vFogFactor;							//从顶点着色器传递过来的雾化因子
out vec4 fragColor;//输出到的片元颜色
void main()
{
	vec4 objectColor=vec4(0.95,0.0,0.0,1.0);//物体颜色
	vec4 fogColor = vec4(0.95,0.95,0.95,1.0);//雾的颜色
 	if(vFogFactor != 0.0){//如果雾因子为0,不必计算光照
		objectColor = objectColor*finalLight;//计算光照之后物体颜色
		fragColor = objectColor*vFogFactor + fogColor*(1.0-vFogFactor);//物体颜色和雾颜色插值计算最终颜色
	}else{
 	    fragColor=fogColor;
 	}
}

雾.gif

5. 本章小结

本章主要介绍了WebGL中混合与舞的相关知识。通过本章的学习,读者可以根据需求开发出各种半透明效果,并使用雾化效果为场景增加真实感。