JavaScript中的2D透视变换

时间:2015-06-08 18:43:54

标签: javascript geometry 2d spatial perspective

寻找一个code示例,说明如何从特定角度的俯视图(90度)计算(准确)矩形的尺寸。

例如我有一个1200mm x 2000mm

的矩形

enter image description here

如果矩形在一侧向下倾斜30 degrees,我将如何确定矩形的新透视测量值。 (从90o观看者角度,自上而下)

enter image description here

从这个角度来看,它看起来像下边缘更短,即使它当然不是。 (伪3D在某种程度上......但在2D形状和2D视图中)

编辑:这是一个参考问题,请添加备用答案&溶液

1 个答案:

答案 0 :(得分:4)

您所描述的透视转换称为缩短,我建议不仅要查看我的答案,还要查看更多信息,因为它是各种应用程序的概念,可以通过不同的方法解决。

请记住,Javascript不是我的强项,所以如果我做出任何语法错误,我会道歉,请纠正我。

对于您的特定形状,简单使用类似的三角形应该为您提供顶点坐标,然后您可以使用它们来构造您的形状。您可以将顶点坐标定义为空间中的矢量。

我首先将您在2d空间中的原始形状定义为一系列4个顶点。 (左下角我将定义为原点。)在Javascript中,您应该定义一个包含4个3值数组的2d数组。 2d数组中的每个数组将是形式[x,y,z]的顶点坐标。 x值将是顶点的水平值,y值将是高度值,z值将是它在3d空间中的距离。 y值可以通过将斜坡的斜边(在这种情况下为2000)乘以斜坡角度的余弦(在这种情况下为30度)来获得。为了进行余弦运算,我们必须将角度从度数转换为弧度。转换总是pi = 180,因此30弧度为pi / 6。可以通过将斜边乘以相同角度的正弦来获得x值。

var hypotenuse = 2000;
var theta = Math.PI/6;
var x = Math.sin(theta)*hypotenuse;
var y = Math.cos(theta)*hypotenuse;
var z = 1200;
var vertices = [[0,y,0], [0,y,z], [x,0,0], [x,0,z]];

Vertex coordinates on an xyz plane.

由于观察者相对于对象的透视,会发生透视变换。因此,为了获得实际的透视变换,我们必须定义观察者的位置。我将在点(x / 2,y + y / 2,z / 2)任意定义他。

var viewer = [x/2,y+y/2,z/2];

Viewer position

然后我们选择一个焦距来定义我们的图像定义的位置。焦距仅与观察者的距离有关,因此它仅被定义为单个点。我将焦距任意地放在(viewer_x,(y + y / 2)/ 2,viewer_z),因为它是观察者下方的距离(y + y / 2)/ 2。 但是,您必须确保焦点与查看器的x和z坐标相同,并且只更改y轴。有关焦距和透视变换的更多信息,请访问{{ 3}}

var focal_length = [viewer[0],(y+y/2)/2,viewer[2]];

Focal Length coordinates

1.现在我们得到矩形的每个顶点到y轴(我们应用透视变换的轴)的距离。 然后我们得到焦距的y坐标到观察者的距离。 3.然后我们得到焦距和顶点距离之间的比率。 然后将顶点的x和z坐标乘以该比率,得到每个顶点的新的forshortened坐标。

通过简单地减去y坐标并获取结果的绝对值来找到距离。我将在for循环中完成所有操作以获得更有效的代码。

var focal_distance = Math.abs(viewer[1] - focal_length[1]); 
//gets distance between focal point y and viewer y
var vert_distance;
for(var i = 0; i< vertices.length-1; i++){
    vert_distance = Math.abs(viewer[1]-vertices[i][1]); 
    //access each individual vertex and and get the distance between vertex y and viewer y
   for (var j = 0; j<vertices[i].length-1; j++){
       vertices[i][j] = vertices[i][j]*(focal_distance/vert_distance);
       //gets the ratio between focal distance and vertex distance and multiplies each vertex by it
   }
}

最后,由于我们沿着y轴进行了缩短,因此不再需要每个顶点的y坐标,因此我们现在将每个顶点保存到一个新的2d顶点数组而不是3d顶点。

var vertices2d = [[0,0],[0,0],[0,0],[0,0]];
//creates a new 2d vertex array of 4 empty 2d vertex coordinates
for(var i = 0; i<vertices.length-1; i++){
    vertices2d[i][0] = vertices[i][0];
    //sets the x values of the 2d vertices = to the x values of 3d vertices
    vertices2d[i][1] = vertices[i][2];
    //sets the y values of the 2d vertices = to the z values of the 3d vertices
}

现在只需将这些2d顶点坐标放入任何图形程序中,您就可以获得所需的结果。

我打算让程序打印掉顶点坐标:

for (var i = 0; i<vertices2d.length-1; i++){
    document.write("(" + vertices2d[i][0] + "," + vertices2d[i][1] + ")");
}

随意浏览观察者坐标,焦距y值,平面的长度和宽度以及斜坡角度以获得不同的结果。 干杯,如果你没有得到,请随时提出任何问题。

不间断的完整代码如下:

var hypotenuse = 2000;
var theta = Math.PI/6;
var x = Math.Sin(theta)*hypotenuse;
var y = Math.Cos(theta)*hypotenuse;
var z = 1200;
var vertices = [[0,y,0], [0,y,z], [x,0,0], [x,0,z]];
var viewer = [x/2,y+y/2,z/2];
var focal_length = [viewer[0],(y+y/2)/2,viewer[2]];
var focal_distance = Math.abs(viewer[1] - focal_length[1]); 
//gets distance between focal point y and viewer y
var vert_distance;
for(var i = 0; i< vertices.length-1; i++){
    vert_distance = Math.abs(viewer[1]-vertices[i][1]); 
    //access each individual vertex and and get the distance between vertex y and viewer y
   for (var j = 0; j<vertices[i].length-1; j++){
       vertices[i][j] = vertices[i][j]*(focal_distance/vert_distance);
       //gets the ratio between focal distance and vertex distance and multiplies each vertex by it
   }
}
var vertices2d = [[0,0],[0,0],[0,0],[0,0]];
//creates a new 2d vertex array of 4 empty 2d vertex coordinates
for(var i = 0; i<vertices.length-1; i++){
    vertices2d[i][0] = vertices[i][0];
    //sets the x values of the 2d vertices = to the x values of 3d vertices
    vertices2d[i][1] = vertices[i][2];
    //sets the y values of the 2d vertices = to the z values of the 3d vertices
}
for (var i = 0; i<vertices2d.length-1; i++){
  document.write("(" + vertices2d[i][0] + "," + vertices2d[i][1] + ")");
}