gpt4 book ai didi

c++ - 射线平面相交 : inaccurate results - rounding errors?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:28:50 34 4
gpt4 key购买 nike

我已经使用 C++ 和 OpenGL 创建了一个简单的 3d 第一人称演示,它似乎运行良好。我的目标是:当用户将相机指向一个平面并单击鼠标左键时,我想绘制一条射线的交点,该射线从玩家的位置与该平面指向相机所面对的方向。

所以,我从两个 vector 开始,Vector positionVector rotation,其中 Vector 是一个非常标准的三维 vector 类:

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 ...

Plane p,其中 Plane 是一个简单的结构,用于存储平面的法线和 d。我直接从 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
};

首先,我将 position 作为射线的起点,我称之为 a。我使用该点和 rotation 找到射线的终点 b。然后我使用一种算法从同一本书中找到射线和平面的交点。我实际上自己实现了相同的方法,但我在这里直接使用书中的代码只是为了确保我没有搞砸任何事情:

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");
}

当我用 OpenGL 渲染这个点时,它看起来非常接近光线和平面的交点。但是通过打印出实际值,我发现对于特定的位置和旋转,交点最多可以偏离 0.000004。这是交点不准确的示例 - 我知道交点不在平面上,因为它的 Y 值应该是 0,而不是 0.000002。我也可以将它代入平面方程并得到不等式:

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

现在,我知道 float 只是实数的近似值,所以我猜这种不准确只是 float 舍入的结果,尽管我可能在代码的其他地方犯了错误。我知道交点只有极小的偏差,但我仍然很关心它,因为我打算使用这些点来定义模型或关卡的顶点,方法是将它们捕捉到任意方向的网格,所以我实际上想要那些点在那个网格上,即使它们稍微不准确。这可能是一种误入歧途的方法 - 我真的不知道。

所以我的问题是:这种不准确只是工作中的浮点舍入,还是我在其他地方犯了错误?

如果只是 float 舍入,有什么办法处理吗?我已经尝试以各种方式舍入旋转和位置 vector 的值,这显然会导致交点不太准确,但有时我仍然会得到不在平面上的交点。我确实读过一个类似问题 ( Is this plane-ray intersection code correct? ) 的答案,其中提到保持尺寸较大,但我不确定这到底是什么意思。

如果之前有人问过这个问题,我很抱歉 - 我进行了搜索,但我没有看到任何我遇到的问题。谢谢!

最佳答案

您的数学似乎是正确的,这看起来确实像是一个舍入误差。我有一种强烈的感觉,就是这一行:

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

也就是说我没有看到任何其他方法来计算 t。您可以通过在 printf 语句中使用“%.12f”(或更多)来验证您是否正在失去精度。查明罪魁祸首的另一种方法是尝试逐步进行 t 计算并打印结果以查看是否在某处失去了精度。

如果精度对您来说真的那么重要,您是否尝试过使用 double float ?

关于c++ - 射线平面相交 : inaccurate results - rounding errors?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15102738/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com