Global Illumination_Screen-Space Directional Occlusion(SSDO)

2023-11-13

之前我们了解过AO、SSAO、HBAO(可参照之前文章Vulkan_SSAO—屏幕空间环境光遮蔽DirectX11进阶9_AO、SSAO、Particle System(GPU)Global Illumination_Horizon-Based Ambient Occlusion(HBAO))。

我们本次来看一下一种基于屏幕空间的全局光照算法。SSAO因为与SSDO、HBAO极其相似,仅是在最后一步时充分利用了随机查询点处的信息来模拟间接光照。
在这里插入图片描述

一、基于屏幕空间的间接光照算法

在这里插入图片描述

从上图(左数前两个)看出,对于着色点p在生成随机的点ABCD时,只有处于实际物体下方的点(A,B,D)都是用来计算SSAO的,算法认为可以把处于实际物体上方的点(C点)作为虚拟点光源(VPL)用于计算着色点p的间接光照。

从上图(左数第三个)看出看出,本算法也是存在一定缺陷的:比如A点实际未在物体内部,但因为深度遮挡关系导致改点会出错,B点虽然未被遮挡,但却无法接收环境光的光照效果。虽然有这些问题但问题不大,毕竟CG的一大定律:看着没问题就行。

在这里插入图片描述
其中,

  • di 为随机点 pi 到着色点 p 的距离;

  • 如果随机点 pi 在实际物体下方 ,则 L 返回0;[公式]

  • Qsi 为直接光源方向与随机点 pi 的夹角;

  • Qri 为随机点 pi 到着色点 p 向量与着色点 p 法线的夹角;

  • As 为 (当然这个公式这是一个参考,可以根据具体情况对公式进行改变):
    在这里插入图片描述

二、算法实现

很简单基于延迟渲染,下边简述其shader流程:

2.1 G-Buffer提取

顶点着色器:

#version 430 core
layout(location = 0) in vec3 _Position;
layout(location = 1) in vec3 _Normal;
layout(location = 2) in vec2 _TexCoord;

layout(std140, binding = 0) uniform u_Matrices4ProjectionWorld
{
	mat4 u_ProjectionMatrix;
	mat4 u_ViewMatrix;
};

uniform mat4 u_ModelMatrix;

out vec2 v2f_TexCoords;
out vec3 v2f_Normal;
out vec3 v2f_FragPosInViewSpace;

void main()
{
	vec4 FragPosInViewSpace = u_ViewMatrix * u_ModelMatrix * vec4(_Position, 1.0f);
	gl_Position = u_ProjectionMatrix * FragPosInViewSpace;
	v2f_TexCoords = _TexCoord;
	v2f_Normal = normalize(mat3(transpose(inverse(u_ViewMatrix * u_ModelMatrix))) * _Normal);	
	v2f_FragPosInViewSpace = FragPosInViewSpace.xyz;
}

片元着色器:

#version 430 core

in  vec3 v2f_FragPosInViewSpace;
in  vec2 v2f_TexCoords;
in  vec3 v2f_Normal;

layout (location = 0) out vec3 Albedo_;
layout (location = 1) out vec3 Normal_;
layout (location = 2) out vec4 Position_;

uniform sampler2D u_DiffuseTexture;
uniform vec4 u_DiffuseColor;
uniform float u_Near = 0.1;
uniform float u_Far = 1000.0f;
uniform vec3 u_LightPos = vec3(-18.5264, 19.4874, 78.5421);
//暂未用,多光源时处理
layout(std140, binding = 0) uniform u_Matrices4ProjectionWorld
{
	mat4 u_ProjectionMatrix;
	mat4 u_ViewMatrix;
};

float LinearizeDepth(float vDepth)
{
    float z = vDepth * 2.0 - 1.0; 
    return (2.0 * u_Near * u_Far) / (u_Far + u_Near - z * (u_Far - u_Near));    
}
void main()
{
	Position_ = vec4(v2f_FragPosInViewSpace.xyz,LinearizeDepth(gl_FragCoord.z));
	Normal_ = normalize(v2f_Normal);
	Albedo_ = texture(u_DiffuseTexture, v2f_TexCoords).xyz ;
}

2.2 SSAO计算

常规SSAO计算流程,不再赘述,想具体了解的看一下之前的详细教程。

顶点着色器:

#version 430 core

layout (location = 0) in vec2 _Position;
layout (location = 1) in vec2 _TexCoords;

out vec2 v2f_TexCoords;

void main()
{
	gl_Position = vec4(_Position, 0.0, 1.0);
	v2f_TexCoords = _TexCoords;
}

片元着色器:

#version 430 core

in  vec2 v2f_TexCoords;
layout (location = 0) out float FragColor_;

uniform sampler2D u_PositionTexture;
uniform sampler2D u_NormalTexture;
uniform sampler2D u_NoiseTexture;
uniform float u_Near = 0.1;
uniform float u_Far = 100.0f;
uniform float u_WindowWidth;
uniform float u_WindowHeight;
uniform vec3 u_Samples[64];

int KernelSize = 64;
float Radius = 1.0;

layout(std140, binding = 0) uniform u_Matrices4ProjectionWorld
{
	mat4 u_ProjectionMatrix;
	mat4 u_ViewMatrix;
};

float LinearizeDepth(float vDepth)
{
    float z = vDepth * 2.0 - 1.0; 
    return (2.0 * u_Near * u_Far) / (u_Far + u_Near - z * (u_Far - u_Near));    
}

void main()
{
	vec2 NoiseScale = vec2(u_WindowWidth/4.0f, u_WindowHeight/4.0f);
    vec3 FragPos = texture(u_PositionTexture, v2f_TexCoords).xyz;
    vec3 Normal = texture(u_NormalTexture, v2f_TexCoords).rgb;
    vec3 RandomVec = texture(u_NoiseTexture, NoiseScale * v2f_TexCoords).xyz;
    vec3 Tangent = normalize(RandomVec - Normal * dot(RandomVec, Normal));
    vec3 Bitangent = cross(Normal, Tangent);
    mat3 TBN = mat3(Tangent, Bitangent, Normal);
    float Occlusion = 0.0;
    for(int i = 0; i < KernelSize; ++i)
    {
        vec3 samples = TBN * u_Samples[i]; 
        samples = FragPos + samples * Radius; 
        vec4 Offset = vec4(samples, 1.0);
        Offset = u_ProjectionMatrix * Offset; 
        Offset.xyz /= Offset.w; 
        Offset.xyz = Offset.xyz * 0.5 + 0.5; 
        
        float SampleDepth = -texture(u_PositionTexture, Offset.xy).w; 
        
        float RangeCheck = smoothstep(0.0, 1.0, Radius / abs(FragPos.z - SampleDepth ));
        Occlusion += (SampleDepth >= samples.z ? 1.0 : 0.0) * RangeCheck;           
    }
    Occlusion = 1.0 - (Occlusion / KernelSize);
	FragColor_  = Occlusion;
}

在这里插入图片描述

具体的滤波操作与下面的SSDO一样便不再赘述,仅见下图:
在这里插入图片描述

2.3 SSDO计算

顶点着色器:

#version 430 core

layout (location = 0) in vec2 _Position;
layout (location = 1) in vec2 _TexCoords;

out vec2 v2f_TexCoords;

void main()
{
	gl_Position = vec4(_Position, 0.0, 1.0);
	v2f_TexCoords = _TexCoords;
}

片元着色器:

#version 430 core

in  vec2 v2f_TexCoords;
layout (location = 0) out float FragColor_;

uniform sampler2D u_PositionTexture;
uniform sampler2D u_NormalTexture;
uniform sampler2D u_NoiseTexture;
uniform float u_Near = 0.1;
uniform float u_Far = 100.0f;
uniform float u_WindowWidth;
uniform float u_WindowHeight;
uniform vec3 u_Samples[64];

int KernelSize = 64;
float Radius = 1.0;

layout(std140, binding = 0) uniform u_Matrices4ProjectionWorld
{
	mat4 u_ProjectionMatrix;
	mat4 u_ViewMatrix;
};

float LinearizeDepth(float vDepth)
{
    float z = vDepth * 2.0 - 1.0; 
    return (2.0 * u_Near * u_Far) / (u_Far + u_Near - z * (u_Far - u_Near));    
}

void main()
{
	vec2 NoiseScale = vec2(u_WindowWidth/4.0f, u_WindowHeight/4.0f);
    vec3 FragPos = texture(u_PositionTexture, v2f_TexCoords).xyz;
    vec3 Normal = texture(u_NormalTexture, v2f_TexCoords).rgb;
    vec3 RandomVec = texture(u_NoiseTexture, NoiseScale * v2f_TexCoords).xyz;
    vec3 Tangent = normalize(RandomVec - Normal * dot(RandomVec, Normal));
    vec3 Bitangent = cross(Normal, Tangent);
    mat3 TBN = mat3(Tangent, Bitangent, Normal);
    float Occlusion = 0.0;
    for(int i = 0; i < KernelSize; ++i)
    {
        vec3 samples = TBN * u_Samples[i]; 
        samples = FragPos + samples * Radius; 
        vec4 Offset = vec4(samples, 1.0);
        Offset = u_ProjectionMatrix * Offset; 
        Offset.xyz /= Offset.w; 
        Offset.xyz = Offset.xyz * 0.5 + 0.5; 
        
        float SampleDepth = -texture(u_PositionTexture, Offset.xy).w; 
        
        float RangeCheck = smoothstep(0.0, 1.0, Radius / abs(FragPos.z - SampleDepth ));
        Occlusion += (SampleDepth >= samples.z ? 1.0 : 0.0) * RangeCheck;           
    }
    Occlusion = 1.0 - (Occlusion / KernelSize);
	FragColor_  = Occlusion;
}

此部分为算法主要实现,根据首先判断点的贡献度,然后根据点类型作为次级光源贡献到着色点。
在这里插入图片描述

2.3 滤波

顶点着色器:

#version 430 core

layout (location = 0) in vec2 _Position;
layout (location = 1) in vec2 _TexCoords;

out vec2 v2f_TexCoords;

void main()
{
	gl_Position = vec4(_Position, 0.0, 1.0);
	v2f_TexCoords = _TexCoords;
}

片元着色器:

#version 430 core

in  vec2 v2f_TexCoords;
layout (location = 0) out float FragColor_;

uniform sampler2D u_SSAOTexture;


void main()
{
    vec2 TexelSize = 1.0 / vec2(textureSize(u_SSAOTexture, 0));
    float Result = 0.0;
    for (int x = -2; x < 2; ++x) 
    {
        for (int y = -2; y < 2; ++y) 
        {
            vec2 Offset = vec2(float(x), float(y)) * TexelSize;
            Result += texture(u_SSAOTexture, v2f_TexCoords + Offset).r;
        }
    }
    FragColor_ = Result / (4.0 * 4.0);
}

在这里插入图片描述

2.4 显示

顶点着色器:

#version 430 core

layout (location = 0) in vec2 _Position;
layout (location = 1) in vec2 _TexCoords;

out vec2 v2f_TexCoords;

void main()
{
	gl_Position = vec4(_Position, 0.0, 1.0);
	v2f_TexCoords = _TexCoords;
}

片元着色器:

#version 430 core

in  vec2 v2f_TexCoords;
out vec4 Color_;

uniform sampler2D u_SSAOTexture;
uniform sampler2D u_Albedo;
uniform sampler2D u_SSDOTexture;
uniform sampler2D u_DirectLightSSDOTexture;

void main()
{
	float Ambient = (texture(u_SSAOTexture, v2f_TexCoords, 0).r);
	vec3 Albedo = texture(u_Albedo, v2f_TexCoords).rgb;
	Color_ = vec4( texture(u_SSDOTexture, v2f_TexCoords).rgb,1);
}

直接来看一下环境光部分:
在这里插入图片描述
再看一下直接使用SSAO的效果:
在这里插入图片描述
最后看一下SSDO的效果:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Global Illumination_Screen-Space Directional Occlusion(SSDO) 的相关文章

  • Linux之线程-读写锁pthread_rwlock_t

    主要内容 1 互斥量及如何使用 2 什么是死锁 如何解决 3 什么是读写锁 如何使用 4 条件变量实现的生产消费者模型 5 信号量实现的生产消费者模型 3 读写锁 特点 读共享 写独占 写优先级高 读写锁仍然是一把锁 有不同的状态 未加锁
  • Linux添加PYTHONPATH方法以及3种修改环境变量方法

    方法一 用于当前终端 export PATH PATH lt 你的要加入的路径 gt 上面的方法只适用于当前终端 一旦当前终端关闭或在另一个终端中 则无效 方法二 用于当前用户 在用户主目录下有一个 bashrc 隐藏文件 可以在此文件中加
  • python数据结构:栈(匹配花括号、尖括号、圆括号、方括号)

    利用数据结构中的栈实现检查花括号 尖括号 圆括号 方括号是否匹配 相比较网上其他的方法 这种自定义类及函数的方法使用起来更加自动化 class StackNode object 初始化结点 def init self self data N
  • unity3d实现LOL中的相机控制功能

    using UnityEngine using System Collections public class CameraController MonoBehaviour private int SightDistancespeed 15
  • ovirt-node和ovirt-engine相连遇到的问题解决办法

    1 Host 192 168 70 7 does not comply with the cluster Default emulated machines The Hosts emulated machines are
  • CentOS7下安装配置Docker

    本文目录 step1 Docker下载安装 step2 设置docker 启动docker step3 docker基本操作 开启docker 查找镜像 拉取镜像 构建镜像 创建脚本文件 创建Dockerfile 构建 运行 step4 D
  • csdn积分获取攻略

    下载积分攻略 1 个人设置里进行手机绑定CSDN账户 奖励50分 右上角设置 账户安全 手机绑定 2 完成任务送若干分积分 http task csdn net 3 上传有效资源获取积分 上传非法 广告资源用户 将被扣除一定积分 严重者封号
  • 联想拯救者R9000P恢复原厂自带的win11系统

    之前重装win10之后 再想换回win11折腾了很久 现将方法分享出来 以便后面有相同需求的人可以较快的解决问题 文中无过程图片 因为我已经弄好了 不懂的地方可以私信或者评论 需要的东西 原厂自带系统 来自百度网盘超级会员V1的分享 hi
  • maven配置多个国内镜像

    一打开 打开maven的settings xml文件 二配置 在约190行下添加如下代码
  • Python报错:NameError: name ‘plt‘ is not defined

    加入以下一行代码即可 导入pyplot并将其命名为plt import matplotlib pyplot as plt
  • 论文阅读:SCDNET: A novel convolutional network for semantic change detection in high resolution optical

    SCDNET 一种用于高分辨率光学遥感图像变化检测网络 变化检测 新的网络架构 SCD的局限性 提出的SCDNET架构 网络结构 多尺度空洞卷积模块 注意力机制 LOSS函数 实验 结论 变化检测 变化检测 Change Detection
  • 双数组TRIE树原理

    原文名称 An Efficient Digital Search Algorithm by Using a Double Array Structure 作者 JUN ICHI AOE 译文 使用双数组结构的一个高效的Digital Sea
  • 【QT】简单易学的QT安装教程

    对于在Windows系统上安装QT 经常会出现各种各样的错误 从不知选择版本到安装好后也无法使用 实属让人头疼 经过多次试错 找到了简单易学的QT方式 同时也会说明其中需要注意的点 一 QT安装和新建QT文件 https download
  • 接口测试流程、测试点和测试工具

    一 什么情况下开展接口测试 1 项目处于开发阶段 前后端联调接口是否请求的通 2 有接口需求文档 开发已完成联调 可以转测 功能测试展开之前 3 版本上线前 进行整体回归测试 查看接口是否有异常 如404等 对准备上线的版本进行抓包 查看服
  • SignalR前后端进行通信时,出现了内存泄露

    在做此需求之前 需要知道 1 当前wafer功能已经用canvas实现了 2 die指的是图片中每一个小格子 3 当前正在工作的die用黄色进行高亮 已经工作过的die用灰色表示 4 几台基本每秒工作3个die wafer图片 最近在做一个

随机推荐

  • 【Linux】基础IO -- 软硬链接

    前言 上篇Linux的文章 我们学习到了文件系统中 对磁盘文件的管理 而本篇文章 我们要以文件系统的基础知识 了解软硬链接 话不多说 马上开始今天的学习 文章目录 前言 一 软链接 1 软链接的语法 2 软链接的本质 3 软链接的应用 二
  • axios vue 加载效果动画_vue+elementUI+axios实现的全局loading加载动画

    在项目中 很多时候都需要loading加载动画来缓解用户的焦虑等待 比如说 我打开了一个页面 而这个页面有很多接口请求 但浏览器的请求并发数就那么几个 再加上如果网速不行的话 那么这时候 用户很可能就会纠结自己到底该不该留下来继续等待呢 所
  • VC编程获取MSN口令的代码

    MSN Messenger uses Windows Credential UI credui dll on WinXP 2003 Password Storage mechanism differs in these OSes so th
  • 微服务的终极杀器SpringCloudAlibaba组件精讲

    一 微服务 1 1 微服务简介 In short the microservice architectural style is an approach to developing a single application as a sui
  • 02_jQuery与Ajax

    jquery jquery的作用 他是js的库 处理html 事件 实现动画效果 方便的为网站提供AJAX交互 命名格式 ji 体积大 用于学习和debug使用 min js 压缩的文件 体积小 用于线上环境使用 使用方法 必须先在页面文件
  • 五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT)

    五种开源协议的比较 BSD Apache GPL LGPL MIT 本篇博客比较了常见的5种开源协议的异同 大家在为自己的代码选择协议的时候可以参考 现今存在的开源协议很多 而经过Open Source Initiative组织通过批准的开
  • 标准C读BMP图象的一个小代码

    include
  • TCP/IP UDP广播无法发送或接收

    TCP IP UDP广播无法发送或者接收数据 在看 TCP IP 网络编程 这本书的时候 看到广播那一节 跟着书上写代码 怎么写都不行 广播就是没法发送 接收 发送端一直在发送数据 接收端就是没有反应 对了好几遍源码 没有问题 实在是愁人
  • 深入浅出理解Paxos算法

    Paxos算法是莱斯利 兰伯特 英语 Leslie Lamport LaTeX中的 La 于1990年提出的一种基于消息传递且具有高度容错特性的一致性算法 Paxos算法一开始非常难以理解 但是一旦理解其实也并不难 之所以难理解其实是因为作
  • 远程服务器无密登入设置

    现在还在输密码进入服务器的话 如果频次高的话 显得就很浪费时间 实际上可以通过无密登陆服务器 只需要设置好ssh就可以 这样只要你打开你电脑的终端不管是Mac OS还是Linux输入ssh root 远程服务器IP 这个命令就会自动登陆到远
  • 如何保障数仓数据质量?

    有赞数据报表中心为商家提供了丰富的数据指标 包括30 页面 100 数据报表以及400 不同类型的数据指标 它们帮助商家更合理 科学地运营店铺 同时也直接提供分析决策方法供商家使用 并且 每天在跑的底层任务和涉及的数据表已经达到千级别 面对
  • 【Python 1-10】Python手把手教程之——一篇讲透if语句以及if语句的特殊用法

    作者 弗拉德 来源 弗拉德 公众号 fulade me if 简单示例 假设你有一个汽车列表 并想将其中每辆汽车的名称打印出来 对于大多数汽车 都应以首字母大写的方式打印其名称 但对于汽车名 bmw 应以全大写的方式打印 下面的代码遍历一个
  • 技术至简-7:2G/3G/4G/5G基站系统中混合调制的技术框架

    2G 3G 4G 5G基站系统并非采用单一的调制技术 是数字调制和模拟调制的综合 是QAM调制与IQ调制的综合 是幅度调制与相位调制的综合 1 调制模型 在此模型中 包含了三种调制 1 数字基带调制 PSK QAM调制 2 模拟基带调制 I
  • Git日常问题: 什么是LFS?及其错误解决办法

    文章目录 Git LFS 错误 Git LFS 解决办法 Git LFS 错误 本地已经存在一个git仓库 想将其推送到一个远程仓库 结果遇到了git lfs错误 打印如下 git remote rename origin old orig
  • 解决DCNv2在Linux上安装失败的问题

    项目场景 今天同学安装 DCN Deformable Convolutional Networks 可变形卷积网络 v2的 PyTorch 版本时遇到了很多问题 弄了将近一天也没解决 于是求助笔者帮忙解决 这里记录一下成功的解决方案 问题描
  • MATLAB算法实战应用案例精讲-【回归算法】XGBoost算法(附Java、Python和R语言代码)

    目录 前言 xgboost面试过程中几个高频问题 1 xgboost如何处理缺失值
  • 什么是JDBC?并写出JDBC的开发流程。

    JDBC Java DataBase Connectivity 直译为 java数据库连接 实际上jdbc是java中的一套和数据库交互的api application program interface 应用程序编程接口 因为java程序
  • 【uni-app】修改原生导航栏文字和文字样式

    修改文字 uni setNavigationBarTitle 这是修改后的导航栏文字 title 首页 修改文字颜色以及导航栏背景色 uni setNavigationBarColor frontColor ffffff 文字颜色 back
  • SystemVerilog-$cast详解

    cast在子类与父类之间的复制 1 子类cast给父类 cast father cls child cls 之前有提到 cast是将两个类型强制转换 cast A B 将B强制类型转换给A 应用在类上 就是句柄的强制赋值操作 那么在子类和父
  • Global Illumination_Screen-Space Directional Occlusion(SSDO)

    之前我们了解过AO SSAO HBAO 可参照之前文章Vulkan SSAO 屏幕空间环境光遮蔽 DirectX11进阶9 AO SSAO Particle System GPU Global Illumination Horizon Ba