通过光线投射拾取对象
我在检测盒子内鼠标点击的光线投射算法中一直遇到不准确的问题。我完全不知道如何正确解决这个问题,而且它已经困扰我好几个星期了。
最容易用图片描述问题(以 [0, 0, -30] 为中心的框):
黑线代表绘制的实际碰撞框,绿色框代表实际被击中的区域。请注意它的偏移量(如果框距离原点较远,偏移量似乎会变大)并且略小于绘制的碰撞框。
这是一些相关的代码,
射线盒投射:
double BBox::checkFaceIntersection(Vector3 points[4], Vector3 normal, Ray3 ray) {
double rayDotNorm = ray.direction.dot(normal);
if(rayDotNorm == 0) return -1;
Vector3 intersect = points[0] - ray.origin;
double t = intersect.dot(normal) / rayDotNorm;
if(t < 0) return -1;
// Check if first point is from under or below polygon
bool positive = false;
double firstPtDot = ray.direction.dot( (ray.origin - points[0]).cross(ray.origin - points[1]) );
if(firstPtDot > 0) positive = true;
else if(firstPtDot < 0) positive = false;
else return -1;
// Check all signs are the same
for(int i = 1; i < 4; i++) {
int nextPoint = (i+1) % 4;
double rayDotPt = ray.direction.dot( (ray.origin - points[i]).cross(ray.origin - points[nextPoint]) );
if(positive && rayDotPt < 0) {
return -1;
}
else if(!positive && rayDotPt > 0) {
return -1;
}
}
return t;
}
鼠标到射线:
GLint viewport[4];
GLdouble modelMatrix[16];
GLdouble projectionMatrix[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
GLfloat winY = GLfloat(viewport[3] - mouse_y);
Ray3 ray;
double x, y, z;
gluUnProject( (double) mouse_x, winY, 0.0f, // Near
modelMatrix, projectionMatrix, viewport,
&x, &y, &z );
ray.origin = Vector3(x, y, z);
gluUnProject( (double) mouse_x, winY, 1.0f, // Far
modelMatrix, projectionMatrix, viewport,
&x, &y, &z );
ray.direction = Vector3(x, y, z);
if(bbox.checkBoxIntersection(ray) != -1) {
std::cout << "Hit!" << std::endl;
}
我尝试将实际射线绘制为一条线,它似乎与绘制的框正确相交。
我通过减去盒子位置的所有点和光线原点/方向部分解决了偏移问题,但我不知道为什么会这样,并且碰撞盒的大小仍然不准确。
有什么想法/替代方法吗?如果需要的话我还有其他代码可以提供。
I've been having a problem with inaccuracies in my ray casting algorithm for detecting mouse hits within a box. I'm completely at a loss as to how to fix this properly and it's been bugging me for weeks.
The problem is easiest described with a picture (box centered around [0, 0, -30]):
The black lines represent the actual hitbox which is drawn and the green box represents what actually appears to get hit. Notice how it's offset (which seems to get larger if the box is further from the origin) and is slightly smaller than the drawn hitbox.
Here's some relevant code,
ray-box cast:
double BBox::checkFaceIntersection(Vector3 points[4], Vector3 normal, Ray3 ray) {
double rayDotNorm = ray.direction.dot(normal);
if(rayDotNorm == 0) return -1;
Vector3 intersect = points[0] - ray.origin;
double t = intersect.dot(normal) / rayDotNorm;
if(t < 0) return -1;
// Check if first point is from under or below polygon
bool positive = false;
double firstPtDot = ray.direction.dot( (ray.origin - points[0]).cross(ray.origin - points[1]) );
if(firstPtDot > 0) positive = true;
else if(firstPtDot < 0) positive = false;
else return -1;
// Check all signs are the same
for(int i = 1; i < 4; i++) {
int nextPoint = (i+1) % 4;
double rayDotPt = ray.direction.dot( (ray.origin - points[i]).cross(ray.origin - points[nextPoint]) );
if(positive && rayDotPt < 0) {
return -1;
}
else if(!positive && rayDotPt > 0) {
return -1;
}
}
return t;
}
mouse to ray:
GLint viewport[4];
GLdouble modelMatrix[16];
GLdouble projectionMatrix[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
GLfloat winY = GLfloat(viewport[3] - mouse_y);
Ray3 ray;
double x, y, z;
gluUnProject( (double) mouse_x, winY, 0.0f, // Near
modelMatrix, projectionMatrix, viewport,
&x, &y, &z );
ray.origin = Vector3(x, y, z);
gluUnProject( (double) mouse_x, winY, 1.0f, // Far
modelMatrix, projectionMatrix, viewport,
&x, &y, &z );
ray.direction = Vector3(x, y, z);
if(bbox.checkBoxIntersection(ray) != -1) {
std::cout << "Hit!" << std::endl;
}
I've tried drawing the actual ray as a line and it seems to intersect the drawn box correctly.
I had the offset problem partially fixed by minusing all the points and the ray origin/direction by the boxes position, but I have no idea why that worked and the size of the hitbox still remained inaccurate.
Any ideas/alternative approaches? I have other code to supply if it's needed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你假设了错误的方向。正确的是:
如果不减去近处和远处的交点,你的方向就会偏离。
You're assuming a wrong direction. Correct would be:
Without subtracting near and far intersection points, your direction will be off.