2D Transformation,为什么会出现这种行为

2D Transformation, why does this behaviour occur

我有以下代码,我在其中尝试为块相对于我定义的偏移量的转换设置动画。 但是我得到的不是平滑的转换,而是这种非常奇怪的行为,它似乎复制成三胞胎,然后加倍,然后回到三胞胎,然后又回到单身。

我知道这是一种视错觉,但我很好奇为什么我没有得到围绕定义点逐渐旋转的预期行为,而是得到了这种推进器效果。

我真的是 2d/3d 操作的新手,我不理解它的所有数学,但我想学习它,这就是我写这篇文章的原因,以了解实际发生的事情哪些数字

我正在寻找为什么会出现这种行为的解释,因为这并不是我所期待的...

回顾一下:我希望随着度数的增加而逐渐旋转,而我却在整个地方都得到了这个动画。我做错了什么?

function BlockPos(x,y,z) {
   this.x = x;
   this.y = y;
   this.z = z;
}
BlockPos.prototype.getX = function() {
  return this.x;
}
BlockPos.prototype.getZ = function() {
  return this.z;
}
BlockPos.prototype.getY = function() {
  return this.y;
}
BlockPos.prototype.setX = function(x) {
  this.x = x;
}
BlockPos.prototype.setZ = function(z) {
  this.z = z;
}
BlockPos.prototype.setY = function(y) {
  this.y = y;
}

function Block(color,blockpos) {
this.color = color;
this.blockpos = blockpos;
}
Block.prototype.getBlock = function() {
   return '<div style="display:inline-block;width:38px;height:38px;position:absolute;left:'+(this.blockpos.getX()*40)+'px;top:'+(this.blockpos.getZ()*40)+'px;border:1px solid gray;background-color:'+this.color+'"></div>';
}

arr = [
   new Block('green',new BlockPos(1,1,1)),
   new Block('green',new BlockPos(1,1,2)),
   new Block('green',new BlockPos(1,1,3)),
   new Block('red',new BlockPos(2,1,1)),
   new Block('red',new BlockPos(3,1,1)),
   new Block('red',new BlockPos(4,1,1)),
   new Block('red',new BlockPos(5,1,1))
];
html = '';
center = new BlockPos(0,1,0);
function rotateAroundPoint(pos, center,angle) {
//POINT rotate_point(float cx,float cy,float angle,POINT p)
  var s = Math.sin(angle);
  var c = Math.cos(angle);
  var p = new BlockPos(pos.getX(),pos.getY(),pos.getZ());
  // translate point back to origin:
  p.x -= center.getX();
  p.z -= center.getZ();

  // rotate point
  var xnew = p.x * c - p.z * s;
  var znew = p.x * s + p.z * c;

  // translate point back:
  p.x = xnew + center.getX();
  p.z = znew + center.getZ();
  return p;

}
function degreesToRadians(degrees) {
   return degrees * 3.14159265358979323846264338327950288 /180
}
function rotate(arr,center,degrees) {
    
     for(var c=0;c<arr.length;c++) {
         
         pos = rotateAroundPoint(arr[c].blockpos,center,degreesToRadians(degrees));
         

         arr[c].blockpos.setX(pos.getX());
         arr[c].blockpos.setZ(pos.getZ());

     }
     return arr;
}
var rotation = 0;
window.setInterval(function() {
  
  rotation+=1;
  if(rotation >= 360) rotation = 0;
  var html = rotation+' degrees<BR/>';
  arr = rotate(arr,center,rotation);
  for(c=0;c<arr.length;c++) {
     html += arr[c].getBlock();
  }
  $('#foo').html(html);
},50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="position:relative;top:200px;left:200px;background-color:yellow;width:500px;height:500px;" id="foo">
</div>

就像你说的那样,这是一种视错觉。由于它旋转得如此之快,方块在每帧之间移动了四分之一甚至三分之一的旋转,所以在您看来,它看起来像是存在多个对象副本,因为它只是 "jumps" 到它的新位置。您的代码没有任何问题,这只是我们眼睛处理运动的方式。您甚至可以通过观察风扇在现实生活中看到这一点。在某些速度下,您会看到叶片缓慢甚至向后移动。

问题的核心在这里:

arr = rotate(arr,center,rotation);

您在已经旋转的 arr 上分配旋转,并且在旋转函数中没有考虑 delta 时间。相反,您将(已经旋转的)arr 旋转了经过的总时间 - 这给出了 acceleration/accumulation 的东西。

考虑增量时间为 1 的相同代码。

function BlockPos(x,y,z) {
   this.x = x;
   this.y = y;
   this.z = z;
}
BlockPos.prototype.getX = function() {
  return this.x;
}
BlockPos.prototype.getZ = function() {
  return this.z;
}
BlockPos.prototype.getY = function() {
  return this.y;
}
BlockPos.prototype.setX = function(x) {
  this.x = x;
}
BlockPos.prototype.setZ = function(z) {
  this.z = z;
}
BlockPos.prototype.setY = function(y) {
  this.y = y;
}

function Block(color,blockpos) {
this.color = color;
this.blockpos = blockpos;
}
Block.prototype.getBlock = function() {
   return '<div style="display:inline-block;width:38px;height:38px;position:absolute;left:'+(this.blockpos.getX()*40)+'px;top:'+(this.blockpos.getZ()*40)+'px;border:1px solid gray;background-color:'+this.color+'"></div>';
}

arr = [
   new Block('green',new BlockPos(1,1,1)),
   new Block('green',new BlockPos(1,1,2)),
   new Block('green',new BlockPos(1,1,3)),
   new Block('red',new BlockPos(2,1,1)),
   new Block('red',new BlockPos(3,1,1)),
   new Block('red',new BlockPos(4,1,1)),
   new Block('red',new BlockPos(5,1,1))
];
html = '';
center = new BlockPos(0,1,0);
function rotateAroundPoint(pos, center,angle) {
//POINT rotate_point(float cx,float cy,float angle,POINT p)
  var s = Math.sin(angle);
  var c = Math.cos(angle);
  var p = new BlockPos(pos.getX(),pos.getY(),pos.getZ());
  // translate point back to origin:
  p.x -= center.getX();
  p.z -= center.getZ();

  // rotate point
  var xnew = p.x * c - p.z * s;
  var znew = p.x * s + p.z * c;

  // translate point back:
  p.x = xnew + center.getX();
  p.z = znew + center.getZ();
  return p;

}
function degreesToRadians(degrees) {
   return degrees * 3.14159265358979323846264338327950288 /180
}
function rotate(arr,center,degrees) {
    
     for(var c=0;c<arr.length;c++) {
         
         pos = rotateAroundPoint(arr[c].blockpos,center,degreesToRadians(degrees));
         

         arr[c].blockpos.setX(pos.getX());
         arr[c].blockpos.setZ(pos.getZ());

     }
     return arr;
}
var rotation = 0;
window.setInterval(function() {
  
  rotation+=1;
  if(rotation >= 360) rotation = 0;
  var html = rotation+' degrees<BR/>';
  arr = rotate(arr,center,1);
  for(c=0;c<arr.length;c++) {
     html += arr[c].getBlock();
  }
  $('#foo').html(html);
},50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="position:relative;top:200px;left:200px;background-color:yellow;width:500px;height:500px;" id="foo">
</div>