2016-03-23 23 views
0

線と矩形の交点が必要です。これまでのところ私は答えhereに従っていますが、テストした後(以下で説明します)、実装が間違っていることに気付きました。C++での線と矩形の交点

bool checkRayLightIntersection(Vec Origin, Vec Dir) { 

    //(-10,20,9) is Hard-code of the light position and we add (5.0f) on X and Z axis to 
    //make it an area instead of a vertex 
    //"Origin" is the position of the eye. Hard coded: (-25, 8, 5) 
    //"Dir" is LightPosition - Origin 

    float randX = 5.0f; //in the future it will be random, that's why this name 
    float randZ = 5.0f; 

    Vec P1 = Vec(-10 - randX, 20, 9 + randZ); 
    Vec P2 = Vec(-10 + randX, 20, 9 + randZ); 
    Vec P3 = Vec(-10 + randX, 20, 9 - randZ); 
    Vec P4 = Vec(-10 - randX, 20, 9 - randZ); 

    //the majority of the methods first find out where the ray intersects the 
    //plane that the rectangle lies on, Ax + By + Cz + D = 0 
    //in our case the equation of that plane is easy (I think) -> D = 20 

    float t = -(-Origin.y + 20)/(-Dir.y); 
    if (t > 0) { 
     Vec hitPoint = Origin + Dir * t; 
     Vec V1 = (P2 - P1).norm(); 
     Vec V3 = (P4 - P3).norm(); 
     Vec V4 = (hitPoint - P1).norm(); 
     Vec V5 = (hitPoint - P3).norm(); 
     float V1dotV4 = V1.dot(V4); 
     float V3dotV5 = V3.dot(V5); 
     if (V1dotV4 > 0 && V3dotV5 > 0) { 
      return true; 
     } 
    } 
    return false; 
} 

私Vecとは、次のように定義された構造体である:

struct Vec { 
    double x, y, z;     // position, also color (r,g,b) 
    Vec(double x_ = 0, double y_ = 0, double z_ = 0){ x = x_; y = y_; z = z_; } 
    Vec operator+(const Vec &b) const { return Vec(x + b.x, y + b.y, z + b.z); } 
    Vec operator-(const Vec &b) const { return Vec(x - b.x, y - b.y, z - b.z); } 
    Vec operator-() const { return Vec(-x, -y, -z); } 
    Vec operator*(double b) const { return Vec(x*b, y*b, z*b); } 
    Vec operator/(double b) const { return Vec(x/b, y/b, z/b); } 
    Vec mult(const Vec &b) const { return Vec(x*b.x, y*b.y, z*b.z); } 
    Vec& norm(){ return *this = *this * (1/sqrtf(x*x + y*y + z*z)); } 
    double dot(const Vec &b) const { return x*b.x + y*b.y + z*b.z; } 
    // cross: 
    Vec operator%(Vec&b){ return Vec(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x); } 
    double max() const { return x>y && x>z ? x : y > z ? y : z; } 
}; 

私は方法をテストしました。だから私がやろうとしたことは、Originから(-10,20,19)のようなRectangleの外にあるはずの点に線を作成することです。私はZ軸に9を加えましたが、長方形は5単位だけ大きくする必要がありました各方向(X、-X、Z、-Z)に移動します。したがって、私の場合:

Dir = (-10, 20, 19) - Orig 

代わりにfalseを返す必要がある場合、このメソッドはtrueを返します。 私が間違っていることを理解してもらえますか?前もって感謝します。

+0

によって長方形のちょうど2つの垂直エッジに対してhitPointをチェックすることでこれを行うことができます。三角形と光線の交点を計算することは、コンピュータグラフィックスでは非常に一般的な問題です。[link](https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm)を参照してください。あなたの四角形は2つの三角形で構成されています – Jonas

+0

2つの三角形を使用した場合、対角線に沿って失敗する可能性があります。ポイントは、いずれの三角形の内側にもないことがあります。すべての点で重複を保証するように注意する必要があります。 – stark

答えて

1

あなたはここにかなり近いようですが、私はあなたがV1dotV4V3dotV5のために得られる結果が不思議に思うでしょう。

飛行方程式が-y + 20 = 0(すなわち、y = 20の平面で、[0、-1、0]で平らな平面)であるため、正しく解けているようです。

あなたは、あなたの飛行機のために戻っ式にそれを差し込むと、結果がhitPointは、平面上に正しくあると仮定すると、0

で、それはあなたのチェックヒットポイントのようになっていることを確認することで、合理的なhitPointを得たことを確認することができます矩形の内側にあるのは間違っています。ドットプロダクトを使用して、hitPointのエッジ[P1、P2]および[P4、P3]への投影がそのエッジの内側にあることを確認しています。問題は[P1、P2]と[P4、P3]が矩形の反対側/平行辺であるため、hitPointがエッジ[P2、P3]と[P4、P1 ]。

あなたは、これは長方形である知っているので、私は

Vec hitPoint = Origin + Dir * t; 
Vec V1 = (P2 - P1).norm(); 
Vec V2 = (P3 - P2).norm(); 
Vec V3 = (P4 - P3).norm(); 
Vec V4 = (P1 - P4).norm(); 
Vec V5 = (hitPoint - P1).norm(); 
Vec V6 = (hitPoint - P2).norm(); 
Vec V7 = (hitPoint - P3).norm(); 
Vec V8 = (hitPoint - P4).norm(); 
if (V1.dot(V5) < 0.0) return false; 
if (V2.dot(V6) < 0.0) return false; 
if (V3.dot(V7) < 0.0) return false; 
if (V4.dot(V8) < 0.0) return false; 
return true; 

を計算するのに十分であるべきだと思う編集は私の最初の主張は、[0,1]の範囲のための2つのエッジを確認することだったが、この実際には正しくありません。すべての4つのエッジをチェックするようにサンプルコードを更新しました。

別のノートあなたは、これは非常に遅く、潜在的に不安定である

Vec hitPoint = Origin + Dir * t; 
Vec V1 = P2 - P1; 
float lengthV1 = V1.length(); 
Vec normV1 = V1.norm(); 

Vec V2 = P4 - P1; 
float lengthV2 = V2.length(); 
Vec normV2 = V2.norm(); 

Vec hitVec = P - P1; 
a = normV1.dot(hitVec); 
b = normV2.dot(hitVec); 
return (0.0f <= a && a <= lengthV1 && 0.0f <= b && b <= lengthV2); 
+0

あなたは確かに正しい、テストされ、働いています!上記の@Jonasのコメントが正しいかどうか疑問に思っていました。この方法は、三角形との交差点を確認するよりもかなり遅いですか? – Tarta

+1

これは、四角形の場合には速くなるはずです。光線長方形交差と光線三角形交差では、最初のステップは、光線が三角形または長方形が横たわる平面と交差する場所を見つけることです。 2番目のステップは、ヒットポイントが三角形または四角形の内側か外側かを判断することです。あなたの長方形を表すために2つの同一平面三角形を使用している場合、同じレイプレーン交差計算がありますが、2つの三角形をチェックして、ヒットポイントが長方形の内側にあるかどうかを判断する必要があります。 – lobudge

+0

は間違いなくクリアです!もう一度あなたの助けに感謝:) – Tarta