图形API学习工程(20):实现简单的菲涅尔效果

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics

目标

菲涅尔效应本身是一个光学现象,在PBR中有重要的作用(见 PBR理论 - LearnOpenGL CN

暂且不提其物理学上的原理,仅从表现效果上来看,它可以计算出:在一个视线下物体 边缘 的部分,例如观察一个球:(越白表示菲涅尔效果越强)
在这里插入图片描述
(图片来源: PBR理论 - LearnOpenGL CN

虽然这一现象在本质上或许较为复杂。但是从效果角度来说,可以简单地用视线方向物体表面法线点乘来近似模拟:
F r e n e l = 1.0 − v ⃗ ⋅ n ⃗ Frenel = 1.0-\vec{v} \cdot\vec{n} Frenel=1.0v n

其中v是归一化后的视线方向,n是归一化后的物体表面法线方向,计算的结果还可以进行一些指数运算以调整效果的范围。


本篇的目标实现简单的菲涅尔效果。所需的代码量极小。

(本来没想专门为此记录一篇,但是其牵扯到的内容是我后续一些目标的前置,所以我必须先做这部分。而且,在实现时我发现有些东西是值得记录的。再加上本篇的内容相对独立且有效果展示,所以最终就为这些极小的代码量而专门记录一篇了)

1. 为计算视线传入数据

世界空间中的视线方向为:
v ⃗ = P 眼 睛 在 世 界 空 间 中 的 位 置 − P 像 素 在 世 界 空 间 中 的 位 置 \vec{v}=P_{眼睛在世界空间中的位置}-P_{像素在世界空间中的位置} v =PP


其中,眼睛在世界空间中的位置实际就是相机的位置,我将需要在UniformBuffer中添加这项数据:
在这里插入图片描述
随后每帧更新:

//眼睛位置:
glm::vec4 eyePosition = glm::vec4(camera->GetPosition(), 0);
renderer->data_scene.eyePosition = eyePosition;

而对于像素在世界空间中的位置不能使用GLSL中的gl_Position或是HLSL中的Pos : SV_POSITION,因为他们都是屏幕空间的坐标,而非世界空间中的位置。要想获得世界空间中的位置,需要在顶点着色器中计算,并作为传入像素着色器的顶点插值数据。


最终,顶点着色器代码做了如下添加:

GLSL:
在这里插入图片描述
HLSL:
在这里插入图片描述

2. Shader中计算菲涅尔

计算菲涅尔效果是放在像素着色器中的。

GLSL:

void main()
{
	//视线方向
	vec3 EyeDir = ub_SceneData.eyePosition.xyz - vs_fs_worldPosition;
	
	//法线点乘视线
	float NdE = dot(normalize(vs_fs_normal),normalize(EyeDir));
	
	//菲涅尔系数
	float fresnel = 1.0 - NdE;
	
	//将菲涅尔系数做指数变化使得效果更明显
	fresnel = pow(fresnel,3);
	
	fColor = vec4(fresnel,fresnel,fresnel,1.0);
}

HLSL:

float4 Main( VS_OUTPUT input ) : SV_Target
{
	//视线方向
	float3 EyeDir = eyePosition.xyz - input.WorldPosition;
	
	//法线点乘视线
	float NdE = dot(normalize(input.Normal),normalize(EyeDir));
	
	//菲涅尔系数
	float fresnel = 1.0 - NdE;
	
	//将菲涅尔系数做指数变化使得效果更明显
	fresnel = pow(fresnel,3);
	
	return float4(fresnel,fresnel,fresnel,1.0);
}

效果

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值