MousePick() auf Meshbasis statt auf BoundingBox?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von STARGÅTE »

Ist es auch irgendwie möglich, das MousePick() auf das echte Mesh reagiert und nicht auf die BoundingBox.
Ich meine bei Entitys die einer Box nicht mal annähernd ähnlich sind, wäre es schon schön, wenn man das Entity nicht bei einem Klick ins Leere bekommt.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von DarkDragon »

Häufig wird hierzu eine Szene zweimal gerendert: einmal normal in den Farbpuffer und einmal in einen zweiten Puffer, wo jedes Objekt eine eindeutige "Farbe" besitzt.

Das ist im übrigen auch der Trick, der bei hardwarebeschleunigten Voronoi-Relaxierungen verwendet wird um die Voronoi Zellen zu rendern.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von STARGÅTE »

Gut, dann frage ich mal weiter.
Wie kann ich denn auf zwei Camera verschiedene Materialien des Entitys anzeigen lassen?
Das man Entitys vor einer Camera mit der Sichtmaske verstecken kann steht ja in der Hilfe, aber ich wollte nun nicht alle Objekte doppelt anlegen.
Es muss ja nicht in PB definiert sein, es würde mir ja reichen es im Material-Script zu definieren.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von PMV »

Da Entities auf der Basis eines Meshs generiert wird, ist es
kein Problem mehrere Entities vom gleichen Mesh zu
haben und hier jeweils ein anderes Material zu nehmen.
Das denke ich sollte sogar die Resourceschonenste
Variante sein.
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von STARGÅTE »

PMV hat geschrieben:Da Entities auf der Basis eines Meshs generiert wird, ist eskein Problem mehrere Entities vom gleichen Mesh zuhaben und hier jeweils ein anderes Material zu nehmen.Das denke ich sollte sogar die ResourceschonensteVariante sein.
Das ist richtig, aber ich muss ja dann immer das eine Entity (was für die Maske ist) zum "echte" synchronisieren und das wäre mir ein Dorn im Auge.

Hintergrund: Es geht um Raumschiffe die ich frei im Raum bewegen können und dies auch unvorhersehbar tun.
Das heißt, Lage und Orientierung müssen ununterbrochen aktualisiert werden.
Klar konnte ich feinliche Raumschiffe auf über eine Kugel anklickbar machen, aber ich möchte halt schon, dass man, wenn man zielt, exakt auf den Flügel oder so schießen könnte.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von PMV »

Dir bleibt wohl nichts anderes über als es aus zu probieren.
Solche Echtzeit-Kollisionen sind Grundsätzlich nicht ohne und
verlangen ordentliche Hardware. Gute Optimierung kann das
natürlich stark verringern, aber PB-OGRE3D hat jetzt grad
mal den Status von allgemein Nutzbar erreicht. So spezielle
Features ist da wohl doch etwas zu viel verlangt. :wink:

Ich hab aber auch in meinem Spiel schon das ein oder
andere Feature umgesetzt, das auf den ersten Blick als
viel zu Rechenintensiv ausschaut. Tatsächlich hat OGRE
aber z.B. kein Problem damit, hundert von Billboard-
Gruppen mit nur einem Bilboard an zu zeigen, wessen Texture
ständig geändert wird. Es muss nur die Maße der Texture
hoch 2 sein, nicht mal Quadratisch.

Wer weis, selbst wenn die erste Version nicht performan
genug ist, könnteste durchaus mit ein paar Tricks zum
Erfolg kommen. Für mich wäre so was auch relevant,
da die Bounding-Box doch viel zu ungenau ist, wenn
Objekte ausgewählt werden, die nicht einem Quadrat
entsprechen. Aber ich brauchs glücklicher weise nicht
für Echtzeit, wäre aber nen nettes Feature. <)
... aktuell muss die Bounding-Box aber trotzdem
reichen, weil gibt andere Dinge die erst mal vorrang
haben. ... vielleicht in einem Jahr. :lol:

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
D.J.Peters
Beiträge: 87
Registriert: 28.11.2010 13:07
Computerausstattung: P4 2x3.2GKz.1GB WIXP 32Bit NVIDEA GT240 1GB DDR3, AMD XP 1.8GHz Linux 32Bit NVIDEA GT240 TIi3200
Wohnort: Germany
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von D.J.Peters »

Ich mache gerade ein Päuschen vom nächtlichem kompelieren und habe daher einige minutem zum "Klugscheißen".

Wenn Ihr oder Du dich mit die Maus über eine 3D Scene bewegst dann gehe einfach mal davon aus
das Du for dem Monitor die aktuelle Kammera bist (gedacht an Position 0.,0,0)
und die x,und y Koordinate der Maus ist ein Strahl (Ray) der in die Scene zeigt.

RayPosition = 0,0,0
RayDirection = mausx,mausy,1

Da aber Fensterkoordinaten von Oben nach unten laufen (top to botton)
und die y Achse der 3D Scene von unten nach oben (bottom to top)
muss man noch die Maus Y Koordinate umkeheren

RayDirection = mausx,Fensterhöhe-mausy,1

Vereinfacht ausgedrückt schiest man nun einen Strahl in die Scene und ermittelt erst grob ob eine
Boundingbox oder Sphere (die das komplette Objekt umschliesen) getroffen wird.

Ist dies der Fall dann geht man eine Ebene tiefer und ermittelt welche Polygone (oft Dreiecke) from Ray getroffen wurden.

Das ganze nennt man dann RayPicking.

Werden mehrer Polygone getroffen nimmt das welches am nahesten zur Kammerea ist.

Die Sache hat nur einen kleinen Haken. :-)

In der Regel sitzt Du noch immer an der gedachten Position 0,0,0 vor deinem Monitor
aber die virtuelle Kamera wurde verschoben und mit Sicherheit auch noch rotiert.

Daher muss vor der Kollisionsberechnung dein Sitzplatzposition und Blickrichtung
in die 3D Scene rotiert und verschoben werden so das deine Position und Richtung der virtuellen Kamera entspricht.

Mathematisch multipliziert man den gedachten "Sehstrahl" = Vektor mit der Model- und Projections Matrix der 3D Engine.

Da verbirgt sich aber schon der nächste kleine Haken. ;-)

Denn eigentlich tranformiert man garnicht den Sehstrahl in die 3D Welt
sondern man tranformiert damit die 3D Welt (in umgkehrter Reihenfolge wieder vor deinem Monitor)
so das die gedachte Sitzposition auch wirklich an Position 0,0,0 ist.

Wenn vorher also die Kamera rotiert und dann verschoben wurde
verschiebt man nun zuert die 3D Scene und rotiert man sie wieder zurück.

Da währen wier beim dritten "Häkchen".

Die nennen wir es mal rückwerts laufende Koordinatentransformation erreicht man dadurch
das man den gedachten Sehstrahl mit der inversen Matrix multipliziert.

Jetzt muss man aber keine Mathebücher pauken wenn man nicht weiss warum es geht
denn das haben andere schon für uns gemacht.

Zum Beispiel in der Form von gluProject() und gluUnproject() da die Engine aber auch im Direct3D Modus
sich befinden kann nützen einem die netten OpenGL tools in diesem Fall nicht sonderlich viel.

Also müste man dieses funktion als Software haben und welch ein Zufall ich hab den "Krämpel"
noch gestern für FreeBASIC portiert.

Code: Alles auswählen

type float as double ' oder single

sub __gluMultMatrixVecd(m as const float ptr, _
                        i as const float ptr, _
                        o as float ptr)
  for j as integer=0 to 3
    o[j] = i[0] * m[0*4+j] + _
           i[1] * m[1*4+j] + _
           i[2] * m[2*4+j] + _
           i[3] * m[3*4+j] 
  next
end sub

sub __gluMakeIdentityd(m as float ptr)
  m[0+4*0] = 1: m[0+4*1] = 0: m[0+4*2] = 0: m[0+4*3] = 0
  m[1+4*0] = 0: m[1+4*1] = 1: m[1+4*2] = 0: m[1+4*3] = 0
  m[2+4*0] = 0: m[2+4*1] = 0: m[2+4*2] = 1: m[2+4*3] = 0
  m[3+4*0] = 0: m[3+4*1] = 0: m[3+4*2] = 0: m[3+4*3] = 1
end sub

sub __gluMultMatricesd(a as const float ptr, _
                       b as const float ptr, _
                       r as float ptr)
  for i as integer = 0 to 3
    dim as integer ii=i*4
    for j as integer = 0 to 3
      r[ii+j] = a[ii]*b[j] + a[ii+1]*b[4+j] + a[ii+2]*b[8+j] + a[ii+3]*b[12+j]
    next
  next
end sub


function __gluInvertMatrixd(src as const float ptr, _
                            inverse as float ptr) as integer
  
  dim as float t
  dim as float temp(3,3)
 
  for i as integer=0 to 3
    for j as integer=0 to 3
      temp(i,j) = src[i*4+j]
    next
  next

  __gluMakeIdentityd(inverse)
  dim as integer j
  for i as integer = 0 to 3
    if (temp(i,i) = 0.0) then
      for j = i + 1 to 3
        if (temp(j,i) <> 0.0) then exit for
      next
      if (j <> 4) then
        for k as integer= 0 to 3
          t = temp(i,k)
          temp(i,k) = temp(j,k)
          temp(j,k) = t
          t = inverse[i*4+k]
          inverse[i*4+k] = inverse[j*4+k]
          inverse[j*4+k] = t
        next
      else
        return 0
      end if
    end if

    t = 1.0 / temp(i,i)
    for k as integer = 0 to 3
      temp(i,k) *= t
      inverse[i*4+k] *= t
    next
    for j as integer = 0 to 3
      if (j <> i) then
        t = temp(j,i)
        for k as integer = 0 to 3
          temp(j,k) -= temp(i,k)*t
          inverse[j*4+k] -= inverse[i*4+k]*t
        next
      end if
    next
  next
  return 1
end function

function __gluUnProject(winx as float, _
                        winy as float, _
                        winz as float, _
                        modelMatrix as const float ptr, _ 
                        projMatrix  as const float ptr, _ 
                        viewport    as const integer ptr, _
                        objx as float ptr, _
                        objy as float ptr, _
                        objz as float ptr) as integer
  dim as float finalMatrix(15)
  dim as float i(3)
  dim as float o(3)
  __gluMultMatricesd(modelMatrix, projMatrix, @finalMatrix(0))
  if (__gluInvertMatrixd(@finalMatrix(0), @finalMatrix(0))=0) then
    return 0
  end if

  i(0)=winx:i(1)=winy:i(2)=winz:i(3)=1.0
  ' Map x and y from window coordinates
  i(0) = (i(0) - viewport[0]) / viewport[2]
  i(1) = (i(1) - viewport[1]) / viewport[3]

  ' Map to range -1 to 1
  i(0) = i(0) * 2 - 1
  i(1) = i(1) * 2 - 1
  i(2) = i(2) * 2 - 1

  __gluMultMatrixVecd(@finalMatrix(0), @i(0), @o(0))
  if (o(3) = 0.0) then return 0
  
  o(0) /= o(3)
  o(1) /= o(3)
  o(2) /= o(3)
  *objx = o(0)
  *objy = o(1)
  *objz = o(2)
  return 1
end function

function __gluProject(objx as float, _
                      objy as float, _
                      objz as float, _
                      modelMatrix as const float ptr, _
                      projMatrix  as const float ptr, _
                      viewport    as const integer ptr, _
                      winx as float ptr, _
                      winy as float ptr, _
                      winz as float ptr) as integer
  dim as float i(3),o(3)
  i(0)=objx:i(1)=objy:i(2)=objz:i(3)=1.0
  __gluMultMatrixVecd(modelMatrix,@i(0), @o(0))
  __gluMultMatrixVecd(projMatrix, @o(0), @i(0))
  if (i(3) = 0.0) then return 0
  i(0) /= i(3)
  i(1) /= i(3)
  i(2) /= i(3)
  ' Map x, y and z to range 0-1
  i(0) = i(0) * 0.5 + 0.5
  i(1) = i(1) * 0.5 + 0.5
  i(2) = i(2) * 0.5 + 0.5

  ' Map x,y to viewport
  i(0) = i(0) * viewport[2] + viewport[0]
  i(1) = i(1) * viewport[3] + viewport[1]
 
  *winx=i(0)
  *winy=i(1)
  *winz=i(2)
  return 1
end function
Da ganze hatte ich vor zwei Jahren für Basic4GL schon mal näher beleuchtet gehabt
weil ich damals mathematisch gesehen noch im Dunklem stand.

Die Purebasic 3D Engine stellt meiner bescheidenen Meinung nach nicht mal 30% der Orge Engine dem Käufer/Nutzer zur Verfügung.

Wo ist da z.B. GetCameraMatrix() oder GetModelViewMatrix() ?

Egal ob DirectX oder OpenGL man brauch diese Funktionen einfach nur zu Exportieren und Das wäre es dann auch schon.

Also muss man einen Umweg gehen und via Kamera und Node Pitch, Yaw und Roll und Position sich die Matrizen selber zusammen "basten".

Ich bin gerade mit meine Softwarefirma bis ende des Monates ausgebucht und in meiner Freizeit quäle ich gerne
die neuen OOP fähigkeiten von FreeBASIC und beruflich die von C++ und JAVA aber zum 1. könnte ich wenn dann
noch Bedarf bestehen sollte eine PureBasic Version für das "Mouse World Picking" zur Verfügung stellen.

Aber hier sind ja auch einige 3D "Freggels" welche manchmal nicht wissen was sie nun schon wieder anstellen können.
Vielleicht hat ja Jemand Lust und Zeit gluUnprojekt für die PureBasic 3D Engine zu verwirklichen

Code: Alles auswählen

PureUnProject(MouseX,MouseY,MouseZ, ViewMatrix, ProjMatrix, WindowLeft, WindowTop, WindowRight, WindowBottom, ResultRayDirectionX, ResultRayDirectionY, ResultRayDirectionZ)

So dann mal ran an die Tastaturen.

Liebe Grüße ich glaube mein Bett ruft gerade.

DJ

PS. Wer mal sehen möchte wie genau die Kollisionskoordinaten sind kann ja mal hier die win32 exe testen.
download: MouseRayPicking.zip
PS. meine vielen Fehler der Rechtschreibung auf dem Forum könnt Ihr gerne ignorieren.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von STARGÅTE »

Das mit dem Strahl ist erst mal eine Gute Idee, schließlich verwende ich RayCollide() auch, um zu ermitteln ob der Spieler die Sonne sieht oder nicht und RayCollide() verwendet schon mal die Physikalische Box, die etwas genauer ist.

Leider ist es jedoch nicht so einfach wie du es hier darstellst: RayDirection = mausx,Fensterhöhe-mausy,1
zu nutzen. Auch hier muss schon eine gewisse Transformation der Koordinaten (FOV der Camera usw.) erfolgen, damit der Strahl immer ins "Unendliche zeigt" und nicht in eine gedachte Ebene vor der Kamera.

"Deine" kleinen Haken sind für mich dagegen keine Haken.
Zur Zeit verwende ich eh für Objekte eine RotationsMatrix, welche auch immer synchron mitläuft, wenn das Objekt sich dreht.
Auch die inverse rotations Matrix speicher ist, da ich diese bereits auch schon verwende, um einen Punkte im 3D-Raum, auch meinen Bildschirm abzubinden.
Ich weiß dass es CameraProjectionX/Y() gibt, allerdings ist bei dem Befehl das Problem, dass er -1 zurück gibt, wenn es außerhalb des Bildschirms ist. Ich brauche aber gerade auch die Koordinaten außerhalb des Bildschirms, damit ich am Rand anzeigen kann, in welche Richtung sich ein Objekt befindet.

Zum Download: Es fehlt dort eine DLL: collisionplugin.dll
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
D.J.Peters
Beiträge: 87
Registriert: 28.11.2010 13:07
Computerausstattung: P4 2x3.2GKz.1GB WIXP 32Bit NVIDEA GT240 1GB DDR3, AMD XP 1.8GHz Linux 32Bit NVIDEA GT240 TIi3200
Wohnort: Germany
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von D.J.Peters »

STARGÅTE hat geschrieben:Auch hier muss schon eine gewisse Transformation der Koordinaten (FOV der Camera usw.) erfolgen, damit der Strahl immer ins "Unendliche zeigt" und nicht in eine gedachte Ebene vor der Kamera.
Nö nö
das steht doch alles in der Projectionsmatrix. (Das ist ja unter anderem ihr Job)
STARGÅTE hat geschrieben:Zum Download: Es fehlt dort eine DLL: collisionplugin.dll
Sorry war etwas müde zip file ist jetzt OK.
Wie schon gesagt habe ich die Collisions engine für Basic4GL geschrieben und da ist das RayPicking auch mit drin.

Terains mit mehreren tausend Dreiecken sind auch kein Problem. (Trust me)

Polygonische Grüsse :-)

DJ

Im Prinzip eine einfache (Matrix*Matrix)*RichtungsVektor Rechenaufgabe.
Für mich als nicht Mathematiker war nur das Bilden der inversen Matrix der Knackpunkt.

Code: Alles auswählen

  __gluMultMatricesd(modelMatrix, projMatrix, @finalMatrix(0))
  if (__gluInvertMatrixd(@finalMatrix(0), @finalMatrix(0))=0) then
    return 0
  end if

  i(0)=winx:i(1)=winy:i(2)=winz:i(3)=1.0
  ' Map x and y from window coordinates
  i(0) = (i(0) - viewport[0]) / viewport[2]
  i(1) = (i(1) - viewport[1]) / viewport[3]

  ' Map to range -1 to 1
  i(0) = i(0) * 2 - 1
  i(1) = i(1) * 2 - 1
  i(2) = i(2) * 2 - 1

  __gluMultMatrixVecd(@finalMatrix(0), @i(0), @o(0))
  if (o(3) = 0.0) then return 0
 
  o(0) /= o(3)
  o(1) /= o(3)
  o(2) /= o(3)
PS. meine vielen Fehler der Rechtschreibung auf dem Forum könnt Ihr gerne ignorieren.
D.J.Peters
Beiträge: 87
Registriert: 28.11.2010 13:07
Computerausstattung: P4 2x3.2GKz.1GB WIXP 32Bit NVIDEA GT240 1GB DDR3, AMD XP 1.8GHz Linux 32Bit NVIDEA GT240 TIi3200
Wohnort: Germany
Kontaktdaten:

Re: MousePick() auf Meshbasis statt auf BoundingBox?

Beitrag von D.J.Peters »

Ach so falls sich Jemand fragen sollte warum man OpenGL Codes aus den GL Tollkits neu schreibt.
Ganz einfach GLU und Co. verwenden natürlich auch Sachen aus der festen Render - Pipeline
und die sind seit OpenGL 3.x deprecated und bei eingigen (aber nicht allen) 4.x Versionen überhaut nicht mehr 'on board'.

Und wer will schon auf gluLockAt() gluPerspektive() gluProject() gluUnProject() etc. verzichten.

Direct3D hat den Kram natürlich auch in seinen Lib's.

DJ
PS. meine vielen Fehler der Rechtschreibung auf dem Forum könnt Ihr gerne ignorieren.
Antworten