用WebGL编写一个3D图形网站

自己的学生生涯也差不多结束了,感觉是时候把自己这一年来学的东西做一个总结,顺便回顾一下以前做过的东西。这几天多动动手,争取写多一些内容。

WebGL简单介绍

如果有听说过OpenGL的话,那么WebGL理解起来就不是那么困难了,简单来说其实就是OpenGL在HTML5的JavaScript移植版。要是OpenGL没听说过,那就把它当成是一个在网页上的图形引擎吧。我们可以在HTML5的网页上创建Canvas(画布)来配置我们的WebGL绘制图形的过程。

要想从最基本的开始写一个很简单的程序也不是那么容易的,写过OpenGL程序的人肯定都知道,想要显示一个简单的正方形也不是一句代码就能解决的事。你得设置好视角,然后你得定义绘图方式,标出矩形每一个顶点的位置,再转换到世界坐标系等等。总之就是一切都是计算机图形学基础的东西,要想好好用WebGL这个写一个能看的动画估计就得花好长时间了。所以我们还是用点现成的东西吧,目前关于WebGL可用的库有很多,比较常用的就是Three.js。

Three.js

这个库已经写的比较完整了,已经有很多很炫的例子,可以在官网上找到。有了Three.js,很多事情变简单了许多。绘制一个3D画面的步骤就变成这样了:

  1. 在HTML网页里配置基本的画布
  2. 在画布上布置WebGL基本元素,比如立方体,球体等等
  3. 配置好Camera,加入光源,着色器等等
  4. 如果需要的话,加入对输入设备的检测,比如鼠标的点击动作
  5. 最后就是加入一个计时器不断地刷新页面,比如动态显示水面的波纹,需要随时更新水平面上点的新的法面向量

现在我们已经不需要考虑物体中每一个点的坐标变换,我们可以对整个物体进行旋转平移操作。我们也不需要编写着色器来为每一个顶点着色,设置缓存来计算每一顶点的RGB值。

前期准备

首先当然是把Three.js库下载下来,可以在Github上找到Three.js,也可一在官网的教程上下载到。我们只需要three.min.js文件就够了。

创建一个html文件,把下面的内容粘贴进去:

<html>
    <head>
        <title>My first Three.js app</title>
        <style>canvas { width: 100%; height: 100% }</style>
    </head>
    <body>
        <script src="js/three.min.js"></script>
        <script>
            // Our Javascript will go here.
        </script>
    </body>
</html>

创建场景

接下来我们要在script标签里面创建我们的场景,我们需要获取到网页窗口的大小然后告诉给渲染器

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

var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

在这里选择了投影变换的Camera,另外一种情况是正交投影的Camera,一般只在CAD工具里面会用到。

THREE.PerspectiveCamera里面的参数有四个。第一个是视角范围,这里是75度的夹角。第二个是视角比例,就是长宽比,设置成这样的值可以保证接下来创建的物体不变形,如果需要拉伸整个场景的长度或者宽度的话才需要修改这个值。

第三个和第四个值分别表示近平面和远平面的距离,这两个值决定了小于和大于多少的距离的物体会被剔除出视野外。近平面一般都设置得比较小,但绝对不能是零,因为当计算物体大小得时候是按照和Camera原点的距离比值计算的,当无限接近于Camera原点的时候物体的大小会变成无穷大。

渲染器需要知道它需要渲染的窗口大小,因此在这里设置成整个网页窗口。我们需要把设置好的元素加入到html里面。

接下来让我们创建一个立方体:

var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

我们只需要调用CubeGeometry方法就能创建一个立方体形状,同时我们需要配置这个立方体的外观,这里用MeshBasicMaterial创建,这是一个单色的材质。每一个添加到场景的物体都需要形状和材质创建,这样我们就生成了一个Mesh。

这里Camera的位置被设置成了(0,0,5),假如仍然在原点的话,网页是无法显示这个立方体的,因为Camera被放置在了立方体内部。

场景渲染

这时候我们的网页还不能显示任何东西,因为关键的渲染步骤还没有完成,我们要让网页自己定时刷新页面来显示图形。

function render() {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}
render();

requestAnimationFram函数会在用户切换到其他页面时停止刷新当前页面。

让立方体动起来

这时候打开网页,看到的只是在黑色背景里面一个绿色的正方形。因为是正对着立方体看的,所以看不出有任何的3D效果。我们可以让立方体动起来观察它,在render函数里面加入:

cube.rotation.x += 0.1;
cube.rotation.y += 0.1;

我们就可以在网页里看到一个疯狂转动的立方体了。

完整代码

<html>
    <head>
        <title>My first Three.js app</title>
        <style>canvas { width: 100%; height: 100% }</style>
    </head>
    <body>
        <script src="js/three.min.js"></script>
        <script>
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);

            var renderer = new THREE.WebGLRenderer();
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            var geometry = new THREE.CubeGeometry(1,1,1);
            var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
            var cube = new THREE.Mesh(geometry, material);
            scene.add(cube);

            camera.position.z = 5;

            var render = function () {
                requestAnimationFrame(render);

                cube.rotation.x += 0.1;
                cube.rotation.y += 0.1;

                renderer.render(scene, camera);
            };

            render();
        </script>
    </body>
</html>

可能遇到的问题

如果打开网页看到空白的页面,那是因为浏览器关闭了访问本地文件的权限,或者是three.min.js放置在了错误的目录。一定要保证three.min.js放置在html文件目录下的js文件夹内。想要避开浏览器对访问本地文件的限制,可以配置chrome绕开限制,或者在目录下开启一个http服务器。如果电脑有安装python,只需要在该目录下输入指令:

python -m SimpleHTTPServer

如果是python3的话

python3 -m http.server

其他

上面的内容主要来自Three.js官方教程,请参考网址Creating_a_scene。如果想了解WebGL,可以学习WebGL教程。想了解OpenGL,可以学习比较常用的NeHe系列教程,NeHe系列已经有中文版了。

Comments !

links

social