在上一篇文章中简单地介绍了一个原生态的webGL小程序,但是通过一个例子下来,我发现原生的api对于初学者的我来说有些吃力,特别是在顶点着色器和片段着色器这两大神兽上,我纠结了十分长的时间。那么,这个世界上总有那么一些人,会为人类的进步无私地奉献。在码农界,这些大神会帮我们封装好一些很复杂的操作,开源他们的实现代码,然后为大家所用。因为是跟着《webGL入门指南》这本书的节奏,所以我也跟着书中推荐的Three.js开始学习。这一节我就在这里介绍介绍Three.js的一些基本内容。
在写代码之前,我一般都会选一个特别好用的代码编辑器,有句话叫:工欲善其事,必先利其器。我在这一周多的时间选了很多编辑器,最让我得心应手的,也就是我现在想要推荐的编辑器:webstorm(本人使用6.0.2版本,网上有很多破解的版本,主要用它来写javascript的脚本代码)以及sublime(神器不必多说,主要用它来写glsl的代码片段),这两把就是本人的刀和剑了。这两个编辑器上手很快,强烈建议使用,当然如果有更好的,请一定告诉我!
另外,请先准备好Three.js的库。
准备好一切以后,我们开始写代码。闲话不说,看看我们第一个Three.js的例子
我这个人比较懒,这个例子来自《webGL入门指南》里的2-1例子
<!DOCTYPE html>
<html>
<head>
<title>A Simple Three.js Page</title>
<scriptsrc="../libs/Three.js"></script>
<script>
function onLoad()
{
// Grab ourcontainer div
var container =document.getElementById("container");
// Create the Three.jsrenderer, add it to our div
var renderer = new THREE.WebGLRenderer();
renderer.setSize(container.offsetWidth,container.offsetHeight);
container.appendChild( renderer.domElement);
// Create a new Three.js scene
var scene = new THREE.Scene();
// Create a camera and add it to the scene
var camera = newTHREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1,4000 );
camera.position.set(0, 0, 3.3333 );
scene.add( camera );
// Now, create arectangle and add it to the scene
var geometry = newTHREE.PlaneGeometry(1, 1);
var mesh = newTHREE.Mesh( geometry, new THREE.MeshBasicMaterial( ) );
scene.add( mesh );
// Render it
renderer.render( scene, camera );
}
</script>
</head>
<body onLoad="onLoad();">
<divid="container" style="width:500px; height:500px;background-color:#000000"></div>
</body>
</html>
运行结果如下:
使用Three.js这个框架以后,一下子就把我们代码量减少了许多。不仅仅如此,在对代码的理解上,我们也会更多地关注逻辑层的实现,而不用花太多的心思关注底层的很多东西。那么,让我们就像上一节课那样把这个网页小例子拿来一步步解析:
Html部分的代码就不做太多的解释了,一个自带id的div
在js代码部分如同注释的片段的顺序,我们将js的代码分为下面这几个部分:
1. 获取div,并初始化一个renderer的渲染器,并将渲染器添加到div标签的子对象中。对应的代码:
var container =document.getElementById("container");
var renderer = new THREE.WebGLRenderer();
renderer.setSize(container.offsetWidth,container.offsetHeight);
container.appendChild( renderer.domElement );
这里给我的感觉就像是得到了HTML网页上的一张画布一样,我们之后所有的渲染和动画的过程都会在这个画布上进行。这里不用太钻牛角尖,在实际使用过程,利用copy+paste改id的方法直接就可以把这段代码拿来用了。
2. 如果我们将我们要创建的webGL应用比喻成一部电影的话,第一步做的就是准备好场地,那么第二步做的是初始化一个场景(在这个场景里面,需要什么演员,需要什么样的机位,需要做什么事情),所对应的代码如下:
var scene = newTHREE.Scene();
3. 有场地,有场景,我们还需要一部相机,不需要陈老师,因为我们写程序的就是陈老师,那么下一步就是初始化一部相机,对应的代码如下:
var camera = new THREE.PerspectiveCamera(45,container.offsetWidth / container.offsetHeight, 1, 4000 );
camera.position.set( 0, 0,3.3333 );
scene.add( camera );
我们来看看初始化相机的代码,PerspectiveCamera这个api的参数和opengl中的gluPerspective的api其实是一一对应的第一个参数表示视野角度(把相机看成自己的眼睛的话,其实感觉就是眼睛睁开的角度),第二个参数是长宽比(理解为相片的长宽比),第三个参数和第四个参数则是近侧裁剪平面和远侧裁剪平面相对于相机来说的距离。如果需要深刻理解这几个参数的话,请自行百度透视投影以及opengl中gluPerspective函数就能理解更透彻了。
而后设置相机的位置,最后向我们的场景中添加相机。
4. 我们一切都准备好了,还差演员。对于这个场景来说,演员就是那块正方形。定义一个演员在Three.js中需要有三个步骤:①定义它的几何参数;②定义它的材质;③将其放入一个网格当中。对应这三个步骤的代码就是:
var geometry = new THREE.PlaneGeometry(1,1);
var mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial( ) );
代码中将②③两步和在了一起,至于PlaneGeometry,只是Three.js事先为我们写好的有关一个矩形的实现方法,另外相关的材质MeshBasicMaterial大可不必太理会,如果要深究,可查看Three.js提供的api文档选择自己喜欢的材质。注意:几何体定义好几何参数以及材质后一定要将其放入网格中,不然无法在场景中显示。
这个演员我们造好了,下一步我们就把它放入我们的场景中
scene.add(mesh);
5. 最后一步我们用渲染renderer这个对象的render函数渲染div
renderer.render(scene,camera);
这个程序对于我们来说,是不是比上面一个例子更好理解?在此感谢为我们学习打好了坚实基础的大神mrdoob,是他编写了Three.js这样优雅简单易懂的框架。
延伸的问题:(请在理解上面的代码后查看)
在这里不禁有个问题了,在很多时候我们自己写个webGL的时候很多代码都是需要重复写的,我们可不可以自己写一个自己的框架,每次编写的时候只需要调用我们自己的函数就能避免这些重复复杂无谓的操作呢?答案是yes
具体的工作可以根据个人需要自己写写看框架。