學習光線追蹤(13)---改進一下三角形碰撞光線的算法

0.簡介

之前繪製了一面牆之後,發現牆的斜對角有縫隙,找到了原因後,更換了其算法。這裏借鑑下面這篇博客中介紹的隨後一種方法。

參考文章

具體原理就不在重複了。

1.修改

爲了方便對比,我把原來的算法和新的算法都整理成了一個新的函數,這樣編碼也規則很多。

光線碰撞代碼做了一些修改,將判斷點在三角形內部換成了一個函數,而不是原來的一堆代碼.

Ray Triangle::intersect(Ray ray)
{
	Ray result(ray.direction, ray.position, ray.intensity, ray.color, nullptr);
	if ((result = Plane::intersect(ray)).polygon == nullptr)
		return Ray(ray.direction, ray.position, ray.intensity, vec3(0, 0, 0), nullptr);
	//這裏說明點在三角面是上
	if (onTriangle0(wA.position, wB.position, wC.position, result.end.position))
	{
		//計算點所在的紋理座標
		vec5 p_end;
		result.end.textureUV = getUVCoord(A, B, C, result.end);
		return result;
	}
	return Ray(ray.direction, ray.position, ray.intensity, vec3(0, 0, 0), nullptr);
}

這個是新方法,我觀察了一下,算法足夠簡練,這樣就夠了。

bool Triangle::onTriangle0(vec3 A, vec3 B, vec3 C, vec3 O)
{
	vec3 v0 = C - A;
	vec3 v1 = B - A;
	vec3 v2 = O - A;

	float dot00 = dot(v0, v0);
	float dot01 = dot(v0, v1);
	float dot02 = dot(v0, v2);
	float dot11 = dot(v1, v1);
	float dot12 = dot(v1, v2);

	float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);

	float u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
	if (u < 0 || u > 1)
		return false;

	float v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
	if (v < 0 || v > 1)
		return false;
	return u + v <= 1;
}

老方法也在這裏貼一下,對比

bool Triangle::onTriangle1(vec3 A, vec3 B, vec3 C, vec3 O)
{
	vec3 a = A - O;
	vec3 b = B - O;
	vec3 c = C - O;
	//在三角形內部
	//double angle = (acos(dot(a, b))+ acos(dot(b, c))+ acos(dot(c, a)))* R_ANGLE;
	//if (fabs(angle-360.0)<0.1)
	//{
	//	return result;
	//}
	vec3 sa = normalize(cross(a, b));
	vec3 sb = normalize(cross(b, c));
	vec3 sc = normalize(cross(c, a));
	return dot(sa, sb) > 0.9999&& dot(sb, sc) > 0.9999&& dot(sc, sa) > 0.9999;
}

原來的方法應該是受到了點在平面上的精度問題,導致有些位置點實際是在平面上,但是由於計算精度問題,使得結果差一點,就不在平面上了,新方法是直接基於向量的計算,所有點都默認在平面上,不會受到是否在平面上的精度誤差影響,也就是對於邊界值來說也適用。在速度上,新算法與老算法在同一個場景兩個三角形相比,快了100ms。

2.效果

新方法效果

對角線的縫隙已經沒有了。

3.源碼

release0.08

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章