将3D对象转换为2D空间

时间:2017-07-11 20:44:37

标签: php math

我试图找到将(x,y,z)翻译成(x,y)所需的数学,这样我就可以用php创建框了。所有点都将在网格上,并且没有旋转。

我已经尝试过这个解决方案https://stackoverflow.com/a/25955134/379249,它让我在那里的一部分,但我需要弄清楚多边形的点

例如,我有一个大框,下面显示为红色。

boxes

我需要能够给它宽度,长度,高度和起点的尺寸,或者我可以给出构成每张脸的所有四个点。

我需要翻译那些让它看起来像是我绊倒的3D。

创建红色框后,我还需要能够使用相同的功能创建其他框,例如绿色,蓝色或橙色框。

我可以创建代码,但我仍然坚持数学来进行翻译。

有什么想法吗?

谢谢!

编辑 **

感谢@ user2464424,我能够非常接近。以下是我的代码。

我生成的图像。

<?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

一些问题。

1:如何在底部获取轴的原点,现在它在右侧颠倒。

2:假设我总是希望在400x400图像上制作它,我怎么能确保它不会消失或者能够放大?

3:如果容器是40x40x40或10x100x100,我怎样才能调整原点,使其始终位于图像的底部,并且框会缩放以适合?

编辑 **

以下是最终代码的链接: https://gist.github.com/rzfarrell/3a9e5046dcfd6bd2d2f4bfa1a34b21ef

这样做: enter image description here

1 个答案:

答案 0 :(得分:1)

在3D空间中3D点对照自由相机的正投影的主要思想是移动和旋转相机,使其最终成为a)以原点为中心,b)不旋转。问题在于,构成3D世界的所有点必须严格遵循相机的变换。

这通常归结为两个步骤:

1)首先,通过反转的原点相机矢量转换点:

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

2)然后,通过相机的俯仰和偏转角度(可能以弧度为单位)旋转原点周围的点:

$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];

你完成了。现在,$x$z表示相机平面中距离相机中心的2D点的坐标,$y是该点与相机平面的垂直距离。

如果要输出图片,可能需要缩放并限制坐标以适合图像尺寸,这是微不足道的。你必须考虑的一件事是忽略所有y<=0点,因为这意味着它们在镜头后面。