26、《每周一点canvas动画》——3D旋转与碰撞

各位同学实在不好意思,最近忙着面试找工作,耽搁了一个星期。由于前一篇文章的关注的量比较多,让我决定以后的文章尽量多加一些高质量的DEMO和配图。可能这比较耗费时间,但质量才是王道,希望大家给点时间。

上一节我们介绍了重力和屏幕环绕在三维环境下的物理效果。其实三维环境中物体的运动状态,基本上与二维环境一样,主要的运动状态无非也就是那么几个:匀速运动,加速运动,碰撞,旋转等。再往后如果想要制作更加复杂有规律的运动效果,你可能需要了解一些抽象的物理概念和数学知识:布朗运动,正态分布,矩阵变换等。本节的主要内容分为两个部分,第一部分介绍三维环境下的旋转。第二部分介绍碰撞检测。

1、坐标旋转

在二维环境下,我们要让物体做圆周运动有两种方法。第一种,需要的条件比较多:

    // centerX, centerY :旋转中心
    // angle: 角度
    // radius: 旋转半径
    ball.x = centerX + Math.sin(angle)*radius;
    ball.y = centerY + Math.cos(angle)*radius;

    //每一帧角度增加形成圆周运动
    angle += speed;

如果忘记了可以看看《每周一点canvas动画》——三角函数(2)圆周运动部分的内容。随着内容的深入,我们通过简单的三角函数变换得到一种更高级的旋转方式,它所用的条件很少:

//x1,y1是球体坐标相对旋转中心的距离
 newX = x1*cos(angle) - y1*sin(angle);
 newY = y1*cos(angle) + x1*sin(angle);

通过上面的这个公式我们同样可以做出圆周运动的效果,但所需的条件就只有一个:物体每一帧的旋转角度angle。

如果忘了,可以查看《每周一点canvas动画》——坐标旋转高级坐标旋转部分的内容。

回到三维的环境下,与二维环境下不同的是我们多了一个维度。除了x轴,y轴,还有z轴。

也就是说我们可以得出三个旋转公式:

//绕Z轴
newX = x * cos(angleZ) - y * sin(angleZ);
newY = y * cos(angleZ) + x * sin(angleZ);

//绕X轴
newY = y * cos(angleX) - z * sin(angleX);
newZ = z * cos(angleX) - y * sin(angleX);

//绕Y轴
newX = x * cos(angleY) - z * sin(angleY);
newZ = z * cos(angleY) + x * sin(angleY);

上面的公式可能相对麻烦,但是你仔细观察就会发现,绕某个轴旋转那么物体的轨迹变动就在另外两个轴形成的面上。简单来说就是,绕X轴,物体的Y,Z坐标发生变化,绕Z轴,物体的X,Y坐标发生变化,同理Y轴。这样一下是不是就好记很多。

下面我们看一看实际的效果图

在上图中,物体的旋转并不是某一个轴,而是同时绕着X轴和Y轴做旋转。代码很简单,具体查看rotate-xy.html

2、碰撞检测

在二维的平面环境中,对物体进行碰撞检测有很多方法,比如:

  1. 外接几何体碰撞检测(外接矩形,外接圆)

  2. 基于距离的碰撞检测方法

  3. 光线投射法

还有些其他的更高级的碰撞检测原理,比如分离轴定理等,大家有空可以自己去研究一下,在《HTML5 canvas核心技术》这一书中有详细的介绍。

相比于二维的环境,三维的环境更加复杂,在这里我们很难使用外接几何体和光线投射法去碰断物体之间是否发生碰撞。那么,只剩基于距离的碰撞检测了,似乎现在这是唯一的方法,但万事无绝对,总归会有更加精准,先进的方法。因为,我本身并不是做游戏开发的,所以了解有限。如果你身边有做游戏开发,尤其3D游戏开发的同学,可以向他们请教下,麻烦分享给大家。

我们知道平面上两点之间的距离是这样计算的:

dx = point1.x - point2.x;
dy = point1.y - point2.y;
distance = Math.sqrt(dx * dx + dy * dy);

同理,三维环境下两点之间的距离遵循如下公式:

dx = point1.x - point2.x;
dy = point1.y - point2.y;
dz = point1.z - point2.z;
distance = Math.sqrt(dx * dx + dy * dy + dz * dz);

下面我们就运用上面的公式做个小的DEMO。具体效果为,当物体发生碰撞后颜色变为蓝色。

核心代码如下:

。。。
 function checkCollision (ballA, i) {
        for (var ballB, dx, dy, dz, dist, j = i + 1; j < numBalls; j++) {
          ballB = balls[j];
          dx = ballA.xpos - ballB.xpos;
          dy = ballA.ypos - ballB.ypos;
          dz = ballA.zpos - ballB.zpos;
          dist = Math.sqrt(dx * dx + dy * dy + dz * dz); //距离计算
          if (dist < ballA.radius + ballB.radius) {      //检测
            ballA.color = "#0000ff";
            ballB.color = "#0000ff";
          }
        }
      }
。。。

详细代码请查看collision.html

到这里,这一章的内容就结束了。我们几乎模拟了所有在二维环境下物体的运动效果。其中最为重要的就是三维环境的搭建和物体的排序。这两段代码,让我们尽可能的实现物体的三维效果。其他的所有效果都是基于这两段代码之上。

你可能发现我们大部分做示例的物体,其实都是由原生canvas API提供的。如:圆,矩形,椭圆等。而并没有原生的API,告诉你如何创建一个三维的物体。后面的章节,我们就学习点、线、面的绘制,并以此为基础创建更加复杂的三维物体。

后面的内容可能更新会稍微慢一点.但是绝对保证质量,尽可能每一篇文章里都写一个高质量的DEMO,希望大家谅解。

以上就是对《每周一点canvas动画》——3D旋转与碰撞的相关介绍,希望对您学习javascript有所帮助,感谢您关注织梦者!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Canvas是HTML5新增的一个用于绘制图形的标签,可以通过JavaScript来控制Canvas进行图形的绘制。在进行Canvas绘制时,可以通过调整画布的位置、大小和旋转角度等属性,来控制绘制出来的图形的位置和形态。 下面我们就来介绍一下Canvas画布的移动、缩放和旋转: 1. 画布移动 画布移动可以通过Canvas提供的translate方法来实现。translate方法接收两个参数,分别表示x轴和y轴方向上的偏移量。偏移量为正值表示向右或向下移动,为负值表示向左或向上移动。 例如,我们可以通过下面的代码将画布向右移动50个像素,向下移动100个像素: ``` context.translate(50, 100); ``` 2. 画布缩放 画布缩放可以通过Canvas提供的scale方法来实现。scale方法接收两个参数,分别表示x轴和y轴方向上的缩放比例。缩放比例为大于1的值表示放大,小于1的值表示缩小。 例如,我们可以通过下面的代码将画布在x轴和y轴方向上都放大2倍: ``` context.scale(2, 2); ``` 3. 画布旋转 画布旋转可以通过Canvas提供的rotate方法来实现。rotate方法接收一个参数,表示旋转的角度,单位为弧度。 例如,我们可以通过下面的代码将画布旋转45度: ``` context.rotate(Math.PI / 4); ``` 需要注意的是,Canvas绘图的坐标系原点默认在画布的左上角,而移动、缩放和旋转操作都是相对于原点进行的。因此,在进行这些操作时,需要先将画布的原点移动到需要的位置,再进行操作。例如,如果需要将画布向右移动50个像素,需要先将原点移动到(50,0)的位置,再进行移动操作: ``` context.translate(50, 0); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值