2017-02-14 11 views
0

아래 그림과 같이 단일 모델의 터빈과 작은 그리드가 있습니다. 모델의 경계 상자가 빨간색 상자로 표시됩니다. 녹색 격자의 어떤 노드가 터빈 경계 상자 위에 있는지 확인하려고합니다. 노드가 바운딩 박스 위에 놓여 있다면, 조금 아래로 움직입니다. 그래서 어떤 노드가 바운딩 박스 위에 있고 어떤 노드가 그렇지 않은지를 명확하게 볼 수 있습니다.모델 회전 후 SharpDX의 히트 테스트가 작동하지 않습니다.

첫 번째 이미지에서 알 수 있듯이 회전하지 않은 모델에서도 완벽하게 작동합니다. 그러나 모델을 -90 ° 회전하면 모든 적중 테스트가 실패합니다. 나는 이것이 왜 일어나는 지 이해하지 못한다. '피킹'에 대한 히트 테스트를 할 때도 동일한 문제가 있습니다.

enter image description here

enter image description here

여기에 내가 노드가 경계 상자 여부 이상 여부를 확인하는 데 사용하는 내 작은 기능입니다. 이 작업을 위해 각 노드에 대해 아래쪽을 가리키는 광선을 만듭니다. 그런 다음 모든 모델의 모든 위치와의 교차점을 기준으로이 광선을 확인합니다. (I 여러 터빈이 있다면, 난 단지 터빈 모델을 가지고 싶지만, 그것의 여러 위치. 이것은 더 빠른 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; 
      } 
     } 
    } 
} 

이전에 언급 한 바와 같이, 각각의 모델은 여러 번 발생할 수 있습니다 장면에서 각 모델을 한 번만 저장하고 각각의 위치에 대한 변형을 계산합니다. 따라서 모델의 각 위치에 대해 하나의 경계 상자가 있습니다.

히트 테스트에 사용하는 '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로 변형되는 동안 바운딩 박스는 위에 표시된 코드로 변형됩니다. 모델과 경계 적합 이후로, 나는 그것들을 계산하는 것이 효과가 있다고 믿습니다.

그러나 왜 내 히트 테스트가 회전되지 않은 개체에서 작동하는지는 모르지만 회전 된 개체에서는 작동하지 않습니다.

의견이 있으십니까?

답변

1

광선 캐스팅에서 할 수있는 한 가지 방법은 경계 상자를 방향으로 변환하는 대신 광선을 모형 공간으로 변환하는 것입니다. 이것은 모델 방향 행렬의 역행렬을 취하여 벡터의 시작점과 끝점에 역행렬을 곱하여 수행됩니다. 그런 다음 모형 공간에 광선을 생성하고 모형 공간 aabb에 대해 모형을 주조합니다.

만약 당신이 aabb를 매트릭스로 향하게한다면 이것은 작동하지 않을 것입니다. 모델의 모든 vert를 방향 매트릭스에 곱한 다음 aabb를 다시 계산하여 새 aabb를 다시 계산해야합니다.그게 네가하고있는 일이라고 나는 믿는다. 그러나 바꿀 박스는 올바른 최대 최소 범위를 갖지 않을 수도있다.

+0

그것은 작동합니다. 하지만 .. 왜? 내 말은, 전과 똑같은 일을하지만, 다른 공간에서는 "오직"하는 것입니다. 더 깊은 통찰력을 줄 수 있겠 어, 어니 딩고? 귀하의 접근 방식이 왜 효과가 있고 왜 회전 된 항목에 실패했는지 이해하고 싶습니다! – Endgegner85

+0

나는 당신의 최소 최대 익스텐트가 제대로 계산되지 않았기 때문에 그것이라고 추측하고 있습니다. 그냥 회전하면 더 이상 최대 범위가 아닙니다. 당신은 방향 매트릭스에서 완전히 다시 계산해야합니다. 모델 공간에서 레이 캐스트를 수행하는 것이 좋습니다. 오리 엔테이션 모델에 비해 수행 속도가 빠르기 때문입니다. – ErnieDingo