02 Three.js中的"Hello World”-旋转的立方体

通过Three.js中的“Hello World”-旋转的立方体来认识一下Three.js中的一些最基本的构件。

构建场景

首先,需要将Three.js库的js文件引入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>

然后在<body>标签上添加一个初始化的事件init()

<body onload="init()">

页面加载完成后,回调会触发设置的init事件。init函数里一共调用了五个方法,分别是:初始化渲染器、初始化场景、初始化相机、添加模型、添加动画:

//初始化函数,页面加载完成后调用
function init(){
  initRenderer();
  initScene();
  initCamera();
  initMesh();
  animate();
}

使用Three.js显示创建的内容,必须需要的三大件:渲染器相机场景。使用相机获取到场景内显示的内容,然后再通过渲染器渲染到画布上。

创建渲染器

//初始化渲染器
function initRenderer(){
  renderer = new THREE.WebGLRenderer(); //实例化渲染器
  renderer.setSize(window.innerWidth, window.innerHeight); //设置宽度和高度
  document.body.appendChild(renderer.domElement);//添加到DOM
}

查看initRenderer函数内的代码:

  1. 第一行首先实例化了一个THREE.WebGLRenderer的渲染器,这是一个基于WebGL渲染的渲染器。【Three.js向下兼容,还有CanvasRendererCSS2DRendererCSS3DRendererSVGRenderer,这四个渲染器分别基于canvas2DCSS2DCSS3DSVG渲染的渲染器】由于作为3D渲染,WebGL渲染的效果最好并且支持的功能更多,所以在Three.js中使用的是THREE.WebGLRenderer
  2. 第二行调用了一个setSize函数,用于设置需要显示的窗口大小。案例中是基于浏览器全屏显示所以设置了浏览器窗口的宽和高。
  3. 第三行中的renderer.domElement是在实例化渲染器的时候生成了一个canvas画布,渲染器渲染界面生成的内容都将在这个画布上显示,所以需要将这个画布添加到dom中来显示渲染的内容。

创建相机

//初始化相机
function initCamera(){
  camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); //实例化相机
  camera.position.set(0, 0, 15);
}

Three.js中有几个不同的相机,这里使用的是THREE.PerspectiveCamera,这个相机的效果是模拟人眼看到的效果,就是具有透视的效果,近大远小。

  1. 第一行首先实例化一个透视相机,需要设置四个值分别是视野、宽高比、近裁面和远裁面。

    视野:当前相机视野的宽度,值越大,渲染出来的内容也会更多。

    宽高比:默认是按照画布显示的宽高比例来设置的,如果比例设置的不对,会发现渲染出来的画面有拉伸或者压缩的感觉。

    近裁面和远裁面:这个是设置相机可以看到的场景内容的范围,如果场景内的内容位置不在这两个值内的话将不会被渲染
    显示到画面中。
     
  2. 第二行设置了相机的位置,通过WebGL的坐标系统,如下图所示:

åæ ç³»

WebGL坐标系统作为3D坐标,在原来2D坐标x、y轴的基础上又多了一个z轴,而z轴的方向是坐标轴向外的方向为正轴,向里的方向为负轴。

camera.position.set函数是设置当前相机的位置,函数传的三个值分别为x轴的坐标、y轴的坐标和z轴的坐标。

创建场景

//初始化场景
function initScene(){
  scene = new THREE.Scene(); //实例化场景
}

初始化场景函数中仅有一行代码就可以实例化一个场景对象。场景只是作为一个容器,将需要显示的内容放在场景对象中,如果需要将一个模型放入到场景中,则可以使用scene.add方法,如:

scene.add(mesh); //添加一个网格(模型)到场景

创建模型

当拥有了渲染器、场景和相机还不能显示对应的内容,因为场景中没有内容存在,即使渲染出来也是一片漆黑,所以此时需要往场景中添加内容,使用initMesh方法来创建一个最简单的模型:

//创建模型
function initMesh(){
  geometry = new THREE.BoxGeometry(2, 2, 2); // 创建几何体
  material = new THREE.MeshNormalMaterial(); // 创建材质
  mesh = new THREE.Mesh(geometry, material); // 创建网格
  scene.add(mesh); // 将网格添加到场景
}

创建一个网格(模型)需要有两种对象:几何体和材质

  • 几何体代表模型的形状,它是由固定点的位置组成,点绘制出面,面组成了模型;
  • 材质是看到当前模型显示出来的效果,如显示的颜色、质感等。
  1. 第一行代码中实例化了一个THREE.BoxGeometry立方体的几何体对象,实例化的三个传值分别代表着立方体的长度、宽度和高度。将三个值设置为相同的数值即可渲染出一个标准的正立方体。
  2. 第二行代码中实例化了一个THREE.MeshNormalMaterial材质,这种材质的特点是会根据面的朝向不同而显示不同的颜色。
  3. 第三行代码中通过THREE.Mesh方法实例化创建了一个网格对象,THREE.Mesh实例化需要传两个参数,分别是几何体对象和材质对象。
  4. 第四行代码通过场景add方法,将网格添加到了场景中,因为没有跟立方体设置位置,故而立方体会默认显示在坐标的原点上面,这个时候相机就可以拍摄到创建的立方体的画面了。

添加动画

动画即多张图片一直切换就显示出来的动画效果,为了能显示动画的效果,首先需要了解requestAnimationFrame函数,这个函数是专门为了动画而出现的一个函数,其与setInterval相比的优势在于不需要设置多长时间重新渲染,而是在当前线程内js空闲时自动渲染,并且最大帧数控制在一秒60帧。所以可以循环调用这个函数来生成动画的效果:

function animate(){
  requestAnimationFrame(animate); //循环调用函数
  ......
}

在循环调用函数的时候,每一帧都让页面重新渲染相机拍摄下来的内容:

renderer.render( scene, camera ); //渲染界面

渲染的render方法需要两个值,第一个值是场景对象,第二个值是相机对象。这意味着可以有多个相机和多个场景,并且可以通过渲染不同的场景和相机让画布上显示不同的画面。

如果仅仅是一直在渲染则立方体在原地没有动,此时需要让立方体动起来:

mesh.rotation.x += 0.06; //每一帧网格模型沿x轴旋转0.06弧度
mesh.rotation.y += 0.02; //每一帧网格模型沿y轴旋转0.02弧度

每一个实例化的网格对象都有一个rotation的值,通过设置这个值可以让立方体旋转起来,在每一帧中让立方体沿着x轴方向旋转0.06弧度、沿着y轴旋转0.02弧度(1π弧度等于180°角度)

Three.js性能检测插件

在Three.js中需要随时检测当前Three.js的性能。现在Three.js常使用的一款插件叫stats。以下介绍stats插件在Three.js中的应用方法:

  • 首先需要将插件的代码在页面中引入:
<script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>
  • 实例化一个stats对象,然后把对象内生成的dom添加到页面当中:
//性能检测框
function initStats(){
  stats = new Stats();
  document.body.appendChild(stats.dom);
}
  • 最后需要在requestAnimationFrame回调里面进行更新显示每次渲染的时间:
//运行动画
function animate(){
  requestAnimationFrame(animate); //循环调用函数
  mesh.rotation.x += 0.06; //每一帧网格模型沿x轴旋转0.06弧度
  mesh.rotation.y += 0.02; //每一帧网格模型沿y轴旋转0.02弧度
            	 
  stats.update(); //更新性能检测框
            	
  renderer.render( scene, camera ); //渲染界面
}

此时在场景中可以看到画布的左上角会有一个性能检测的小框:

前面的数值代表着当前每秒的渲染帧率,括号中的值是当前场景渲染的帧率范围。

使用了性能检测插件后,附上所有的源代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>three.js-01</title>
    <style>
      *{
          margin: 0px;
		  padding: 0px;
      }
      canvas{
          width: 100%;
          height: 100%;
          display: block;
      }
    </style>
    <script type="text/javascript" src="js/jquery-1.10.2.js"></script>
  </head>
  <body onload="init()">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>
	<script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>
	<script>
      //声明部分全局变量
      var renderer, camera, scene, geometry, material, mesh;
            
      //初始化渲染器
      function initRenderer(){
        renderer = new THREE.WebGLRenderer(); //实例化渲染器
        renderer.setSize(window.innerWidth, window.innerHeight); //设置宽度和高度
        document.body.appendChild(renderer.domElement);//添加到DOM
      }
            
      //初始化场景
      function initScene(){
        scene = new THREE.Scene(); //实例化场景
      }
            
      //初始化相机
      function initCamera(){
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); //实例化相机
        camera.position.set(0, 0, 15);
      }
            
      //创建模型
      function initMesh(){
        geometry = new THREE.BoxGeometry(2, 2, 2); // 创建几何体
        material = new THREE.MeshNormalMaterial(); // 创建材质
            	
        mesh = new THREE.Mesh(geometry, material); // 创建网格
        scene.add(mesh); // 将网格添加到场景
      }
            
      //运行动画
      function animate(){
        requestAnimationFrame(animate); //循环调用函数
        mesh.rotation.x += 0.06; //每一帧网格模型沿x轴旋转0.06弧度
        mesh.rotation.y += 0.02; //每一帧网格模型沿y轴旋转0.02弧度
            	 
        stats.update(); //更新性能检测框
            	
        renderer.render( scene, camera ); //渲染界面
      }
            
      //性能检测框
      function initStats(){
        stats = new Stats();
        document.body.appendChild(stats.dom);
      }
            
      //初始化函数,页面加载完成后调用
      function init(){
        initRenderer();
        initScene();
        initCamera();
        initMesh();
        initStats();
        animate();
      }
    </script>
  </body>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值