备注SSAO介绍AO环境光遮挡、AmbientOcclusion。 模拟光线到达物体的能力和粗略的全局方法。
Sao屏幕的环境光遮挡(Screen Space Ambient Occlusion )是实现环境光遮挡效果的渲染技术。 通过获取像素的深度缓冲区、法线缓冲区并计算实现,近似表现物体在间接光下产生的阴影
历史帅印于Siggraph 2002年由ILM展出
2007年,Crytek将SSAO应用于离岛危机
原理
获取深度、法线缓冲利用深度值,反向按压各像素在世界空间的三维位置利用法线,得到法线半球利用法线半球产生随机向量,计算(多次采样)像素随机后的坐标,与采样点深度进行比较,AO中后期)模糊等
private void Start () {cam=this.GetComponentCamera; cam.depthtexturemode=cam.depthtexturemode.depth normals; }获取相机组件
深度纹理模式为带深度和带法线的
材质球
这里的UV是屏幕空间的UV
相机空间坐标重建的具体参考: https://庄兰.智惠.com/p/92315967
法向量正交基的构造
切线其实是半球面上的随机向量。 (随机方法请参照以下内容。
AO采样核心
第二步:
_SampleKeneralRadius :示例半球的半径长度
第三步:
由于都是在观察空间中进行计算,所以在得到randomPos之后,通过将投影矩阵相乘并进行视图映射,可以得到对应的屏幕坐标
rclipPos :也就是球面上的点
Sao优化1 .当随机正交基应用于求法半球正交基时,其第二阶段生成随机变量。
_ScreenParams.xy是屏幕的长宽比,除以4是为了支持4×4像素的贴图。
因为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强弱; 3358www.Sina.com/场景烘焙弥补虽然整个场景烘焙(包括AO信息)不能在单个物体的细节中完全包含AO,但在三维建模软件中纹理不影响静态或动态。 缺点:
操作比其他方式复杂,需要将模型烘焙到细节后再烘焙到纹理。 添加不利于整个场景的UW处理AO纹理贴图整合()后期可以通过其他纹理通道整合资源); 只有物体自身拥有AO信息,获取不利于资源优化的AO信息物体之间。 游戏引擎发挥AO的优势:
包括操作工作量巨大、整个场景烘焙和AO选择。 不受物体本身的UW的影响,Unity通过生成灯光贴图uvs生成模型的第二个纹理坐标数据。 (TODO! 不知道(可以生成简易。
缺点:缺少单个物体的细节(调整参数可以提高烘焙细节,但会增加烘焙纹理的数量和大小以及烘焙时间); 受物体是否为静态的影响,在物体与物体之间的AO信息上获得AO信息。 Sao的优缺点:
动态物体无法进行烘焙,其效果质量取决于最终图像的像素尺寸。 实时计算,不依赖场景的复杂度场景。可用于动态灵活,操作简单。
缺点:比上述两种方式性能消耗量大,计算非常http://www.Sina.com/ao http://www.Sina.com /
strong>上要比离线渲染烘焙(上述2种)不佳(理论上)。 SSAO性能消耗
主要在两个方面
AO法向半球的随机采样 For结构代码采样数:64 x 长 x 宽次AO核心计算每个像素需要采样64次屏幕深度值、法线值
双边滤波的多重采样
作业 实现SSAO效果
原图
AO图
混合图 使用其它AO算法实现进行对比 HBAO原理
全称Horizon-Based Ambient Occlusion,水平基准环境光遮蔽。
将360度分等份,在各个方向上做RayMarching,同时对这些方向加入随机旋转。下图以分4个方向来做
对于其中一个方向。再RayMarching过程中,得到一个最大的horizon angle(水平角)
根据点P及其法线,计算出切面角tangent angle
通过horizon angle 和 tangent angle,计算得出AO。(注意这里角度的范围,是实现的细节)
对其它三个方向相同操作,将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/屏幕分辨率高hfloat2 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 HBAO性能是有较大提升的,更适用于移动端。HBAO采样数大量减少,如果一个像素采样4个方向,4个RayMarching的话,也即16个采样点。而SSAO 要64个采样点,相当于4倍。其实可以理解为HBAO的通过角度的大小,节约了一部分的采样点。效果上看,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