Vulkan_片元着色器特效3(菲涅尔效果)

47 篇文章 9 订阅
20 篇文章 6 订阅

之前我们介绍了反射效果、折射效果、色散效果的模拟,本部分我们将反射效果、折射效果综合到一起的菲涅尔(Fresnel)效果(在BRDF模型中,有专门的涅菲尔项计算方法,此处方法与之不同,但效果类似)。
在这里插入图片描述

基本原理

本部分场景基本上与前面一节的相同,所不同的是场景中的玻璃球同时具有折射与反射效果。玻璃球正对摄像机的部分主要是折射效果,而边缘主要是反射效果,这就是前面提到的菲涅尔效果。

造成菲涅尔效果的原因是,当光线到达两种材质的接触面时,一部分光线被反射,另一部分光线被折射。大致的规律是当入射角较小时主要发生折射,当入射角较大时主要发生反射。

这与大家平时在湖边或池塘边的感觉一样:当目光相对于水面基本垂直时,主要看到的是水面下的内容;而当目光相对于水面入射角很大时,主要看到的是湖面反射的内容,而看不到水面下的内容,下图简单地说明了这个问题。
在这里插入图片描述
了解了菲涅尔效果的基本原理后还有一个重要的问题需要解决,那就是在给定情况下反射和折射各自所占的比例为多少。这个问题的精确计算比较复杂,需要用到专门为菲涅尔效果建立的复杂数学模型,基于这些模型的计算难以满足游戏实时性的需要。

实际开发中我们可以采用简化的数学模型,也就是将折反射比例分成 3 种情况进行计算,具体情况如下所列。

  • 若入射角小于一定的值,只计算折射效果。
  • 若入射角大于一定的值,只计算反射效果。
  • 若入射角在一定的范围内,则首先单独计算折射效果与反射效果,再将两种效果的计算结果按一定的比例进行融合

二、开发步骤

我们首先把设置两个临界值,当入射光线的反向与法线的余弦值为0.7及0.2时作为变化条件,这样我们可以将球体分为三个部分:

在这里插入图片描述
划分好区域后,我们便需要对不同部分进行折射反射等采样融合操作:

 //菲涅尔效果
 vec4 FresnelEffect(in float coefficient){  
	vec3 cI = normalize (inPos);
	vec4 finalColorZS;		//若是折射的采样结果
	vec4 finalColorFS;		//若是反射的采样结果
	vec4 finalColor;  		//最终颜色
	const float maxH=0.7;	    //入射角余弦值若大于此值则仅计算折射
	const float minH=0.2;	    //入射角余弦值若小于此值则仅计算反射
	float sizeH=maxH-minH;    //混合时余弦值的跨度 
	float testValue=abs(dot(-cI,inNormal));	//计算视线向量与法向量的余弦值
	if(testValue>maxH) 
	{//余弦值大于maxH仅折射
	    vec3 cR = refract(cI,inNormal,coefficient );//折射
	    cR = vec3(inInvModelView * vec4(cR, 0.0));
	    cR.x *= -1.0;
	    finalColor = texture(samplerColor, cR, inLodBias);
		//finalColor=vec4(0,0,1,0);
	} 
	else if(testValue<=maxH && testValue>=minH)
	{//余弦值在minH~maxH范围内反射、折射融合

	    vec3 cR = reflect(cI, normalize(inNormal));//反射
		cR = vec3(inInvModelView * vec4(cR, 0.0));
		cR.x *= -1.0;
		finalColorFS = texture(samplerColor, cR, inLodBias);
		
		vec3 cRZS = refract(cI,inNormal,coefficient);//折射
	    cRZS = vec3(inInvModelView * vec4(cRZS, 0.0));
	    cRZS.x *= -1.0;
	    finalColorZS = texture(samplerColor, cRZS, inLodBias);
		
	    float ratio=(testValue-minH)/sizeH;					//融合比例
	    finalColor=finalColorZS*ratio+(1.0-ratio)*finalColorFS;	//折反射结果线性融合
		//finalColor=vec4(0,1,0,0);
	}  
	else
	{//余弦值小于minH仅反射
		vec3 cR = reflect (cI, normalize(inNormal));//反射
		cR = vec3(inInvModelView * vec4(cR, 0.0));
		cR.x *= -1.0;
		finalColor = texture(samplerColor, cR, inLodBias);
		//finalColor=vec4(1,0,0,0);
	}  
	return finalColor;								//返回最终结果
}

最后在main中调用:

 void main()
 {
	vec4 color = vec4(0,0,0,0);
	color.r = FresnelEffect(0.95).r;
	color.g = FresnelEffect(0.945).g;
	color.b = FresnelEffect(0.94).b;
	...
 }

生成可见开头效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值