256 |
262 |
263 |
264 |
265 |
List
266 |
267 |
268 |
* 渐变/突变/条纹
269 |
将 uv 纹理坐标传递到片元着色器里
270 |
271 |
272 |
273 |
274 |
+ 添加示例
275 |
点击这里添加您自己的Three.js示例到展示容器
276 |
277 |
278 |
279 |
💡 使用说明
280 |
1. 点击示例列表中的项目加载对应的Three.js场景
281 |
2. 在代码区域查看实现代码
282 |
3. 点击"添加您的示例"将您自己的代码添加到容器
283 |
284 |
285 |
286 |
287 |
292 |
295 |
296 |
297 |
298 |
299 |
306 |
307 | // 旋转立方体示例 function initScene() { // 创建场景 const scene = new
308 | THREE.Scene(); scene.background = new THREE.Color(0x0a0a1a); //
309 |
310 |
311 |
312 |
313 |
365 |
366 |
367 |
--------------------------------------------------------------------------------
/documents/纹理.md:
--------------------------------------------------------------------------------
1 | geometry 决定了物体内在的形状,而 material 决定了物体表面的效果,其中的关键就是使用`texture`纹理。
2 |
3 | `texture`纹理 允许我们将图像应用到几何体对象上,并通过**调整纹理的属性来实现更丰富的视觉效果**。
4 |
5 | 需要注意的是 **纹理往往是 threejs 中内存占用最多的部分** (宽度 _ 高度 _ 4 \* 1.33 字节),文件越小 下载速度越快,尺寸越小 内存占用越少。
6 |
7 | 通过纹理加载器`TextureLoader`来加载纹理文件。
8 |
9 | ```js
10 | // 创建纹理加载器
11 | const loader = new THREE.TextureLoader();
12 | loader.load("../assets/grass.png", (texture) => {
13 | // 设置纹理的颜色空间 更符合人眼视觉
14 | texture.colorSpace = THREE.SRGBColorSpace;
15 | // 创建材质
16 | const lambert = new THREE.MeshLambertMaterial({
17 | map: texture,
18 | });
19 | const mesh = new THREE.Mesh(geometry, lambert);
20 | // 添加到场景
21 | scene.add(mesh);
22 | });
23 | ```
24 |
25 | 可以使用`LoadingManager`在加载纹理时获取进度 设置 loading
26 |
27 | ```js
28 | const loadManager = new THREE.LoadingManager();
29 | const loader = new THREE.TextureLoader(loadManager);
30 | // 加载进度
31 | loadManager.onProgress = (urlOfLastItemLoaded, itemsLoaded, itemsTotal) => {
32 | const progress = itemsLoaded / itemsTotal;
33 | progressBarElem.style.transform = `scaleX(${progress})`;
34 | };
35 | // 加载完成
36 | loadManager.onLoad = () => {
37 | const cube = new THREE.Mesh(geometry, materials);
38 | scene.add(cube);
39 | cubes.push(cube); // 添加到我们要旋转的立方体数组中
40 | };
41 | ```
42 |
43 | 纹理存在两种滤镜模式:放大滤镜`Magnification Filters`和缩小滤镜`Minification Filters`,它们分别定义了 纹理大于1纹理元素 和 纹理小于或等于1纹理元素
44 | ```js
45 | // 放大滤镜
46 | THREE.NearestFilter
47 | THREE.LinearFilter
48 |
49 | // 缩小滤镜
50 | THREE.NearestFilter
51 | THREE.NearestMipmapNearestFilter
52 | THREE.NearestMipmapLinearFilter
53 | THREE.LinearFilter
54 | THREE.LinearMipmapNearestFilter
55 | THREE.LinearMipmapLinearFilter
56 | ```
57 |
58 | 纹理可以重复、偏移和旋转
59 | ```js
60 | const timesToRepeatHorizontally = 4;
61 | const timesToRepeatVertically = 2;
62 | someTexture.repeat.set(timesToRepeatHorizontally, timesToRepeatVertically);
63 |
64 | const xOffset = .5; // offset by half the texture
65 | const yOffset = .25; // offset by 1/4 the texture
66 | someTexture.offset.set(xOffset, yOffset);
67 |
68 | someTexture.center.set(.5, .5); // 设置旋转中心
69 | someTexture.rotation = THREE.MathUtils.degToRad(45);
70 | ```
71 |
72 | 纹理提供了包裹模式 基于属性`Wrapping S`和`Wrapping T`
73 |
74 | * THREE.ClampToEdgeWrapping
75 | 每条边上的最后一个像素无限重复。
76 |
77 | * THREE.RepeatWrapping
78 | 纹理重复
79 |
80 | * THREE.MirroredRepeatWrapping
81 | 在每次重复时将进行镜像
--------------------------------------------------------------------------------
/documents/贴图map/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Creating a scene
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/documents/贴图map/index.js:
--------------------------------------------------------------------------------
1 | import * as THREE from "three";
2 | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
3 | import GUI from "three/examples/jsm/libs/lil-gui.module.min.js";
4 | import { RGBELoader } from "three/examples/jsm/Addons.js";
5 |
6 | const scene = new THREE.Scene();
7 | scene.background = new THREE.Color("#000");
8 | const camera = new THREE.PerspectiveCamera(
9 | 45,
10 | window.innerWidth / window.innerHeight,
11 | 1,
12 | 500
13 | );
14 | const renderer = new THREE.WebGLRenderer();
15 | renderer.setSize(window.innerWidth, window.innerHeight);
16 | // 摆设相机位置,设置视点方向
17 | camera.position.set(0, 0, 100);
18 | camera.lookAt(0, 0, 0);
19 |
20 | //创建鼠标控制器
21 | let controls = new OrbitControls(camera, renderer.domElement);
22 | //监听控制器,每次拖动后重新渲染画面
23 | controls.addEventListener("change", function () {
24 | renderer.render(scene, camera); //执行渲染操作
25 | });
26 |
27 | // 创建纹理加载器
28 | let textureLoader = new THREE.TextureLoader();
29 | const map = textureLoader.load("/textures/xxxx.png");
30 | const aoMap = textureLoader.load("/textures/xxxx.png");
31 | const alphaMap = textureLoader.load("/textures/xxxx.png");
32 | const lightMap = textureLoader.load("/textures/xxxx.png");
33 | const specularMap = textureLoader.load("/textures/xxxx.png");
34 | // 创建场景加载器
35 | const rgbeLoader = new RGBELoader();
36 | rgbeLoader.load("/textures/xxxx.hdr", (envMap) => {
37 | // 设置为环境映射模式
38 | envMap.mapping = THREE.EquirectangularReflectionMapping;
39 | // 设置为场景贴图
40 | scene.background = envMap;
41 | scene.environment = envMap; // 场景中没有环境贴图的物理材质 会以他为环境贴图
42 | // 设置材质的环境贴图
43 | planeMaterial.envMap = envMap;
44 | });
45 |
46 | const planeGeometry = new THREE.PlaneGeometry(1, 1);
47 | const planeMaterial = new THREE.MeshBasicMaterial({
48 | color: 0xffffff,
49 | map: map,
50 | transparent: true,
51 | aoMap: aoMap,
52 | alphaMap: alphaMap,
53 | lightMap: lightMap,
54 | specularMap: specularMap,
55 | reflectivity: 0.5,
56 | });
57 | const plane = new THREE.Mesh(planeGeometry, planeMaterial);
58 | scene.add(plane);
59 |
60 | GUI.add(planeMaterial, "aoMapIntensity")
61 | .min(0)
62 | .max(1)
63 | .step(0.01)
64 | .name("环境遮罩光强度");
65 |
66 | document.body.appendChild(renderer.domElement);
67 |
68 | renderer.render(scene, camera);
69 |
--------------------------------------------------------------------------------
/documents/贴图map/贴图.md:
--------------------------------------------------------------------------------
1 | MeshBasicMaterial 是提供给物体最基础的材质(不受光照影响),标准材质受光照影响
2 |
3 | 在材质中为了让效果更好,我们可以使用贴图
4 |
5 | 贴图:物体材质的背景,可以设置透明度
6 | 透明贴图:黑跟白,控制贴图展示区域的亮度
7 | 环境贴图:使贴图反射周围的光,可以设置反射率
8 | 高光贴图:控制贴图不同位置反射的情况
9 | 光照贴图:将复杂的光照信息预先计算并存储为图像
10 | 环境光遮蔽贴图:由建模提供,更深度的优化阴影和光照
11 |
12 | 在 threejs 中我们需要以代码的方式,为材质设置这些贴图
13 |
14 | - `import { RGBELoader } from "three/examples/jsm/Addons.js";` 引入 HDR 加载器
15 | - `material.map` 设置贴图
16 | - `material.aoMap` 设置环境遮罩贴图
17 | - `material.aoMapIntensity` 设置环境遮罩贴图的强度
18 | - `material.alphaMap` 设置透明贴图
19 | - `material.lightMap` 设置光照贴图
20 | - `material.specularMap` 设置高光贴图
21 | - `material.envMap` 设置环境贴图
22 | - `material.reflectivity ` 设置反射强度
23 | - `MeshPhongMaterial.bumpMap` 设置凹凸贴图
24 | - `MeshPhongMaterial.normalMap ` 设置法线贴图
--------------------------------------------------------------------------------
/documents/阴影shadow/image-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XIwE1/threejs-study-notes/220d81d1e475e7283d25ad53dac8827efba3ec23/documents/阴影shadow/image-1.png
--------------------------------------------------------------------------------
/documents/阴影shadow/image-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XIwE1/threejs-study-notes/220d81d1e475e7283d25ad53dac8827efba3ec23/documents/阴影shadow/image-2.png
--------------------------------------------------------------------------------
/documents/阴影shadow/image-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XIwE1/threejs-study-notes/220d81d1e475e7283d25ad53dac8827efba3ec23/documents/阴影shadow/image-3.png
--------------------------------------------------------------------------------
/documents/阴影shadow/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XIwE1/threejs-study-notes/220d81d1e475e7283d25ad53dac8827efba3ec23/documents/阴影shadow/image.png
--------------------------------------------------------------------------------
/documents/阴影shadow/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
shadow
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/documents/阴影shadow/index.js:
--------------------------------------------------------------------------------
1 | import * as THREE from "three";
2 | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
3 |
4 | const scene = new THREE.Scene();
5 | scene.background = new THREE.Color("#000");
6 |
7 | const camera = new THREE.PerspectiveCamera(
8 | 75,
9 | window.innerWidth / window.innerHeight,
10 | 0.1,
11 | 1000
12 | );
13 | camera.position.set(0, 10, 15);
14 |
15 | const renderer = new THREE.WebGLRenderer({ antialias: true });
16 | renderer.setSize(window.innerWidth, window.innerHeight);
17 | renderer.shadowMap.enabled = true;
18 |
19 | document.body.appendChild(renderer.domElement);
20 |
21 | const controls = new OrbitControls(camera, renderer.domElement);
22 | controls.target.set(0, 5, 0);
23 | controls.update();
24 | // controls.addEventListener("change", function () {
25 | // renderer.render(scene, camera);
26 | // });
27 |
28 | // 创建地板
29 | {
30 | const planeSize = 40;
31 | const loader = new THREE.TextureLoader();
32 | const texture = loader.load(
33 | "https://threejsfundamentals.org/threejs/resources/images/checker.png"
34 | );
35 | texture.wrapS = THREE.RepeatWrapping;
36 | texture.wrapT = THREE.RepeatWrapping;
37 | texture.magFilter = THREE.NearestFilter;
38 | texture.colorSpace = THREE.SRGBColorSpace;
39 | const repeats = planeSize / 2;
40 | texture.repeat.set(repeats, repeats);
41 | const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
42 | const planeMat = new THREE.MeshPhongMaterial({
43 | map: texture,
44 | side: THREE.DoubleSide,
45 | });
46 | const mesh = new THREE.Mesh(planeGeo, planeMat);
47 | mesh.receiveShadow = true;
48 | mesh.rotation.x = Math.PI * -0.5;
49 | scene.add(mesh);
50 | }
51 |
52 | // 创建光源
53 | {
54 | const color = 0xffffff;
55 | const intensity = 100;
56 | const light = new THREE.PointLight(color, intensity);
57 | light.castShadow = true;
58 | light.position.set(0, 10, 0);
59 | scene.add(light);
60 |
61 | const helper = new THREE.PointLightHelper(light);
62 | scene.add(helper);
63 | }
64 |
65 | // 摆放球体和立方体
66 | {
67 | const cubeSize = 4;
68 | const geometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
69 | const material = new THREE.MeshPhongMaterial({ color: "#8ac" });
70 | const cubeMesh = new THREE.Mesh(geometry, material);
71 | cubeMesh.receiveShadow = true;
72 | cubeMesh.castShadow = true;
73 | cubeMesh.position.set(cubeSize + 1, cubeSize / 2, 0);
74 | scene.add(cubeMesh);
75 |
76 | const sphereRadius = 3;
77 | const sphereWidthDivisions = 32;
78 | const sphereHeightDivisions = 16;
79 | const shpereGeo = new THREE.SphereGeometry(
80 | sphereRadius,
81 | sphereWidthDivisions,
82 | sphereHeightDivisions
83 | );
84 | const sphereMat = new THREE.MeshPhongMaterial({ color: "#8ac" });
85 | const sphereMesh = new THREE.Mesh(shpereGeo, sphereMat);
86 | sphereMesh.receiveShadow = true;
87 | sphereMesh.castShadow = true;
88 | sphereMesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
89 | scene.add(sphereMesh);
90 | }
91 |
92 | // 创建墙体用于接收阴影
93 | {
94 | const cubeSize = 30;
95 | const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
96 | const cubeMat = new THREE.MeshPhongMaterial({
97 | color: "#CCC",
98 | side: THREE.BackSide,
99 | });
100 | const mesh = new THREE.Mesh(cubeGeo, cubeMat);
101 | mesh.receiveShadow = true;
102 | mesh.position.set(0, cubeSize / 2 - 0.1, 0);
103 | scene.add(mesh);
104 | }
105 | function animation() {
106 | requestAnimationFrame(animation);
107 | renderer.render(scene, camera);
108 | }
109 | animation();
110 |
--------------------------------------------------------------------------------
/documents/阴影shadow/阴影.md:
--------------------------------------------------------------------------------
1 | Three.js 默认使用 **shadow maps(阴影贴图)**
2 |
3 | 阴影贴图的工作方式:光能够从自身开始给物体渲染阴影。(光和物体都要设置投射属性)
4 |
5 | 每个光源在投射阴影时都会重新绘制场景,多个灯光分别绘制多次。
6 | 常见解决方案:1. 允许多个光源,但只让一个光源投射阴影。 2. 使用光照贴图或者环境光贴图,但会导致静态光照
7 |
8 | 使用假阴影,例如在平面上放一个近似阴影的灰度纹理
9 |
10 | 
11 |
12 | 有三种光可以投射阴影,分别为 **DirectionalLight 方向光**、 **PointLight 点光源**、**SpotLight 聚光灯**
13 |
14 | 有几个属性需要设置:
15 |
16 | ```js
17 | // 1. 设置渲染器中的阴影属性
18 | renderer.shadowMap.enabled = true;
19 | // 2. 设置光 能投射阴影
20 | const light = new THREE.DirectionalLight(color, intensity);
21 | light.castShadow = true;
22 | // 每个网格都能被设置是否 投射阴影 和 被投射阴影
23 | // 3. 设置网格(地面)能被投射阴影
24 | mesh.receiveShadow = true;
25 | // 4. 设置球体和立方体都能投射阴影 和 被投射阴影
26 | cubeMesh.castShadow = true;
27 | cubeMesh.receiveShadow = true;
28 | ```
29 |
30 | * 将渲染器的shadowMapEnabled属性设置为true(告诉渲染器可以渲染隐形)
31 | * 将物体及光源的castShadow属性设置为true(告诉物体及光源可以透射阴影)
32 | * 将接收该阴影的物体的receiveShadow属性设置为true(告诉物体可以接收其他物体的阴影)
33 |
34 |
35 | **DirectionalLight 方向光**:
36 |
37 | 类似正交相机
38 |
39 | 
40 |
41 | **SpotLight 聚光灯**
42 |
43 | 类似透视相机
44 |
45 | 
46 |
47 | **PointLight 点光源**
48 |
49 | 只需设置near和far,相当于6个面的聚光灯组合而成,场景的阴影渲染6次。
50 |
51 | 
--------------------------------------------------------------------------------
/documents/雾fog/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XIwE1/threejs-study-notes/220d81d1e475e7283d25ad53dac8827efba3ec23/documents/雾fog/image.png
--------------------------------------------------------------------------------
/documents/雾fog/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
fog
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/documents/雾fog/index.js:
--------------------------------------------------------------------------------
1 | import * as THREE from "three";
2 | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
3 |
4 | const scene = new THREE.Scene();
5 |
6 | const camera = new THREE.PerspectiveCamera(
7 | 75,
8 | window.innerWidth / window.innerHeight,
9 | 0.1,
10 | 100
11 | );
12 | camera.position.z = 2;
13 |
14 | const renderer = new THREE.WebGLRenderer({ antialias: true });
15 | renderer.setSize(window.innerWidth, window.innerHeight);
16 | renderer.shadowMap.enabled = true;
17 |
18 | document.body.appendChild(renderer.domElement);
19 |
20 | const controls = new OrbitControls(camera, renderer.domElement);
21 | controls.update();
22 |
23 |
24 | {
25 | const color = 'lightblue';
26 | const fog = new THREE.Fog(color, 1, 2);
27 | scene.fog = fog;
28 | scene.background = new THREE.Color(color);
29 | }
30 | {
31 |
32 | const color = 0xFFFFFF;
33 | const intensity = 3;
34 | const light = new THREE.DirectionalLight( color, intensity );
35 | light.position.set( - 1, 2, 4 );
36 | scene.add( light );
37 | }
38 |
39 | const boxWidth = 1;
40 | const boxHeight = 1;
41 | const boxDepth = 1;
42 | const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
43 |
44 | function makeCubeInstance( geometry, color, x ) {
45 | const material = new THREE.MeshPhongMaterial( { color: color } );
46 | const cubeMesh = new THREE.Mesh( geometry, material );
47 | cubeMesh.position.x = x;
48 | scene.add( cubeMesh );
49 | return cubeMesh;
50 | }
51 |
52 | const cubes = [
53 | makeCubeInstance(geometry, 0x44aa88, 0),
54 | makeCubeInstance(geometry, 0x8844aa, -2),
55 | makeCubeInstance(geometry, 0xaa8844, 2),
56 | ];
57 |
58 | function animation() {
59 | requestAnimationFrame(animation);
60 | cubes.forEach((cube) => {
61 | cube.rotation.x += 0.01;
62 | cube.rotation.y += 0.01;
63 | })
64 | renderer.render(scene, camera);
65 | }
66 | animation();
67 |
--------------------------------------------------------------------------------
/documents/雾fog/雾.md:
--------------------------------------------------------------------------------
1 | 雾通常是基于 **离摄像机的指定距离褪色至某种特定颜色的方式**
2 |
3 | 添加雾是通过创建 **Fog** 或者 **FogExp2** 实例并设定**scene的fog属性**
4 |
5 | 设定 near 和 far 属性,代表距离摄像机的距离。
6 |
7 | 在 near 和 far 中间的物体,会从它们自身材料的颜色褪色到雾的颜色
8 |
9 | ```js
10 | const scene = new THREE.Scene();
11 | {
12 | const color = 0xFFFFFF; // white
13 | const near = 10;
14 | const far = 100;
15 | scene.fog = new THREE.Fog(color, near, far);
16 | }
17 | ```
18 |
19 | 
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
index
7 |
8 |
17 |
18 |
19 |
document
20 |
34 |
demo
35 |
36 |
37 | minecraft demo
38 | lineSketch demo
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "threejs-study-notes",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite --host",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/three": "^0.164.1",
13 | "vite": "^5.2.0"
14 | },
15 | "dependencies": {
16 | "@gltf-transform/cli": "^4.0.8",
17 | "global": "^4.4.0",
18 | "three": "^0.164.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------