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

版权声明:欢迎转载,共同进步。请注明出处:http://blog.csdn.net/puppet_master https://blog.csdn.net/puppet_master/article/details/81144266

反射公式

反射是经常用到的一个公式,之前在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++代码如下:

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

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

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

折射公式

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

其中入射光线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++代码如下:

	//refractRatio = sinθ' / sinθ 
	static bool Refract(const Vector3& vec, const Vector3& normal, float refractRatio, Vector3& refractDir)
	{
		Vector3 inVec = vec;
		inVec.Normalize();
		float dt = Vector3::Dot(inVec, normal); //cosθ
		float s2 = 1.0 - dt * dt; // sinθ ^ 2
		float st2 = refractRatio * refractRatio * s2;// sinθ’ ^ 2 = refractRato ^ 2 * sinθ ^ 2
		float cost2 = 1 - st2;
		if (cost2 > 0)
		{
			refractDir = (inVec - normal * dt) * refractRatio - normal * sqrt(cost2);
			return true;
		}
		return false;
	}

猜你喜欢

转载自blog.csdn.net/puppet_master/article/details/81144266