浅聊 Three.js 屏幕空间反射SSR-SSRShader
浅聊 Three.js 屏幕空间反射SSR(2)-SSRShader
前置基础
渲染管线中的相机和屏幕示意图
-Z (相机朝向的方向)||| +--------------+ <- 屏幕/投影平面| | || | || | (f) | <- 焦距| | || | || +--------------+| || || O <- 相机原点 (也称为视点)| |||+---------------------- X (水平轴)
一、计算 viewPosition
根据深度图计算屏幕空间上的 视图位置。
float clipW = cameraProjectionMatrix[2][3] * viewZ+cameraProjectionMatrix[3][3];
vec3 viewPosition = getViewPosition( vUv, depth, clipW );
二、计算反射位置 d1viewPosition
vec3 viewNormal=getViewNormal( vUv );// 入射光线方向
vec3 viewIncidentDir=normalize(viewPosition);// 反射光线方向
vec3 viewReflectDir=reflect(viewIncidentDir, viewNormal);// 反射光线最大长度
float maxReflectRayLen=maxDistance/dot(-viewIncidentDir, viewNormal);// 反射位置
vec3 d1viewPosition = viewPosition + viewReflectDir * maxReflectRayLen;
处理反射位置在近平面(即 -cameraNear)之的情况
目标:
确保反射光线的目标位置 (d1viewPosition) 不在近平面之前。如果在近平面之前,则将其调整到近平面上。
if(d1viewPosition.z > -cameraNear){//https://tutorial.math.lamar.edu/Classes/CalcIII/EqnsOfLines.aspxfloat t= (-cameraNear - viewPosition.z) / viewReflectDir.z;d1viewPosition = viewPosition + viewReflectDir * t;
}
^ -z|||| * 视点(viewPosition)| \| \|------------ (近平面,z = -cameraNear)| \| \| *| \| \| * d1viewPosition (初始位置)|-------------------------------------> x
解释:
反射光线的参数方程:
P ( t ) = v i e w P o s i t i o n + t ∗ v i e w R e f l e c t D i r P(t) = viewPosition + t * viewReflectDir P(t)=viewPosition+t∗viewReflectDir
我们需要找到 t t t 使得:
P ( t ) . z = − c a m e r a N e a r P(t).z = -cameraNear P(t).z=−cameraNear
因此,我们需要解方程:
v i e w P o s i t i o n . z + t ∗ v i e w R e f l e c t D i r . z = − c a m e r a N e a r viewPosition.z + t * viewReflectDir.z = -cameraNear viewPosition.z+t∗viewReflectDir.z=−cameraNear
解这个方程,得到:
t = − c a m e r a N e a r − v i e w P o s i t i o n . z v i e w R e f l e c t D i r . z t = \frac{-cameraNear - viewPosition.z}{ viewReflectDir.z} t=viewReflectDir.z−cameraNear−viewPosition.z
最后, 调整反射后目标位置:
d 1 v i e w P o s i t i o n = v i e w P o s i t i o n + v i e w R e f l e c t D i r ∗ t ; d1viewPosition = viewPosition + viewReflectDir * t; d1viewPosition=viewPosition+viewReflectDir∗t;
三、计算反射位置在屏幕空间下的位置
// 屏幕分辨率
uniform vec2 resolution;// 视图空间转屏幕空间
vec2 viewPositionToXY(vec3 viewPosition){vec2 xy;vec4 clip = cameraProjectionMatrix * vec4(viewPosition,1);//clipxy = clip.xy;float clipW = clip.w;//NDCxy /= clipW;//uvxy = (xy + 1.) / 2.;//screenxy *=resolution;return xy;
}vec2 d1 = viewPositionToXY(d1viewPosition);
四、屏幕空间光线步进(Ray Marching)
参考: DDA 画直线算法
// 片段着色器中的当前像素坐标
vec2 d0 = gl_FragCoord.xy;vec2 d1 = viewPositionToXY(d1viewPosition);// x 和 y 方向上的距离
float xLen = d1.x-d0.x;
float yLen = d1.y-d0.y;// 两个点之间的欧几里得距离
float totalLen = length(d1-d0);// 在 x 和 y 方向上步数的最大值,用于决定采样的步数
float totalStep = max(abs(xLen), abs(yLen));// 每一步在 x 和 y 方向上的增量
float xSpan = xLen / totalStep;
float ySpan = yLen / totalStep;for(float i = 0.; i<float(MAX_STEP); i++) {if(i >= totalStep) break;vec2 xy = vec2(d0.x + i * xSpan, d0.y + i * ySpan);if(xy.x < 0. || xy.x > resolution.x || xy.y < 0. || xy.y > resolution.y) break;// 比例进度, 0~1float s = length(xy - d0) / totalLen;vec2 uv = xy / resolution;float d = getDepth(uv);// 当前像素的视图空间深度值float vZ = getViewZ(d);if(-vZ >= cameraFar) continue;float cW = cameraProjectionMatrix[2][3] * vZ+cameraProjectionMatrix[3][3];vec3 vP = getViewPosition( uv, d, cW );// https://comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdffloat recipVPZ = 1. / viewPosition.z;// 基于插值得到的透视矫正后的深度值float viewReflectRayZ = 1. / (recipVPZ + s * (1. / d1viewPosition.z - recipVPZ));if(viewReflectRayZ <= vZ){// 只处理无限厚度的情况vec3 vN = getViewNormal(uv);if(dot(viewReflectDir,vN) >= 0.) continue;float distance = pointPlaneDistance(vP, viewPosition, viewNormal);if(distance > maxDistance) break;vec4 reflectColor = texture2D(tDiffuse, uv);gl_FragColor = reflectColor;}
}
只处理 viewReflectRayZ <= vZ的情况
^ -z||| * viewPosition (反射的起始位置)| \| \| \| \| \| * viewReflectRayZ (矫正后的深度值)| \| \| * vZ (当前像素深度值)| \| \| \| \|-------------------------------------> x
-
在透视投影下,深度值绝对值越小,表示距离相机越近。在进行光线行进时,我们希望光线从起点出发,经过所有可能的深度值,直到目标位置
-
viewReflectRayZ 是矫正后的深度值,它应该始终小于或等于 vZ,以确保光线距离起点从近到远进行插值和计算。
-
如果 viewReflectRayZ 大于 vZ, 这种情况可能导致光线跳过当前像素,直接到达更远的像素,产生穿透问题
-
通过确保 viewReflectRayZ <= vZ,可以保证光线在行进过程中深度值是连续变化的,从而提高插值的精度,避免因不连续的深度值变化而产生的伪影
只处理钝角的情况
点积大于或等于零,表示这两个单位向量的夹角小于或等于 90 度。
点到平面距离
float pointPlaneDistance(vec3 point,vec3 planePoint,vec3 planeNormal){// https://mathworld.wolfram.com/Point-PlaneDistance.html https://en.wikipedia.org/wiki/Plane_(geometry) http://paulbourke.net/geometry/pointlineplane/float a = planeNormal.x;float b = planeNormal.y;float c = planeNormal.z;float x0 = point.x;float y0 = point.y;float z0 = point.z;float x = planePoint.x;float y = planePoint.y;float z = planePoint.z;float d = -(a * x + b * y + c * z);float distance = (a * x0 + b * y0 + c * z0 + d)/sqrt(a * a + b * b + c * c);return distance;
}
相关文章:

浅聊 Three.js 屏幕空间反射SSR-SSRShader
浅聊 Three.js 屏幕空间反射SSR(2)-SSRShader 前置基础 渲染管线中的相机和屏幕示意图 -Z (相机朝向的方向)||| -------------- <- 屏幕/投影平面| | || | || | (f) | <- 焦距| | ||…...
Windows图形界面(GUI)-DLG-C/C++ - 月历控件(MonthCalendar)
公开视频 -> 链接点击跳转公开课程博客首页 -> e链接点击跳转博客主页 目录 月历控件(MonthCalendar) 使用场景 控件操作 月历控件(MonthCalendar) 使用场景 日程安排:用户可以通过月历控件选择特定的日期来安排会议或活动。事件管理&#x…...

【Langchain大语言模型开发教程】基于文档问答
🔗 LangChain for LLM Application Development - DeepLearning.AI Embedding: https://huggingface.co/BAAI/bge-large-en-v1.5/tree/main 学习目标 1、Embedding and Vector Store 2、RetrievalQA 引包、加载环境变量 import osfrom dotenv import…...

大厂面试-基本功
大厂面试第4季 服务可用性多少个9是什么意思遍历集合add或remove操作bughashcode冲突案例BigdecimalList去重复IDEA Debugger测试框架ThreaLocal父子线程数据同步 InheritableThreadLocal完美解决线程数据同步方案 TransmittableThreadLocal 服务可用性多少个9是什么意思 遍历集…...

RV1103使用rtsp和opencv推流视频到网页端
参考: Luckfox-Pico/Luckfox-Pico-RV1103/Luckfox-Pico-pinout/CSI-Camera Luckfox-Pico/RKMPI-example Luckfox-Pico/RKMPI-example 下载源码 其中源码位置:https://github.com/luckfox-eng29/luckfox_pico_rtsp_opencv 使用git clone由于项目比较大&am…...

与Bug较量:Codigger之软件项目体检Software Project HealthCheck来帮忙
在软件工程师的世界里,与 Java 小程序中的 Bug 作战是一场永不停歇的战役。每一个隐藏在代码深处的 Bug 都像是一个狡猾的敌人,时刻准备着给我们的项目带来麻烦。 最近,我就陷入了这样一场与 Java 小程序 Bug 的激烈较量中。这个小程序原本应…...

Git --- Branch Diverged
Git --- Branch Diverged Branch Diverged是如何形成的如何解决RebaseMerge Branch Diverged是如何形成的 尝试提交并将更改推送到 master 分支时,是否看到这条烦人的消息 原因是: 直到更改 B 之前,我的分支和“origin/master”完全相同。从…...
go标准库---net/http服务端
1、http简单使用 go的http标准库非常强大,调用了两个函数就能够实现一个简单的http服务: func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) func ListenAndServe(addr string, handler Handler) error handleFunc注册一个路…...

Linux文件和目录常用命令
1.操作命令 查看目录内容 ls 切换目录 cd 创建和删除操作 touch rm mkdir 拷贝和移动文件 cp mv 查看文件内容 cat more grep 其他 echo 重定向 > 和 >> 管道 | 1.1 终端实用技巧 1>自动补全 在敲出 文件/目录/命令 的前几个字母之后,按下…...
【C++刷题】优选算法——链表
链表常用技巧和操作总结 常用技巧 画图 引入虚拟头节点 不要吝啬空间,大胆定义变量 快慢双指针常用操作 创建一个新节点 尾插 头插 两数相加 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {int carry 0;ListNode* newHead new ListNode, *cur newHea…...
Flex和Bison
Flex和Bison是Linux和Unix环境下两个非常强大的工具,分别用于生成词法分析器和语法分析器。它们在编译器设计、文本处理等领域有着广泛的应用。下面我将详细介绍Flex和Bison的基本概念、功能、用法以及它们之间的关系。 一、Flex 1. 基本概念 Flex(其…...
Matlab-FPGA 小数转换为定点二进制小数脚本和转coe文件格式脚本
Matlab-FPGA 小数转换为定点二进制小数脚本: % 更新于2023年6月17日,修改旋转因子文件,不修改fpga %首先明确我们的二维FFT的数组维数,此为1024*8的二维矩阵,1024行,8列 column 1024; row 8; nk[]; Ncolumn*row; fo…...

逆向案例二十三——请求头参数加密,某区块链交易逆向
网址:aHR0cHM6Ly93d3cub2tsaW5rLmNvbS96aC1oYW5zL2J0Yy90eC1saXN0L3BhZ2UvNAo 抓包分析,发现请求头有X-Apikey参数加密,其他表单和返回内容没有加密。 直接搜索关键字,X-Apikey,找到疑似加密位置,注意这里…...
CSS 导航栏:设计、定制与优化
CSS 导航栏:设计、定制与优化 CSS(层叠样式表)是网页设计中不可或缺的一部分,它允许开发者通过定义样式来控制网页的布局和外观。在网页设计中,导航栏是一个关键元素,它帮助用户浏览网站并找到他们感兴趣的…...
JS 如何处理链接被用户点击中键的操作
今天在开发中遇到一个问题,在使用类似Bootstrap中的Tabs组件时,当在tab导航链接点击中键时会打开一个新的窗口访问链接,于是我尝试在别的普通链接上点击中键时也会如此,我猜测这是浏览器的默认行为。 由于我开发的是一个浏览器在…...
Android 11 使用HAL层的ffmpeg库(1)
1.frameworks/av/media目录下面的修改 From edd6f1374c1f15783d9920ebda22ea915e503775 Mon Sep 17 00:00:00 2001 From: GW00219471 <zhumingxingnoboauto.com> Date: Wed, 17 Jan 2024 15:16:10 0800 Subject: [PATCH] ?UTF-8?q?[V35CUX-4542]:E7A7BBE6A48Dcux20E8…...

友力科技数据中心搬迁方案
将当前运行机房中的所有设备、应用系统安全搬迁至新数据中心机房,实现平滑切换、平稳过渡,最大限度地降低搬迁工作对业务的影响。 为了确保企事业单位能够顺利完成数据中心机房搬迁工作,我们根据实际经验提供了4个基本原则,希望能…...
GitHub敏感信息扫描工具
目录 功能设计 技术实现 程序使用 文件配置 下载地址 功能设计 GitPrey是根据企业关键词进行项目检索以及相应敏感文件和敏感文件内容扫描的工具,其设计思路如下: 根据关键词在GitHub中进行全局代码内容和路径的搜索(in:file,path),将项目结果做项目信息去重整理得到…...

Linux云计算 |【第一阶段】ENGINEER-DAY4
主要内容: 配置Linux网络参数、配置静态主机名、查看/修改/激活/禁用网络连接、指定DNS、虚拟网络连接、虚拟机克隆、SSH客户端、SCP远程复制、SSH无密码验证(SERVICE-DAY5)、虚拟网络类型 一、网络参数配置 修改网卡配置文件主要是需要配置…...

C++与VLC制作独属于你的动态壁纸背景
文章目录 前言效果展示为什么要做他如何实现他实现步骤获取桌面句柄代码获取桌面句柄libvlc_media_player_set_hwnd函数 动态壁纸代码 总结 前言 在当今的数字世界中,个性化和自定义化的体验越来越受到人们的欢迎。动态壁纸是其中一种很受欢迎的方式,它…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...