浅聊 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+tviewReflectDir

我们需要找到 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+tviewReflectDir.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.zcameraNearviewPosition.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+viewReflectDirt;

三、计算反射位置在屏幕空间下的位置
// 屏幕分辨率
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;
}

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

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

相关文章

前端vue框架的项目文件创建及常见Vue指令运用

前言 本文介绍前端Vue框架&#xff0c;先从npm工具创建的Vue项目开始&#xff0c;对项目结构的一些文件用途进行说明&#xff0c;随后对Vue文件编写所用的两种风格&#xff08;选项式API和组合式API风格&#xff09;做了区分&#xff0c;同时对编写代码中常见的生命周期钩子函…

Pytorch使用前期准备

一、检查英伟达驱动和CUDA Toolkit是否正确安装 1.任务管理器性能选项卡中能正确显示显卡型号则表示显卡驱动正确安装 2. CUDA Toolkit会跟随pytorch自动安装 二、虚拟环境的准备 Miniconda — Anaconda documentationhttps://docs.anaconda.com/miniconda/ 1.安装anaconda或者…

腾讯元宝上线“3D角色梦工厂”:快速生成专属3D角色!

7月16日&#xff0c;腾讯旗下大模型应用“腾讯元宝”上线“3D角色梦工厂”&#xff0c;允许用户通过上传一张五官清晰的正面头像&#xff0c;并选择不同的角色模板&#xff0c;迅速生成个人3D角色&#xff01; 技术特点 “3D角色梦工厂”将大模型生成技术与3D应用相结合&#…

大模型(LLM)选择指南:AI解决方案的12个决策点

今天我们来看看国外各家领先的大型语言模型&#xff08;LLM&#xff09;&#xff0c;这些模型来自OpenAI、Google、Anthropic、Cohere、Meta、Mistral AI以及Databricks等不同的供应商。我们会根据几个关键因素来评估这些模型&#xff0c;包括性能&#xff08;涵盖价格、质量和…

NET 语言识别,语音控制操作、语音播报

System.Speech. 》》System.Speech.Synthesis; 语音播报 》》System.Speech.Recognition 语音识别 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Speech.Recog…

在 Windows 上运行 Linux:WSL2 完整指南(二)

系列文章目录 在 Windows 上运行 Linux&#xff1a;WSL2 完整指南&#xff08;一&#xff09;&#x1f6aa; 在 Windows 上运行 Linux&#xff1a;WSL2 完整指南&#xff08;二&#xff09;&#x1f6aa; 文章目录 系列文章目录前言四、常见问题及解决方法问题二&#xff1a;0…

昇思25天学习打卡营第17天|LLM-基于MindSpore的GPT2文本摘要

打卡 目录 打卡 环境准备 准备阶段 数据加载与预处理 BertTokenizer 部分输出 模型构建 gpt2模型结构输出 训练流程 部分输出 部分输出2&#xff08;减少训练数据&#xff09; 推理流程 环境准备 pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspo…

AV1技术学习:Affine Motion Compensation

一、Affine Model Parameter 除了传统的平移运动补偿&#xff0c;AV1 还支持仿射变换模型&#xff0c;将当前像素点 (x, y) 通过以下方式投影到参考帧中的预测像素点 (x, y). 参数 (h13, h23) 对应于平移模型中使用的常规运动向量。 参数 h11 和 h22 控制垂直和水平轴上的比例…

Spring后端框架复习总结

之前写的博客太杂,最近想把后端框架的知识点再系统的过一遍,主要是Spring Boot和Mybatis相关,带着自己的理解使用简短的话把一些问题总结一下,尤其是开发中和面试中的高频问题,基础知识点可以参考之前写java后端专栏,这篇不再赘述。 目录 Spring什么是AOP?底层原理?事务…

【HarmonyOS NEXT】网络请求 - 分页加载

分页加载关键字&#xff1a;onReachEnd 一、申请网络权限 在 module.json5 文件中&#xff0c;添加网络权限&#xff1a; {"module": {..."requestPermissions": [{"name": "ohos.permission.INTERNET","usedScene": {&qu…

K8S实战进阶

title ‘K8S实战进阶’ date 2024-04-02T16:57:3608:00 draft true 一、搭建Kubernetes集群 1.1 搭建方案 1.1.1 minikube minikube 是一个工具&#xff0c; 能让你在本地运行 Kubernetes。 minikube 在你的个人计算机&#xff08;包括 Windows、macOS 和 Linux PC&…

图像生成(Text-to-Image)发展脉络

这篇博客对 图像生成&#xff08;image generation&#xff09; 领域的经典工作发展进行了梳理&#xff0c;包括重要的一些改进&#xff0c;目的是帮助读者对此领域有一个整体的发展方向把握&#xff0c;并非是对每个工作的详细介绍。 脉络发展&#xff08;时间顺序&#xff0…

WGS84经纬度坐标 GCJ02火星坐标 BD09百度坐标互相转换

WGS84经纬度坐标 GCJ02火星坐标 BD09百度坐标互相转换 背景&#xff1a;uniapp做的微信小程序&#xff0c;使用到了相机拍照并获取位置坐标信息&#xff1b;在腾讯地图上展示坐标点位置信息&#xff1b; 由于业务需要我们的PC端用的不是腾讯地图&#xff0c;需要使用WGS84坐标或…

uniapp判断h5/微信小程序/app端+实战展示

文章目录 导文使用条件编译的基本语法常见的平台标识符示例实战展示使用场景举例注意事项 导文 这里是导文 当你在开发Uni-app时&#xff0c;需要根据不同的平台&#xff08;比如App端、H5端、微信小程序等&#xff09;来执行不同的代码逻辑&#xff0c;可以使用条件编译来实现…

03 Git的基本使用

第3章&#xff1a;Git的基本使用 一、创建版本仓库 一&#xff09;TortoiseGit ​ 选择项目地址&#xff0c;右键&#xff0c;创建版本库 ​ 初始化git init版本库 ​ 查看是否生成.git文件&#xff08;隐藏文件&#xff09; 二&#xff09;Git ​ 选择项目地址&#xff0c…

Redis分布式系统中的主从复制

本篇文章主要对Redis的主从复制进行讲解。主要分析复制的原理&#xff0c;包括:建立复制、全量复制、部分复制、全量复制、心跳检测等。希望本篇文章会对你有所帮助。 文章目录 一、主从复制简介 二、配置主从复制模式 断开主从复制 安全性 只读 传输延迟 三、拓扑结构 四、主…

Java开发之Java容器

#来自ゾフィー&#xff08;佐菲&#xff09; 1 总览 1.1 List ArrayList&#xff1a; Object[]数组Vector&#xff1a;Object[]数组LinkedList&#xff1a; 双向链表&#xff0c;JDK1.6 之前为循环链表&#xff0c;JDK1.7 取消了循环 1.2 Set HashSet&#xff1a;无序&#xf…

mybatis 报CannotGetJdbcConnectionException

目录 报错起因 报错截图 运行环境 数据库配置 解决思路 报错起因 在web项目上拉取代码启动web服务抛CannotGetJdbcConnectionException。 报错截图 运行环境 windows idea maven tomcat springMVC mybatis 数据库配置 urlxxx driverClassNamexxx usernamexxx pass…

docker compose 容器 编排分组

遇到问题&#xff1a;执行docker compose up -d 后docker compose 创建的容器们 在desktop-docker 中都在docker下一堆 搜索想着能不能把这个docker名字改一下&#xff0c;但是都没有找到这样的一个方案&#xff1b; 最后发现&#xff0c;我执行docker compose up -d 命令所在…

【数据结构】二叉树OJ题_对称二叉树_另一棵的子树

对称二叉树 题目 101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2…