C++ と OpenGL を使用した単純な 3D 一人称デモでデモをセットアップしましたが、かなりうまく機能しているようです。私の目標は次のとおりです。ユーザーがカメラを平面に向けてマウスの左ボタンをクリックすると、プレイヤーの位置からカメラが向いている方向を指している光線とその平面の交点を描きたいと思います。
そこで、2 つの Vector と から始めますVector position
。Vector rotation
ここで、Vector は非常に標準的な 3 次元のベクトル クラスです。
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 著の本「Real-Time Collision Detection」から直接コピーしました。
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.000002 ではなく 0 であるため、交点が平面上にないことはわかっています。また、それを平面方程式にサブサブして、不等式を取得することもできます。
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
さて、浮動小数点数は実数の近似値に過ぎないことを知っているので、この不正確さは浮動小数点の丸めの影響にすぎないと推測していますが、コードのどこかで間違いを犯した可能性があります。交差点が非常にわずかにずれていることはわかっていますが、これらのポイントを使用してモデルまたはレベルの頂点を任意の方向のグリッドにスナップすることで定義することを計画しているため、まだ気にしています。それらのポイントは、多少不正確であっても、そのグリッド上にあります。これは見当違いのアプローチかもしれません - 私にはよくわかりません。
だから私の質問は、この不正確さは仕事での浮動小数点の丸めだけですか、それともどこかで間違いを犯しましたか?
浮動小数点の丸めだけの場合、対処する方法はありますか? さまざまな方法で回転ベクトルと位置ベクトルの値を丸めてみましたが、明らかに交点の精度が低下しますが、それでも平面上にない交点が得られることがあります。寸法を大きく保つことについて言及している同様の質問 ( Is this plane-ray Intersection code correct? ) への回答を読みましたが、それが何を意味するのか正確にはわかりません。
この質問が以前に尋ねられた場合は申し訳ありません-検索しましたが、私が問題を抱えているものは何も見つかりませんでした. ありがとう!