上个月学习Peter Shirley-Ray Tracing in One Weekend的系列三本书,收获真的很多。这个系列的书真的是手把手教你如何从零开始构建一个光线跟踪渲染器,对新手(像我)非常友好。但是书中有很多章节需要有一定的数学功底才能看懂,本文想分享一下关于in One Weekend-chapter 8:Metal中一笔带过的折射公式推导,内容主要来自于《Mathematics for 3D Game Programming and Computer Graphics, 3rd Edition》[1],加上我个人的理解,如有错误,欢迎指出。

(配图为raytracer构建后渲染)


问题简述

已知入射向量 \(L\) 和交点法线 \(N\),和入射光线所在介质折射率 \(\eta _ { \mathrm { L } }\) 及折射光线所在介质折射率 \(\eta _ { \mathbf { T } }\) ,求折射向量 \(T\)。如图:

  • 设入射角为 \(\theta _ { \mathrm { L } }\) ,折射角为 \(\theta _ { \mathbf { T } }\)
  • 设 \(L\) 和 \(N\) 已经标准化为单位向量,所求 \(T\) 也为单位向量
  • 注意此处 \(L\) 的方向指向外,保留与书上一致(实际入射方向应为\(-L\))
  • L、T可以理解为light和transmission的缩写

图 1


推导过程

(若推导过程感觉理解困难可以先考虑二维情况再考虑三维,其实入射光线和折射光线都在一个二维平面上)

关键公式:折射定律或斯涅尔定律(Snell's Law),用于计算折射角 \(\theta _ { \mathbf { T } }\) :

推导思路:
将 \(T\) 分解为平行于 \(N\)(-\(N\)) 和垂直于 \(N\) 的向量 (\(-G\)),见图 1。(用这两个向量的线性组合\(a*-N+b*G\)表示 \(T\),问题就在于求两个系数a、b和向量 \(G\),将问题转换为求\(a\)、\(b\)、\(G\))

1. 求 \(a\)

求\(a\)实际上就是求向量\(T\)在向量\(-N\)上的投影,利用点乘公式即可计算出\(a=\cos \theta _ { \mathrm { T } }\),由于所求 \(T\) 和 \(-N\) 都为单位向量,所以其点乘展开式最终化简为\(\cos \theta _ { \mathrm { T } }\)。

\(T \cdot (-N) = |T| |-N| \cos \theta _ { \mathrm { T } }=\cos \theta _ { \mathrm { T } }\)

\(T \cdot (-N) = |-N|\cdotp Proj = Proj\)

联立上式即可

2. 求 \(b\)

基本思路和求 \(a\) 一样,这里求出 \(b = \sin \theta _ { \mathrm { T } }\)

(实际此处先求出的是cos<T,-G>,根据由于垂直关系,两角互余,等值于 \(\sin \theta _ { \mathrm { T } }\) )

3. 求 \(G\)

\(G\) 同 \(\operatorname { perp } _ { \mathrm { N } } \mathbf { L }\)平行(\(\operatorname { perp } _ { \mathrm { N } } \mathbf { L }\)为\(L\)垂直于\(N\)的分量,见图 1),由于 \(L\) 为单位向量,\(\left\| \operatorname { perp } _ { \mathbf { N } } \mathbf { L } \right\| = \sin \theta _ { \mathbf { L } }\),\(G\) 可表示为:

(求 \(\operatorname { perp } _ { \mathrm { N } } \mathbf { L }\) 的过程有点像施密特正交化的过程,都是一个向量去除某个方向的分量,除以 \(\sin \theta _ { \mathbf { L } }\) 即标准化为单位向量)

4. 所以 \(T\) 可以表示为:

利用斯涅尔定律替换\(\frac { \sin \theta _ { \mathrm { T } } } { \sin \theta _ { \mathrm { L } } }\):

将 \(\cos \theta _ { \mathrm { T } }\) 用 \(\sqrt { 1 - \sin ^ { 2 } \theta _ { \mathrm { T } } }\)代替,\(\sin \theta _ { \mathrm { T } }\) 用 \(\left( \eta _ { \mathrm { L } } / \eta _ { \mathrm { T } } \right) \sin \theta _ { \mathrm { L } }\) 代替:

最后,将 \(\sin ^ { 2 } \theta _ { \mathrm { L } }\) 用 \(1 - \cos ^ { 2 } \theta _ { \mathrm { L } } = 1 - ( \mathbf { N } \cdot \mathbf { L } ) ^ { 2 }\) 带入可得最终 \(T\) 的表达式:

(如果 \(\eta _ { \mathbf { L } } > \eta _ { \mathbf { T } }\),方程式中根号内的量可能为负,光线发生全反射,应用反射公式计算向量方向。即当 \(\sin \theta _ { \mathrm { L } } \leq \eta _ { \mathrm { T } } / \eta _ { \mathrm { L } }\),上式才可用于计算折射向量。)

其他

最后放一张in one weekend中计算折射向量的函数,参数 v 即为入射光线方向,只要将上诉公式加以对照即可写出。(记得上述 \(-L=v\))

参考文献

  1. Eric Lengyel. Mathematics for 3D Game Programming and Computer Graphics, 3rd Edition. Course Technology PTR, 2011.
  2. Peter Shirley. Ray Tracing in One Weekend. Amazon Digital Services LLC, January 26, 2016.

折射向量计算(Refraction Vector Calculation)的更多相关文章

  1. 【3D数学基础】三维空间折射向量计算

    问题:在三维空间中,已知折射率 e .入射角 L 和法线 N. 要求:计算出折射向量 T. 其中: L. N 和 T 都为单位向量. 如图片所示,下面所有的公式都看着这张图片来求解的: 首先,我们必须 ...

  2. 由浅入深学习PBR的原理和实现

    目录 一. 前言 1.1 本文动机 1.2 PBR知识体系 1.3 本文内容及特点 二. 初阶:PBR基本认知和应用 2.1 PBR的基本介绍 2.1.1 PBR概念 2.1.2 与物理渲染的差别 2 ...

  3. shader函数

    Intrinsic Functions (DirectX HLSL) The following table lists the intrinsic functions available in HL ...

  4. unity shader 常用函数列表

    此篇博客转自csdn的一位大牛. 中间排版出了一些问题 Intrinsic Functions (DirectX HLSL) The following table lists the intrins ...

  5. DirectX HLSL 内置函数

    Intrinsic Functions (DirectX HLSL) The following table lists the intrinsic functions available in HL ...

  6. HLSL Shader编程基础总结

    转自:https://blog.csdn.net/Blues1021/article/details/47093487 基本前提概念 Shader是一种映射到GPU硬件汇编语言上的高级语言,Shade ...

  7. 【SIGGRAPH】用【有说服力的照片真实】技术实现最终幻想15的视觉特效

    原文:西川善司 http://www.4gamer.net/games/075/G007535/20160726064/   最终幻想15的演讲会场.相当大,听众非常多.      在本次计算机图形和 ...

  8. Nvidia Anisotropic Lighting

    http://http.download.nvidia.com/developer/SDK/Individual_Samples/DEMOS/Direct3D9/HLSL_Aniso.zip Anis ...

  9. Nvidia VertexTextureFetch Water

    http://http.download.nvidia.com/developer/SDK/Individual_Samples/samples.html http://http.download.n ...

随机推荐

  1. vue的路由懒加载

    路由懒加载官方介绍 非懒加载写法: import Login from '@/components/Login' 所有路由涉及到的文件会被打包到 app.xxx.js 中 懒加载写法: const L ...

  2. [leetcode]238. 除自身以外数组的乘积

    题目描述 给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积. 示例: 输 ...

  3. 并发编程——ConcurrentHashMap#helpTransfer() 分析

    前言 ConcurrentHashMap 鬼斧神工,并发添加元素时,如果 map 正在扩容,其他线程甚至于还会帮助扩容,也就是多线程扩容.就这一点,就可以写一篇文章好好讲讲.今天一起来看看. 源码分析 ...

  4. .NET中OpenFileDialog使用报线程错误的解决方法

    昨天,在做一个NPOI读取的小demo的时候,使用OpenFileDialog打开文件,最开始的写法,直接在按钮点击事件中写,会报错,代码如下: OpenFileDialog ofd = new Op ...

  5. Docker的下载与安装

    一丶下载 1.win10之外的 Docker下载地址: https://www.docker.com/products/docker-toolbox 2.win10 Docker下载地址: https ...

  6. Jave Web阿里云短信服务发送验证码

    首先得在阿里云根据流程开通短信服务,申请签名和模版,具体看文档 因为这是个web项目,用到了thymeleaf模板,所以在pom.xml中加入如下依赖 <dependency> <g ...

  7. oracle逐步学习总结之约束(基础五)

    原创作品,转自请在文章明显位置注明出处:https://www.cnblogs.com/sunshine5683/p/10167717.html oracle中的约束主要有非空约束(not null) ...

  8. Activity正确获取View宽高

    在View的measure完成后,一般可以通过getMeasureWidth/getMeasureWidth方法可以正确的获取View的宽高,而在特殊情况下,可能需要多次measure才能确定最终的测 ...

  9. Intellij IDEA 使用GitHub+Git

    1.配置Git路径 打开Settings(File-->Settings) --> 在搜索栏内输入git,回车跳转到Git配置页面 --> 将git的运行路径填入Path to Gi ...

  10. node 静态伺服(搭建服务)

    基本功能 不急着写下第一行代码,而是先梳理一下就基本功能而言有哪些步骤. 在本地根据指定端口启动一个http server,等待着来自客户端的请求 当请求抵达时,根据请求的url,以设置的静态文件目录 ...