云计算百科
云计算领域专业知识百科平台

Three.js初尝试(初学者学习笔记)

项目部署

# 1. 创建 Vite 项目
npm create vite@latest my-threejs-project

# 2. 进入项目目录
cd my-threejs-project

# 3. 安装基础依赖(Vite、Vue 等)
npm install

# 4. 安装 Three.js
npm install three

# 5. 【可选】如果是 TypeScript 项目,安装类型定义
npm install –save-dev @types/three
# 注意:这是为 TypeScript 提供类型提示和自动补全的依赖,
# JavaScript 项目不需要安装!

创建完后package.json中依赖如下:

有了依赖之后在想使用three.js的地方引入依赖即可

//引入three库
import * as Three form 'three'

如何用three.js创建一个几何体?

three.js有核心三大要素:scene(场景),camera(相机),renderer(渲染器)

1、场景(scene)

3d世界的容器,相当于一个展示的舞台,电影拍摄的摄影棚

//创建一个场景
const scene=new Three.Scene();

// 场景的主要属性
scene.background = new THREE.Color(0x87CEEB); // 背景颜色
scene.fog = new THREE.Fog(0x000000, 10, 100); // 雾化效果
scene.environment = environmentMap; // 环境贴图
scene.overrideMaterial = null; // 强制所有物体使用同一材质

2、相机(camera)

相当于观察者的眼睛,决定能看到什么

而相机分为两种:

透视相机 (PerspectiveCamera) 模拟人眼视角,近大远小
正交相机 (OrthographicCamera) 等轴视图,无透视变形

//创建透视相机
const camera = new Three.PerspectiveCamera(
45,//视角,数值越大视角越大,看到的东西越多(0-180)
window.innerWidth / window.innerHeight,//相机宽高比,设置的窗口大小宽高比
0.1,//近平面,最近能看到的物体位置
1000//远平面,最远能看到的物体位置
);

//创建正交相机
const camera =new Three.OrthographicCamera(
left, // 左裁剪面
right, // 右裁剪面
top, // 上裁剪面
bottom, // 下裁剪面
near, // 近裁剪面
far // 远裁剪面
);

相机通常会预先设置一些属性,如:

  • 位置 camera.position.set()
  • 看向某个点 camera.lookAt()
  • 缩放倍数 camera.zoom = ;

3、渲染器(renderer)

将3d绘制到2d画布,是展示的中最后一步

const renderer = new Three.WebGLRenderer({
canvas: canvasElement, // 使用现有canvas元素
antialias: true, // 开启抗锯齿,性能开销大
alpha: true, // 透明背景
precision: "highp", // 精度:highp/mediump/lowp

})

创建物体的完整流程

第一步:几何体定义形状

下面展示不同的常见基本图形:

//1、立方体
const boxGeometry = new Three.BoxGeometry();

// 默认值
new THREE.BoxGeometry(
1, // width: 宽度 = 1
1, // height: 高度 = 1
1, // depth: 深度 = 1
1, // widthSegments: 宽度分段数 = 1
1, // heightSegments: 高度分段数 = 1
1 // depthSegments: 深度分段数 = 1
);

// 所以以下代码创建的是:
const box = new THREE.BoxGeometry();
// 一个 1×1×1 大小的立方体,没有细分
// 只有6个面,8个顶点

//2、球体
const sphereGeometry = new Three.SphereGeometry();

// 默认值
new THREE.SphereGeometry(
1, // radius: 半径 = 1
32, // widthSegments: 水平分段数 = 32
16, // heightSegments: 垂直分段数 = 16
0, // phiStart: 水平起始角度 = 0
Math.PI * 2, // phiLength: 水平扫描角度 = 2π(360度)
0, // thetaStart: 垂直起始角度 = 0
Math.PI // thetaLength: 垂直扫描角度 = π(180度,完整球体)
);

// 所以以下代码创建的是:
const sphere = new THREE.SphereGeometry();
// 一个半径为1的完整球体
// 有32×16=512个细分面

//3、平面
const planeGeometry = new Three.PlaneGeometry();

// 默认值
new THREE.PlaneGeometry(
1, // width: 宽度 = 1
1, // height: 高度 = 1
1, // widthSegments: 宽度分段数 = 1
1 // heightSegments: 高度分段数 = 1
);

// 所以以下代码创建的是:
const plane = new THREE.PlaneGeometry();
// 一个1×1大小的平面
// 只有2个三角面,4个顶点

//4、圆柱体
const cylinderGeometry = new Three.CylinderGeometry();

// 默认值
new THREE.CylinderGeometry(
1, // radiusTop: 顶部半径 = 1
1, // radiusBottom: 底部半径 = 1
1, // height: 高度 = 1
8, // radialSegments: 径向分段数 = 8
1, // heightSegments: 高度分段数 = 1
false, // openEnded: 是否开口 = false
0, // thetaStart: 起始角度 = 0
Math.PI * 2 // thetaLength: 扫描角度 = 2π(360度,完整圆柱)
);

// 所以以下代码创建的是:
const cylinder = new THREE.CylinderGeometry();
// 一个顶部半径=1,底部半径=1,高度=1的完整圆柱
// 侧面有8个分段

第二步:材质-定义外观

材质类型对比

材质受光性能特点用途
​MeshBasicMaterial​ ❌ 否 不受光照影响,纯色或纹理 基础展示
​MeshLambertMaterial​ ✅ 是 漫反射材质,哑光效果 塑料、布料
​MeshPhongMaterial​ ✅ 是 镜面高光,光泽效果 金属、玻璃
​MeshStandardMaterial​ ✅ 是 基于物理的渲染(PBR) 真实感材质
​MeshPhysicalMaterial​ ✅ 是 标准材质的扩展,更真实 车漆、清漆
​MeshNormalMaterial​ ❌ 否 将法线显示为RGB颜色 调试用
​MeshDepthMaterial​ ❌ 否 显示深度信息 深度图
​MeshMatcapMaterial​ ❌ 否 材质捕捉材质 风格化

// 基础材质示例
const basicMaterial = new THREE.MeshBasicMaterial({
// 基础颜色
color: 0x00ff00, // 颜色(16进制)
opacity: 1.0, // 透明度(0-1)
transparent: false, // 是否透明(opacity<1时需为true)
alphaTest: 0.5, // 透明度测试阈值

// 线框模式
wireframe: false, // 是否显示为线框
wireframeLinewidth: 1, // 线框线宽

// 面渲染
side: THREE.FrontSide, // 渲染的面:FrontSide/BackSide/DoubleSide
vertexColors: false, // 是否使用顶点颜色

// 贴图
map: colorMap, // 颜色贴图
alphaMap: alphaMap, // 透明度贴图
aoMap: aoMap, // 环境光遮蔽贴图
envMap: environmentMap, // 环境贴图

// 混合模式
blending: THREE.NormalBlending, // 混合模式
depthTest: true, // 深度测试
depthWrite: true, // 深度写入
polygonOffset: false, // 多边形偏移
});

第三步:创建网格

// 创建网格(组合几何体和材质)
const mesh = new THREE.Mesh(geometry, material);

// 也可以先创建后指定材质
const mesh = new THREE.Mesh(geometry);
mesh.material = material;

总结一下思路:

  • 创建一个场景(Scene)作为容器。
  • 创建一个或多个相机(Camera)来定义视角。
  • 创建一个渲染器(Renderer)并设置大小,然后将渲染器的画布(domElement)添加到页面上。
  • 创建几何体(Geometry)和材质(Material),将它们组合成网格(Mesh),然后把网格添加到场景中。
  • 使用渲染器,传入场景和相机,进行渲染。
  • 核心对象的层级关系图

    渲染器 (Renderer)
        │
        └── canvas元素 (domElement)
        
    场景 (Scene) ← 独立于渲染器存在
        │
        ├── 相机 (Camera) ← 可以添加到场景,但不是必须
        │
        ├── 网格 (Mesh)
        │   ├── 几何体 (Geometry) ← 被网格引用
        │   └── 材质 (Material) ← 被网格引用
        │
        ├── 灯光 (Light)
        │
        ├── 辅助对象 (AxesHelper, GridHelper)
        │
        └── 其他3D对象

    首次尝试搓出一个自动旋转的正方体

    代码

    import { createApp } from 'vue'
    import './style.css'
    import App from './App.vue'
    import *as Three from "three"

    createApp(App).mount('#app')

    //1、创建场景
    const scene = new Three.Scene();

    //2、创建相机(透视相机)
    const camera = new Three.PerspectiveCamera(
    45,//视角,数值越大视角越大,看到的东西越多
    window.innerWidth / window.innerHeight,//相机宽高比设置的窗口大小宽高比
    0.1,//近平面,最近能看到的物体位置
    1000//远平面,最远能看到的物体位置
    )

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

    //测试:创建几何体
    const geometry = new Three.BoxGeometry(1, 1, 1);
    //创建材质
    const material = new Three.MeshBasicMaterial({ color: 0x00ff00 });
    //创建网格
    const cube = new Three.Mesh(geometry, material);

    //将网格添加到场景中
    scene.add(cube);

    //设置相机位置
    camera.position.z = 5;
    //相机看向?
    camera.lookAt(0, 0, 0);

    //动态渲染附加函数,渲染
    function animate() {
    requestAnimationFrame(animate);

    //实现旋转
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render(scene, camera);
    }

    //静态渲染
    // renderer.render(scene, camera);
    animate();

    关于渲染函数

    代码所示是自动旋转,而渲染函数的整体步骤和结构就应该是:

    (1)在外部提供渲染函数入口

    (2)内部先调用requestAnimationFrame(animate);

    (3)中间写变化

    (4)结尾重新渲染renderer.render(scene,camera);

    由于好奇所以又探索了如何通过鼠标来旋转:

    要引入Three官方的函数

    // 必须导入 OrbitControls
    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

    创建控制器对象:

    // 6、创建 OrbitControls
    const controls = new OrbitControls(camera, renderer.domElement);

    // 7、配置控制器
    controls.enableDamping = true; // 启用阻尼(惯性效果)
    controls.dampingFactor = 0.05; // 阻尼系数
    controls.rotateSpeed = 0.5; // 旋转速度
    controls.enableZoom = true; // 允许缩放
    controls.enablePan = true; // 允许平移
    controls.minDistance = 2; // 最小缩放距离
    controls.maxDistance = 10; // 最大缩放距离

    并且略微修改渲染函数的中间代码:

    //动态渲染附加函数,渲染
    function animate() {
    requestAnimationFrame(animate);

    //实现旋转
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    controls.update();

    renderer.render(scene, camera);
    }

    上述基本过程对于如何整合到框架中不再赘述

    添加坐标辅助器

    添加世界坐标系可以帮助我们了解位置

    //添加世界坐标辅助器(可以看成一个物体)
    const axesHelper = new Three.AxesHelper(5);//相当于设置线段长度
    scene.add(axesHelper);

    一个疑问:canvas到底是什么

    // 当你创建渲染器时
    const renderer = new THREE.WebGLRenderer();

    // 实际上内部发生了这些事:
    // 1. Three.js 在内存中创建了一个 <canvas> 元素
    // 2. 将这个 canvas 存储在 renderer.domElement
    // 3. 设置 WebGL 上下文

    // 这个 canvas 元素是:
    console.log(renderer.domElement); // 输出: <canvas></canvas>
    console.log(renderer.domElement instanceof HTMLCanvasElement); // true

    画布自适应

    为了解决用户时而会改变窗口大小但画布只渲染一次的问题,现在要解决画布自适应

    主要是更新相机的视角以及渲染器的大小(宽高)

    window.addEventListener('resize', () => {
    const width = window.innerWidth;
    const height = window.innerHeight;

    // 更新相机
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // 更新渲染器
    renderer.setSize(width, height);
    renderer.setPixelRatio(window.devicePixelRatio);
    });

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Three.js初尝试(初学者学习笔记)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!