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.效果
對角線的縫隙已經沒有了。