2017-07-11 1 views
1

Ich versuche die Mathematik zu finden, die benötigt wird, um (x, y, z) in (x, y) zu übersetzen, damit ich Boxen mit PHP erstellen kann. Alle Punkte sind am Gitter und es gibt keine Rotationen.3D-Objekt auf 2D-Raum übersetzen

Ich habe diese Lösung https://stackoverflow.com/a/25955134/379249 ausprobiert, die mir dort einen Teil des Weges kommt, aber ich brauche die Punkte der Polygone, um herauszufinden,

Zum Beispiel habe ich eine große Kiste unten in rot dargestellt.

boxes

Ich brauche es, die Abmessungen von entweder Breite, Länge, Höhe und Ausgangspunkt in der Lage zu geben, oder kann ich es alle vier Punkte geben, die jedes Gesicht.

Ich muss diese übersetzen, damit es 3D erscheint, worüber ich gestolpert bin.

Sobald die rote Box erstellt wurde, müsste ich auch in der Lage sein, andere Boxen mit der gleichen Funktion wie die grüne, blaue oder orange zu erstellen.

Ich kann den Code erstellen, aber ich bin auf der Mathematik fest, um die Übersetzungen zu tun.

Irgendwelche Ideen?

Danke!

EDIT **

Dank @ user2464424 ich in der Lage bin, um es ganz in der Nähe zu bekommen. Unten ist mein Code.

Und mein generiertes Bild.

<?php 
function RotatePoint($sin,$cos,$x,$y) { 
    return array($x*$cos - $y*$sin, $y*$cos + $x*$sin); 
} 

$im = imagecreatetruecolor(200, 200); 

$white = imagecolorallocate($im, 255, 255, 255); 
imagefilledrectangle($im, 0, 0, 200, 200, $white); 

$brown = imagecolorallocate($im, 120, 53, 31); 
$green = imagecolorallocate($im, 23, 255, 65); 
$blue = imagecolorallocate($im, 31, 23, 255); 
$orange = imagecolorallocate($im, 255, 185, 23); 

function draw_box(&$image, $color, $start, $width, $length, $height) 
{ 
    $camx = 80; 
    $camy = 240; 
    $camz = 40; 

    $yaw = 10; 
    $pitch = 20; 
    $sy = sin(-$yaw); $cy = cos(-$yaw); $sp = sin(-$pitch); $cp = cos(-$pitch); 

    $start_x = $start[0]; 
    $start_y = $start[1]; 
    $start_z = $start[2]; 

    // Draw 6 faces 
    for ($i = 0; $i < 6; $i++) 
    { 
     switch ($i) 
     { 
      case 0: 
       $face = array(
        array($start_x, $start_y, $start_z), 
        array($start_x+$width, $start_y, $start_z), 
        array($start_x+$width, $start_y, $start_z+$height), 
        array($start_x, $start_y, $start_z+$height) 
       ); 
       break; 
      case 1: 
       $face = array(
        array($start_x, $start_y+$length, $start_z), 
        array($start_x+$width, $start_y+$length, $start_z), 
        array($start_x+$width, $start_y+$length, $start_z+$height), 
        array($start_x, $start_y+$length, $start_z+$height) 
       ); 
       break; 
      case 2: 
       $face = array(
        array($start_x, $start_y, $start_z), 
        array($start_x, $start_y+$length, $start_z), 
        array($start_x, $start_y+$length, $start_z+$height), 
        array($start_x, $start_y, $start_z+$height) 
       ); 
       break; 
      case 3: 
       $face = array(
        array($start_x+$width, $start_y, $start_z), 
        array($start_x+$width, $start_y+$length, $start_z), 
        array($start_x+$width, $start_y+$length, $start_z+$height), 
        array($start_x+$width, $start_y, $start_z+$height) 
       ); 
       break; 
      case 4: 
       $face = array(
        array($start_x, $start_y, $start_z+$height), 
        array($start_x+$width, $start_y, $start_z+$height), 
        array($start_x+$width, $start_y+$length, $start_z+$height), 
        array($start_x, $start_y+$length, $start_z+$height) 
       ); 
       break; 
      case 5: 
       $face = array(
        array($start_x, $start_y, $start_z), 
        array($start_x+$width, $start_y, $start_z), 
        array($start_x+$width, $start_y+$length, $start_z), 
        array($start_x, $start_y+$length, $start_z) 
       ); 
       break; 
     } 


     $polygon = array(); 
     foreach ($face as $point) 
     { 
      $x = $point[0] - $camx; 
      $y = $point[1] - $camy; 
      $z = $point[2] - $camz; 

      $rot = RotatePoint($sy,$cy,$x,$y); 
      $x = $rot[0]; 
      $y = $rot[1]; 

      $rot = RotatePoint($sp,$cp,$z,$y); 
      $z = $rot[0]; 
      $y = $rot[1]; 

      $polygon[] = $x; 
      $polygon[] = $z; 
     } 

     imagepolygon($image, $polygon, 4, $color); 
    } 
} 

draw_box($im, $brown, array(0, 0, 0), 80, 80, 80); 

draw_box($im, $green, array(0, 0, 0), 40, 40, 40); 

draw_box($im, $blue, array(0, 0, 40), 30, 20, 10); 

draw_box($im, $orange, array(60, 0, 0), 15, 40, 80); 

imagepng($im, './image.png'); 

imagedestroy($im); 
?> 
<img src="image.png"> 

enter image description here

Ein paar Fragen.

1: Wie bekomme ich den Ursprung der Achse unten, jetzt ist es auf dem Kopf nach rechts.

2: Soll ich es immer auf einem 400x400 Bild produzieren, wie würde ich sicherstellen, dass es nicht geht oder in der Lage zu skalieren?

3: Wenn der Container 40x40x40 oder 10x100x100 ist, wie kann ich den Ursprung so einstellen, dass er immer am unteren Rand des Bildes liegt und die Box skaliert?

EDIT **

Hier ist ein Link auf den endgültige Code: https://gist.github.com/rzfarrell/3a9e5046dcfd6bd2d2f4bfa1a34b21ef

Dies macht: enter image description here

+1

Ich denke, was Sie versuchen zu erreichen ist orthographische Projektion, ist das richtig? – user2464424

+2

Es gibt * bazillions * Möglichkeiten, 3D auf 2D zu projizieren. Wenn Sie noch nicht wissen, dann werfen Sie einen Blick auf: https://en.wikipedia.org/wiki/Graphical_projection. Übersetzungen sind auch einfach (nur x '= x + delta, etc.). Drehungen sind viel schwieriger: https://en.wikipedia.org/wiki/Rotation_(mathematics) –

+0

@ user2464424 ja orthographische Projektion ist, was ich suche. – bones

Antwort

1

Die Hauptidee der orthographischen Projektion eines 3D-Punktes gegen eine Freie Kamera im 3D-Raum ist es, die Kamera so zu bewegen und zu drehen, dass sie a) am Ursprung zentriert und b) nicht gedreht wird. Der Haken ist, dass alle Punkte, aus denen die 3D-Welt besteht, der Kamera während der Transformation starr folgen müssen.

Dies läuft darauf hinaus in der Regel bis zu einem zweistufigen Verfahren:

1) Zuerst wird den Punkt durch den Ursprungs-Kameravektor übersetzen invertiert:

$x = $pointx - $camx; $y = $pointy - $camy; $z = $pointz - $camz; 

2) Dann drehen, um den Punkt, um die Ursprung durch die Nick- und Gierwinkel der Kamera negiert (möglicherweise in Radiant):

$sy = sin(-$yaw); $cy = cos(-$yaw); $sp = sin(-$pitch); $cp = cos(-$pitch); 

function RotatePoint($sin,$cos,$x,$y) { 
    return array($x*$cos - $y*$sin, $y*$cos + $x*$sin); 
} 

$rot = RotatePoint($sy,$cy,$x,$y); 
$x = $rot[0]; 
$y = $rot[1]; 

$rot = RotatePoint($sp,$cp,$z,$y); 
$z = $rot[0]; 
$y = $rot[1]; 

und du bist fertig. Jetzt repräsentieren $x und $z die Koordinaten des 2D-Punktes in der Kameraebene von der Mitte der Kamera und $y ist der senkrechte Abstand des Punktes zur Kameraebene.

Wenn Sie ein Bild ausgeben möchten, können Sie die Koordinaten skalieren und auf die Bildgröße beschränken, die trivial ist. Eine Sache, die Sie beachten müssen, ist, alle Punkte zu ignorieren, die y<=0 haben, weil es bedeutet, dass sie hinter der Kamera sind.

+0

danke! Ich habe einen funktionierenden Code bekommen und meine Frage damit aktualisiert, habe aber noch ein paar Probleme zu lösen. – bones

+1

@bones Sie sind willkommen, aber zahlen mehr Aufmerksamkeit, gibt es Verwirrung in einigen Teilen. Zunächst einmal sollten die Ausrichtungswinkel der Kamera im Bogenmaß sein. Verwenden Sie die Funktion ['deg2rad'] (http://php.net/manual/en/function.deg2rad.php), um die Konvertierung durchzuführen. Denken Sie daran, dass sobald Sie die Punktkoordinaten transformiert haben, Sie mit ihnen alles machen können, was Sie wollen. Zum Beispiel können Sie '$ z' negieren, um das Ergebnis auf den Kopf zu stellen. Da der "Bildschirm" ein Bild mit (0,0) in der oberen linken Ecke ist, möchten Sie einen Offset wie '= $ CanvasHalfWidth + $ x;' und '= $ CanvasHalfHeight- $ z;' – user2464424

+1

@ hinzufügen. bones Zum Skalieren können Sie auch '$ x' und' $ z' mit einem Faktor multiplizieren, der Zoom genannt werden kann. Sobald Sie die Änderungen vorgenommen haben, versuchen Sie die Kameraposition (-25, -50, 100), Gier = Grad 2 Rad (-35) und Tonhöhe = Grad 2 Rad (35). Ich habe mit diesen Parametern versucht und ein nettes mehr oder weniger zentriertes Bild bekommen. – user2464424