图形学相关数学(反射,折射公式)

本文详细解析了反射与折射公式的数学推导过程,并提供了C++实现代码。从几何光学角度出发,解释了光线在不同介质界面反射与折射的原理,包括法线、入射角和折射角等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

				版权声明:欢迎转载,共同进步。请注明出处:http://blog.youkuaiyun.com/puppet_master					https://blog.youkuaiyun.com/puppet_master/article/details/81144266				</div>
							            <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-db05db230f.css">
					<div class="htmledit_views" id="content_views">
            <h2><a name="t0"></a><span style="color:#7c79e5;">反射公式</span></h2>

反射是经常用到的一个公式,之前在Phong光照的时候推导过一次,这次再整理一下。反射过程如图所示:

首先需要保证光方向向量AB,法向量N均为单位向量,反射向量AC,光入射方向AD = -AB

θ为入射角,由反射公式我们知道,AC与AB沿y轴对称,AD与AC沿x轴对称

EB = N * |AB|cosθ = N * dot(N,AB)

DC = 2 * EB = -2 * N * dot(N, AB)

AC = AD + DC = -AB + 2 * N * dot(N,AB)

C++代码如下:


 
  1. static Vector3 Reflect(const Vector3& vec, const Vector3& normal)
  2. {
  3. return -vec + normal * 2.0f * Vector3::Dot(vec, normal);
  4. }

这里面使用的是vec是指向光源方向的Vec(似乎在shader里面使用这种表示方法更多一些),如果vec指的是由光源方向指向入射点的位置(光线追踪使用得更多一些),则反射公式表示为:


 
  1. static Vector3 Reflect(const Vector3& vec, const Vector3& normal)
  2. {
  3. return vec - normal * 2.0f * Vector3::Dot(vec, normal);
  4. }

 

折射公式

最近在玩光线追踪,遇到了一个折射光线的代码,看了半天没太理解,后来拿出笔推算了一遍,才算是理解了原来折射公式还是比较复杂的。下面记录一下推导的过程,先来一张图:

其中入射光线L,折射光线T,入射角θ,折射角θ',法线方向N,入射向量分解为L1,L2,折射向量分解为T1,T2。

首先需要的知识点是折射定律(似乎是中学时学过的):

(1)折射光线位于入射光线和界面法线所决定的平面内;

(2)折射线和入射线分别在法线的两侧;

(3)入射角i的正弦折射角i′的正弦的比值,对折射率一定的两种媒质来说是一个常数。

假设上方介质为1,下方介质为2,则n1 * sinθ1 = n2 * sinθ2,n21 = n2 / n1,表示介质2相对于介质1的折射率。

换成上图公式则为,sinθ' / sinθ  =  n1 / n2 = η。

cosθ = dot(N, -V) = -dot(N,V)。

cosθ' ^2 = 1 - sinθ' ^ 2 = 1 - η * η * sinθ ^2 = 1 - η * η * (1 - cosθ ^ 2)

cosθ' = sqrt(1 - η * η * (1 - dot(N,V) ^ 2))

上图中,将入射光线和出射光线分别拆分成垂直于x轴和垂直于y轴的两条方向上的光线。

T = T1 + T2,L = L1 + L2,T和L以及N均为单位向量|T| = |L|

L = L1 + L2,L = -Ncosθ + L2  => L2 = L + Ncosθ

|T2| = |T|sinθ',|L2| = |L|sinθ,二者相除,且由于|T| = |L|,得到 T2 = L2 * sinθ’ / sinθ = (L + Ncosθ)η

T1与N反方向,故T1 = -N * |T1| = -N * |T|cosθ',由于|T|为单位向量,即 T1 = -N * cosθ'

T = T1 + T2 => T = -N cosθ' + (L + Ncosθ)η

T = -N * sqrt(1 - η * η * (1 - dot(N,V) ^ 2)) + (L - N * dot(N,V)) η

C++代码如下:


 
  1. //refractRatio = sinθ' / sinθ
  2. static bool Refract(const Vector3& vec, const Vector3& normal, float refractRatio, Vector3& refractDir)
  3. {
  4. Vector3 inVec = vec;
  5. inVec.Normalize();
  6. float dt = Vector3::Dot(inVec, normal); //cosθ
  7. float s2 = 1.0 - dt * dt; // sinθ ^ 2
  8. float st2 = refractRatio * refractRatio * s2; // sinθ’ ^ 2 = refractRato ^ 2 * sinθ ^ 2
  9. float cost2 = 1 - st2;
  10. if (cost2 > 0)
  11. {
  12. refractDir = (inVec - normal * dt) * refractRatio - normal * sqrt(cost2);
  13. return true;
  14. }
  15. return false;
  16. }

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值