ProfilProfil
 Registrieren
 Login
Bild der WocheBild der Woche

(von Backslider)
Kommentare (0)
****

Weitere
User onlineBenutzer online
Gäste online: 4
Mitglieder online: Keine
Registrierte Mitglieder: 2117
Neustes Mitglied: vitapen

Ein Model mit einem Ray kollidieren

Neue Antwort erstellen
 

 

Autor Nachricht
 
 
JayKore
Member


Anmeldedatum: 18.05.2009
Beiträge: 41

Antworten mit Zitat
BeitragVerfasst 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
Benutzer-Profile anzeigen Private Nachricht senden


Kevin
Member


Anmeldedatum: 24.10.2008
Beiträge: 882
Wohnort: Karlsruhe

Antworten mit Zitat
BeitragVerfasst 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* Wink


MfG
Kevin
_________________
Mein Youtube Kanal


Zuletzt bearbeitet von Kevin am 06.06.2009, 00:25, insgesamt einmal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden


JayKore
Member


Anmeldedatum: 18.05.2009
Beiträge: 41

Antworten mit Zitat
BeitragVerfasst 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
Benutzer-Profile anzeigen Private Nachricht senden


Beiträge der letzten Zeit anzeigen:   
 
Neue Antwort erstellen Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de