Skip to content

threejs入门学习第一篇

Three.js

Three.js使用JavaScript语言对WebGL进行了封装,让前端开发人员不需要了解大量的专业知识也能够轻松进行web 3D开发,降低前端入门3D开发的门槛,提升开发效率。粗鄙的说就是:你不懂计算机图形学,只要理解了three.js的一些基本概念就可以开始入门web 3D开发

理解Three.js的基本要素

1、渲染器

WebGLRenderer负责将所有的数据渲染绘制到canvas上,即浏览器页面里。

2、场景

场景是所有物体的容器,需要绘制的数据都要塞到场景里,摄像机拍照后,交给渲染器去渲染到指定的canvas上

3、相机

摄像机默认指向Z轴负方向,上方向朝向Y轴正方向,默认放置在原点。一般是创建透视相机PerspectiveCamera,决定场景中哪些角度的内容会显示出来。
Three.js 使用的坐标系是右手坐标系,即右手伸开,拇指为X,四指为Y,手心为Z。

javascript
const fov = 75; // 视野范围,向上75度角观察。
const aspect = 2; // 相机默认值,画布宽高比,默认是2
const near = 0.1; // 可视区最近距离
const far = 5; // 可视区最远距离
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

4、网格

一个网格Mesh通常包括几何体(物体的形状)、材质以及在场景中的位置朝向等

兼容性检测 - detector.js

顾名思义,引入该文件用于判断浏览器对canvas、webgl的兼容性,页面增加不兼容的友好提示信息。

性能监视器 - stats.js

用于监视threejs运行中的刷新率,如果刷新率过低,说明我们的代码存在性能问题,我们需要对我们的代码做优化。
地址:https://github.com/mrdoob/stats.js

轨道控制器 - orbitControls.js

用于场景交互的,可以让我们用鼠标控制场景的平移、旋转、缩放等。
地址:https://github.com/mrdoob/three.js/blob/r145/examples/js/controls/OrbitControls.js

可视化控制 - dat.gui.js/lil-gui

顾名思义,就是直接在页面中,通过修改参数,改变我们的threejs对象的绘制。或者使用另外一个插件lil-gui,这个插件我在r145版本里看见在使用
地址:https://github.com/dataarts/dat.gui

一个最基础的示例 - 只是用于学习

对应的js文件

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图元</title>
    <style>
        body { margin: 0px; padding: 0px; }
        canvas { width: 100%; height: 100% }
    </style>
</head>
<body>
<canvas id="three_canvas"></canvas>
<div id="webgl_warning"></div>
<script src="../lib/three.js"></script>
<script src="../lib/detector.js"></script>
<script src="../lib/controls/orbitControls.js"></script>
<script src="../lib/stats/stats.js"></script>
<script src="../lib/dat-ui/dat.gui.js"></script>
<script>
// 准备场景、相机、渲染器、光线
let scene = null;
let camera = null;
let renderer = null;
let light = null;
let stats = null;// 性能监控
let controls = null;// 轨道控制器,必须等相机和渲染器创建完毕
let GUIOBJ = null;
let gui = null;// 可视化控制
let initThree =  function() {
    // 增加一个性能监视器
    stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild(stats.domElement);

    // 创建渲染器
    const canvas = document.querySelector('#three_canvas');
    renderer = new THREE.WebGLRenderer({canvas});// 创建渲染器,canvas可传可不传。传一个canvas对象更灵活
    renderer.setPixelRatio(window.devicePixelRatio);// 设置渲染器的分辨率倍数,分辨率越高消耗的资源越多
    renderer.setSize(window.innerWidth, window.innerHeight);// 设置渲染器的宽高

    // 创建相机
    const fov = 75;// 视野范围,垂直方向75度角
    const aspect = window.innerWidth / window.innerHeight;// 画布的宽高比,默认是2,建议使用画布在浏览器里的大小比,
    const near = 0.1;// 近平面
    const far = 1000;// 远平面,近平面和远平面限制了摄像机面朝方向的可绘区域,任何距离小于或超过这个范围的物体都将被裁剪掉(不绘制)
    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

    // 增加一个轨道控制器
    controls = new THREE.OrbitControls(camera, canvas);

    camera.position.z = 5;// 设置相机距离原点的距离,相机z轴移动,避免相机与场景里的物体重合
    // 对相机有任何操作,必须更新控制器
    controls.update();

    GUIOBJ = {
        name: "GUI Control",
        width: 1,
        height: 1,
        depth: 1,
        speed: 0.001
    };
    gui = new dat.GUI();
    gui.add(GUIOBJ, "name");
    gui.add(GUIOBJ, "width");
    gui.add(GUIOBJ, "height");
    gui.add(GUIOBJ, "depth");
    gui.add(GUIOBJ, "speed").min(0).max(1).step(0.001);

    // 创建场景
    scene = new THREE.Scene();

    // 创建一束光线
    const color = 0xFFFFFF;// 光颜色
    const intensity = 1;// 光照强度
    light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);// 设置光源发射点的位置
    scene.add(light);

    // 增加坐标轴 轴线长100
    const axes = new THREE.AxesHelper(100);
    scene.add(axes);
}

// 初始化立方体
let cube = null;
let initBox = function() {
    const boxWidth = 1;
    const boxHeight = 1;
    const boxDepth = 1;
    const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
    const material = new THREE.MeshPhongMaterial({color: 0xff0000});// MeshPhongMaterial受到灯光影响的材质
    cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
}

let animate = function (time) {
    cube.scale.x = GUIOBJ.width;
    cube.scale.y = GUIOBJ.height;
    cube.scale.z = GUIOBJ.depth;
    // 给立方体加一个小动画
    time *= GUIOBJ.speed;
    cube.rotation.x = time;
    cube.rotation.y = time;

    // 渲染场景和相机
    renderer.render(scene, camera);
    // 随动画更新性能监视器
    stats.update();
    // 随动画更新控制器 如果 controls.enableDamping 或 controls.autoRotate 设置为 true
    controls.update();
    
    // 回调动画
    requestAnimationFrame(animate);
}

if (Detector.webgl) {
    // 启动方法或其他初始化方法
    initThree();
    initBox();
    animate();
} else {
    let warning = Detector.getWebGLErrorMessage();
    document.getElementById('webgl_warning').appendChild(warning);
}
</script>
</body>
</html>

BoxGeometry 几何体

可构造立方体或者长方体等几何体

javascript
new THREE.BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
// 六个参数分别为宽x轴、高y轴、深z轴、x轴方向上分割成几份、y轴方向上分割成几份、z轴方向上分割成几份

宽、高、深这三个参数是必须的,widthSegments、heightSegments、depthSegments默认是1

CircleGeometry 圆形平面

可构造正三角形、正多边形、圆、半圆形

javascript
new THREE.CircleGeometry(radius, segments, thetaStart, thetaLength)
// 四个参数分别为半径
// 平面由多少部分分割组成,最少是3个,默认是8个
// 起始角
// 圆的角度,画多大的圆,最大是2 * Math.PI,即一个圆的弧度值

ConeGeometry 锥形

setAnimationLoop

创建动画时,建议使用渲染器的setAnimationLoop代替window.requestAnimationFrame方法

Designed & Powerd by liujun