FireMonkey 3D: 2D zu 3D Koordinaten berechnen



  • Ahoi.

    Ich habe ein TGrid3D welches ich über Bedienelemente verschiebe und drehe(rotiere). Wenn ich auf das TGrid3D klicke, dann möchte ich gern die 3D Koordinate meines 2D Mausklicks. Also den Schnittpunkt auf der Fläche des TGrid3D den mein "Mausstrahl" berühren würde. Ich dachte das ginge so:

    http://docwiki.embarcadero.com/Libraries/de/FMX.Types3D.RayCastPlaneIntersect

    void __fastcall TForm1::Grid3D1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
              float X, float Y, TVector3D &RayPos, TVector3D &RayDir)
    {
        TVector3D Intersection;
        RayCastPlaneIntersect(RayPos, RayDir, Grid3D1->AbsolutePosition, Grid3D1->AbsoluteDirection, Intersection);
    // 
    }
    

    Ich erhalte aber den Fehler:

    [ilink32 Fehler] Error: Nicht auflösbares externes 'System::Types::TVector3D::TVector3D()' referenziert von ...

    Kann mir jemand eventuell sagen was mein Fehler ist?



  • Ist mein XE3-Trial kaputt oder wird es zu spät für mich und ich sollte ins Bett? ^^

    TPoint3D point;
    TVector3D vector;

    Allein jede dieser Zeilen für sich gibt mir ein "nicht aufgelösbares externes...."
    Aber im Funktionskopf von MouseUp steht es doch auch drin und funktioniert dort. 😕



  • Hier in dem Beispiel wird es auch so verwendet (Das Beispiel ist für XE2): http://edn.embarcadero.com/article/42114

    TPoint3D P0, P1, P2, P3;
    

    Bin etwas verwirrt deswegen.



  • Selbstgespräch weiterführ... 😉

    Es scheint dass hier die "Types" in XE3 verschoben und erweitert wurden:

    XE2: http://docwiki.embarcadero.com/Libraries/XE2/de/FMX.Types3D.TPoint3D

    XE3: http://docwiki.embarcadero.com/Libraries/XE3/de/System.Types.TPoint3D

    Daher muss es jetzt wohl so lauten:

    TPoint3D P0(0,0,0);
    P0.X = 3;
    

    Das Problem sollte hiermit dann gelöst sein. 🤡



  • Meine Eingangsfrage ist aber wohl damit doch noch nicht ganz gelöst.

    void __fastcall TForm1::Grid3D1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
              float X, float Y, TVector3D &RayPos, TVector3D &RayDir)
    {
        TVector3D Intersection(0,0,0,0);
        Grid3D1->Context->Pick(X, Y, Grid3D1->Projection, RayPos, RayDir);
        RayCastPlaneIntersect(RayPos, RayDir, Grid3D1->AbsolutePosition, Grid3D1->AbsoluteDirection, Intersection);
    
        TControl3D *cube = new TCube(Viewport3D1);
        cube->Parent = Dummy1;
        cube->SetSize(.3, .3, .3);
        cube->Position->Point = TPoint3D(Intersection.X, Intersection.Y, Intersection.Z);
    }
    

    Hilfelinks:
    http://docwiki.embarcadero.com/Libraries/XE3/de/FMX.Types3D.TContext3D.Pick
    http://docwiki.embarcadero.com/Libraries/de/FMX.Types3D.TControl3D.AbsolutePosition
    http://docwiki.embarcadero.com/Libraries/de/FMX.Types3D.RayCastPlaneIntersect

    Der "cube" soll, egal wie ich das Grid drehe, immer im Grid liegen und immer an der Position wo ich mit der Maus drauf klicke. Aufbau in XE3:
    TViewPort3D -> TDummy -> TGrid3D
    Das TDummy drehe ich über eine TTrackbar, womit sich das TGrid3D (und andere Objekte) automatisch mitdreht.

    1. Wenn ich das Grid noch nicht gedreht habe Rotation(0,0,0), dann liegen die "cube" links neben dem Mausklick. Warum eigentlich nicht mittig vom Mausklick?
    http://docwiki.embarcadero.com/Libraries/XE3/de/FMX.Objects3D.TCube
    http://docwiki.embarcadero.com/Libraries/de/FMX.Types3D.TControl3D.Position

    Es steht leider nirgendwo beschrieben wo X,Y,Z beim TCube starten. Aber laut Designer hätte ich fest behauptet mittig im Cube.

    2. Sobald ich das TDummy drehe und anschließend auf das TGrid3D klicke, liegen die Cubes nicht mehr im TGrid3D. Habe ich irgendwas vergessen oder mache ich etwas falsch?



  • Es geht auch scheinbar "kleiner" und produziert das selbe falsche Ergebnis wie oben:

    void __fastcall TForm1::Grid3D1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
              float X, float Y, TVector3D &RayPos, TVector3D &RayDir)
    {
        TVector3D Intersection(0,0,0,0);
        Grid3D1->RayCastIntersect(RayPos, RayDir, Intersection);
    
        TControl3D *cube = new TCube(Viewport3D1);
        cube->Parent = Dummy1;
        cube->SetSize(.3, .3, .3);
        cube->Position->Point = TPoint3D(Intersection.X, Intersection.Y, Intersection.Z);
    }
    

    http://docwiki.embarcadero.com/Libraries/de/FMX.Types3D.TControl3D.RayCastIntersect



  • ~FireMonkey schrieb:

    Es steht leider nirgendwo beschrieben wo X,Y,Z beim TCube starten. Aber laut Designer hätte ich fest behauptet mittig im Cube.

    Habe keinerlei Erfahrung mit 3D-Programmierung, aber logisch würde mir erscheinen, dass X und Y sich wie in 2D auf die Ecke "links oben" beziehen und Z auf "vorne".



  • Dafür liegt es aber Z mittig im Gitter. Aber eventuell hängt das ja damit zusammen das bei einer Drehung die Position auch nicht mehr stimmt.



  • Du erstellst deinen Cube als Parent = Dummy1;
    Und Fragst wiso dein Cube nicht mit dem Grid3D dreht der auch unter dem Dummy1 zu finden ist?

    Ich frag mich auch immer, wiso dreht ich mich nicht mit wenn ich neben dem Karusell stehe 😃

    Setz den Cube als Parent vom Grid3D damit er sich mit dem Grid3D drehen kann

    cube->Parent = Grid3D1;

    Bei Firemonkey ist eigentlich immer die Position Mittig und Length/Width/Height gehen vom Mittelpunkt aus.
    Es gibt aber noch die versteckte Eigenschaft <Object>->RotationCenter die leider nicht im ObjektInspector angezeigt wird.



  • Du erstellst deinen Cube als Parent = Dummy1;
    Und Fragst weiso dein Cube nicht mit dem Grid3D dreht der auch unter dem Dummy1 zu finden ist?

    Ähm, dass war eigentlich nicht das Problem. Da muss ich mich unverständlich ausgedrückt haben. 😉

    Das Cube dreht sich natürlich passend mit. Wenn ich den Parent auf Grid3D ändern würde, setzt er den Cube von Anfang an völlig falsch. Grid3D ist ein Unterelement von TDummy, welches ich letztendlich drehe, um die ganze Scene zu drehen.

    Also wegen dem Mittelpunkt. Bei Size 1 ist es korrekt mittig, aber durch das setzten von cube->SetSize(.3, .3, .3) ist der Mittelpunkt plötzlich rechts oben?

    http://docwiki.embarcadero.com/Libraries/XE2/de/FMX.Types3D.TControl3D.SetSize

    Sobald ich TDummy1 drehe, womit sich auch automatisch das Grid3D1 dreht und auch der Cube, setzt er das Cube scheinbar an die korrekte Stelle, aber mit einem falschen Z Wert. Drehe ich nämlich zurück auf den Ausgangspunkt [0,0,0], dann sitzt der Cube mit X und Y an der Stelle wo ich mit der Maus auf den TViewPort3D hingeklickt habe (Fingertest auf Monitor). Nur Z stimmt ganz und gar nicht.



  • Das mit dem Mittelpunkt schien an der Perspektive zu liegen. Komisch.

    Ich habe mal das Beispielprojekt zum Download gemacht:
    XE3 FireMonkey D.zip
    Download File (166.4 KB)
    http://minus.com/lbityVUhZWOgnX

    Eventuell hat ja jemand Lust das kurz einzuladen und anzuschauen? 😉

    Über die Trackbar kurz ein wenig bewegen, mit der Maus eine Stelle auf dem Grid anvisieren, am besten mit Finger markieren, dann klicken und zurückdrehen auf Ursprung. Dann sieht man das der Cube an der Stelle des Fingers ist, aber dessen Z-Achse falsch ist.



  • Bin eben wieder rein und "Oh Wunder", mir ist eben dann auch sofort die Lösung eingefallen. So funktioniert es:

    void __fastcall TForm1::Grid3D1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
              float X, float Y, TVector3D &RayPos, TVector3D &RayDir)
    {
        TVector3D Intersection(0,0,0,0);
        Grid3D1->RayCastIntersect(RayPos, RayDir, Intersection);
        Intersection = Dummy1->AbsoluteToLocalVector(Intersection);
    
        TControl3D *cube = new TCube(Viewport3D1);
        cube->Parent = Dummy1;
        cube->SetSize(.3, .3, .3);
        cube->Position->Point = TPoint3D(Intersection.X, Intersection.Y, Intersection.Z);
    }
    

    Da man ja eine Absolute Position erhält, das Objekt aber immer in Relation zu TDummy steht, muss man es erst deren Vector umwandeln.

    http://docwiki.embarcadero.com/Libraries/XE3/de/FMX.Types.TControl.AbsoluteToLocalVector


Anmelden zum Antworten