| |
JayKore Member
Anmeldedatum: 18.05.2009 Beiträge: 41
|
Verfasst am: 05.06.2009, 17:45 Titel: Ein Model mit einem Ray kollidieren |
|
Hallo,
ich hatte bei meinen ersten Schritten in XNA bereits feststellen müssen, das es die methode mesh.intersect nicht mehr gibt in XNA. Out of the box kann man nur boxes oder spheres intersecten. Da ich aber unbedingt eine Gerade mit einem Modell testen möchte, um einen genauen Hitpoint zu bekommen, habe ich die Geschichte in XNA zu Fuss gemacht.
1. Wir benötigen eine Methode, die ermittelt, ob und wo eine Gerde durch eine Trianle eines meshes trifft, denn wir müssen nacher alle Triangles eines Models testen. Hier die Methode
| Code: |
public static int TriangleIntersection(Vector3 orig, Vector3 dir,
Vector3 vert0, Vector3 vert1, Vector3 vert2,out float u,out float v,out Vector3 edge1,out Vector3 edge2)
{
// Aproximalwert (bisher nicht erforderlich gewesen)
float EPSILON = 0.000001f;
float t;
float det, inv_det;
Vector3 tvec, pvec, qvec;
// Erstellen der Dreieckspunktverbindungsvektoren
edge1 = Vector3.Subtract(vert1, vert0);
edge2 = Vector3.Subtract(vert2, vert0);
// Erstellen einer Normalen auf dem Strahl und einer Ecke
pvec = Vector3.Cross(dir, edge2);
// Determinante festlegen
det = Vector3.Dot(edge1, pvec);
// Erstellung des Verbindungsvektors zwishen dem Ortsvektor der Geraden und dem initialen Dreickspunkt
tvec = Vector3.Subtract(orig, vert0);
// Erstellen des Punktprodukts für Stützvektor u
u = Vector3.Dot(tvec, pvec);
qvec = Vector3.Cross(tvec, edge1);
//Bestimmung des Stützvektors v und t
v = Vector3.Dot(dir, qvec);
t = Vector3.Dot(edge2, qvec);
// Produkt der Stützvektoren und t mit der invertierten Determinante ergibt die Skalarfaktoren der Ebenen-
// Stützvektoren
inv_det = 1.0f / det;
t *= inv_det; u *= inv_det; v *= inv_det;
// u/v auf Gültigkeit prüfen
if (float.IsInfinity(u) | float.IsInfinity(v) | float.IsNaN(u) | float.IsNaN(v))
return 0;
if (u < 0.0 | v < 0.0)
return 0;
if (u + v > 1.0)
return 0;
return 1;
}
|
Wir brauchen eine abstraktere Methode, die uns den Durchstoßpunkt der Geraden durch die Triangle, sowie den Abstand des Ortsvektors der Geraden zum Durchstoßpunkt der Triangel anhand der Skalarwerte u und v liefert.
| Code: |
public static bool RayIntersectsTriangle(Vector3 Orig, Vector3 Ray,
Vector3 Vertex0, Vector3 Vertex1, Vector3 Vertex2, out Vector3 Hitpoint,out float Length)
{
bool tmp = false;
Hitpoint = new Vector3();
Length = 0f;
float u, v; Vector3 edge1, edge2;
if (TriangleIntersection(Orig,Ray,Vertex0,Vertex1 ,Vertex2 ,out u,out v,out edge1,out edge2 ) == 1)
{
tmp = true;
Hitpoint = Vertex0 + u * edge1 + v * edge2;
Length = Vector3.Subtract(Hitpoint, Orig).Length();
}
return tmp;
}
|
Nun benötigen wir nur noch alle Vertices eines Models oder eines einzelnen meshes. Hier sind beide Varianten:
| Code: |
public VertexPositionNormalTexture[] StripMesh(ModelMesh Mesh)
{
int count = Mesh.MeshParts[Mesh.MeshParts.Count - 1].BaseVertex + Mesh.MeshParts[Mesh.MeshParts.Count - 1].NumVertices;
VertexPositionNormalTexture[] Data = new VertexPositionNormalTexture[count];
Mesh.VertexBuffer.GetData<VertexPositionNormalTexture>(Data);
return Data;
}
public VertexPositionNormalTexture[] StripModel(Model Model)
{
ArrayList Arr = new ArrayList();
foreach (ModelMesh Mesh in Model.Meshes)
{
Arr.AddRange(StripMesh(Mesh));
}
return (VertexPositionNormalTexture[])Arr.ToArray(typeof(VertexPositionNormalTexture));
}
|
und eine Methode die alle Triangles in der soeben erhaltenen Vertexlist auf den nächsten Durchstoßpunkt mit einer Geraden prüft:
| Code: |
public static bool IntersectRay2VertexCollection2(Vector3 Origin, Vector3 Ray, VertexPositionNormalTexture[] Data, out Vector3 ClosestHit, out float NearestDistance)
{
bool tmp = false;
ClosestHit = new Vector3(); NearestDistance = 0f;
for (int i = 0; i < Data.Length / 3; i++)
{
Vector3 Hitpoint; float Distance = 0f;
if (WorldMath.RayIntersectsTriangle(Origin, Ray,
Data[i * 3].Position, Data[i * 3 + 1].Position, Data[i * 3 + 2].Position,
out Hitpoint, out Distance))
{
if (tmp == true)
{
if (Distance < NearestDistance)
{
ClosestHit = Hitpoint;
}
}
else
{
NearestDistance = Distance;
ClosestHit = Hitpoint;
}
tmp = true;
}
}
return tmp;
}
|
Zuletzt bearbeitet von JayKore am 05.06.2009, 18:23, insgesamt einmal bearbeitet |
|
| Nach oben |
|

|
Kevin Member
Anmeldedatum: 24.10.2008 Beiträge: 882 Wohnort: Karlsruhe
|
Verfasst am: 05.06.2009, 17:55 Titel: |
|
Jo, ist ganz nett.
Aber warum verwendest du nicht die Ray Klasse von XNA, die solltest du deinen Methoden übergeben.
Mit Rays ist PerTriangleIntersection nicht möglich (da kommt dann deine variante ins spiel), allerdings kann man Kollision mit Spheres und AABB prüfen.
Bei deiner Methode würde ich auch aufpassen, da das wenn du es häufiger verwendest sehr auf die Framerate geht (bei Modellen mit vielen Polygonen).
Aber man kann z.B. eine LowPoly Version eines 3D Models nehmen und damit prüfen.
Trotzdem gut, danke *thumps up*
MfG
Kevin _________________ Mein Youtube Kanal
Zuletzt bearbeitet von Kevin am 06.06.2009, 00:25, insgesamt einmal bearbeitet |
|
| Nach oben |
|

|
JayKore Member
Anmeldedatum: 18.05.2009 Beiträge: 41
|
Verfasst am: 05.06.2009, 18:10 Titel: |
|
| Kevin hat Folgendes geschrieben: | Jo, ist ganz nett.
Aber warum verwendest du nicht die Ray Klasse von XNA, die solltest du deinen Methoden übergeben.
|
Das ist in der Tat schöner zur Wiederverwenung. In diesem Beispiel wollte ich aber ganz bewußt nicht spezielle Eigenheiten von XNA nutzen.
| Kevin hat Folgendes geschrieben: |
Mit Rays ist PerTriangleIntersection nicht möglich (da kommt dann deine variante ins spiel), allerdings kann man Kollision mit Spheres und AABB prüfen.
Bei deiner Methode würde ich auch aufpassen, da das wenn du es häufiger verwendest sehr auf die Framerate geht (bei Modellen mit vielen Polygonen).
Aber man kann z.B. eine LowPoly Version eines 3D Models nehmen und damit prüfen.
|
Es gibt einige Situation in den Spheres und die anderen einfachen Körper nicht reichen. Allerdings hast Du vollkommen recht, man darf diese Geschichte nicht oft durchlaufen wegen der Performance. Im Idealfall bekomme ich es hin rekursiv vom einfachen in den komplizierten Test zu gehen.
D.h. Der Ray trifft die BoundingSphere eines Models->Prüfung der Boundingspheres der einzelnen Meshes-> Prüfung der Triangles des getroffenen meshes |
|
| Nach oben |
|

|
|
|
|