Jex

ThreeJS 基础学习 (1)

基础学习目标:了解三维相关概念和练习ThreeJS API

Three.js是一个基于WebGL的3D图形库,它提供了许多高级功能和工具,使得创建3D内容变得更加简单。
学习资料:
Three.js中文网
GitHub - mrdoob/three.js: JavaScript 3D Library.
three.js docs

概念

需要练习3维空间的观测效果

[✓] 1. Three.js基础概念

  • 场景(Scene):标准的场景,用于放置所有的物体和光源。

想象一个舞台,所有的演员(物体)和灯光(光源)都在这个舞台上。场景就是这个舞台,它是一个容器,用来放置你想展示的所有3D物体和光源。

  • 相机(Camera):定义了从哪个角度观察场景。
    • 透视相机(PerspectiveCamera):模拟人眼的视角,远处的物体看起来比近处的小。
    • 正交相机(OrthographicCamera):所有物体大小不变,不受距离的影响,常用于2D游戏或工程图。

相机就像是观众的眼睛,决定了我们从哪个位置和角度看这个舞台。在Three.js中,有多种相机,如透视相机和正交相机,它们决定了观看物体的方式。

  • 渲染器(Renderer):决定如何在浏览器中绘制场景。
    • WebGLRenderer:使用WebGL进行渲染的主要渲染器。
    • WebGL1Renderer:专为WebGL 1设计的渲染器。
    • CSS2DRenderer、CSS3DRenderer:使用CSS进行2D和3D渲染。
    • SVGRenderer:使用SVG进行渲染。

渲染器就像是导演,它决定了如何在浏览器中展示这个舞台和演员。它处理了所有的绘图和光影效果,确保场景看起来真实和流畅。

  • 几何体(Geometry):定义物体的形状。
    • BoxGeometry:立方体。
    • CircleGeometry:圆形。
    • ConeGeometry:圆锥体。
    • CylinderGeometry:圆柱体。
    • DodecahedronGeometry:十二面体。
    • IcosahedronGeometry:二十面体。
    • LatheGeometry:车削几何体。
    • PlaneGeometry:平面。
    • RingGeometry:环形。
    • SphereGeometry:球体。
    • TorusGeometry:圆环体。
    • TorusKnotGeometry:环形结。
    • TubeGeometry:管状体。
    • BufferGeometry:直接操作顶点数据的低级几何体,用于高性能场景。

几何体是物体的“骨架”。它定义了物体的形状,比如立方体、球体或复杂的3D模型。你可以把它想象成一个雕塑的模型。

  • 材质(Material):定义物体的外观,如颜色、光滑度等。
    • MeshBasicMaterial:基础材质,不受光照影响。
    • MeshLambertMaterial:有漫反射效果的材质。
    • MeshPhongMaterial:有高光效果的材质。
    • MeshStandardMaterial:基于物理的渲染(PBR)材质。
    • MeshPhysicalMaterial:扩展了MeshStandardMaterial,增加了更多的物理属性。
    • MeshToonMaterial:卡通风格材质。
    • ShaderMaterial:自定义着色器材质。
    • RawShaderMaterial:自定义原始着色器材质。
    • LineBasicMaterial、LineDashedMaterial:线条材质。

如果说几何体是雕塑的模型,那么材质就是这个雕塑的“皮肤”。它定义了物体的颜色、光泽、透明度等外观特性。比如,你可以给一个球体一个金属的材质,使它看起来像一个金属球。

  • 光源(Lights):场景中的光源,如点光源、方向光等。
    • AmbientLight:环境光,均匀照亮场景中的所有物体。
    • DirectionalLight:方向光,从一个方向发出的光,如太阳光。
    • HemisphereLight:半球光,上下两部分有不同的颜色。
    • PointLight:点光源,从一个点发出的光。
    • SpotLight:聚光灯,从一个点发出并沿着特定方向的光。
    • RectAreaLight:矩形区域光,发出的光形状为矩形。

光源就像是舞台上的灯光,它照亮了场景中的物体,使我们能够看到它们。不同的光源会产生不同的光照效果,如点光源是一个点发出的光,方向光则是从一个方向发出的光。

[✓] 2. 设置基本场景

学习如何设置一个基本的Three.js场景,包括创建场景、相机、渲染器,以及添加基本的几何体和光源。

[✓] 3. 加载外部模型和纹理

  • 使用GLTFLoader加载GLTF格式的3D模型。
  • 学习如何加载和应用纹理到物体上。

4. 动画和交互

  • 使用requestAnimationFrame进行动画循环。
  • 学习如何使用OrbitControls实现相机的旋转、缩放和平移。
  • 学习如何使用Raycaster实现物体的点击和交互。

5. 高级材质和光照

  • 学习使用ShaderMaterial创建自定义材质。
  • 深入了解Three.js中的各种光源和阴影效果。

6. 性能优化

  • 使用Stats.js监控渲染性能。
  • 学习如何减少几何体的顶点和面数。
  • 使用InstancedMesh进行实例化渲染。

7. 扩展和插件

  • 了解Three.js的社区和插件生态,如postprocessing库等。

8. 实践项目

选择一个小项目进行实践,如制作一个3D产品展示、一个小游戏等。

Demo

First 3D demo


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>First 3D ThreeJS</title>
</head>

<body>
  <div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>
  <script type="module">
    // 现在浏览器支持ES6语法,自然包括import方式引入js文件
    import * as THREE from 'three';
    //随便输入一个API,测试下是否已经正常引入three.js
    // console.log(THREE.Scene);
    // 扩展库OrbitControls.js
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    // 扩展库GLTFLoader.js
    import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
    //引入性能监视器stats.js
    import Stats from 'three/addons/libs/stats.module.js';

    // ------------------ 场景 ---------------------------
    // 创建3D场景对象Scene
    const scene = new THREE.Scene();
    //创建一个长方体几何对象Geometry
    const geometry = new THREE.BoxGeometry(100, 100, 100);
    //创建一个材质对象Material
    const material = new THREE.MeshBasicMaterial({
      color: 0xff0000,//0xff0000设置材质颜色为红色
      transparent: true,//开启透明
      opacity: 0.5,//设置透明度
    });

    // ------------------ 相机📷 ---------------------------
    // 实例化一个透视投影相机对象
    // 定义相机输出画布的尺寸(单位:像素px)
    const width = 800; //宽度
    const height = 500; //高度
    // 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
    const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);

    //相机在Three.js三维坐标系中的位置
    // 根据需要设置相机位置具体值
    camera.position.set(200, 200, 200);

    //相机观察目标指向Threejs 3D空间中某个位置
    camera.lookAt(0, 0, 0); //坐标原点

    const mesh = new THREE.Mesh(geometry, material);
    console.log('---------', mesh);
    // 相机位置xyz坐标:0,10,0
    mesh.position.set(0, 10, 0);
    // 相机位置xyz坐标:200, 200, 200
    camera.position.set(200, 200, 200);
    scene.add(mesh);

    // -------------------渲染器-----------
    // 创建渲染器对象
    const renderer = new THREE.WebGLRenderer();
    // 定义threejs输出画布的尺寸(单位:像素px)
    renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
    renderer.render(scene, camera); //执行渲染操作
    document.body.appendChild(renderer.domElement);
    document.getElementById('webgl').appendChild(renderer.domElement);

    // -------------控制器---------------------
    // 设置相机控件轨道控制器OrbitControls
    const controls = new OrbitControls(camera, renderer.domElement);
    // 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
    controls.addEventListener('change', function () {
      renderer.render(scene, camera); //执行渲染操作
    });//监听鼠标、键盘事件

    // -------------性能---------------
    //创建stats对象
    const stats = new Stats();
    //stats.domElement:web页面上输出计算结果,一个div元素,
    document.body.appendChild(stats.domElement);
    // 渲染函数
    function render() {
      //requestAnimationFrame循环调用的函数中调用方法update(),来刷新时间
      stats.update();
      renderer.render(scene, camera); //执行渲染操作
      requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
    }
    render();
  </script>
</body>
</html>