简体   繁体   English

射线平面相交:不准确的结果-舍入误差?

[英]Ray-plane intersection: inaccurate results - rounding errors?

I've set up a demo with simple 3d first-person demo using C++ and OpenGL, and it seems to work reasonably well. 我已经使用C ++和OpenGL建立了一个简单的3d第一人称演示示例,它似乎运行得很好。 My goal is this: when the user points the camera at a plane and clicks the left mouse button, I want to draw the intersection of a ray pointing in the direction the camera is facing from the player's position with that plane. 我的目标是:当用户将相机指向某个平面并单击鼠标左键时,我想绘制一条光线,该光线指向相机从玩家位置到该平面的朝向。

So, I start off with two Vectors, Vector position and Vector rotation , where Vector is a pretty standard three-dimensional vector class: 因此,我从两个向量开始, Vector positionVector rotation ,其中向量是一个非常标准的三维向量类:

class Vector
{
  public:
    GLfloat x, y, z;

    Vector() {};

    Vector(GLfloat x, GLfloat y, GLfloat z)
    {
      this->x = x;
      this->y = y;
      this->z = z;
    }

    GLfloat dot(const Vector &vector) const
    {
      return x * vector.x + y * vector.y + z * vector.z;
    }

    ... etc ...

And Plane p , with Plane being a simple struct storing the normal of the plane and d. Plane p ,其中Plane是存储平面和d的法线的简单结构。 I copied this struct directly from the book "Real-Time Collision Detection," by Christer Ericson: 我直接从Christer Ericson的“实时碰撞检测”一书中复制了此结构:

struct Plane 
{
  Vector n; // Plane normal. Points x on the plane satisfy Dot(n,x) = d
  float d; // d = dot(n,p) for a given point p on the plane
};

To start, I take position as the start of the ray, which I call a . 首先,我把position作为光线的开始,我称之为a I use that point and rotation to find the end of the ray, b . 我使用该点和rotation找到射线b的尽头。 Then I use an algorithm for finding the intersection of a ray and a plane from that same book. 然后,我使用一种算法从同一本书中找到射线与平面的交点。 I've actually implemented the same method myself, but I'm using the code from the book directly here just to make sure I didn't mess anything up: 我实际上已经实现了相同的方法,但是我在这里直接使用本书中的代码,只是为了确保我不会弄乱任何东西:

void pickPoint()
{
    const float length = 100.0f;

    // Points a and b
    Vector a = State::position;
    Vector b = a;

    // Find point b of directed line ab
    Vector radians(Math::rad(State::rotation.x), Math::rad(State::rotation.y), 0);
    const float lengthYZ = Math::cos(radians.x) * length;

    b.y -= Math::sin(radians.x) * length;
    b.x += Math::sin(radians.y) * lengthYZ;
    b.z -= Math::cos(radians.y) * lengthYZ;

    // Compute the t value for the directed line ab intersecting the plane
    Vector ab = b - a;

    GLfloat t = (p.d - p.n.dot(a)) / p.n.dot(ab);

    printf("Plane normal: %f, %f, %f\n", p.n.x, p.n.y, p.n.z);
    printf("Plane value d: %f\n", p.d);
    printf("Rotation (degrees): %f, %f, %f\n", State::rotation.x, State::rotation.y, State::rotation.z);
    printf("Rotation (radians): %f, %f, %f\n", radians.x, radians.y, radians.z);
    printf("Point a: %f, %f, %f\n", a.x, a.y, a.z);
    printf("Point b: %f, %f, %f\n", b.x, b.y, b.z);
    printf("Expected length of ray: %f\n", length);
    printf("Actual length of ray: %f\n", ab.length());
    printf("Value t: %f\n", t);

    // If t in [0..1] compute and return intersection point
    if(t >= 0.0f && t <= 1.0f) 
    {
        point = a + t * ab;
        printf("Intersection: %f, %f, %f\n", point.x, point.y, point.z);
    }
    // Else no intersection
    else
    {
        printf("No intersection found\n");
    }

    printf("\n\n");
}

When I render this point with OpenGL, it looks to be pretty close to the where the intersection of the ray and the plane would be. 当我使用OpenGL渲染此点时,它看起来非常接近射线与平面的交点。 But from printing out the actual values, I discovered that for specific positions and rotations, the intersection point can be off by up to 0.000004. 但是从打印实际值后,我发现对于特定的位置和旋转,相交点最多可以偏移0.000004。 Here's an example of where the intersection is inaccurate - I know the intersection point is NOT on the plane because its Y value should be 0, not 0.000002. 这是一个交点不准确的示例-我知道交点不在平面上,因为其Y值应为0,而不是0.000002。 I could also sub it back into the plane equation and get an inequality: 我也可以将其重新归入平面方程并得到不等式:

Plane normal: 0.000000, 1.000000, 0.000000
Plane value d: 0.000000
Rotation (degrees): 70.100044, 1.899823, 0.000000
Rotation (radians): 1.223477, 0.033158, 0.000000
Point a: 20.818802, 27.240383, 15.124892
Point b: 21.947229, -66.788452, -18.894285
Expected length of ray: 100.000000
Actual length of ray: 100.000000
Value t: 0.289702
Intersection: 21.145710, 0.000002, 5.269455

Now, I know floating-point numbers are just approximations of real numbers, so I'm guessing this inaccuracy is just the effect of floating-point rounding, though it's possible I made a mistake somewhere else in the code. 现在,我知道浮点数只是实数的近似值,因此我猜想这种不准确性只是浮点舍入的结果,尽管我可能在代码的其他地方犯了一个错误。 I know the intersection is off only by an extremely small amount, but I still care about it because I'm planning to use these points to define vertices of a model or level by snapping them to an arbitrarily-oriented grid, so I actually want those points to be ON that grid, even if they're slightly inaccurate. 我知道交点只有极少的距离,但是我仍然很在意它,因为我打算使用这些点将模型或级别的顶点捕捉到任意定向的网格中,因此我实际上想要这些点在该网格上,即使它们有点不准确。 This might be a misguided approach - I don't really know. 这可能是一种误导的方法-我真的不知道。

So my question is: is this inaccuracy just floating-point rounding at work, or did I make a mistake somewhere else? 所以我的问题是:这种误差仅仅是工作中的浮点取整,还是我在其他地方犯了错误?

If it is just floating-point rounding, is there any way to deal with it? 如果只是浮点舍入,有什么办法可以解决? I've tried rounding the values of the rotation and position vectors in various ways, which obviously results in a less accurate intersection point, but I still sometimes get intersections that aren't on the plane. 我尝试过以各种方式对旋转和位置向量的值进行四舍五入,这显然会导致交点的准确性降低,但有时我仍然会获得不在平面上的交点。 I did read an answer to a similar question ( Is this plane-ray intersection code correct? ) that mentions keeping the dimensions large, but I'm not sure exactly what that means. 我确实读过一个类似问题的答案( 这个平面射线相交代码正确吗? ),提到要保持较大的尺寸,但是我不确定这到底意味着什么。

Sorry if this question has been asked before - I searched, but I didn't see anything that was quite what I'm having trouble with. 抱歉,如果您之前曾问过这个问题-我进行了搜索,但没有发现我遇到的任何麻烦。 Thanks! 谢谢!

Your math seems correct and this definitely looks like a rounding error. 您的数学似乎正确,并且这肯定看起来像是舍入错误。 I have a strong feeling that it is this line: 我有强烈的感觉就是这条线:

GLfloat t = (p.d - p.n.dot(a)) / p.n.dot(ab);

That said I don't see any other method to compute t. 就是说,我看不到其他任何计算t的方法。 You could maybe verify if you are losing precision by using "%.12f" (or more) in your printf statements. 您可以通过在printf语句中使用“%.12f”(或更多)来验证是否丢失了精度。 Another way to pinpoint the culprit is to try doing your t computation step by step and printing the results along the way to see if you are losing precision somewhere. 查明罪魁祸首的另一种方法是尝试逐步进行t计算,并沿途打印结果以查看是否在某处丢失了精度。

Did you try using double precision floating point, if precision really matters to you that much? 如果精度对您真的很重要,您是否尝试过使用双精度浮点数?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM