3d到2d投影算法(透视投影) - Javascript

时间:2017-11-20 15:01:05

标签: javascript projection perspective

我正在寻找采用3D坐标并将其更改为2D坐标的算法。

我尝试了这个维基百科页面的步骤:https://en.wikipedia.org/wiki/3D_projection#Perspective_projection

我的代码到目前为止是这样的:

      var WIDTH = 1280/2;
      var HEIGHT = 720/2;
      // Distance from center of Canvas (Camera) with a Field of View of 90 digress, to the Canvas
      var disToCanvas = Math.tan(45) * WIDTH/2;
      
      var canvas = document.createElement('canvas');
      canvas.width = WIDTH;
      canvas.height = HEIGHT;
      
      document.body.appendChild(canvas);
      
      var ctx = canvas.getContext('2d');
      
      var Player = function (){ // Camera
      // Camera Coordinates
      	this.x = 0;
        this.y = 0;
        this.z = 0;
      // Camera Rotation (Angle)
        this.rx = 0;
        this.ry = 90;
        this.rz = 0;
      };
      var player = new Player();
      
      var Point = function (x, y ,z){
      // Point 3D Coordinates
      	this.x = x;
        this.y = y;
        this.z = z;
      // Point 2D Coordinates
        this.X2d = 0;
        this.Y2d = 0;
        
      // The function that changes 3D coordinates to 2D
        this.update = function (){
          var X = (player.x - this.x);
          var Y = (player.y - this.y);
          var Z = (player.z - this.z);
          
          var Cx = Math.cos(player.rx); // cos(θx)
          var Cy = Math.cos(player.ry); // cos(θy)
          var Cz = Math.cos(player.rz); // cos(θz)
          
          var Sx = Math.sin(player.rx); // sin(θx)
          var Sy = Math.sin(player.ry); // sin(θy)
          var Sz = Math.sin(player.rz); // sin(θz)
          
          var Dx = Cy * (Sy*Y + Cz*X) - Sy*Z;
          var Dy = Sx * (Cy*Z + Sy * (Sz*Y + Cz*X)) + Cx * (Cy*Y + Sz*X);
          var Dz = Cx * (Cy*Z + Sy * (Sz*Y + Cz*X)) - Sx * (Cy*Y + Sz*X);
          
          var Ex = this.x / this.z * disToCanvas; // This isn't 100% correct
          var Ey = this.y / this.z * disToCanvas; // This isn't 100% correct
          var Ez = disToCanvas;                   // This isn't 100% correct
          
          this.X2d = Ez/Dz * Dx - Ex + WIDTH/2;  // Adding WIDTH/2 to center the camera
          this.Y2d = Ez/Dz * Dy - Ez + HEIGHT/2; // Adding HEIGHT/2 to center the camera
        }
      }
      // CREATING, UPDATING AND RENDERING A SQUARE
      var point = [];
      point[0] = new Point(10, 10, 10);
      point[1] = new Point(20, 10, 10);
      point[2] = new Point(20, 20, 10);
      point[3] = new Point(10, 20, 10);
      
      var run = setInterval(function (){
      	for (key in point){
        	point[key].update();
        }
        
        ctx.beginPath();
        ctx.moveTo(point[0].X2d, point[0].Y2d);
        ctx.lineTo(point[1].X2d, point[1].Y2d);
        ctx.lineTo(point[2].X2d, point[2].Y2d);
        ctx.lineTo(point[3].X2d, point[3].Y2d);
        ctx.lineTo(point[0].X2d, point[0].Y2d);
        
      }, 1000/30);
html, body {
      	width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        
        background: rgba(73,72,62,.99);
      }
      canvas {
      	position: absolute;
        margin: auto;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        
        outline: 1px solid white;
      }
<html>
  <head>
  </head>
  <body>
  </body>
</html>

我想要一个可以根据相机的位置和旋转将3D转换为2D的功能。

1 个答案:

答案 0 :(得分:1)

看一下你链接的维基百科页面,看来你的方程式中有D的错误。它应该是:

var Dx = Cy * (Sz*Y + Cz*X) - Sy*Z;
var Dy = Sx * (Cy*Z + Sy * (Sz*Y + Cz*X)) + Cx * (Cz*Y + Sz*X);
var Dz = Cx * (Cy*Z + Sy * (Sz*Y + Cz*X)) - Sx * (Cz*Y + Sz*X);

此外,我认为您使用错误的坐标E,即“观察者相对于显示表面的位置”,并且不应该取决于该点的坐标。

2D位置的y坐标似乎也包含错误;你使用Ez而不是Ey。

此外,我可以推荐this site。它是为C ++和OpenGL编写的,但它包含了很多很好的解释和图表,可以更好地理解你想要做什么。