为虚假3D动画添加视角

时间:2016-01-06 21:03:53

标签: javascript canvas 3d

我正在制作基于画布的动画,并且我试图在2D画布中获得3D效果。

到目前为止,情况进展顺利!我已经得到了我的"轨道三角形线"工作得很好:



var c = document.createElement('canvas');
c.width = c.height = 100;
document.body.appendChild(c);
var ctx = c.getContext("2d");

function Triangles() {
  this.rotation = {
    x: Math.random()*Math.PI*2,
    y: Math.random()*Math.PI*2,
    z: Math.random()*Math.PI*2
  };
  /* Uncomment this for testing perspective...
  this.rotation = {
    x: Math.PI/2,
    y: 0,
    z: 0
  };
  */
}
Triangles.prototype.draw = function(t) {
  this.rotation.z += t/1000;
  var i, points;
  for( i=0; i<15; i++) {
    points = [
      this.computeRotation(Math.cos(0.25*i),-Math.sin(0.25*i),0),
      this.computeRotation(Math.cos(0.25*(i+1)),-Math.sin(0.25*(i+1)),-0.1),
      this.computeRotation(Math.cos(0.25*(i+1)),-Math.sin(0.25*(i+1)),0.1)
    ];
    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.moveTo(50+40*points[0][0],50+40*points[0][1]);
    ctx.lineTo(50+40*points[1][0],50+40*points[1][1]);
    ctx.lineTo(50+40*points[2][0],50+40*points[2][1]);
    ctx.closePath();
    ctx.fill();
  }
};
Triangles.prototype.computeRotation = function(x,y,z) {
  var rz, ry, rx;
  rz = [
    Math.cos(this.rotation.z) * x - Math.sin(this.rotation.z) * y,
    Math.sin(this.rotation.z) * x + Math.cos(this.rotation.z) * y,
    z
  ];
  ry = [
    Math.cos(this.rotation.y) * rz[0] + Math.sin(this.rotation.y) * rz[2],
    rz[1],
    -Math.sin(this.rotation.y) * rz[0] + Math.cos(this.rotation.y) * rz[2]
  ];
  rx = [
    ry[0],
    Math.cos(this.rotation.x) * ry[1] - Math.sin(this.rotation.x) * ry[2],
    Math.sin(this.rotation.x) * ry[1] + Math.cos(this.rotation.x) * ry[2]
  ];
  return rx;
};

var tri = new Triangles();
requestAnimationFrame(function(start) {
  function step(t) {
    var delta = t-start;
    ctx.clearRect(0,0,100,100)
    tri.draw(delta);
    start = t;
    requestAnimationFrame(step);
  }
  step(start);
});
&#13;
&#13;
&#13;

正如你所看到的,它使用旋转矩阵来计算旋转后点的位置,并且我使用它来使用输出x和y坐标绘制三角形。

我想通过使用z坐标并为此动画添加透视来更进一步,这将使三角形在前景时略大,而在背景中则更小。但是,我不知道该怎么做。

我想这更像是一个数学问题,而不是编程问题,对不起!

2 个答案:

答案 0 :(得分:1)

定义焦距以控制透视量。值越大,透视量越少。然后

var fl = 200; // focal length;
var px = 100; // point in 3D space
var py = 200;
var pz = 500;

然后得到屏幕X,Y

var sx = (px * fl) / pz;
var sy = (py * fl) / pz;

结果点相对于视图的中心,因此您需要将其居中到画布上。

sx += canvas.width/2;
sy += canvas.height/2;

这是重点。

假设被观察的点位于视图的前方,并且远离焦点的焦距。

答案 1 :(得分:0)

我已经设法找到一个基本的解决方案,但我确定有更好的解决方案,所以如果你有更完整的答案,请随意添加它!但是现在......

由于坐标系已经基于原点而直接在Z轴上观察(x,y)平面,因此实际上只需将(x,y)坐标乘以值与z成比例。例如,x * (z+2)/2在这种情况下可以正常使用

但是,必然会有一个更恰当,更通用的解决方案!