1.1 Three.js基本框架

在本网站第1课 绘制一个三角形等一系列文章中,使用的都是WebGL原生API来编程。但之后就应该自己编写一个代码库,以用于随后的通用3D编程,这样就可以将相对复杂的原生API封装起来,提高编程效率。

现在有很多不错的WebGL开源框架,Three.js就是其中的一个,它是一个3D JavaScript库,封装了底层的图形接口,使得程序员能够在无需掌握繁冗的图形学知识的情况下,也能用简单的代码实现三维场景的渲染。它是由西班牙程序员Ricardo Cabello Miguel开发的,此人更出名的网名为Mr.doob。

Three.js在地址为http://mrdoob.github.io/three.js/,在那儿你可以下载到全部源代码、文档和示例,我使用的版本为r71。

本文会建立一个Three.js基本框架,以后的示例都是在这个框架的基础上实现的。我们会将“第1课 绘制一个三角形”的步骤用这个框架再实现一次。接下来的绝大多数示例都参考自《Learning Three.js:The Javascript 3D Library for WebGL》,在本网站可下载到此书的电子英文版和源代码。

基本框架

在WebGL原生API中,要在页面上生成内容,大致需要以下几步:

而要构建一个Three.js框架,必须拥有三样东西:

下面就是网页代码:

<!DOCTYPE html>

<html>
<head>
    <title>示例01.01 – 基本框架</title>
    <script src="Scripts/jquery-2.1.3.min.js"></script>
    <script src="Scripts/Threejs/three.min.js"></script>
    <style>
        body{
            /* 将margin设置为0,overflow设置为hidden,可让浏览器显示全屏 */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <!-- 作为Canvas容器的div -->
    <div id="WebGL-output">
</div>

<script type="text/javascript">

    // 页面加载完毕后,就可以运行Three.js了。
    $(function () {

        var stats = initStats();

        // 创建渲染器,并设置视口大小和清除色
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(0x00204d);
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 将WebGL的输出canvas放置到div中
        $("#WebGL-output").append(renderer.domElement);

        // 创建scene对象,用来容纳网格、相机、光源等对象
        var scene = new THREE.Scene();

        // 创建相机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 设置相机位置,观察目标设置为场景中央
        camera.position.x = 0;
        camera.position.y = 0;
        camera.position.z = 3;
        camera.lookAt(scene.position);

        renderer.render(scene, camera);
    });
</script>
</body>
</html>

以上代码还使用了jquery库,这不是必须的,但可以让某些DOM操作更加便捷。

若现在运行程序,只会显示墨绿色的背景,我们需要在场景中添加一个黄色的三角形。

添加网格(Mesh)对象

Three.js中绘制的绝大多数对象都是网格(Mesh),一个Mesh通常是由一个几何体(Geometry)对象和一个材质(Material)对象组合而成。

其中Geometry对象保存了Mesh对象的顶点信息和索引信息,而Material对象保存与渲染效果相关的属性。通过设置材质可以改变物体的颜色、纹理贴图、光照模式等。

Three.js并没有内置三角形的几何体对象,所以我们需要从几何体基类Geometry自己定义顶点和索引。代码如下:

var triangleGeometry = new THREE.Geometry();
// 三角形的三个顶点坐标
triangleGeometry.vertices.push(new THREE.Vector3(0.0, 0.5, 0.0));
triangleGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.0));
triangleGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.0));
// 其实是设置顶点索引
triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));

我们只需要将这个三角形设置为黄色,所以只需要用到最简单的材质——MeshBasicMaterial,代码如下:

// 设置材质,只是简单将颜色设置为黄色
var triangleMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });

最后由以上两个对象生成网格对象,并添加到场景中。

// 由几何体和材质创建网格,并添加到场景中
var triangle = new THREE.Mesh(triangleGeometry, triangleMaterial);
scene.add(triangle);

添加动画

接来下添加动画。requestAnimationFrame()函数是专门为创建脚本式动画而设计的,它比传统的setInterval()和setTimeout()方法更适合于创建动画。用setlnterval()或setTimeout()方法创建动画时,需要确定动画更新的最佳频率。但是这个最佳频率对于动画的的设计人员来说是很难确定的。但是,浏览器可以比较容易确定这个最佳频率的。浏览器上可能会同时运行多个动画,这可能会影响这个帧频。在这种情形下,浏览器会降低所有动画的帧频,这样它们就以流畅但稍低的频率执行动画。

在代码中,需要将renderer.render(scene, camera);替换为以下代码:

render();

function render() {
     // 让三角形绕y轴旋转
     triangle.rotation.y += 0.02;

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

如果现在运行代码,就可以看到一个黄色三角形正在绕竖直的y轴旋转。你会发现有一半时间三角形会变得不可见,这是因为没有在材质中没有将side属性设置为THREE.DoubleSide的缘故。

这里还引入了一个小的辅助库,它可以检测出动画的帧频。要显示这个统计图形,需要先引入这个库

<script src="Scripts/Threejs/stats.js"></script>

然后添加一个<div>元素作为容器:

<div id="Stats-output"></div>

最后初始化统计对象并添加到<div>元素中:

function initStats() {

    var stats = new Stats();

    stats.setMode(0); // 0: fps, 1: ms

    // 将状态信息放置到屏幕左上角
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';

    $("#Stats-output").append(stats.domElement);

    return stats;
}

别忘了初始化对象:

$(function () {
var stats = initStats();
…
}}

以及在render()方法中调用它的update()方法

function render() {
    stats.update();
    …
}

使用dat.GUI库

最后我们还要使用一个名为dat.GUI的库创建一个简单的用户界面,用以修改代码中的变量。

首先要在<header>元素中添加这个库:

<script src="/Scripts/Threejs/dat.gui.min.js"></script>

接下来要定义一个JavaScript对象,用来保存我们想要通过dat.GUI库修改的那些变量。本例中添加了2个变量,用来控制三角形的颜色和是否以线框模式绘制三角形。

var controls = new function () {
    this.color = triangleMaterial.color.getStyle();
    this.wireframe = triangleMaterial.wireframe;
}

接下来把这个对象传递给dat.GUI对象:

var gui = new dat.GUI();
gui.addColor(controls, 'color').onChange(function (e) {
    triangle.material.color.setStyle(e);
});
gui.add(controls, 'wireframe').onChange(function (e) {
    triangle.material.wireframe = e;
});

至此我们已经完成了全部的任务。程序截图如下:

基本框架

点击图片可观看程序。

完整代码

<!DOCTYPE html>
<html>
<head>
    <title>示例01.01 - 基本框架</title>
    <script src="Scripts/jquery-2.1.3.min.js"></script>
    <script src="Scripts/Threejs/three.min.js"></script>
    <script src="Scripts/Threejs/stats.js"></script>
    <script src="Scripts/Threejs/dat.gui.min.js"></script>    
    <style>
        body{
            /* 将margin设置为0,overflow设置为hidden,可让浏览器显示全屏 */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    
    <div id="Stats-output">
    </div>
    <!-- 作为Canvas容器的div -->
    <div id="WebGL-output">
</div>

<script type="text/javascript">

    // 页面加载完毕后,就可以运行Three.js了。
    $(function () {

        var stats = initStats();

        // 创建渲染器,并设置视口大小和清除色
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(0x00204d);
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 将WebGL的输出canvas放置到div中
        $("#WebGL-output").append(renderer.domElement);

        // 创建scene对象,用来容纳网格、相机、光源等对象
        var scene = new THREE.Scene();

        // 创建相机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 设置相机位置,观察目标设置为场景中央
        camera.position.x = 0;
        camera.position.y = 0;
        camera.position.z = 3;
        camera.lookAt(scene.position);

        var triangleGeometry = new THREE.Geometry();
        // 三角形的三个顶点坐标
        triangleGeometry.vertices.push(new THREE.Vector3(0.0, 0.5, 0.0));
        triangleGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.0));
        triangleGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.0));
        // 其实是设置顶点索引
        triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));

        // 设置材质,只是简单将颜色设置为黄色
        var triangleMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });

        // 由几何体和材质创建网格,并添加到场景中
        var triangle = new THREE.Mesh(triangleGeometry, triangleMaterial);
        scene.add(triangle);

        // 设置三角形颜色和线框模式的js对象
        var controls = new function () {
            this.color = triangleMaterial.color.getStyle();
            this.wireframe = triangleMaterial.wireframe;
        }

        // 添加用户界面
        var gui = new dat.GUI();
        gui.addColor(controls, 'color').onChange(function (e) {
            triangle.material.color.setStyle(e);
        });
        gui.add(controls, 'wireframe').onChange(function (e) {
            triangle.material.wireframe = e;
        });

        render();

        function render() {
            stats.update();

            // 让三角形绕y轴旋转
            triangle.rotation.y += 0.02;

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

        function initStats() {

            var stats = new Stats();

            stats.setMode(0); // 0: fps, 1: ms

            // 将状态信息放置到屏幕左上角
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            $("#Stats-output").append(stats.domElement);

            return stats;
        }
    });
</script>
</body>
</html>
文件下载(已下载 2305 次)

发布时间:2015/7/27 下午10:18:14  阅读次数:5294

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号