問題を示すために使用したい例では、以下の画像に示すようにタービンと小さなグリッドの単一モデルがあります。モデルのバウンディングボックスは赤いボックスとして表示されます。緑色のグリッド内のどのノードがタービンのバウンディングボックスの上にあるかを確認しようとします。ノードがバウンディングボックスの上にある場合、そのノードを少し下に移動するので、どのノードがバウンディングボックスを超えているのかがわかります。SharpDXのヒットテストは、モデルを回転させても機能しません。
最初の画像でわかるように、回転していないモデルでも問題なく動作します。しかし、モデルを-90°回転させると、すべてのヒットテストが失敗します。なぜこれが起こるのか分かりません!私はピッキングのためのヒットテストを行うときに同じ問題があります。ここで
私は、ノードが任意のバウンディングボックスの上にあるかどうかをチェックするために使用私の小さな関数です。このタスクでは、各ノードの下端を指すレイを作成します。そして、私はこの光線を、私のすべてのモデルのすべての位置との交差点に対してチェックします。 (私は、複数のタービンを持っていた場合、私は唯一のタービンモデルであるだろうが、それの複数の位置は。これは、より高速なGPUでレンダリングすることができます。)
foreach (var node in level.VisualGraph.Nodes)
{
SharpDX.Vector3 upperVector = new SharpDX.Vector3(node.Position.X, 1.0f, node.Position.Z);
SharpDX.Ray ray = new SharpDX.Ray(upperVector, new SharpDX.Vector3(0.0f, -1.0f, 0.0f));
foreach (var model in level.Models)
{
foreach (var position in model.Positions)
{
if (position.BoundingBox.GeometricBoundingBox.Intersects(ref ray))
{
node.Position = new SharpDX.Vector3(node.Position.X, 0.6f, node.Position.Z);
break;
}
}
}
}
前に述べたように、各モデルは数回発生する可能性がありますシーン内では、各モデルを1回だけ保存し、それぞれの位置の変換を計算します。したがって、モデルの各位置に1つのバウンディングボックスがあります。
ヒットテストに使用している 'GeometricBoundingBox'は、SharpDX.BoundingBoxです。モデルに新しい位置を追加すると、最小と最大のモデルのすべての頂点をチェックすることによって新しい境界ボックスを作成します。
bool isFirst = true;
foreach (var vertex in vertices)
{
if (isFirst)
{
_min = new SharpDX.Vector3(vertex.GetPosition().X, vertex.GetPosition().Y, vertex.GetPosition().Z);
_max = new SharpDX.Vector3(vertex.GetPosition().X, vertex.GetPosition().Y, vertex.GetPosition().Z);
isFirst = false;
}
else
{
_min.X = Math.Min(_min.X, vertex.GetPosition().X);
_min.Y = Math.Min(_min.Y, vertex.GetPosition().Y);
_min.Z = Math.Min(_min.Z, vertex.GetPosition().Z);
_max.X = Math.Max(_max.X, vertex.GetPosition().X);
_max.Y = Math.Max(_max.Y, vertex.GetPosition().Y);
_max.Z = Math.Max(_max.Z, vertex.GetPosition().Z);
}
}
バウンディングボックスが最初の時または、親の位置の変化の世界行列のために作成された場合、以下のように、私は私の「GeometricBoundingBox」を計算します。
SharpDX.Vector4 testMin = Helper.Math.Multiply(new SharpDX.Vector4(_min, 1.0f), worldMatrix);
SharpDX.Vector4 testMax = Helper.Math.Multiply(new SharpDX.Vector4(_max, 1.0f), worldMatrix);
GeometricBoundingBox = new SharpDX.BoundingBox(new SharpDX.Vector3(testMin.X, testMin.Y, testMin.Z), new SharpDX.Vector3(testMax.X, testMax.Y, testMax.Z));
使用されている世界行列上記のようにバウンディングボックスを計算するためにも、位置のモデルを変換するために使用されます。私はこのように計算します:
public void UpdateWorldMatrix()
{
SharpDX.Matrix rotationMatrix = SharpDX.Matrix.RotationYawPitchRoll(RotationY, RotationX, RotationZ);
// We need to calculate the transformation matrix once and apply it for the initial offset before we can calculate the final matrix.
SharpDX.Matrix initialMatrix = SharpDX.Matrix.Scaling(Scaling * _parentModel.InitialScaling) * rotationMatrix;
SharpDX.Vector3 initialTranslation = Helper.Converters.ToVector(Helper.Math.Multiply2(_parentModel.InitialTranslation, initialMatrix));
// Calculate world matrix and update bounding box.
WorldMatrix = SharpDX.Matrix.Scaling(Scaling * _parentModel.InitialScaling) * rotationMatrix * SharpDX.Matrix.Translation(Position + Translation + initialTranslation);
if (ParentStaticPosition != null)
WorldMatrix = SharpDX.Matrix.Multiply(WorldMatrix, ParentStaticPosition.WorldMatrix);
BoundingBox.ReBuild(WorldMatrix);
}
境界ボックスは、両方のモデルで私のタービンモデルに完璧にフィットします。モデルが各位置についてGPU上で変換されている間、境界ボックスは上記のコードによって変換されます。モデルとバウンディングフィットから、私はそれらの計算が機能すると信じています。
しかし、回転していないオブジェクトでヒットテストが機能する理由はわかりませんが、回転したオブジェクトでは機能しません。
ご意見はありますか?
それが動作します。しかし、なぜ?私は以前とまったく同じことをしていますが、別の空間では「唯一の」ことをしていますよね?あなたは私にさらなる洞察力を与えることができます、アーニーディンゴ?私はあなたのアプローチがなぜ働いたのか理解したいと思っています。 – Endgegner85
私はそれがあなたの最小最大エクステントが正しく計算されていないためだと推測しています。ちょうどそれらを回転させることは、もはやそれらが最小最大範囲ではないことを意味する。あなたはオリエンテーションマトリックスからそれらを完全に再計算しなければなりません。私はモデル空間でレイキャストを行うことをお勧めします。これは、オリエンテーションモデルに対して行うよりも速いからです – ErnieDingo