Project2 详解 

回到项目<<<

实验概况

实验要求
  制作一个和下图类似的会动的机器人

  

硬件环境

  CPU:Intel(R) Core(TM) i7-4712MQ CPU @ 2.30GHz 2.29GHZ

  Memory: 8GB

  Graphics: NVIDIA 353.62 GeForce 840M

软件环境

  OS: Windows 10 家庭版

  IDE:WebStorm 2016.2.3

  Programming Language:WebGL,JavaScript(Three.js)

WebGL介绍

   百度百科中对WebGL的介绍是:

  WebGL(全写Web Graphics Library)是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起, 通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染, 这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。

  而three.js是JavaScript编写WebGL的第三方库。

  项目二就是利用three.js库进行编程。

实验过程

1.作机器人3D图

  首先对将要作的机器人有个基本的设计,比如它的每一部分分别是由什么构成的,这里采取的设计是连接处使用球,其它部分 使用矩形或方形,以及对应几何体的大小大概是多少,之后发现有不对劲的地方,再对这些参数进行调节。

  Three.js中构造球形、长方形的方式如下:

//作出一个球

//几何特性

  var sphereGeometry = new THREE.SphereGeometry(0.5, 10, 10);

//颜色材质

  var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});

//合成球形

var RightHand= new THREE.Mesh(sphereGeometry, sphereMaterial);

  

//作一个矩形

  var cubeGeometry = new THREE.BoxGeometry(0.5, 2, 0.5);

  var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});

  var LegL=new THREE.Mesh(cubeGeometry,cubeMaterial);

  

//设置位置,把LegL对象的位置设置在(0,0,0)位置上

  LegL.position.set(0,0,0);

  

  最后作出的机器人正视图为:

2.让机器人动起来

平移旋转操作

  首先对于行走这个动作,整个身体的每个部位都会随着向前移动,也就是除了局部的平移旋转之外,还必须有个额外的整体向前平移 的步长,如何设置这个平移的大小呢,我们必须控制处于机器人迈一步的状态时,头部等基本没有局部运动的部分处于前脚和后脚的中心直线上, 所以这里设置的步长大小为一只左脚(或右脚)迈出时向前迈的距离。

//设置步长

  step=2*(2+0.5)*Math.sin(30*Math.PI/180);

  function HeadBodyGo() {

//控制基本没有局部运动的部分向前移动

//对于Tween.js的使用将在下面介绍

  var Head_tween=new TWEEN.Tween(Head.position);

  Head_tween.to({x:StartPoint-step},1000);

  var neck_tween=new TWEEN.Tween(neck.position);

  neck_tween.to({x:StartPoint-step},1000);

  var Body_tween=new TWEEN.Tween(Waist.position);

  Body_tween.to({x:StartPoint-step},1000);

  Head_tween.start();

  neck_tween.start();

  Body_tween.start();

  }

  之后就是一些局部运动的控制了:

  腿部的运动类似于手肘的运动,这里重点解释手肘的局部运动。手肘分为三个部分(Arm1,Elbow,Arm2),Arm2的运动是在Arm1的基础 上的,为了机器人不散架,首先我们是的Arm1,Elbow,Arm2先旋转一个角度Alpha1,之后Arm2在绕着Arm2的一段进行旋转Alpha2,再利用 Tween.js控制过程的连续性,就能完成运动。

  Arm1R_tween_po.to({x:StartPoint-Math.cos(-sita)-step,y:Arm1_temp-Math.sin(-sita)},1000);

  Arm1R_tween_ro.to({z:-sita},1000);

  ElbowR_tween_po.to({x:StartPoint-2.5*Math.cos(-sita)-step,y:Elbow_temp-2.25*Math.sin(-sita)},1000);

  Arm1L_tween_po.to({x:StartPoint+Math.cos(-sita)-step,y:Arm1_temp+Math.sin(-sita)},1000);

  Arm1L_tween_ro.to({z:sita},1000);

  ElbowL_tween_po.to({x:StartPoint+2.5*Math.cos(-sita)-step,y:Elbow_temp+2.25*Math.sin(-sita)},1000);

  Arm2R_tween_po.to({x:StartPoint-4*Math.cos(-sita)-step,y:Arm2_temp-3*Math.sin(-sita)},1000);

  Arm2R_tween_ro.to({z:-sita-10*Math.PI/180},1000);

  HandR_tween_po.to({x:StartPoint-3.75*Math.cos(-sita)-step,y:Hand_temp-3.75*Math.sin(-sita)},1000);

  Arm2L_tween_po.to({x:StartPoint+4*Math.cos(-sita)-step,y:Arm2_temp+3*Math.sin(-sita)},1000);

  Arm2L_tween_ro.to({z:sita-10*Math.PI/180},1000);

  HandL_tween_po.to({x:StartPoint+3.75*Math.cos(-sita)-step,y:Hand_temp+3.75*Math.sin(-sita)},1000);

让动作连续起来

  这里使用的是tween.js来使得定义某个属性在两个值之间的过渡,使得运动的过程是连续的(tweening补间)

  举个例子如下,下面这段代码是让Arm1R.position中的从当前的位置在1秒内移动到下列代码中对应的位置(其它旋转什么的类似):

  var Arm1R_tween_po=new TWEEN.Tween(Arm1R.position);

  Arm1R_tween_po.to({x:StartPoint-Math.cos(-sita)-step,y:Arm1_temp-Math.sin(-sita)},1000);

控制运动

  这里使用了一个全局变量count来计数,当count满足一定条件时迈左脚,摆右手,满足另一个条件时迈右脚,摆左手。

  if(count%40==0)

  {

  console.log("LeftGo");

  LeftGo();

  }

  else if(count%40==20)

  {

  //动作

  console.log("RightGo");

  RightGo();

  }

requestAnimationFrame

  这是three.js中用于制定一个函数,按照浏览器定义的间隔时间调用,浏览器会尽可能保证回话过程平滑、高效。这里我们就可以使得 把负责渲染的函数放进去,让动画持续进行,代码如下:

  function renderScene() {

  stats.update();

  TWEEN.update();

  ...

//再调用

  requestAnimationFrame(renderScene);

  renderer.render(scene,camera);

  }

3.一些其他细节

视角调节

  Three.js中视角用过设置视椎看向哪个方向来确定,可以类比于相机,如下图:

//这里的视角即相机视角

var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

camera.position.x = -25;

>camera.position.y = 40;

>camera.position.z = 30;

// camera.position.x=-45;

// camera.position.y=0;

// camera.position.z=0;

//设置相机看向那个方向

camera.lookAt(scene.position);

设置灯光以及阴影

var spotLight=new THREE.SpotLight(0xffffff);

spotLight.position.set(-60,60,-10);

spotLight.castShadow=true;

scene.add(spotLight);

//对于想要有影子的对象,添加这句代码

Object.receiveShadow=true;

窗口Reload

  当机器人快走出去的时候刷新一下窗口,使得又回到原来的位置继续移动

if(count==1800)

{

window.location.reload();

}

count++;

  Return>>>