UnityShader——SSAO

目录

1.是什么

2.原理

3.各部分解释

2.1.从屏幕空间到视图空间

2.2.以法线半球为基,获取随机向量

2.3.应用偏移,并将其转换为uv坐标

2.4.获取深度

2.5.比较并计算贡献

2.6.最后计算

4.改进

4.1.平滑过渡

4.2.模糊

5.变量和语句解释

5.1._DepthBias

5.2._RangeCheck

5.3.ssDepth >= 0.9999

6.其他事项

6.1.颜色叠加

6.2.向量的随机

6.3.墙面噪声

7.效果演示


1.是什么

        SSAO,全称Screen Space Ambient Occlusion,即屏幕空间环境光遮蔽。其用处是用来模拟全局光照下,一些细节处的阴影。如墙角,缝隙等。也可以让画面整体的立体感增强。

        SSAO是由AO发展而来,AO由于性能问题难以被用于实时渲染,因此出现了SSAO,以相对差的效果换取性能。


2.原理

        对于一个屏幕上像素点而言,将其通过逆变换和深度纹理转换为视图空间的点。然后以其法线半球为基,生成随机向量,用该向量对该点进行偏移,再将偏移后的点转到屏幕空间,用此时的点对深度纹理进行采样,得到一个采样深度,用该深度与原深度(未偏移的点采样的深度)比较,如果采样深度小于原深度,说明被遮挡,计算其贡献;反之未遮挡,贡献为0。将一个点的每一次偏移的贡献相加除以偏移的次数,即为该点最终的颜色。

        我说的可能没那么清楚,下面通过画图演示一下过程(虽然图画的也丑就是了):


3.各部分解释

2.1.从屏幕空间到视图空间

        这里采用的是通过先将点转换到远裁剪面,然后通过真实深度获取真实的视图空间的坐标。参考了这篇文章(https://zhuanlan.zhihu.com/p/92315967)中的方法一。

        这里简单讲述其原理:

        我们知道,一个点从世界坐标转为屏幕坐标需要进行视图变换(世界空间->视图空间),投影变换(视图空间->裁剪空间),透视除法(裁剪空间->ndc空间),视口映射(ndc空间->屏幕空间)。那么我们只需要反向进行就能够得到一个屏幕坐标在视图空间的坐标。

        首先是将屏幕坐标转到ndc空间,这里可以直接调用shader中的函数来计算,需要注意的是,这里的screenPos需要除以其w分量才能正常使用(如果有uv坐标,可以直接使用uv坐标):

//screenPos
float4 screenPos = ComputeScreenPos(UnityObjectToClipPos(v.vertex));
float2 ndcUV = (screenPos.xy / screenPos.w) * 2 - 1;//uv
float2 ndcUV = uv * 2 - 1;

        然后是将ndc转为裁剪,我们先将该点视为远裁剪面上的点,则:

float3 clipPos = float3(ndcUV.x, ndcUV.y, 1) * _ProjectionParams.z;

        然后将裁剪转为视图,由于转为视图后仍是原裁剪面上的点,所以乘以该点的线性深度值来获取真实坐标。之所以用clipPos.xyzz进行计算,则是因为裁剪空间下,远裁剪面的zw相同。

//获取深度和法线(因为后面要用,所以这里将法线一起获取了)
float4 depthNormal = tex2D(_CameraDepthNormalsTexture, f.uv);
float3 ssNormal; //ss -> Screen Space
float ssDepth; 
DecodeDepthNormal(depthNormal, ssDepth, ssNormal);
float ssDepth01 = Linear01Depth(ssDepth);//变换
float3 viewPos = mul(unity_CameraInvProjection, clipPos.xyzz).xyz * ssDepth01;

        至此,视图空间的坐标已得到。

2.2.以法线半球为基,获取随机向量

        我们首先需要知道TBN矩阵,它是由切线,副切线,法线三者构成的一个3*3的矩阵,用途是做切线空间与其他空间转换的媒介。并且这种转换不会改变向量的长度(前提是三个都是单位向量)。

        所以我们先在切线空间中随机生成一个x在[-1,1],y在[-1,1],z在[0,1]的向量,然后将其转换到视图空间下。

float3 viewNormal = normalize(ssNormal);
//随机生成,是正交基呈现随机性
float3 viewTangent = normalize(GetRandomVec(f.uv.xy));
float3 viewBitangent = cross(viewTangent, viewNormal);
viewTangent = cross(viewBitangent, viewNormal);
float3x3 TBN = float3x3(viewTangent.x, viewBitangent.x, viewNormal.x,viewTangent.y, viewBitangent.y, viewNormal.y,viewTangent.z, viewBitangent.z, viewNormal.z);//for循环中的语句
float3 randomVec = GetRandomVecHalf(f.uv.yx * i);
//_AORadius是一个由c#脚本传进的参数,目的是控制阴影的大小
float3 randomVecView = mul(TBN, randomVec) * _AORadius;

2.3.应用偏移,并将其转换为uv坐标

        将随机向量应用到原点,然后通过一系列转换将其变为uv坐标,以采样深度法线纹理。

float3 viewOffPos = viewPos + randomVecView;
float4 clipOffPos = mul(unity_CameraProjection, float4(viewOffPos, 1));
float2 sampleUV = clipOffPos.xy / clipOffPos.w;
sampleUV = sampleUV * 0.5 + 0.5;

2.4.获取深度

        waaaagh!

//获取深度
float4 sampleDepthNormal = tex2D(_CameraDepthNormalsTexture, sampleUV);
float sampleDepth;
//获取这个法线的原因是我懒得单独获取深度了
float3 sampleNormal;
DecodeDepthNormal(sampleDepthNormal, sampleDepth, sampleNormal);

2.5.比较并计算贡献

        需要注意的是,这里比较的是实际的深度值,需要经过LinearEyeDepth转换。

        我这里使用大于判断,是因为最后会将进行1 - ao的运算,相当于黑白取反。

//for外
ssDepth = LinearEyeDepth(ssDepth);//for内
sampleDepth = LinearEyeDepth(sampleDepth);
//_DepthBias:防止自遮挡
float depthDiff = sampleDepth - ssDepth - _DepthBias;
//_RangeCheck:去除不正常的阴影
if (depthDiff > 0 && depthDiff < _RangeCheck)
{ao += 1;
}

2.6.最后计算

        取平均。

//1-是因为上面进行了相反的运算,所以这里1-再反一次;
//pow和AOStrength都是为了控制强度
ao = 1 - pow(ao / _SampleTime, 1) * _AOStrength;

4.改进

4.1.平滑过渡

        添加距离衰减,远距离贡献小,近距离贡献大;

        同样因为取反操作,所以这里的代码逻辑为:远距离贡献大,近距离贡献小。

float weight = smoothstep(0, _AORadius, length(randomVec));float depthDiff = sampleDepth - ssDepth - _DepthBias;
if (depthDiff > 0 && depthDiff < _RangeCheck)
{ao += 1 * weight;
}

4.2.模糊

        因为直接生成的ssao会呈现一种噪声密布的状态

就像这样

         所以需要对其进行模糊,模糊的方法很多,我使用的是高斯模糊,原理就不说明了。效果如下:

模糊后的

5.变量和语句解释

5.1._DepthBias

        用于防止自遮挡,因为有时会出现由于精度误差导致的自己遮挡自己的问题。这个变量会将最后的深度差再减小一些,或者理解为将采样的深度适当减小一些。这样就不会出现自遮挡的问题了。

5.2._RangeCheck

        有时我们会发现,明明不该出现阴影的地方出现了阴影,比如两个仅仅只有前后关系的物体交界处。这个变量就是为了防止这种情况,如果深度差小于指定值,才会计算贡献,反之舍弃。

奇怪的阴影

5.3.ssDepth >= 0.9999

        上面没有写出来,其位置是在片元着色器中用原点获取深度之后。用处是为了防止天空盒与物体交界处出现阴影(理论上_RangeCheck就能解决这问题,但不知道什么原因不行):

if (ssDepth >= 0.9999)
{return 1;
}
奇怪的阴影2

6.其他事项

6.1.颜色叠加

        最后ssao求出来后还有的颜色叠加过程,我是图方便直接叠上去了。

6.2.向量的随机

        向量的随机性会极大程度地影响最后ssao的效果,所以请尽量保证向量的随机性。

6.3.墙面噪声

        我的实现会导致_AORadius增大时,墙面上会出现噪点,可以通过增大_SampleTime来降低其存在感。当然这不是一个好办法,我解决后会更新该文章。


7.效果演示

         代码在https://github.com/RedShaoWuHuaQu/UnityShader/tree/main/SSAO中。

before
after

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90816.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式】外观模式(门面模式)

外观模式&#xff08;Facade Pattern&#xff09;详解一、外观模式简介 外观模式&#xff08;Facade Pattern&#xff09; 是一种 结构型设计模式&#xff0c;它为一个复杂的子系统提供一个统一的高层接口&#xff0c;使得子系统更容易使用。 外观模式又称为门面模式&#xff0…

【6.1.1 漫画分库分表】

漫画分库分表 “数据量大了不可怕&#xff0c;可怕的是不知道如何优雅地拆分。” &#x1f3ad; 人物介绍 架构师老王&#xff1a;资深数据库架构专家&#xff0c;精通各种分库分表方案Java小明&#xff1a;对分库分表充满疑问的开发者ShardingSphere师傅&#xff1a;Apache S…

Tomcat问题:启动脚本startup.bat中文乱码问题解决

一、问题描述 我们第一次下载或者打开Tomcat时可能在控制台会出现中文乱码问题二、解决办法 我的是8.x版本的tomcat用notepad打开&#xff1a;logging.properties 找到&#xff1a;java.util.logging.ConsoleHandler.encoding设置成GBK&#xff0c;重启tomcat即可

Linux中Gitee的使用

一、Gitee简介&#xff1a;Gitee&#xff08;码云&#xff09;是中国的一个代码托管和协作开发平台&#xff0c;类似于GitHub或GitLab&#xff0c;主要面向开发者提供代码管理、项目协作及开源生态服务。适用场景个人开发者&#xff1a;托管私有代码或参与开源项目。中小企业&a…

Oracle大表数据清理优化与注意事项详解

一、性能优化策略 1. 批量处理优化批量大小选择&#xff1a; 小批量(1,000-10,000行)&#xff1a;减少UNDO生成&#xff0c;但需要更多提交次数中批量(10,000-100,000行)&#xff1a;平衡性能与资源消耗大批量(100,000行)&#xff1a;适合高配置环境&#xff0c;但需监控资源使…

Anaconda及Conda介绍及使用

文章目录Anaconda简介为什么选择 Anaconda&#xff1f;Anaconda 安装Win 平台macOS 平台Linux 平台Anaconda 界面使用Conda简介Conda下载安装conda 命令环境管理包管理其他常用命令Jupyter Notebook&#xff08;可选&#xff09;Anaconda简介 Anaconda 是一个数据科学和机器学…

外包干了一周,技术明显退步

我是一名本科生&#xff0c;自2019年起&#xff0c;我便在南京某软件公司担任功能测试的工作。这份工作虽然稳定&#xff0c;但日复一日的重复性工作让我逐渐陷入了舒适区&#xff0c;失去了前进的动力。两年的时光匆匆流逝&#xff0c;我却在原地踏步&#xff0c;技术没有丝毫…

【QT】多线程相关教程

一、核心概念与 Qt 线程模型 1.线程与进程的区别: 线程是程序执行的最小单元&#xff0c;进程是资源分配的最小单元&#xff0c;线程共享进程的内存空间(堆&#xff0c;全局变量等)&#xff0c;而进程拥有独立的内存空间。Qt线程只要关注同一进程内的并发。 2.为什么使用多线程…

VS 版本更新git安全保护问题的解决

问题&#xff1a;我可能移动了一个VS C# 项目&#xff0c;然后&#xff0c;发现里面的git版本检测不能用了 正在打开存储库: X:\Prj_C#\3D fatal: detected dubious ownership in repository at X:/Prj_C#/3DSnapCatch X:/Prj_C#/3D is owned by:S-1-5-32-544 but the current …

Git常用命令一览

Git 是基于 Linux内核开发的版本控制工具。与常用的版本控制工具 CVS, Subversion 等不同&#xff0c;它采用了分布式版本库的方式&#xff0c;不必服务器端软件支持&#xff08;ps&#xff1a;这得分是用什么样的服务端&#xff0c;使用http协议或者git协议等不太一样。并且在…

基于 JSON 文件定位图片缺陷点并保存

基于JSON的图片缺陷处理流程 ├── 1. 输入检查 │ ├── 验证图片文件是否存在 │ └── 验证JSON文件是否存在 │ ├── 2. 数据加载 │ ├── 打开并加载图片 │ └── 读取并解析JSON文件 │ ├── 3. 缺陷信息提取 │ ├── 检查JSON中是否存在shapes字…

Redis基础学习(五大值数据类型的常用操作命令)

目录 一、Redis基本知识与Redis键&#xff08;key&#xff09;常用操作命令。 二、Redis的五大值的数据类型。&#xff08;value&#xff09; 三、Redis关于键&#xff08;key&#xff09;的值常用操作指令表格统计。 &#xff08;1&#xff09;字符串&#xff08;String&#…

Ubuntu——办公软件 LibreOffice 安装与使用指南

十四、LibreOffice 安装与使用1、核心组件组件​​​​图标​​​​对应MS Office​​​​核心功能定位​​​​Writer​​&#x1f4dd;Word专业文档处理与排版​​Calc​​&#x1f4ca;Excel数据计算与分析​​Impress​​&#x1f3ac;PowerPoint演示文稿制作​​Draw​​&…

Securecrt丢失tab以及终端重新配色

今天在使用 Securecrt 的时候&#xff0c;发现 Securecrt 的 tab 标签消失不见了&#xff0c;仔细回想起来&#xff0c;应该是上一次误按了 alt enter 最大化&#xff0c;然后导致配置丢失的问题 还有表现就是菜单中的 Session Tabs 无论勾选还是不勾选都没有任何变化&#xf…

frp搭建内网穿透教程

frp搭建内网穿透教程 步骤1&#xff1a;准备工作 公网服务器&#xff1a;需要一台具有公网IP的服务器作为中转服务器&#xff0c;安装frp服务器端&#xff08;frps&#xff09;。内网设备&#xff1a;需要暴露服务的内网设备&#xff0c;安装frp客户端&#xff08;frpc&#xf…

【JavaEE进阶】图书管理系统(未完待续)

目录 用户登录 添加图书 图书列表 修改图书 删除图书 批量删除 拦截器 &#x1f343;前言 什么是拦截器? 拦截器的基本使用 自定义拦截器 注册配置拦截器 拦截路径 拦截器执行流程 项目实现统一拦截 定义拦截器 注册配置拦截器 前⾯图书管理系统, 咱们只完成了⽤⼾登录和图书列…

基于同花顺API的熊市与牛市识别模型开发及因子分析

基于同花顺API的熊市与牛市识别模型开发及因子分析 1. 引言 1.1 研究背景与意义 金融市场中的牛市与熊市识别一直是投资者和研究人员关注的重点问题。牛市(Bull Market)通常指价格持续上涨的市场环境,投资者信心充足,交易活跃;而熊市(Bear Market)则指价格持续下跌的市场…

AMD 锐龙 AI MAX+ 395 处理器与端侧 AI 部署的行业实践

2025 年 7 月 10 日&#xff0c;AMD 在深圳召开 Mini AI 工作站行业解决方案峰会&#xff0c;正式发布基于锐龙 AI MAX 395 处理器的端侧 AI 部署方案&#xff0c;与 200 余家生态伙伴共同探讨 AI 技术在千行百业的落地路径。这一硬件平台通过异构计算架构与开放生态设计&#…

期权盘位是什么意思?

本文主要介绍期权盘位是什么意思&#xff1f;“期权盘位”并非金融交易中的标准术语&#xff0c;可能是口语化表达或对某些概念的简化描述。期权盘位是什么意思&#xff1f;1. 期权盘口的“价位”&#xff08;买卖报价位置&#xff09;在期权交易中&#xff0c;“盘口”通常指实…

【Trea】Trea国内版|国际版|海外版下载|Mac版|Windows版|Linux下载配置教程

【Trea】Trea国内版&#xff5c;国际版&#xff5c;海外版下载&#xff5c;Mac版&#xff5c;Windows版下载配置教程 本文适用读者&#xff1a; 想要第一次安装 Trea需要在 Windows 或 macOS 上完成环境配置想深入了解 Doubao、DeepSeek、ChatGPT、Claude 等模型在 Trea 中的接…