图形化开发(二)02——Three.js之分析-创建渲染器、相机、场景 & 创建生成一个模型 & 实现动画效果
分析
<body onload="init()">
ready和onload的区别: ready加载完js和css就执行,onload必须加载完图片之后。
//初始化函数,页面加载完成是调用
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
}
第一行,我们实例化了一个THREE.WebGLRenderer,这是一个基于WebGL渲染的渲染器,当然,Three.js向下兼容,还有CanvasRenderer,CSS2DRenderer,CSS3DRenderer和SVGRenderer,这四个渲染器分别基于canvas2D,CSS2D,CSS3D和SVG渲染的渲染器。由于,作为3D渲染,WebGL渲染的效果最好,并且支持的功能更多,我们以后的课程也只会用到THREE.WebGLRenderer,需要使用其他渲染器时,会重点提示。
第二行,调用了一个设置函数
setSize
方法,这个是设置我们需要显示的窗口大小。案例我们是基于浏览器全屏显示,所以设置了浏览器窗口的宽和高。
第三行,
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
,这个相机的效果是模拟人眼看到的效果,就是具有透视的效果,近大远小。
第一行,我们实例化了一个透视相机,需要四个值分别是视野,宽高比,近裁面和远裁面。我们分别介绍一下这四个值:
- 视野:当前相机视野的宽度,值越大,渲染出来的内容也会更多。
- 宽高比:默认是按照画布的显示的宽高比例来设置,如果比例设置的不对,会发现渲染出来的画面有拉伸或者压缩的感觉。
- 近裁面和远裁面:这个是设置相机可以看到的场景内容的范围,如果场景内的内容位置不在这两个值内的话,将不会被显示到渲染的画面中。
第二行,我们设置了相机的位置。
WebGL坐标系统作为3D坐标,在原来的2D坐标xy轴上面又多了一个z轴,大家注意z轴的方向,是坐标轴朝向我们的方向是正轴,我们眼看去的方向是是z轴的负方向。
camera.position.set函数是设置当前相机的位置,函数传的三个值分别是x轴坐标,y轴坐标和z轴坐标。我们只是将相机的放到了z正轴坐标轴距离坐标原点的15的位置。相机默认的朝向是朝向0点坐标的,我们也可以设置相机的朝向,这将在后面相机介绍是,专门介绍相机的相关。
创建场景
//初始化场景
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 ); //将网格添加到场景
}
第一行代码里,我们实例化了一个
THREE.BoxGeometry
立方体的几何体对象,实例化的三个传值分别代表着立方体的长度,宽度和高度。我们全部设置的相同的值,将渲染出一个标准的正立方体。
第二行里面,我们实例化了一个THREE.MeshNormalMaterial材质,这种材质的特点是,它会根据面的朝向不同,显示不同的颜色。
第三行,通过
THREE.Mesh
方法实例化创建了一个网格对象,THREE.Mesh
实例化需要传两个值,分别是几何体对象和材质对象,才可以实例化成功。
第四行,添加
动画
function animate() {
requestAnimationFrame(animate); //循环调用函数
...
}
在循环调用的函数中,每一帧我们都让页面重新渲染相机拍摄下来的内容:
renderer.render( scene, camera ); //渲染界面
渲染的
render
方法需要两个值,第一个值是场景对象,第二个值是相机对象。这意味着,你可以有多个相机和多个场景,可以通过渲染不同的场景和相机让画布上显示不同的画面。
但是,如果现在一直渲染的话,我们发现就一个立方体在那,也没有动,我们需要做的是让立方体动起来:
mesh.rotation.x += 0.01; //每帧网格模型的沿x轴旋转0.01弧度
mesh.rotation.y += 0.02; //每帧网格模型的沿y轴旋转0.02弧度
每一个实例化的网格对象都有一个
rotation
的值,通过设置这个值可以让立方体旋转起来。在每一帧里,我们让立方体沿x轴方向旋转0.01弧度,沿y轴旋转0.02弧度(1π弧度等于180度角度)。