【Three.js】随着元宇宙开启WEB3D之路

11,722 阅读4分钟

「这是我参与11月更文挑战的第 19 天,活动详情查看:2021最后一次更文挑战」。

当视频游戏遇到Web 2.0时会发生什么? 当虚拟世界相遇地球的地理空间地图?当模拟变成现实,生活和商业变成虚拟?当你使用虚拟地球在物理地球上导航时,你的化身就变成了你的在线代理?这一切发生的就是元宇宙。

元宇宙设想了一个由虚拟世界和3D技术广泛应用重塑的未来。Three.js 是一个非常令人印象深刻的 JavaScript 3D 库,它也使用 WebGL(或 2d Canvas)进行渲染。随着 WebGL API 标准的改进,以及对 WebXR 的支持,Three.js 成为了一个可以用来营造沉浸式体验的主流工具。与此同时,浏览器对 3D 渲染和 WebXR 设备 API 的支持也得到提升,使得 web 成为一个越来越有吸引力的 3D 内容平台。

Three.js

Three.jsRicardo Cabello(@mrdoob) 在2010年开发的一个JavaScript库(如今它在Github上有许多贡献者)。这个令人难以置信的工具让用户可以在浏览器上处理 3D 图形,使用 WebGL 技术非常简单和直观的方式来实现。而 WebGL 技术已经非常普及和被浏览器广泛支持。

1.jpg

WebGL 在许多设备和浏览器中创建丰富的交互体验,点击查看浏览器支持程度。

2.jpg

开始

本文将以 Vue 为基础框架来构建 Three.js 示例,关于代码可以查阅 GitHub

首先安装依赖:

npm install three --save

构建

现在开始添加代码到页面,如下:

<template>
    <div id="app"></div>
</template>

<script>
import * as THREE from "three";
export default {
    name: "App",
    data() {
        return {};
    },
    mounted() {
        this.init();
    },
    methods: {
        init() {
            const scene = new THREE.Scene();

            // 创建一个基本透视相机 camera
            const camera = new THREE.PerspectiveCamera(
                75,
                window.innerWidth / window.innerHeight,
                0.1,
                1000
            );
            camera.position.z = 4;

            // 创建一个抗锯齿渲染器
            const renderer = new THREE.WebGLRenderer({ antialias: true });

            // 配置渲染器清除颜色
            renderer.setClearColor("#000000");

            // 配置渲染器尺寸
            renderer.setSize(window.innerWidth, window.innerHeight);

            // 添加渲染器到DOM
            document.body.appendChild(renderer.domElement);

            // 创建一个立方体网格
            const geometry = new THREE.BoxGeometry(1, 1, 1);
            const material = new THREE.MeshBasicMaterial({ color: "#433F81" });
            const cube = new THREE.Mesh(geometry, material);

            // 将立方体到场景中
            scene.add(cube);

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

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

                renderer.render(scene, camera);
            };

            render();
        },
    },
};
</script>

然后再添加简单的样式:

body {
    margin: 0;
}
canvas {
    width: 100%;
    height: 100%;
}

执行脚本 yarn serve ,打开浏览器将看到如下效果:

h.gif

这是每个 Three.js 应用程序一种常见模式,包括 WebGlRendererSceneCamera ,如下:

  1. 创建渲染器WebGlRenderer
  2. 创建 Scene
  3. 创建Camera

渲染器是放置场景结果的地方。在 Three.js 中,可以有多个场景,每个场景可以有不同的对象。

h3.png

在示例中创建 WebGLRenderer,再将窗口的大小作为参数传递给它,然后将它附加到 DOM 中。

// 创建一个抗锯齿渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });

// 配置渲染器清除颜色
renderer.setClearColor("#000000");

// 配置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);

// 添加渲染器到DOM
document.body.appendChild(renderer.domElement);

首先需要创建一个空场景,将在其中添加创建的立方体对象:

const scene = new THREE.Scene();

最后创建一个相机 camera ,将 视野 、纵横比以及近平面和远平面作为参数:

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

到此 Three.js 应用程序的 3 个基本元素已经完成了。

几何、材料和网格

第二种常见模式是向场景添加对象:

  1. 创建几何
  2. 创建材质
  3. 创建网格
  4. 将网格添加到场景中。

在 Three.js 中,网格是几何体与材质的组合。

h4.png

几何是对象的数学公式,在 Three.js 中有很多几何,将在以后的章节中探索它,几何体提供了要添加到场景中的对象的顶点。

h5.png

材质可以定义为对象的属性及其与场景光源的行为。如下图所示,有不同类型的材料。

h6.png

现在知道了网格、几何体和材质是什么,将把它们添加到场景中。在示例中,使用基本材质创建一个立方体:

// 创建一个立方体网格
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: "#1b55e3" });
const cube = new THREE.Mesh(geometry, material);

// 将立方体到场景中
scene.add(cube);

请求动画帧

最后一段代码是为场景设置动画,使用 requestAnimationFrame,它允许有一个以每秒 60 帧(最多)运行的函数。

const render = () => {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
};

render();

立方体动画

为了在渲染循环中为立方体设置动画,需要更改它的属性。当创建一个网格时,可以访问一组在动画制作时非常有用的属性。

// Rotation (XYZ)  弧度
cube.rotation.x;
cube.rotation.y;
cube.rotation.z;

// Position (XYZ)
cube.position.x;
cube.position.y;
cube.position.z;

// Scale (XYZ)
cube.scale.x;
cube.scale.y;
cube.scale.z;

在示例中,为立方体设置 X 和 Y 旋转动画:

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

控制台

作为前端,控制台是最好的调试工具。当使用 Three.js 时,控制台是必不可少的工具。

效果增持

现在理解了示例的逻辑,将向场景中添加更多片段,目的是生成更复杂的片段。

/**
 * 创建材质的方法
 */
const createMesh = (boxOptions, meshOptions) => {
    const geometry = new THREE.BoxGeometry(...boxOptions);
    const material = new THREE.MeshBasicMaterial(meshOptions);
    return new THREE.Mesh(geometry, material);
};

const cube01 = createMesh([1, 1, 1], {
    color: "#A49FEF",
    wireframe: true,
    transparent: true,
});
scene.add(cube01);

const cube01_wireframe = createMesh([3, 3, 3], {
    color: "#433F81",
    wireframe: true,
    transparent: true,
});
scene.add(cube01_wireframe);

const cube02 = createMesh([1, 1, 1], {
    color: "#A49FEF",
});
scene.add(cube02);

const cube02_wireframe = createMesh([3, 3, 3], {
    color: "#433F81",
    wireframe: true,
    transparent: true,
});

scene.add(cube02_wireframe);

const bar01 = createMesh([10, 0.05, 0.5], {
    color: "#00FFBC",
});
bar01.position.z = 0.5;
scene.add(bar01);

const bar02 = createMesh([10, 0.05, 0.5], {
    color: "#ffffff",
});
bar02.position.z = 0.5;
scene.add(bar02);

const render = () => {
    requestAnimationFrame(render);

    cube01.rotation.x += 0.01;
    cube01.rotation.y += 0.01;

    cube01_wireframe.rotation.x += 0.01;
    cube01_wireframe.rotation.y += 0.01;

    cube02.rotation.x -= 0.01;
    cube02.rotation.y -= 0.01;

    cube02_wireframe.rotation.x -= 0.01;
    cube02_wireframe.rotation.y -= 0.01;

    bar01.rotation.z -= 0.01;
    bar02.rotation.z += 0.01;

    renderer.render(scene, camera);
};

render();

运行后效果如图:

h7.gif