Camera Picking wie in B3D (OpenGL)

Übersicht Sonstiges Smalltalk

Neue Antwort erstellen

Kernle 32DLL

Betreff: Camera Picking wie in B3D (OpenGL)

BeitragMo, Apr 19, 2010 0:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Hiho,

Ich habe ein kleines OpenGL (ES) Problem, weshalb ich es einfach mal in den Smalltalk werf, vielleicht hat ja jemand eine Idee. Undzwar will ich so ein CameraPicking wie in B3D in OpenGL nachbauen kann.

Da ich mich mit sowas recht wenig auskenne, sind meine Ansätze in die Richtung auch sehr beschränkt, und ich weis auch nicht so ganz nach was ich suchen soll. Basierend auf dem was ich bisher gelesen habe, dachte ich mir das ich per Raycast eine Virtuelle Linie durch den Bildschirmpunkt machen kann, den ich dann nutze um eine Kollision zwischen der Linie und Eventuellen Objekten zu prüfen.

Dabei werfen sich mir verschiedenste Probleme in den Weg. Zum einen, wie realisiere ich damit eine Punktfindung, wie ich sie z.B. mit PickedX erreiche? Und wie überprüfe ich überhaupt schnellstmöglich ob sich Die Virtuelle Linie im Objekt befindet? Mein Hauptproblem bei dem ganzen ist das ich anders als bei B3D keine Zentrale Liste für alle 3D-Objekte habe, und daher erst beim Ende des Rendervorgangs die Tatsächliche Position des Objektes kenne.

Für jede Art von Gedankenansatz (oder Pseudocode) wäre ich Dankbar.

So long,
Kernle
Mein PC: "Bluelight" - Xtreme Gamer PC [Video]
Meine Projekte: Cube-Wars 2010 [Worklog]
Anerkennungen: 1. Platz BCC #7 , 1. Platz BCC #22 , 3. Platz BAC #89
Ich war dabei: NRW Treff III, IV ; Frankfurter BB Treffen 2009
 

Ava

Gast

BeitragMo, Apr 19, 2010 4:20
Antworten mit Zitat
Blitz3D ist lange her ... aber soweit ich mich erinnere, checkt CameraPicking nur von der Camera aus sichtbare Objekte, oder ?

Vielleicht wäre ja diese Kombination eine OpenGL Möglichkeit für Dich, die Dir - ohne viel Extras drumherum - weiterhelfen kann:
Arrow http://wiki.delphigl.com/index.php/Selektion
Arrow http://wiki.delphigl.com/index.php/gluUnProject

Da Du für jeden Denkanstoss dankbar bist - und da es auch schon sehr spät ist ^^ - werfe ich das einfach mal so in den Raum, weil es mir gerade spontan dazu in den Sinn kam. Smile

LG, Ava

Kernle 32DLL

BeitragMo, Apr 19, 2010 8:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Leider ist diese Art der Selektion kein Teil der OpenGL ES Spezifikation, und daher geht das nicht :/
Mein PC: "Bluelight" - Xtreme Gamer PC [Video]
Meine Projekte: Cube-Wars 2010 [Worklog]
Anerkennungen: 1. Platz BCC #7 , 1. Platz BCC #22 , 3. Platz BAC #89
Ich war dabei: NRW Treff III, IV ; Frankfurter BB Treffen 2009

Goodjee

BeitragMo, Apr 19, 2010 10:32
Antworten mit Zitat
Benutzer-Profile anzeigen
mit gluUnproject ermittelst du den richtungsvektor deines strahls.
so erhälst du eine geradengleichung die du dann auf schnittpunkte mit kollisionsradien, ebenen oder sonstwas testen kannst.

BlitzMax: [AUSKLAPPEN]
Local x:Double

Local y:Double

Local z:Double

Local x2:Double

Local y2:Double

Local z2:Double

Local modelview:Double[16]

glGetDoublev(GL_MODELVIEW_MATRIX,Varptr modelview[0])

Local projection:Double[16]

glGetDoublev(GL_PROJECTION_MATRIX,Varptr projection[0])

Local viewport:Int[4]

glGetIntegerv(GL_VIEWPORT,Varptr viewport[0])

gluUnProject(mx,height-my,0,Varptr modelview[0],Varptr projection[0],Varptr viewport[0],Varptr x, Varptr y, Varptr z)

gluUnProject(mx,height-my,1,Varptr modelview[0],Varptr projection[0],Varptr viewport[0],Varptr x2, Varptr y2, Varptr z2)


so kriegst du 2punkte raus, durch die du dann eine gerade legen kannst. diesen richtungsvektor der gerade kannst du dann jedem objekt beim malen übergeben und überprüfen, ob dieses objekt auf der geraden liegt
"Ideen sind keine Coladosen, man kann sie nicht recyclen"-Dr. House
http://deeebian.redio.de/ http://goodjee.redio.de/

Nibor

BeitragMo, Apr 19, 2010 20:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Oder die mathematische Lösung:

Gegeben ist ein Strahl: x = o + d*t (x,o,d sind Vektoren, t ein Float)
Nun bestehen alle Objekte aus Dreiecken. Um nun herauszufinden, ob ein Objekt gepickt wurde, muss
1. ein Strahl ermittelt werden, der aus der Kamera durch den entsprechenden Pixel hindurch geschickt wird
Ich gehe jetzt mal davon aus, dass das von Goodjee hierfür funktioniert
2. müssen alle Dreiecke der Objekte auf Kollision mit dem Strahl ermittelt werden. Schneidet sich ein Dreieck des Objektes, dann wird das Objekt getroffen (es müssen aber alle Dreiecke aller Objekte überprüft werden, damit wirklich das vorderste ausgewählt wird)


Zur Strahl-Dreiecks-Kollision:
Von dem Dreieck wird ein Punkt als Aufpunkt p, und die Verbindungen davon zu den anderen beiden Punkten als Richtungsvektoren (a1, a2) verwendet, was dann die Ebene ergibt, in der das Dreieck liegt: x = p + u*a1 + v*a2

Nun müssen t, u und v berechnet werden, was man mit einfacher linearer Algebra machen kann (siehe http://de.wikipedia.org/wiki/D...hematik%29 ), man muss nur die Ebene und den Strahl gleichsetzen, was dann zu folgendem Ergebnis führt:

D = det(-d a1 a2)

t = det(o-p a1 a2) / D
u = det(-d o-p a2) / D
v = det(-d a1 o-p) / D

Wobei noch zu erwähnen wäre, dass wenn D=0 ist, es keinen Schnittpunkt mit der Ebene gibt.
Ist D positiv, so wird das Dreieck von hinten geschnitten und sollte nicht als Kollision verarbeitet werden (kann sein das ich mich hier vertan habe und es ist wenn D negativ ist). Ist t<0, so liegt der Schnittpunkt hinter der Kamera, zählt also auch nicht.

Ist u>=0 und v>=0 und u+v<=1, so wird das Dreieck gepickt (Punkt liegt dann bei o+t*d)
t ist die Entfernung, in der die Kollision erfolgt, wobei man dann das Objekt verwendet, das am nächsten dran ist.

Code: [AUSKLAPPEN]

Function RayTriangle:Byte(ray:Ray, tri:vec3[], frontfacing_only:Byte=True)
   Local vec_dst:vec3=vec3.Create(ray.o.v[0]-tri[0].v[0], ray.o.v[1]-tri[0].v[1], ray.o.v[2]-tri[0].v[2])
   Local vec_r1:vec3=vec3.Create(tri[1].v[0]-tri[0].v[0], tri[1].v[1]-tri[0].v[1], tri[1].v[2]-tri[0].v[2])
   Local vec_r2:vec3=vec3.Create(tri[2].v[0]-tri[0].v[0], tri[2].v[1]-tri[0].v[1], tri[2].v[2]-tri[0].v[2])
   Local minus_d:vec3=vec3.Create(-ray.d.v[0], -ray.d.v[1], -ray.d.v[2])
   
   Local det:Float=vec3.Det(minus_d, vec_r1, vec_r2)
   If det=0 Or (frontfacing_only And det>0) Then Return False
   
   Local t:Float=vec3.Det(vec_dst, vec_r1, vec_r2)/det
   If t<ray.min_t Then Return False
   
   Local lambda:Float=vec3.Det(minus_d, vec_dst, vec_r2)/det
   If lambda<0 Or lambda>1 Then Return False
   
   Local my:Float=vec3.Det(minus_d, vec_r1, vec_dst)/det
   If my<0 Or my+lambda>1 Then Return False
   
   If t<ray.t Then
      ray.t=t
      Return 2
   EndIf
   Return 1
End Function

Type Ray
   
   Field o:vec3
   Field d:vec3
   Field t:Float
   Field min_t:Float
   
   Method New()
      t=1e10
   End Method
   
   Function Create:Ray(o:vec3, d:vec3, min_t:Float=0.0)
      Local r:Ray=New Ray
      r.o=o
      r.d=d
      r.d.Normalize()
      r.min_t=min_t
      Return r:Ray
   End Function
   
   
   
   
   Method Transform:Ray(mat:mat4)
      Local r:Ray=Create(vec3.Cast(mat.Transform(vec4.Cast(o, 1.0))), vec3.Cast(mat.Transform(vec4.Cast(d, 0.0))))
      r.t=t
      Return r:Ray
   End Method
   
   
   
   
End Type


Evtl. müssen Strahl und Dreiecke noch durch die entsprechenden Matrizen transformiert werden, damit die Ergebnisse korrekt sind.
http://www.blitzforum.de/showcase/203/

Skabus

BeitragFr, Mai 14, 2010 1:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

Es kommt vielleicht etwas spät, aber ich bin eben beim Lernen für Computergrafik, auf ne Seite gestoßen,
die uns nen Prof empfohlen hat...zufällig wird dort das Thema "Picking" ausführlich angesprochen:

http://www.lighthouse3d.com/opengl/picking/ (allerdings auf Englisch)


Vielleicht hilft es dir ja oder jemand anderes der sich mit dem Thema befassen will.
Mir hat es geholfen!

MfG Ska

P.S.: FALLS irgendwer partu nicht mit dem Englisch klarkommt(besser man gewöhnt sich dran aber naja) kann ich das auch gerne übersetzen, falls Lighthouse nix dagegen hat^^
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

Nibor

BeitragFr, Mai 14, 2010 10:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Also meine Erfahrung ist, dass das OpenGL-Picking langsamer als die rechnerische Lösung ist.
http://www.blitzforum.de/showcase/203/

Skabus

BeitragFr, Mai 14, 2010 11:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Kann sein, hab ich nicht ausprobiert...

Aber evtl. kann nicht jeder die rechnerische Lösung intuitiv nachvollziehen.
Außerdem zweifle ich, deine ausführliche Beschreibung in allen Ehren, daran, dass es besonders
effektiv ist, alle Drecke der Szene auf Picking zu testen...

Oder versteh ich da was falsch?

Außerdem: Nach welchem Schema erkenne ich denn jetzt welche Objekt welches ist?
Ich kann sicher mathematisch leicht testen ob ein Strahl irgendwo ein Dreieck schneidet,
aber das sagt mir noch nichts darüber aus welches Objekt genau gepickt wurde,oder?

Ich habs jetzt nicht ausprobiert, aber es erscheint mir ein wenig leichter über Indizes und dem SelectionRenderer ein Picking durchzuführen, also 5 Funktionen zu schreiben die ne, durchaus
schöne aber mir net so ganz einleuchtende, mathematische Lösung erlauben...

MfG Ska
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

Nibor

BeitragFr, Mai 14, 2010 12:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Zugegeben, die OpenGL-Variante ist vielleicht leichter zu implementieren und bei sehr großen Szenen mit vielen Dreiecken dauert meine Lösung auch etwas, aber gäbe auch noch einige Optimierungsmöglichkeiten (z.B. Octrees oder Bounding Volumes, die vorher auf Kollision mit dem Strahl getestet werden). Und bei der OpenGL-Methode muss die Szene ja sogar für jedes Picken neu gerendert werden, was auch dauert (auch wenn nur ein kleiner Ausschnitt verwendet wird.

Das Schema, nach dem bei mir überprüft wird:
Man hat ein paar Objekte, die aus Dreiecken bestehen und überprüft werden sollen.
Dann werden für jedes Objekt nacheinander die Dreiecke auf einen Schnittpunkt mit dem Strahl überprüft, die Entfernung des Schnittpunktes und das zugehörige Objekt dann zwischengespeichert. Weitere Schnittpunkte sind dann nur gültig, wenn sie vor dem alten liegen (das neue Objekt überschreibt dann das alte).
So hat man am Ende den Schnittpunkt mit der kürzesten Entfernung und das zugehörige Objekt.

Zusätzlich könnte man bei mir auch noch das gepickte Dreieck ermitteln oder die Strahlen von wo anders als der Kamera wegschicken, man hat einfach mehr Möglichkeiten.

PS:
Mir ist gerade noch eingefallen, dass ich die OpenGL-Variante noch auf meinem alten Laptop ausprobiert hab, die Mathematische Lösung hingegen auf meinem neuen PC. Das Ergebnis könnte deshalb auch verfälscht sein...

@Kernle 32DLL: Hast du dein Problem eigentlich gelöst?
http://www.blitzforum.de/showcase/203/

Neue Antwort erstellen


Übersicht Sonstiges Smalltalk

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group