c++ - 三角-三角碰撞检测问题
问题描述
我正在为一个大学项目开发游戏引擎,但我无法让碰撞检测系统工作。我发现这篇论文解释了由 Chaman-Leopoldj 创建的三角形-三角形碰撞检测算法,但不知何故我无法实现它。我知道它有点长,但算法可以在第 8 页和第 22-24 页找到
这是我写的代码:
这是包装函数
bool Octree::triangleTriangleIntersection(glm::vec3 A, glm::vec3 B, glm::vec3 C, glm::vec3 P, glm::vec3 Q, glm::vec3 R) {
glm::vec3 U = B - A;
glm::vec3 V = C - A;
glm::vec3 S = Q - P;
glm::vec3 T = R - P;
glm::vec3 AP = P - A;
float sigma = dot(U * V, U * V);
glm::vec3 alpha = (S * (U * V)) / sigma;
glm::vec3 beta = (T * (U * V)) / sigma;
glm::vec3 gamma = (AP * (U * V)) / sigma;
float alphau = dot(alpha, U);
float alphav = dot(alpha, V);
float alphauv = dot(alpha, U - V);
float gammau = dot(gamma, U);
float gammav = dot(gamma, V);
float gammauv = dot(gamma, U - V);
float betau = dot(beta, U);
float betav = dot(beta, V);
float betauv = dot(beta, U - V);
float Xm, XM, Sm = 0, SM = 1;
float Ym, YM, Tm = 0, TM = 1;
if (findSolution_x(-gammau, alphau, betau, 1 - gammau, -1 - gammav, alphav, betav, -gammav, Xm, XM)) {
if (Xm > Sm) Sm = Xm;
if (XM < SM) SM = XM;
}
else {
return false;
}
if (findSolution_x(-gammau, alphau, betau, 1 - gammau, -gammauv, alphauv, betauv, 1 - gammauv, Xm, XM)) {
if (Xm > Sm) Sm = Xm;
if (XM < SM) SM = XM;
}
else {
return false;
}
if (findSolution_x(-1 - gammav, alphav, betav, -gammav, -gammauv, alphauv, betauv, 1 - gammauv, Xm, XM)) {
if (Xm > Sm) Sm = Xm;
if (XM < SM) SM = XM;
}
else {
return false;
}
if (Sm > SM)
return false;
else {
float delta = (SM - Sm) / 20;
for (float s = Sm; s <= SM; s += delta) {
if (findSolution_y(-gammau, alphau, betau, 1 - gammau, -1 - gammav, alphav, betav, -gammav, s, Ym, YM)) {
if (Ym > Tm) Tm = Ym;
if (YM < TM) TM = YM;
}
else {
return false;
}
if (findSolution_y(-gammau, alphau, betau, 1 - gammau, -gammauv, alphauv, betauv, 1 - gammauv, s, Ym, YM)) {
if (Ym > Tm) Tm = Ym;
if (YM < TM) TM = YM;
}
else {
return false;
}
if (findSolution_y(-1 - gammav, alphav, betav, -gammav, -gammauv, alphauv, betauv, 1 - gammauv, s, Ym, YM)) {
if (Ym > Tm) Tm = Ym;
if (YM < TM) TM = YM;
}
else {
return false;
}
if (Tm > TM)
return false;
else
return true;
}
}
return false;}
解决_x
bool Octree::findSolution_x(float m, float a, float b, float n, float M, float A, float B, float N, float& Xm, float& XM) {
const float epsilon = 0.00001;
float denom = (a*B- A* b);
float Sm1, SM1;
Sm1 = (m* B- N* b);
SM1 = (n* B- M* b);
if (b< 0 || B< 0) {
Sm1 *= -1;
SM1 *= -1;
}
Sm1 /= denom;
SM1 /= denom;
float Sm1Rounded = round(Sm1);
float SM1Rounded = round(SM1);
if (abs(Sm1Rounded - Sm1 <= epsilon)) Sm1 = Sm1Rounded;
if (abs(SM1Rounded - SM1 <= epsilon)) SM1 = SM1Rounded;
Xm = Sm1;
XM = SM1;
if (denom == 0) {
Xm *= -1;
}
return true;}
解决_y
bool Octree::findSolution_y(float m, float a, float b, float n, float M, float A, float B, float N, float x, float& Ym, float& YM) {
const float epsilon = 0.00001;
float Sm1, SM1, Sm2, SM2;
Sm1 = m- (a* x);
Sm2 = M- (A* x);
SM1 = n- (a* x);
SM2 = N- (A* x);
if (b< 0 || B< 0) {
Sm1 *= -1;
SM1 *= -1;
Sm2 *= -1;
SM2 *= -1;
}
if (Sm1 > SM1 || Sm2 > SM2) return false;
Sm1 /= b;
SM1 /= b;
Sm2 /= B;
SM2 /= B;
float Sm1Rounded = round(Sm1);
float SM1Rounded = round(SM1);
float Sm2Rounded = round(Sm2);
float SM2Rounded = round(SM2);
if (abs(Sm1Rounded - Sm1 <= epsilon)) Sm1 = Sm1Rounded;
if (abs(SM1Rounded - SM1 <= epsilon)) SM1 = SM1Rounded;
if (abs(Sm2Rounded - Sm2 <= epsilon)) Sm2 = Sm2Rounded;
if (abs(SM2Rounded - SM2 <= epsilon)) SM2 = SM2Rounded;
if (param2 > 0 && param6 > 0) {
Sm1 >= Sm2 ? Ym = Sm1 : Ym = Sm2;
SM1 >= SM2 ? YM = SM2 : YM = SM1;
}
else if (param2 > 0) {
Ym = Sm1;
YM = SM1;
}
else if (param6 > 0) {
Ym = Sm2;
YM = SM2;
}
return true;}
我怀疑我在我的一个 if 中设置了错误的条件,但我只是按照论文的指导方针进行的,所以我真的不知道。希望你们能帮助我。
编辑:需要 epsilon 来舍入低于某个误差的值。这是一个源自 assimp 没有正确读取 OBJ 值的问题,例如将 1.000000 变成 1.0000045。
解决方案
我不会尝试为您调试您的代码,并且有人会因为不完整的答案而对我投反对票,但我将提供一些基本建议。
这是调试这么大的东西的基本建议。在我看来,您需要设置一个简单的测试。编写一个与您的代码链接的小程序。手动创建您知道碰撞的两个三角形,然后查看您的代码是否检测到它。
不?弄清楚它们是如何碰撞的以及你应该如何检测到它,然后将打印语句添加到你的代码中应该发生碰撞的地方,看看为什么它没有捕捉到它。
您可能想要做的是使用一些纸张。布置几个三角形,然后手动(不涉及计算机)逐步执行您正在使用的代码,看看它是否有意义。
如果没有,请提出您自己的代码。我认为您可以将三角形碰撞定义为:
如果 T1 的任何段与 T2 的任何段相交。您应该能够找出测试两条线段是否相交的方法,然后将 T1 的所有线段与 T2 运行。
或者,如果一个三角形完全封装在另一个三角形内。一个大三角形和一个小三角形。
这是编码的乐趣和沮丧的一部分——学习理解你正在使用的算法。
推荐阅读
- dialogflow-es - dialogflow api 中缺少 401 个未经授权的身份验证参数
- java - 如何将具有给定索引的新元素添加到链接列表中?
- excel - Excel公式:左和函数右
- python - 在 python 中进行网页抓取以获取知识
- javascript - 如何使用可以单击的ngFor在对象数组中具有函数
- django - Django:在测试中检查响应的内容类型
- python - 如何根据单词中的频率对字母进行排序?
- django - 通过 .extra() 过滤 Django 对象 选择 lat 和 lng 半径
- java - 将 ArrayList 中的信息从一个类传递到 WindowsBuilder GUI 类
- html - 在 WordPress 中,如何设置文本限制或在达到一定长度时打破文本