【技美百人计划】图形 4.2 SSAO算法 屏幕空间环境光遮蔽(&HBAO)

本文介绍了屏幕空间环境光遮蔽(SSAO)和水平基准环境光遮蔽(HBAO)的原理、实现及优化。SSAO通过获取深度和法线缓冲来计算环境光遮蔽,而HBAO则通过减少采样点并优化角度计算,提高性能。文章详细探讨了两种算法的优缺点,并提供了实际应用和优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

笔记

SSAO介绍

AO

环境光遮蔽,AmbientOcclusion。一种模拟光线到达物体的能力和粗略的全局方法。

SSAO

屏幕环境光遮蔽,Screen Space Ambient Occlusion, 一种实现环境光遮蔽遮蔽效果的渲染技术。通过获取像素的深度缓冲、法线缓冲来计算实现,来近似的表现物体在间接光下产生的阴影

历史

AO在Siggraph 2002年会由ILM展示
2007年,Crytek将SSAO应用于孤岛危机

原理

在这里插入图片描述

  1. 获取深度、法线缓冲
  2. 利用深度值,反推每个像素在世界空间中的三维位置
  3. 利用法线,得到法向半球
  4. 利用法向半球产生随机向量,计算像素随机后的坐标(多次采样)
  5. 与采样点的深度进行比较,加权到AO中
  6. 后期(模糊等)

SSAO算法实现

获取深度、法线缓冲数据

C#

private void Start(){
	cam = this.GetComponent<Camera>();
    cam.depthTextureMode = cam.depthTextureMode | DepthTextureMode.DepthNormals;
}

获取相机组件
深度纹理模式设置为 带深度带法线

Shader
在这里插入图片描述
在这里插入图片描述
这里的UV是屏幕空间的UV

重建相机空间坐标

具体参考:https://zhuanlan.zhihu.com/p/92315967

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

构建法向量正交基

在这里插入图片描述
tangent其实是半球面上 随机的一个向量(随机的方法参考下文)
在这里插入图片描述

AO采样核心

在这里插入图片描述
第二步:
_SampleKeneralRadius : 采样半球的半径长度
第三步:
因为都是在观察空间下进行的计算,所以得到randomPos后,乘以投影矩阵,再视图映射即可得到相应的屏幕坐标
rclipPos :即是球面上的点

SSAO优化

1. 随机正交基

应用于求法向半球的正交基时,其第二步生成随机变量。
在这里插入图片描述
_ScreenParams.xy 是屏幕的长宽,除以4是为了对应4x4像素的贴图。
因为i.uv 的增量是 1/_ScreenParams.x 或 1/_ScreenParams.y ,noiseUV增量也即 x或y增0.25,也即Noise贴图走一个格子。

2. AO累加平滑优化——范围判断

在这里插入图片描述

如果从天空盒的位置产生半球,采样到深度差很大的球体遮挡会产生ao,导致天空的像素上有阴影
在这里插入图片描述

加一个深度差绝对值的阈值判断,能够避免采样到深度差太大的无关遮挡
原本:
在这里插入图片描述

改成:
在这里插入图片描述

3. AO累加平滑优化——自身判断

在这里插入图片描述

4. AO累加平滑优化——AO权重

在这里插入图片描述
随机点的xy 越靠近的,权重越大

5. 模糊

在这里插入图片描述

烘培AO

三维建模软件烘培

烘培AO到纹理

优点:

  1. 单一物体可控性强(通过单一物体的材质球上的AO纹理贴图),可以控制单一物体的AO的强弱;
  2. 弥补场景烘焙的细节,整体场景的烘焙(包含AO信息),并不能完全包含单一物体细节上的AO,而通过三维建模软件烘焙到纹理的方式,增加物体的AO细节。
  3. 不影响其(Unity场景中)静态或者动态。

缺点:

  1. 操作较其它方式繁琐,需要对模型进行UW处理,再进行烘焙到纹理。
  2. 不利于整体场景的整合(如3DMax烘焙到纹理,只能选择单一物体,针对整体场景的处理工作量巨大);
  3. 增加AO纹理贴图,不利于资源优化(后期可通过其它纹理通道整合资源);
  4. 只有物体本身具有AO信息,获取物体之间的AO信息工作量巨大

游戏引擎烘培AO

优点:

  1. 操作简易,整体场景的烘焙,包含AO的选择。
  2. 不受物体本身的UW影响,Unity通过Generate Lightmap UVs生成模型第二个纹理坐标数据。(TODO!!!不懂)
  3. 可以生成物体与物体之间的AO信息
    缺点:
  4. 缺少单一物体的细节(可调整参数提高烘焙细节,但换之将增加烘焙纹理数量和尺寸,以及烘焙时间);
  5. 受物体是否静态影响,动态物体无法进行烘焙而获得AO信息。

SSAO优缺点

优点:

  1. 不依赖场景的复杂度,其效果质量依赖于最终图片像素大小。
  2. 实时计算,可用于动态场景。
  3. 可控性强,灵活性强,操作简单。
    缺点:
  4. 性能消耗较之上述2种方式更多,计算非常昂贵
  5. AO质量上要比离线渲染烘焙(上述2种)不佳(理论上)。

SSAO性能消耗

主要在两个方面

AO法向半球的随机采样

  1. For结构代码
  2. 采样数:64 x 长 x 宽次AO核心计算
  3. 每个像素需要采样64次屏幕深度值、法线值
    在这里插入图片描述

双边滤波的多重采样

在这里插入图片描述

作业

实现SSAO效果


原图

AO图

混合图

使用其它AO算法实现进行对比

HBAO原理

全称Horizon-Based Ambient Occlusion,水平基准环境光遮蔽。

  1. 将360度分等份,在各个方向上做RayMarching,同时对这些方向加入随机旋转。下图以分4个方向来做
    在这里插入图片描述

  2. 对于其中一个方向。再RayMarching过程中,得到一个最大的horizon angle(水平角)
    在这里插入图片描述

  3. 根据点P及其法线,计算出切面角tangent angle
    在这里插入图片描述

  4. 通过horizon angle 和 tangent angle,计算得出AO。(注意这里角度的范围,是实现的细节)
    在这里插入图片描述

  5. 对其它三个方向相同操作,将AO值加起来平均后,得到最终点P的AO值

HBAO效果实现

核心代码:

fixed4 frag_Ao (v2f i) : SV_Target
    {

		//采样获得深度值和法线值
		float3 viewNormal;
		float linear01Depth;
		float4 depthnormal = tex2D(_CameraDepthNormalsTexture,i.uv);
		DecodeDepthNormal(depthnormal,linear01Depth,viewNormal);

		//获取像素相机屏幕坐标位置
		float3 viewPos = reconstructViewPos(i.uv);

		//获取像素相机屏幕法线,法相z方向相对于相机为负(so 需要乘以-1置反),并处理成单位向量
		viewNormal = normalize(viewNormal) * float3(1, 1, -1);
		float deltaAngle = 2.0 * UNITY_PI / _RayAngleStep;
		// 1/屏幕分辨率宽w , 1/屏幕分辨率高h
		float2 InvScreenWH = _ScreenParams.zw - 1.0;

		//_RayMarchingRadius 屏幕空间的采样半径
		float rayMarchingStepSize = _RayMarchingRadius/_RayMarchingStep; 
		
		//采样核心
		float ao = 0;

		for(int j = 1; j <= _RayAngleStep; j++)
		{
			float uvAngle = deltaAngle * j;
			float maxHAngle = _AngleBias;

			//两个叉乘求tangent线 
			float3 marchingDir =  float3(GetRayMarchingDir(uvAngle), 0.0f);
			float3 temp = cross(marchingDir , viewNormal);
			float3 tangent = cross(temp, viewNormal);
			float sinTangentAngle = length(tangent.z)/length(tangent);
			sinTangentAngle *= tangent.z > 0.0f ? 1.0f : -1.0f;

			for(int k = 1; k < _RayMarchingStep; k++)
			{
				float2 deltaUV = round( marchingDir * rayMarchingStepSize * k) * InvScreenWH;
				float2 stepUV = i.uv + deltaUV ;
				float3 pointPos = reconstructViewPos(stepUV);
				float3 diffPos = pointPos - viewPos;
				float exist = (diffPos.z < -0.04 ? 1.0 : 0.0);//差值z需小于0,并且加一点bias//这个漏了,明显错误,想了好久
				float sinHAngle = length(diffPos.z)/length(diffPos) * exist;

				if(sinHAngle > maxHAngle)
				{
					maxHAngle = sinHAngle;
				}
			}

			if(maxHAngle  > _AngleBias)
			{
				ao += maxHAngle - sinTangentAngle;
			}
		}

		ao = ao / _RayAngleStep;
		float4 color;
		color = max(0.0, 1 - ao * _AOStrength);
		color.a = 1;
		return color;
    }

补充函数

inline float2 RotateDirections(float2 dir, float2 rot) 
{
	return float2(dir.x * rot.x - dir.y * rot.y,
				dir.x * rot.y + dir.y * rot.x);
}

inline float2 GetRayMarchingDir(float angle)
{
	float sinValue, cosValue;
	sincos(angle, sinValue, cosValue);
	return RotateDirections(float2(cosValue, sinValue), float2(1.0, 0));
}

float3 reconstructViewPos(float2 uv)
{
	float3x3 proj = (float3x3)unity_CameraProjection;
	float2 p11_22 =  float2(unity_CameraProjection._11, unity_CameraProjection._22);
	float2 p13_31 =  float2(unity_CameraProjection._13, unity_CameraProjection._22);
	float depth;
	float3 viewNormal;
	float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
	DecodeDepthNormal(cdn, depth, viewNormal);
	depth *= _ProjectionParams.z;
	return float3((uv * 2.0 - 1.0 - p13_31) / p11_22 * (depth), depth);
}

HBAO效果

之前的SSAO

对比HBAO、SSAO

  1. HBAO性能是有较大提升的,更适用于移动端。HBAO采样数大量减少,如果一个像素采样4个方向,4个RayMarching的话,也即16个采样点。而SSAO 要64个采样点,相当于4倍。其实可以理解为HBAO的通过角度的大小,节约了一部分的采样点。
  2. 效果上看,HBAO近处的细节相比于SSAO,是会差一截的。原因是步进(RayMarching)是基于屏幕的,越近,像素点之间的信息就越少。

HBAO优化

1. 基础阈值

当sin(H)大于一个bias时,才有ao
在这里插入图片描述
在这里插入图片描述

2. 非连续问题

只有在半球区域内的遮挡才有效,与避免从天空盒采样到遮挡同理。
在这里插入图片描述


原HBAO

解决非连续问题后的HBAO
在代码中,加入阈值判断,可以看出远处墙体的阴影少了。
3. 衰减

离像素点越远的采样点,影响应该越小
使用公式:W(r)= 1 - r²


公式曲线
Per-Sample Attenuation: 逐采样衰减。考虑阈值内的各个采样点,分别乘以权重给出贡献。

Per-Sample Attenuation

原HBAO

添加衰减后的HBAO
加入了衰减后,可以发现阴影的扩散变小了,更紧凑了。

其它AO

GTAO,Bent Normal,AAO,TSSAO,VXAO,UE4的Distance Filed Ambient Occlusion

参考资料

https://www.bilibili.com/video/BV16q4y1U7S3?p=2
https://developer.download.nvidia.cn/presentations/2008/SIGGRAPH/HBAO_SIG08b.pdf
https://blog.csdn.net/puppet_master/article/details/82929708

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值