全局光照RSM

news/2025/3/22 4:04:11/

Reflective Shadow Maps(RSM)

一切被直接光照照到的物体,会作为次级光源。

问题1:哪些面片被直接照亮

使用ShadowMap就可以知道哪些面片被直接照亮

问题2:各个面片对P点的贡献分别是多少。

在这里插入图片描述
对渲染方程代入如上计算,得到如下结果
在这里插入图片描述
在上式中, L i ( q → p ) L_i(q\rightarrow p) Li(qp)可优化为如下函数
因为:
f r = ρ / π , ρ 为反射率 L i = f r ⋅ ϕ d A , ϕ 是直接光照的光强 f_r = \rho / \pi,\rho 为反射率\\ \quad\\ L_i = f_r \cdot \frac{\phi}{dA},\phi 是直接光照的光强 fr=ρ/πρ为反射率Li=frdAϕϕ是直接光照的光强
因此有次级光源光强
E p ( x , n ) = ϕ p m a x { 0 , d o t ( n p , ( x − x p ) } m a x { 0 , d o t ( n , x p − x ) } ∣ ∣ x − x p ∣ ∣ 4 E_p(x,n)=\phi_p \frac{max\{0,dot(n_p,(x-x_p)\}max\{0,dot(n,x_p-x)\}}{||x-x_p||^4} Ep(x,n)=ϕp∣∣xxp4max{0,dot(np,(xxp)}max{0,dot(n,xpx)}

L 0 = E p ( x , n ) ∗ f r ( p , p → q , w o ) L_0 = E_p(x,n) * f_r(p,p\rightarrow q,w_o) L0=Ep(x,n)fr(p,pq,wo)

其他近似

  1. 不考虑Visbility项,认为次级光源不会被遮挡。
  2. 不对所有次级光源采样,只对该点在ShadowMap中周围的部分像素采样。

ShadowMap记录值

  1. 深度
  2. 世界坐标
  3. 法线
  4. 次级光源强度 ϕ \phi ϕ

特点与效果

对于特定情况效果比较好,如手电筒(用RSM做手电筒!!!?)
好处:非常好写,第一个Path生成RSM,第二个path用眼睛看向场景。
问题:

  1. 直接光源较多时,间接光源也会成倍增多
  2. 不会计算反射光的可见性检查
  3. 次级光源效果和运行速度,会根据采样率的不同的不同

如何实现

第一步,先找到哪些物体表面能够被直接照亮,使用ShadowMap,认为每一个ShadowMap的像素就是一个次级光源。
第二步,次级光源如何贡献到点P:我们认为所有的反射物(次级光源),都是Diffuse的

RSM与VPL(Virtual Point Light 虚拟点光源)

RSM与离线渲染中的VPL方式是比较相似的,RSM是硬件加速版本的VPL(Virtual Point Light 虚拟点光源)。

RSM实现步骤

第一个Pass

在摄像机视角渲染整个场景,并记录场景中可见的像素点的颜色视口矩阵下的法线视口矩阵下的坐标

得到一组场景信息,可以理解为GBuffer。
在这里插入图片描述

第2个Pass

从光源视口下看向场景,生成RSM图。
记录的从光源视口下可见像素点的反射光颜色值相机视角下的法线相机视角下的坐标光源视角下的坐标
得到的结果是一组256x256的RSM图
在这里插入图片描述在这里插入图片描述
············反射光颜色值 ······························· 相机视角下的法线 ··················
在这里插入图片描述在这里插入图片描述

··········· 相机视角下的坐标 ·························· 光源视角下的坐标(主要保存z轴深度)·······························

第3个Pass

1.将Pass1中保存的像素坐标转化到与RSM相同的光源坐标

	ivec2 FragPos = ivec2(gl_GlobalInvocationID.xy);//当前执行单元在全局工作组中的位置的有效索引vec3 FragViewNormal = normalize(texelFetch(u_NormalTexture, FragPos, 0).xyz);vec3 FragAlbedo = texelFetch(u_AlbedoTexture, FragPos, 0).xyz;vec3 FragViewPos = texelFetch(u_PositionTexture, FragPos, 0).xyz;// 获取 摄像机视口下像素 在光源视口下的位置坐标vec4 FragPosInLightSpace = u_LightVPMatrixMulInverseCameraViewMatrix * vec4(FragViewPos, 1);FragPosInLightSpace /= FragPosInLightSpace.w;vec2 FragNDCPos4Light = (FragPosInLightSpace.xy + 1) / 2;

2. 计算该像素点的直接光照

如果该像素点在光照空间外,则只提供一个基本的环境光照。
当该像素在光照空间内,首先判断该点是否在阴影中

  • 如果在阴影中,则只计算环境光照
  • 如果不在阴影中,则计算直接光照
// 直接光照&环境光照vec3 testOutput;vec3 DirectIllumination;// 如果该像素在RSM范围之外,以0.1倍源像素作为其环境光照// FragPosInLightSpace.z范围在【-1,0】的区间中.属于可被光照直接照射的范围// 这里可通过与RSM中的深度进行比较,来确定是否有阴影生成,或是否可被作为次级光源if(	FragPosInLightSpace.z < -1.0f || FragPosInLightSpace.z > 0.0f||\FragPosInLightSpace.x >=  1.0f || FragPosInLightSpace.x <= -1.0f||\FragPosInLightSpace.y >=  1.0f || FragPosInLightSpace.y <= -1.0f )//{DirectIllumination = vec3(0.1) * FragAlbedo;testOutput = vec3(0.f,0.f,0.f);}else//反之,将原像素经过夹角衰减后的值作为直接光照{	// view space下的光照坐标vec3 RSWLightPosition =texture(u_RSMLightPositionTexture,FragNDCPos4Light.xy).xyz;// 判断是否在阴影中(近小【-1】远大【0】)if(RSWLightPosition.z + 0.001 > FragPosInLightSpace.z){//不在阴影中DirectIllumination = FragAlbedo* max(dot(-u_LightDirInViewSpace, FragViewNormal), 0.1);// ;}else{//在阴影中DirectIllumination = vec3(0.1) * FragAlbedo;}}

在这里插入图片描述

3. 计算该像素点的间接光照

将该着色点投影到光照视口下的点,则已知该点在RSM纹理上的xy轴位置。

在RSM图中,在(x,y)像素上以R为半斤的周围进行随机采样,每一个采样点作为次级光源进行光照计算。

// 计算间接光照vec3 IndirectIllumination = vec3(0);float RSMTexelSize = 1.0 / u_RSMSize;for(int i = 0; i < u_VPLNum; ++i){if(FragPosInLightSpace.z > -1.0f && FragPosInLightSpace.z <0.0f){//获取随机采样数组vec3 VPLSampleCoordAndWeight = u_VPLsSampleCoordsAndWeights[i].xyz;// 在光源视口下的该像素点周围一圈进行采样vec2 VPLSamplePos = FragNDCPos4Light + u_MaxSampleRadius * VPLSampleCoordAndWeight.xy * RSMTexelSize;// 在RSM图中获取采样点的次级光源颜色值vec3 VPLFlux = texture(u_RSMFluxTexture, VPLSamplePos).xyz;// 获取采样点在摄像机视口坐标下的的法线和位置坐标vec3 VPLNormalInViewSpace = normalize(texture(u_RSMNormalTexture, VPLSamplePos).xyz);vec3 VPLPositionInViewSpace = texture(u_RSMPositionTexture, VPLSamplePos).xyz;// 计算该采样点对该像素的间接光照值IndirectIllumination += calcVPLIrradiance(VPLFlux, VPLNormalInViewSpace, VPLPositionInViewSpace, FragViewPos, FragViewNormal, VPLSampleCoordAndWeight.z);}}IndirectIllumination *= FragAlbedo;//间接光vec3 Result = IndirectIllumination / u_VPLNum;

在这里插入图片描述

4. 将直接光照与间接光照加起来

得到结果,渲染!

vec3 Result = DirectIllumination  + IndirectIllumination / u_VPLNum ;

在这里插入图片描述
区别【好像没太大区别 dog.jpg】
在这里插入图片描述


http://www.ppmy.cn/news/1106654.html

相关文章

C--小Why的商品归位-- 牛客小白月赛77

输入 3 3 1 1 2 1 3 2 3 输出 2 解析&#xff1a; 先不考虑购物车的容量&#xff0c;即购物车容量为无限大。这样我们可以通过每种货物上车、下车的时间计算出每一个时间点内&#xff0c;购物车中货物的数量。 统计出所有时间点内&#xff0c;货物数量的最大值max。这个最大…

阿里云k8s服务之间偶尔获取不到dns解析安装ACK NodeLocal DNSCache

1.背景 feign.RetryableException: No route to host (Host unreachable) executing POST http://osale-thirdparty/empty/detect 服务突然会中断&#xff0c;开发在看日志的时候会出现host找不到的情况&#xff0c;阿里云技术推荐安装dns缓存组件&#xff0c;加上这个组件会解…

第二章 Linux多进程开发 2.24-2.31 信号集及相关函数 共享内存 守护进程

有时间需要重新回顾 2.24 信号集及相关函数 1.用户通过键盘 Ctrl C, 产生2号信号SIGINT (信号被创建) 2.信号产生但是没有被处理 &#xff08;未决&#xff09; - 在内核中将所有的没有被处理的信号存储在一个集合中 &#xff08;未决信号集&#xff09; - SIGINT信号状态被…

QT Creator更改主题和编辑器风格(附几款黑色主题)

适用于qtcreator 一、使用自带主题与编辑器风格 打开Qt选择"工具"->"选项"&#xff1b; 2. 选择"环境"->"Theme"切换不同的主题风格 这里切换的是外边框的风格&#xff0c;如果编辑器中有同名的风格&#xff0c;编辑器的风格也…

解决 tesserocr报错 Failed to init API, possibly an invalid tessdata path : ./

问题描述 我们在初次使用tesserocr库的时候&#xff0c;可能会报以下错误&#xff1a; RuntimeError: Failed to init API, possibly an invalid tessdata path: ./ 这是因为我们在使用 conda 创建的环境中找不到"tessdata"这个文件夹。 解决办法 这时候把Tessera…

管理类联考——数学——汇总篇——知识点突破——应用题——口诀

口诀记忆 路程 平均速度:时间相等求算术,路程相等求调和。 年龄 同增同减差不变 线性规划 先看边界后取整 口诀解析 路程 平均速度:时间相等求算术,路程相等求调和。 解题方法 (1)当行驶两段路程所花的时间相等时,总路程的平均速度为两段路程各自平均速度的算术…

一片编程文章

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

算法通关村第13关【青铜】| 数字与数学基础问题

数字统计专题 1.数组元素积的符号 思路&#xff1a;每回碰到负数就取反 class Solution {public int arraySign(int[] nums) {int res nums[0];if(nums[0]>0){res 1;}else if(nums[0]<0){res -1;}else{return res;}for(int i 1;i<nums.length;i){if(nums[i]<…