当前位置: 首页 > news >正文

Three.js学习

简介

Three.js 是一个基于 WebGL 的 JavaScript 3D 库,它为开发者提供了一系列易于使用的 API,让开发者能够在网页上轻松创建和展示复杂的 3D 场景、动画和交互效果,而无需深入了解 WebGL 的底层细节。下面将从其特点、应用场景和基本原理等方面详细介绍 Three.js。

特点

  • 简单易用:Three.js 对 WebGL 复杂的底层操作进行了封装,提供了直观且易于理解的 API,降低了开发 3D 网页应用的门槛。例如,创建一个简单的 3D 立方体,只需要几行代码:
import * as THREE from 'three';

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

// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 渲染循环
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
}
animate();
  • 功能强大:Three.js 支持多种几何体(如立方体、球体、平面等)、材质(如基础材质、标准材质、纹理材质等)、光照(如环境光、平行光、点光源等)、动画(如关键帧动画、Tween 动画等)以及模型加载(如 GLTF、OBJ 等格式)。
  • 跨平台兼容:由于基于 WebGL 技术,Three.js 可以在支持 WebGL 的现代浏览器(如 Chrome、Firefox、Safari 等)中运行,无需额外的插件。

应用场景

  • 游戏开发:可以利用 Three.js 创建各种类型的网页游戏,如角色扮演游戏、射击游戏、益智游戏等。通过创建 3D 场景、角色和道具,以及实现动画和交互效果,为玩家带来沉浸式的游戏体验。
  • 数据可视化:将数据以 3D 形式展示,使数据更加直观和易于理解。例如,展示地理信息、科学数据、商业数据等。
  • 虚拟现实(VR)和增强现实(AR):结合 VR 和 AR 设备,Three.js 可以创建沉浸式的虚拟和增强现实体验。例如,在网页上实现 3D 虚拟展厅、AR 购物等应用。
  • 建筑和室内设计:创建 3D 建筑模型和室内场景,让客户能够提前预览设计效果,进行交互式的漫游和体验。

基本原理

Three.js 的核心是场景(Scene)、相机(Camera)和渲染器(Renderer)。

  • 场景(Scene:是所有 3D 对象的容器,就像一个舞台,所有的物体、灯光等都将放置在这个舞台上。
  • 相机(Camera:决定了我们从哪个角度观察场景。Three.js 提供了多种类型的相机,如透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)。透视相机模拟了人眼的视觉效果,有近大远小的特点;正交相机则没有透视效果,物体的大小不会随距离变化。通过new THREE.PerspectiveCamera()创建透视相机。
  • 渲染器(Renderer:负责将场景和相机的内容渲染到网页上的画布中。Three.js 提供了多种渲染器,如 WebGL 渲染器(WebGLRenderer)和 CSS3D 渲染器(CSS3DRenderer)。通过new THREE.WebGLRenderer()创建 WebGL 渲染器。

通过组合场景、相机和渲染器,以及添加各种几何体、材质、光照和动画,就可以创建出丰富多彩的 3D 网页应用。

1. 基础设置与初始化

1.1 场景(THREE.Scene

场景是 Three.js 中所有对象的容器,就像一个舞台,所有的物体、灯光等都将放置在这个舞台上。

import * as THREE from 'three';
const scene = new THREE.Scene();

这样创建一个场景并导出供其他模块使用。

1.2 相机(THREE.PerspectiveCamera

相机决定了我们从哪个角度观察场景。PerspectiveCamera是透视相机,它模拟了人眼的视觉效果,有近大远小的特点。

// 主相机
const camera = new THREE.PerspectiveCamera(
    45, // 视角大小
    window.innerWidth / window.innerHeight, // 宽高比
    0.1, // 近裁剪面
    1000 // 远裁剪面
);
camera.position.set(0, 0, 5); // 设置相机位置

封装创建相机的函数:

const defaultOptions = {
    fov: 45,
    aspect: window.innerWidth / window.innerHeight,
    near: 0.1,
    far: 1000,
    position: [0, 0, 5]
};

const createCamera = (options = {}) => {
    const cameraOpts = Object.assign(defaultOptions, options);
    const camera = new THREE.PerspectiveCamera(...Object.values(cameraOpts));
    camera.position.set(...cameraOpts.position);
    return camera;
};

export default createCamera;

1.3 渲染器(THREE.WebGLRenderer

渲染器负责将场景和相机的内容渲染到网页上的画布中。

class Renderer extends THREE.WebGLRenderer {
    constructor(scene, camera) {
        super({ antialias: true }); // 开启抗锯齿
        this.scene = scene;
        this.camera = camera;
        this.init();
    }

    init() {
        this.setSize(window.innerWidth, window.innerHeight); // 设置渲染器大小
        document.body.appendChild(this.domElement); // 将渲染器的DOM元素添加到页面中
        this.render(this.scene, this.camera); // 渲染场景
    }

    // 创建动画函数
    animation(cb) {
        if (typeof cb!== 'function') {
            console.error('animation callback必须是一个函数');
            return;
        }
        this.setAnimationLoop(cb); // 设置动画循环
    }
}

export default Renderer;

2. 几何体与网格

2.1 几何体(THREE.BoxGeometryTHREE.PlaneGeometry等)

几何体定义了物体的形状,例如立方体、平面、球体等。

// 创建立方体几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);

// 创建平面几何体
const planeGeometry = new THREE.PlaneGeometry(30, 30);

2.2 材质(THREE.MeshBasicMaterialTHREE.MeshStandardMaterial等)

材质决定了物体的外观,如颜色、光泽等。

// 基础网格材质,不受光照影响
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });

// 标准网格材质,受光照影响
const standardMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });

不同材质的使用:

let material;
switch (val) {
    case 'basic':  // 基础网格材质(不受光照影响)
        material = new THREE.MeshBasicMaterial({
            color: materialParam.color,
            wireframe: materialParam.wireframe
        });
        break;
    case 'normal':  // 法向可视化材质
        material = new THREE.MeshNormalMaterial();
        break;
    case 'lambert':  // Lambert漫反射材质(适合哑光表面)
        material = new THREE.MeshLambertMaterial({
            color: materialParam.color
        });
        break;
    case 'phong':  // Phong高光材质(适合光滑表面)
        material = new THREE.MeshPhongMaterial({
            color: materialParam.color,
            shininess: materialParam.shininess
        });
        break;
    default:
        console.warn('未知材质类型');
        break;
}

2.3 网格(THREE.Mesh

网格是几何体和材质的组合,将形状和外观结合在一起形成一个可渲染的物体。

const mesh = new THREE.Mesh(cubeGeometry, basicMaterial);
scene.add(mesh); // 将网格添加到场景中

3. 光照

3.1 环境光(THREE.AmbientLight

环境光会均匀照亮场景中的所有物体,没有特定的方向。

const ambientLight = new THREE.AmbientLight(0xffffff, 0.2); // 颜色为白色,强度为0.2
scene.add(ambientLight);

3.2 平行光(THREE.DirectionalLight

平行光从一个特定的方向照射物体,就像太阳光一样。

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3); // 设置光源位置
scene.add(directionalLight);

如何设置平行光的阴影:

directionalLight.castShadow = true; // 开启平行光投射阴影
plane.receiveShadow = true; // 平面接收阴影
renderer.shadowMap.enabled = true; // 开启渲染器的阴影映射

4. 辅助工具

4.1 坐标轴辅助工具(THREE.AxesHelper

坐标轴辅助工具用于可视化场景中的坐标轴,方便我们确定方向。

const axesHelper = new THREE.AxesHelper(10); // 长度为10
scene.add(axesHelper);

4.2 网格辅助工具(THREE.GridHelper

网格辅助工具用于可视化场景中的网格,帮助我们确定物体的位置。

const gridHelper = new THREE.GridHelper(20, 20); // 大小为20,分割为20份
scene.add(gridHelper);

4.3 轨道控制器(OrbitControls

轨道控制器允许用户通过鼠标交互来控制相机的视角,实现旋转、缩放和平移。

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);

封装辅助工具类:

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

class Helper {
    constructor(options = {}, camera, renderer, scene) {
        const defaultOpts = {
            OrbitControls: true,
            axesHelper: { size: 10 },
            gridHelper: { size: 20, division: 20 }
        };
        this.options = Object.assign(options, defaultOpts);
        this.camera = camera;
        this.renderer = renderer;
        this.scene = scene;
        this.init();
    }

    init() {
        const { OrbitControls, axesHelper, gridHelper } = this.options;
        OrbitControls && this.initOribit();
        axesHelper && this.initAxesHelper(axesHelper);
        gridHelper && this.initGrid(gridHelper);
    }

    initOribit() {
        this.oribitControl = new OrbitControls(this.camera, this.renderer.domElement);
    }

    initAxesHelper(option) {
        const { size } = option;
        const axesHelper = new THREE.AxesHelper(size);
        this.scene.add(axesHelper);
    }

    initGrid(option) {
        const { size, division } = option;
        const grid = new THREE.GridHelper(size, division);
        this.scene.add(grid);
    }
}

export default Helper;

5. 纹理与材质

5.1 纹理加载(THREE.TextureLoader

纹理加载器用于加载图像纹理,将其应用到物体的材质上。

const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('/src/assets/texture/地球.jpeg');
const material = new THREE.MeshStandardMaterial({ map: texture });

纹理的使用:

const texture = new THREE.TextureLoader().load('/src/assets/texture/地球.jpeg');
const textureAlpha = new THREE.TextureLoader().load('/src/assets/texture/world_normal.jpg');

shpere.material = new THREE.MeshStandardMaterial({
    map: texture,
    normalMap: textureAlpha
});

6. 模型加载

6.1 GLTF 模型加载(GLTFLoader

GLTFLoader 用于加载 GLTF 或 GLB 格式的 3D 模型。

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

const gltfLoader = new GLTFLoader();
const darcoLoader = new DRACOLoader();
darcoLoader.setDecoderPath('/node_modules/three/examples/jsm/libs/draco/');
gltfLoader.setDRACOLoader(darcoLoader);

gltfLoader.load('/src/assets/models/gltf/ferrari.glb', (gltf) => {
    const model = gltf.scene;
    model.traverse(mesh => {
        if (mesh.isMesh) {
            mesh.castShadow = true;
        }
    });
    scene.add(model);
});

6.2 OBJ 模型加载(OBJLoaderMTLLoader

OBJLoader 用于加载 OBJ 格式的 3D 模型,MTLLoader 用于加载对应的材质文件。

import { MTLLoader } from 'three/addons/loaders/MTLLoader';
import { OBJLoader } from 'three/addons/loaders/OBJLoader';

const mtlLoader = new MTLLoader();
const basePath = '/src/assets/models/obj/';
mtlLoader.setPath(basePath);
mtlLoader.load('ambulance.mtl', (material) => {
    material.preload();
    const objLoader = new OBJLoader();
    objLoader.setMaterials(material);
    objLoader.load(`${basePath}ambulance.obj`, (object) => {
        object.traverse(mesh => {
            if (mesh.isMesh) {
                mesh.castShadow = true;
            }
        });
        scene.add(object);
    });
});

7. 动画

7.1 关键帧动画(THREE.KeyframeTrackTHREE.AnimationClipTHREE.AnimationMixer

关键帧动画允许我们通过定义关键帧来创建物体的动画效果。

// 1. 创建关键帧数据
const times = [0, 4, 8];
const positions = [0, 0, 0, 3, 4, 5, 0, 0, 0];
const kf = new THREE.KeyframeTrack('box.position', times, positions);

// 2. 创建剪辑对象clip
const clip = new THREE.AnimationClip('moving_clip', 8, [kf]);

// 3. 创建一个播放器mixer
const mixer = new THREE.AnimationMixer(cube);
const action = mixer.clipAction(clip);
action.play();
action.loop = THREE.LoopRepeat;

const clock = new THREE.Clock();
renderer.animation(() => {
    if (mixer) {
        mixer.update(clock.getDelta());
    }
    renderer.render(scene, camera);
});

相关文章:

  • 5分钟快速申请一个EDU教育邮箱
  • Python 编程题 第十节:重复数字、相邻字符去重、2的幂、最长公共子串、冒泡排序
  • 【2025年3月最新】Cities_Skylines:城市天际线1全DLC解锁下载与教程
  • vue中父组件与子组件的created方法执行顺序
  • Linux内核实时机制28 - RT调度器11 - RT 组调度
  • C# PaddleOCR字符识别
  • Git 使用指南
  • OSPF-5 3类LSA SummaryLSA
  • MySQL---DDL(3.17)
  • 【工作记录】F12查看接口信息及postman中使用
  • 【鸿蒙开发】Hi3861学习笔记- 定时器中断
  • 谷歌生态变革!Google Play宣布上线PC游戏平台
  • python中多重继承和泛型 作为模板让子类实现具体业务逻辑
  • MySQL 基础学习文档
  • 李宏毅NLP-1-课程介绍
  • Excel导出工具类--复杂的excel功能导出(使用自定义注解导出)
  • C++实现线程安全的队列
  • 【Spring】第二弹:通过反射机制初步理解 IoC
  • C++从入门到入土(八)——多态的原理
  • 【GIS】重要技术3DGS
  • 当创业热土遇上年轻气息,上海南汇新城发展如何再发力?
  • 阚吉林任重庆市民政局党组书记,原任市委组织部主持日常工作的副部长
  • 马云再次现身阿里打卡创业公寓“湖畔小屋”,鼓励员工坚持创业精神
  • 浙江一民企拍地后遭政府两次违约,“民告官”三年又提起民事诉讼
  • 国家主席习近平同普京总统共见记者
  • 上海将发布新一版不予行政处罚清单、首份减轻行政处罚清单