HTML5中国

 找回密码
 立即注册

QQ登录

只需一步,快速开始

HTML5中国 首页 应用推荐 查看内容

canvas动画——3D旋转与碰撞

2016-9-19 09:20| 发布者: Hyukoh| 查看: 615| 评论: 0|原作者: 我仍旧在这里|来自: SegmentFault

摘要: 其实三维环境中物体的运动状态,基本上与二维环境一样,主要的运动状态无非也就是那么几个:匀速运动,加速运动,碰撞,旋转等。

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


  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、碰撞检测


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

  •   外接几何体碰撞检测(外接矩形,外接圆)
  •   基于距离的碰撞检测方法
  •   光线投射法

  还有些其他的更高级的碰撞检测原理,比如分离轴定理等,大家有空可以自己去研究一下,在《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,告诉你如何创建一个三维的物体。后面的章节,我们就学习点、线、面的绘制,并以此为基础创建更加复杂的三维物体。


原文链接:https://segmentfault.com/a/1190000006930544?utm_source=tuicool&utm_medium=referral

来源作者:我仍旧在这里


鲜花

握手

雷人

路过

鸡蛋
更多

相关阅读

最新评论

HTML5中国微信

小黑屋|关于我们|HTML5论坛|友情链接|手机版|HTML5中国 ( 京ICP备11006447号 京公网安备:11010802018489号  

GMT+8, 2017-1-20 03:19

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

返回顶部