opengl实现线性雾

实现线性雾的几个关键因素

1,指定雾的开始距离,结束距离,雾颜色

2,将模型上的点变换到眼睛坐标系

3,计算雾浓度

线性雾原理:开始位置到结束位置之间,雾的浓度越来越高,浓度的变化和距离成正比。

效果图

opengl实现线性雾_第1张图片

雾的顶点shader

attribute vec3 pos;//顶点坐标
attribute vec2 texcoord;//纹理坐标
attribute vec3 normal;//法线坐标

uniform mat4 M;//模型矩阵
uniform mat4 P;//投影矩阵
uniform mat4 V;//观察矩阵
uniform mat4 NM;//法线在世界空间的变化矩阵

varying vec3 V_Normal;//世界空间中的法线坐标
varying vec3 V_WorldPos;//世界空间中的顶点坐标
varying vec4 V_EyeSpacePos;//模型中的点在眼睛坐标系中的位置

void main()
{
	V_Normal=mat3(NM)*normal;//将法线变换到世界空间
	vec4 worldPos=M*vec4(pos,1.0);
	V_WorldPos=worldPos.xyz;
	V_EyeSpacePos=V*worldPos;//将物体变换到眼睛坐标系
	
	gl_Position=P*V*worldPos;
	
	
}

雾的片元shader

uniform vec4 U_LightPos;
uniform vec3 U_EyePos;
uniform vec4 U_LightDirection;
uniform float U_Cutoff;
uniform float U_DiffuseIntensity;
uniform vec4 U_AmbientLightColor;
uniform vec4 U_AmbientMaterial;
uniform vec4 U_DiffuseLightColor;
uniform vec4 U_DiffuseMaterial;
uniform vec4 U_SpecularLightColor;
uniform vec4 U_SpecularMaterial;

uniform float U_FogStart;//雾的开始位置
uniform float U_FogEnd;//雾的结束位置
uniform vec4 U_FogColor;//雾颜色

varying vec3 V_Normal;
varying vec3 V_WorldPos;
varying vec4 V_EyeSpacePos;//cal fog

//计算雾浓度
float CalculateLinearFog(float distance)
{
	float fogAlpha=(distance-U_FogStart)/(U_FogEnd-U_FogStart);
	//clamp 越界处理获得三个参数中大小处在中间的那个值
	fogAlpha=1.0-clamp(fogAlpha,0.0,1.0);
	return fogAlpha;
}

void main()
{
	//角度转弧度
	float radianCutoff=U_Cutoff*3.14/180.0;//聚光灯中心线向量和入射光线的最大夹角
	float cosThta=cos(radianCutoff);
	//聚光灯中心向量归一化
	vec3 spotLightDirection=normalize(U_LightDirection.xyz);

	//计算环境光
	vec4 ambientColor=U_AmbientLightColor*U_AmbientMaterial;

	//计算漫反射光
	//L vector  L是入射光向量 从物体执行光源
	vec3 L=vec3(0.0);
	float distance=0.0;
	float attenuation=1.0;
	//light attribute
	float constantFactor=0.5;
	float linearFactor=0.3;
	float expFactor=0.1;

	if(U_LightPos.w==0.0)
	{
		//方向光光源的入射方向向量 就是光源的位置
		L=U_LightPos.xyz;
	}
	else
	{
		//model point -> light pos
		//point light / spot light
		
		//如果光源不是方向光光源,则入射光向量是模型上被照射点到光源这两点的向量
		L=U_LightPos.xyz-V_WorldPos;
		distance=length(L);//计算被照射点到光源的距离
		//因为非方向光光源的光照强度会随着距离发生衰减,下面计算衰减系数
		attenuation=1.0/(constantFactor+linearFactor*distance+expFactor*distance*distance);
	}

	L=normalize(L);//入射光向量归一化

	//N vector
	vec3 n=normalize(V_Normal);
	float diffuseIntensity=0.0;

	if(U_LightPos.w!=0.0f&&U_Cutoff>0.0)//计算聚光灯的光照强度
	{
		//计算聚光灯入射光线和中心线向量的夹角余弦  注意L前面的负号
		//shader中计算光照时,入射光线都是从物体指向光源的向量
		float currentCosThta=max(0.0,dot(-L,spotLightDirection));
		if(currentCosThta>cosThta)//这个判断非常有必要,可以减少很多计算量  
		{
			if(dot(L,n)>0.0)
			{
				diffuseIntensity=pow(currentCosThta,U_LightDirection.w);
			}
		}
	}
	else//计算点光源的光照强度
	{
		//point light or direction light
		diffuseIntensity=max(0.0,dot(L,n));
	}
	vec4 diffuseColor=U_DiffuseLightColor*U_DiffuseMaterial*diffuseIntensity*attenuation*U_DiffuseIntensity;
	
	//specular
	//inverse view direction : object->eye
	vec3 viewDir=U_EyePos-V_WorldPos;
	viewDir=normalize(viewDir);

	//reflection 计算镜面光的反射向量
	vec3 halfVector=L+viewDir;
	halfVector=normalize(halfVector);

	float specularIntensity=0.0;
	if(diffuseIntensity==0.0)
	{
		specularIntensity=0.0;
	}
	else
	{
		//shiness
		specularIntensity=pow(max(0.0,dot(n,halfVector)),128.0);
	}

	vec4 specularColor=U_SpecularLightColor*U_SpecularMaterial*specularIntensity*attenuation;
	float fogAlpha=CalculateLinearFog(abs(V_EyeSpacePos.z/V_EyeSpacePos.w));
	gl_FragColor=mix(U_FogColor,ambientColor+diffuseColor+specularColor,fogAlpha);
}



你可能感兴趣的:(opengl_shader专题)