├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── public ├── audio │ ├── bgm.mp3 │ └── roadBgm.mp3 ├── draco │ ├── README.md │ ├── draco_decoder.js │ ├── draco_decoder.wasm │ ├── draco_encoder.js │ ├── draco_wasm_wrapper.js │ └── gltf │ │ ├── draco_decoder.js │ │ ├── draco_decoder.wasm │ │ ├── draco_encoder.js │ │ └── draco_wasm_wrapper.js ├── font │ ├── AlimamaFangYuanTiVF-Thin.ttf │ ├── ali.woff │ └── ali.woff2 ├── mesh │ ├── 2024-Model3-d.glb │ ├── Driving.fbx │ ├── city_road.glb │ ├── line.glb │ ├── road-d.glb │ ├── road.glb │ ├── sm_car.gltf │ ├── sm_car_data.bin │ ├── sm_car_img0.webp │ ├── sm_car_img1.webp │ ├── sm_car_img2.webp │ ├── sm_car_img3.webp │ ├── sm_car_img4.webp │ ├── sm_car_img5.webp │ ├── sm_car_img6.webp │ ├── sm_car_img7.webp │ ├── sm_car_img8.webp │ ├── sm_speedup.gltf │ ├── sm_speedup_data.bin │ ├── sm_startroom.raw.gltf │ └── sm_startroom.raw_data.bin └── texture │ ├── decal.png │ ├── t_car_body_AO.raw.jpg │ ├── t_env_light.hdr │ ├── t_env_night.hdr │ ├── t_floor_normal.webp │ ├── t_floor_roughness.webp │ ├── t_startroom_ao.raw.jpg │ └── t_startroom_light.raw.jpg ├── src ├── Experience │ ├── Debug.ts │ ├── Experience.ts │ ├── Postprocessing.ts │ ├── Shaders │ │ ├── DynamicEnv │ │ │ ├── frag.glsl │ │ │ └── vert.glsl │ │ ├── ReflecFloor │ │ │ ├── frag.glsl │ │ │ └── vert.glsl │ │ ├── Speedup │ │ │ ├── frag.glsl │ │ │ └── vert.glsl │ │ └── TestObject │ │ │ ├── frag.glsl │ │ │ └── vert.glsl │ ├── Utils │ │ └── meshReflectorMaterial.ts │ ├── World │ │ ├── CameraShake.ts │ │ ├── Car.ts │ │ ├── City.ts │ │ ├── DynamicEnv.ts │ │ ├── Furina.ts │ │ ├── Road.ts │ │ ├── Speedup.ts │ │ ├── StartRoom.ts │ │ ├── TestObject.ts │ │ └── World.ts │ └── resources.ts ├── global.d.ts ├── main.ts ├── style.css └── vite-env.d.ts ├── style.css ├── tsconfig.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Model3ThreeJsExpo 2 | 3 | 通过Three.js创建一个互动的在线展示平台,可视化特斯拉Model 3的的部分技术。网站利用Three.js提供的API,实现了Model 3的三维模型展示、动画效果以及与用户交互的功能。 4 | 5 | 预览地址:http://model3.newhao2021.top/ 6 | 7 | github地址:https://github.com/varrff/Model3ThreeJsExpo 8 | 9 | # 使用 10 | 11 | 安装依赖 12 | 13 | ```sh 14 | pnpm i 15 | ``` 16 | 17 | 本地调试 18 | 19 | ```sh 20 | pnpm run dev 21 | ``` 22 | 23 | 构建 24 | 25 | ```sh 26 | pnpm run build 27 | ``` 28 | 29 | 预览 30 | 31 | ```sh 32 | pnpm run preview 33 | ``` 34 | 35 | 36 | 37 | # 关键概念 38 | 39 | ### Catmull-Rom样条曲线 40 | 41 | Catmull-Rom样条曲线是一种平滑的插值曲线,可以用于创建自然的路径和轨迹。在Three.js中,`THREE.CatmullRomCurve3`类用于生成三维空间中的Catmull-Rom样条曲线。该曲线通过一组控制点进行插值,生成光滑的曲线,常用于动画路径、相机路径等。 42 | 43 | 这里使用了样条曲线创建了Autopilot部分的距离预警线 44 | 45 | ### 管道几何体(Tube Geometry) 46 | 47 | 管道几何体(Tube Geometry)是Three.js中用于创建沿着一条路径生成的管状三维几何体的类。这种几何体在表示道路、轨迹、隧道等需要具有实际厚度的三维结构时非常有用。下面我们将详细介绍管道几何体的概念、创建方法及其应用。 48 | 49 | 这里使用了样条曲线创建了FSD部分的行驶预测路线 50 | 51 | # 代码部分 52 | 53 | ## World文件结构 54 | 55 | ```sh 56 | - src 57 | - World 58 | - **CameraShake.ts**: 摄像机抖动效果文件。 59 | - **Car.ts**: 汽车部分。 60 | - **City.ts**: Autopilot部分文件。 61 | - **Road.ts**: FSD部分文件。 62 | - **Speedup.ts**: 加速效果文件。 63 | - **StartRoom.ts**: 起始房间对象文件。 64 | - **TestObject.ts**: 测试对象文件。 65 | - **World.ts**: 世界管理文件,负责加载和管理整个场景中的所有对象和效果。 66 | 67 | ``` 68 | 69 | ## 首页部分 70 | 71 | 首页的加速流光效果以及相机抖动部分推荐alphardex大佬的文章:https://juejin.cn/post/7352762271003017252,也非常感谢大佬热心帮助我解决了部分问题。 72 | 73 | ## Autopilot部分(road.ts) 74 | 75 | ### `addExisting` 方法 76 | 77 | 这个方法用于将现有的模型添加到场景中,并启动动画。 78 | 79 | - **加载模型**: 从`base.am.items`中获取已经加载的GLTF模型。 80 | - **设置模型位置和缩放**: 调整模型的位置和缩放比例,使其适应场景。 81 | - **添加模型到容器**: 将模型添加到当前组件的容器中。 82 | 83 | ### `run` 方法 84 | 85 | 负责启动模型的动画循环。 86 | 87 | - **启动汽车运行**: 调用`carRun`方法开始汽车动画。 88 | - **递归动画**: 使用`requestAnimationFrame`进行递归动画,每帧更新模型的位置。 89 | 90 | ### `carRun` 方法 91 | 92 | 用于处理汽车模型的动画效果。 93 | 94 | - **克隆模型**: 使用`SkeletonUtils.clone`确保每次都是新的克隆对象。 95 | - **设置材质**: 创建并应用新的材质,使汽车模型支持光照和反射。 96 | - **创建护盾**: 调用`createShield`方法生成护盾效果。 97 | - **添加汽车到容器**: 将新的汽车模型添加到容器中。 98 | - **定义动画参数和函数**: 定义汽车动画的参数和递归动画函数`animateCar`。 99 | 100 | ### `createShield` 方法 101 | 102 | 用于创建护盾效果。 103 | 104 | - **定义控制点**: 使用`THREE.Vector3`定义护盾的路径控制点。 105 | - **创建曲线和几何体**: 用`THREE.CatmullRomCurve3`创建样条曲线,并生成对应的管道几何体。 106 | - **创建材质和纹理**: 用Canvas创建线性渐变纹理,并应用到管道材质上。 107 | - **设置动画**: 使用`gsap`实现护盾渐变动画和控制点的动态更新。 108 | 109 | ### `updateControlPoint` 方法 110 | 111 | 更新控制点的位置,使护盾效果更加动态。 112 | 113 | - **递增或递减操作**: 根据目标值和步长更新控制点的x和z坐标。 114 | - **更新曲线和几何体**: 更新样条曲线的控制点,并重新生成管道几何体。 115 | 116 | ### `removeAllModelsAndAnimations` 方法 117 | 118 | 用于移除所有模型并停止所有动画。 119 | 120 | - **移除模型和对象**: 从容器中移除道路模型、管道和汽车模型,并释放相关资源。 121 | - **停止动画循环**: 取消所有动画帧请求,停止动画。 122 | 123 | ### `playAuto` 方法 124 | 125 | 用于播放背景音乐。 126 | 127 | - **加载和播放音乐**: 使用Howl.js库加载并播放背景音乐。 128 | 129 | 130 | 131 | ## FSD部分(city.ts) 132 | 133 | ### `setCar` 方法 134 | 135 | 用于设置汽车模型,目前只是加载了汽车模型数据。 136 | 137 | ### `createRoad` 方法 138 | 139 | 用于创建道路。 140 | 141 | - **定义控制点**: 使用`THREE.Vector3`定义道路的路径控制点。 142 | - **更新道路几何体**: 调用`updateRoadGeometry`方法,根据控制点创建道路几何体。 143 | - **设置材质和动画**: 创建材质并使用GSAP动画库实现过渡动画。 144 | 145 | ### `updateRoadGeometry` 方法 146 | 147 | 更新道路几何体。 148 | 149 | - **检查控制点**: 确认控制点存在。 150 | - **创建曲线和几何体**: 用`THREE.CatmullRomCurve3`创建样条曲线,并生成管道几何体。 151 | - **调整顶点位置**: 调整几何体顶点的y坐标。 152 | - **创建材质和纹理**: 用Canvas创建线性渐变纹理,并应用到管道材质上。 153 | - **更新或创建道路对象**: 更新现有道路对象的几何体或创建新的道路对象并添加到场景中。 154 | 155 | ### `updateControlPoint` 方法 156 | 157 | 更新控制点的位置,使道路效果更加动态。 158 | 159 | - **递增或递减操作**: 根据目标值和步长更新控制点的x和z坐标。 160 | - **更新道路几何体**: 调用`updateRoadGeometry`方法更新几何体。 161 | 162 | ### `runRoad` 方法 163 | 164 | 负责启动道路的动画。 165 | 166 | - **定义多个动画步骤**: 使用GSAP库定义一系列动画,平滑地移动和旋转模型。 167 | - **启动控制点动画**: 定义和启动控制点更新动画,使道路效果动态变化。 168 | 169 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Model3 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
首页
17 |
18 |
19 |
Autopilot
20 |
21 |
22 |
FSD
23 |
24 |
25 |
Model 3
26 | 27 |
28 |

Autopilot

29 |

8 个摄像头和强大的视觉处理能力可实现 360 度视野范围,对周围环境的监测距离最远可达 250 米。

30 |

Model 3 可监测前方区域是否有车辆、摩托车、自行车或行人等物体。

31 |

如果在 Model 3 发出前撞预警时未立即采取措施,在碰撞即将发生的情况下,自动紧急制动系统(如果已启用)可能会自动进行制动。

32 |
33 | 34 |
35 |

FSD 完全自动驾驶

36 |
37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shader-template-ts", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite --port 3000 ", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "@types/howler": "^2.2.11", 13 | "@types/three": "^0.162.0", 14 | "typescript": "^5.4.3", 15 | "vite": "^5.2.7", 16 | "vite-plugin-glsl": "^1.3.0" 17 | }, 18 | "dependencies": { 19 | "furina": "^1.0.3", 20 | "gsap": "^3.12.5", 21 | "howler": "^2.2.4", 22 | "kokomi.js": "^1.9.99", 23 | "lil-gui": "^0.19.2", 24 | "lygia": "^1.1.3", 25 | "postprocessing": "^6.35.3", 26 | "simplex-noise": "^4.0.1", 27 | "three": "^0.162.0", 28 | "three-csg-ts": "^3.2.0", 29 | "three-stdlib": "^2.30.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | furina: 9 | specifier: ^1.0.3 10 | version: 1.0.3 11 | gsap: 12 | specifier: ^3.12.5 13 | version: 3.12.5 14 | howler: 15 | specifier: ^2.2.4 16 | version: 2.2.4 17 | kokomi.js: 18 | specifier: ^1.9.99 19 | version: 1.9.99(three@0.162.0) 20 | lil-gui: 21 | specifier: ^0.19.2 22 | version: 0.19.2 23 | lygia: 24 | specifier: ^1.1.3 25 | version: 1.1.3 26 | postprocessing: 27 | specifier: ^6.35.3 28 | version: 6.35.4(three@0.162.0) 29 | simplex-noise: 30 | specifier: ^4.0.1 31 | version: 4.0.1 32 | three: 33 | specifier: ^0.162.0 34 | version: 0.162.0 35 | three-stdlib: 36 | specifier: ^2.30.1 37 | version: 2.30.1(three@0.162.0) 38 | 39 | devDependencies: 40 | '@types/howler': 41 | specifier: ^2.2.11 42 | version: 2.2.11 43 | '@types/three': 44 | specifier: ^0.162.0 45 | version: 0.162.0 46 | typescript: 47 | specifier: ^5.4.3 48 | version: 5.4.5 49 | vite: 50 | specifier: ^5.2.7 51 | version: 5.2.11 52 | vite-plugin-glsl: 53 | specifier: ^1.3.0 54 | version: 1.3.0(vite@5.2.11) 55 | 56 | packages: 57 | 58 | /@esbuild/aix-ppc64@0.20.2: 59 | resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} 60 | engines: {node: '>=12'} 61 | cpu: [ppc64] 62 | os: [aix] 63 | requiresBuild: true 64 | dev: true 65 | optional: true 66 | 67 | /@esbuild/android-arm64@0.20.2: 68 | resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} 69 | engines: {node: '>=12'} 70 | cpu: [arm64] 71 | os: [android] 72 | requiresBuild: true 73 | dev: true 74 | optional: true 75 | 76 | /@esbuild/android-arm@0.20.2: 77 | resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} 78 | engines: {node: '>=12'} 79 | cpu: [arm] 80 | os: [android] 81 | requiresBuild: true 82 | dev: true 83 | optional: true 84 | 85 | /@esbuild/android-x64@0.20.2: 86 | resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} 87 | engines: {node: '>=12'} 88 | cpu: [x64] 89 | os: [android] 90 | requiresBuild: true 91 | dev: true 92 | optional: true 93 | 94 | /@esbuild/darwin-arm64@0.20.2: 95 | resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} 96 | engines: {node: '>=12'} 97 | cpu: [arm64] 98 | os: [darwin] 99 | requiresBuild: true 100 | dev: true 101 | optional: true 102 | 103 | /@esbuild/darwin-x64@0.20.2: 104 | resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} 105 | engines: {node: '>=12'} 106 | cpu: [x64] 107 | os: [darwin] 108 | requiresBuild: true 109 | dev: true 110 | optional: true 111 | 112 | /@esbuild/freebsd-arm64@0.20.2: 113 | resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} 114 | engines: {node: '>=12'} 115 | cpu: [arm64] 116 | os: [freebsd] 117 | requiresBuild: true 118 | dev: true 119 | optional: true 120 | 121 | /@esbuild/freebsd-x64@0.20.2: 122 | resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} 123 | engines: {node: '>=12'} 124 | cpu: [x64] 125 | os: [freebsd] 126 | requiresBuild: true 127 | dev: true 128 | optional: true 129 | 130 | /@esbuild/linux-arm64@0.20.2: 131 | resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} 132 | engines: {node: '>=12'} 133 | cpu: [arm64] 134 | os: [linux] 135 | requiresBuild: true 136 | dev: true 137 | optional: true 138 | 139 | /@esbuild/linux-arm@0.20.2: 140 | resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} 141 | engines: {node: '>=12'} 142 | cpu: [arm] 143 | os: [linux] 144 | requiresBuild: true 145 | dev: true 146 | optional: true 147 | 148 | /@esbuild/linux-ia32@0.20.2: 149 | resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} 150 | engines: {node: '>=12'} 151 | cpu: [ia32] 152 | os: [linux] 153 | requiresBuild: true 154 | dev: true 155 | optional: true 156 | 157 | /@esbuild/linux-loong64@0.20.2: 158 | resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} 159 | engines: {node: '>=12'} 160 | cpu: [loong64] 161 | os: [linux] 162 | requiresBuild: true 163 | dev: true 164 | optional: true 165 | 166 | /@esbuild/linux-mips64el@0.20.2: 167 | resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} 168 | engines: {node: '>=12'} 169 | cpu: [mips64el] 170 | os: [linux] 171 | requiresBuild: true 172 | dev: true 173 | optional: true 174 | 175 | /@esbuild/linux-ppc64@0.20.2: 176 | resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} 177 | engines: {node: '>=12'} 178 | cpu: [ppc64] 179 | os: [linux] 180 | requiresBuild: true 181 | dev: true 182 | optional: true 183 | 184 | /@esbuild/linux-riscv64@0.20.2: 185 | resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} 186 | engines: {node: '>=12'} 187 | cpu: [riscv64] 188 | os: [linux] 189 | requiresBuild: true 190 | dev: true 191 | optional: true 192 | 193 | /@esbuild/linux-s390x@0.20.2: 194 | resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} 195 | engines: {node: '>=12'} 196 | cpu: [s390x] 197 | os: [linux] 198 | requiresBuild: true 199 | dev: true 200 | optional: true 201 | 202 | /@esbuild/linux-x64@0.20.2: 203 | resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} 204 | engines: {node: '>=12'} 205 | cpu: [x64] 206 | os: [linux] 207 | requiresBuild: true 208 | dev: true 209 | optional: true 210 | 211 | /@esbuild/netbsd-x64@0.20.2: 212 | resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} 213 | engines: {node: '>=12'} 214 | cpu: [x64] 215 | os: [netbsd] 216 | requiresBuild: true 217 | dev: true 218 | optional: true 219 | 220 | /@esbuild/openbsd-x64@0.20.2: 221 | resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} 222 | engines: {node: '>=12'} 223 | cpu: [x64] 224 | os: [openbsd] 225 | requiresBuild: true 226 | dev: true 227 | optional: true 228 | 229 | /@esbuild/sunos-x64@0.20.2: 230 | resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} 231 | engines: {node: '>=12'} 232 | cpu: [x64] 233 | os: [sunos] 234 | requiresBuild: true 235 | dev: true 236 | optional: true 237 | 238 | /@esbuild/win32-arm64@0.20.2: 239 | resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} 240 | engines: {node: '>=12'} 241 | cpu: [arm64] 242 | os: [win32] 243 | requiresBuild: true 244 | dev: true 245 | optional: true 246 | 247 | /@esbuild/win32-ia32@0.20.2: 248 | resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} 249 | engines: {node: '>=12'} 250 | cpu: [ia32] 251 | os: [win32] 252 | requiresBuild: true 253 | dev: true 254 | optional: true 255 | 256 | /@esbuild/win32-x64@0.20.2: 257 | resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} 258 | engines: {node: '>=12'} 259 | cpu: [x64] 260 | os: [win32] 261 | requiresBuild: true 262 | dev: true 263 | optional: true 264 | 265 | /@rollup/pluginutils@5.1.0: 266 | resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} 267 | engines: {node: '>=14.0.0'} 268 | peerDependencies: 269 | rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 270 | peerDependenciesMeta: 271 | rollup: 272 | optional: true 273 | dependencies: 274 | '@types/estree': 1.0.5 275 | estree-walker: 2.0.2 276 | picomatch: 2.3.1 277 | dev: true 278 | 279 | /@rollup/rollup-android-arm-eabi@4.18.0: 280 | resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} 281 | cpu: [arm] 282 | os: [android] 283 | requiresBuild: true 284 | dev: true 285 | optional: true 286 | 287 | /@rollup/rollup-android-arm64@4.18.0: 288 | resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} 289 | cpu: [arm64] 290 | os: [android] 291 | requiresBuild: true 292 | dev: true 293 | optional: true 294 | 295 | /@rollup/rollup-darwin-arm64@4.18.0: 296 | resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} 297 | cpu: [arm64] 298 | os: [darwin] 299 | requiresBuild: true 300 | dev: true 301 | optional: true 302 | 303 | /@rollup/rollup-darwin-x64@4.18.0: 304 | resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} 305 | cpu: [x64] 306 | os: [darwin] 307 | requiresBuild: true 308 | dev: true 309 | optional: true 310 | 311 | /@rollup/rollup-linux-arm-gnueabihf@4.18.0: 312 | resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} 313 | cpu: [arm] 314 | os: [linux] 315 | requiresBuild: true 316 | dev: true 317 | optional: true 318 | 319 | /@rollup/rollup-linux-arm-musleabihf@4.18.0: 320 | resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} 321 | cpu: [arm] 322 | os: [linux] 323 | requiresBuild: true 324 | dev: true 325 | optional: true 326 | 327 | /@rollup/rollup-linux-arm64-gnu@4.18.0: 328 | resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} 329 | cpu: [arm64] 330 | os: [linux] 331 | requiresBuild: true 332 | dev: true 333 | optional: true 334 | 335 | /@rollup/rollup-linux-arm64-musl@4.18.0: 336 | resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} 337 | cpu: [arm64] 338 | os: [linux] 339 | requiresBuild: true 340 | dev: true 341 | optional: true 342 | 343 | /@rollup/rollup-linux-powerpc64le-gnu@4.18.0: 344 | resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} 345 | cpu: [ppc64] 346 | os: [linux] 347 | requiresBuild: true 348 | dev: true 349 | optional: true 350 | 351 | /@rollup/rollup-linux-riscv64-gnu@4.18.0: 352 | resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} 353 | cpu: [riscv64] 354 | os: [linux] 355 | requiresBuild: true 356 | dev: true 357 | optional: true 358 | 359 | /@rollup/rollup-linux-s390x-gnu@4.18.0: 360 | resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} 361 | cpu: [s390x] 362 | os: [linux] 363 | requiresBuild: true 364 | dev: true 365 | optional: true 366 | 367 | /@rollup/rollup-linux-x64-gnu@4.18.0: 368 | resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} 369 | cpu: [x64] 370 | os: [linux] 371 | requiresBuild: true 372 | dev: true 373 | optional: true 374 | 375 | /@rollup/rollup-linux-x64-musl@4.18.0: 376 | resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} 377 | cpu: [x64] 378 | os: [linux] 379 | requiresBuild: true 380 | dev: true 381 | optional: true 382 | 383 | /@rollup/rollup-win32-arm64-msvc@4.18.0: 384 | resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} 385 | cpu: [arm64] 386 | os: [win32] 387 | requiresBuild: true 388 | dev: true 389 | optional: true 390 | 391 | /@rollup/rollup-win32-ia32-msvc@4.18.0: 392 | resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} 393 | cpu: [ia32] 394 | os: [win32] 395 | requiresBuild: true 396 | dev: true 397 | optional: true 398 | 399 | /@rollup/rollup-win32-x64-msvc@4.18.0: 400 | resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} 401 | cpu: [x64] 402 | os: [win32] 403 | requiresBuild: true 404 | dev: true 405 | optional: true 406 | 407 | /@tweenjs/tween.js@23.1.2: 408 | resolution: {integrity: sha512-kMCNaZCJugWI86xiEHaY338CU5JpD0B97p1j1IKNn/Zto8PgACjQx0UxbHjmOcLl/dDOBnItwD07KmCs75pxtQ==} 409 | dev: true 410 | 411 | /@types/draco3d@1.4.10: 412 | resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==} 413 | dev: false 414 | 415 | /@types/estree@1.0.5: 416 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 417 | dev: true 418 | 419 | /@types/howler@2.2.11: 420 | resolution: {integrity: sha512-7aBoUL6RbSIrqKnpEgfa1wSNUBK06mn08siP2QI0zYk7MXfEJAaORc4tohamQYqCqVESoDyRWSdQn2BOKWj2Qw==} 421 | dev: true 422 | 423 | /@types/offscreencanvas@2019.7.3: 424 | resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} 425 | dev: false 426 | 427 | /@types/stats.js@0.17.3: 428 | resolution: {integrity: sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==} 429 | dev: true 430 | 431 | /@types/three@0.162.0: 432 | resolution: {integrity: sha512-0j5yZcVukVIhrhSIC7+LmBPkkMoMuEJ1AfYBZfgNytdYqYREMuiyXWhYOMeZLBElTEAlJIZn7r2W3vqTIgjWlg==} 433 | dependencies: 434 | '@tweenjs/tween.js': 23.1.2 435 | '@types/stats.js': 0.17.3 436 | '@types/webxr': 0.5.16 437 | fflate: 0.6.10 438 | meshoptimizer: 0.18.1 439 | dev: true 440 | 441 | /@types/webxr@0.5.16: 442 | resolution: {integrity: sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==} 443 | 444 | /bidi-js@1.0.3: 445 | resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} 446 | dependencies: 447 | require-from-string: 2.0.2 448 | dev: false 449 | 450 | /blueimp-md5@2.19.0: 451 | resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} 452 | dev: false 453 | 454 | /camera-controls@2.8.3(three@0.162.0): 455 | resolution: {integrity: sha512-zFjqUR6onLkG+z1A6vAWfzovxZxWVSvp6e5t3lfZgfgPZtX3n74aykNAUaoRbq8Y3tOxadHkDjbfGDOP9hFf2w==} 456 | peerDependencies: 457 | three: '>=0.126.1' 458 | dependencies: 459 | three: 0.162.0 460 | dev: false 461 | 462 | /cannon-es@0.20.0: 463 | resolution: {integrity: sha512-eZhWTZIkFOnMAJOgfXJa9+b3kVlvG+FX4mdkpePev/w/rP5V8NRquGyEozcjPfEoXUlb+p7d9SUcmDSn14prOA==} 464 | dev: false 465 | 466 | /core-util-is@1.0.3: 467 | resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} 468 | dev: false 469 | 470 | /draco3d@1.5.7: 471 | resolution: {integrity: sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==} 472 | dev: false 473 | 474 | /esbuild@0.20.2: 475 | resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} 476 | engines: {node: '>=12'} 477 | hasBin: true 478 | requiresBuild: true 479 | optionalDependencies: 480 | '@esbuild/aix-ppc64': 0.20.2 481 | '@esbuild/android-arm': 0.20.2 482 | '@esbuild/android-arm64': 0.20.2 483 | '@esbuild/android-x64': 0.20.2 484 | '@esbuild/darwin-arm64': 0.20.2 485 | '@esbuild/darwin-x64': 0.20.2 486 | '@esbuild/freebsd-arm64': 0.20.2 487 | '@esbuild/freebsd-x64': 0.20.2 488 | '@esbuild/linux-arm': 0.20.2 489 | '@esbuild/linux-arm64': 0.20.2 490 | '@esbuild/linux-ia32': 0.20.2 491 | '@esbuild/linux-loong64': 0.20.2 492 | '@esbuild/linux-mips64el': 0.20.2 493 | '@esbuild/linux-ppc64': 0.20.2 494 | '@esbuild/linux-riscv64': 0.20.2 495 | '@esbuild/linux-s390x': 0.20.2 496 | '@esbuild/linux-x64': 0.20.2 497 | '@esbuild/netbsd-x64': 0.20.2 498 | '@esbuild/openbsd-x64': 0.20.2 499 | '@esbuild/sunos-x64': 0.20.2 500 | '@esbuild/win32-arm64': 0.20.2 501 | '@esbuild/win32-ia32': 0.20.2 502 | '@esbuild/win32-x64': 0.20.2 503 | dev: true 504 | 505 | /estree-walker@2.0.2: 506 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 507 | dev: true 508 | 509 | /ev-emitter@2.1.2: 510 | resolution: {integrity: sha512-jQ5Ql18hdCQ4qS+RCrbLfz1n+Pags27q5TwMKvZyhp5hh2UULUYZUy1keqj6k6SYsdqIYjnmz7xyyEY0V67B8Q==} 511 | dev: false 512 | 513 | /fflate@0.6.10: 514 | resolution: {integrity: sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==} 515 | 516 | /fsevents@2.3.3: 517 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 518 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 519 | os: [darwin] 520 | requiresBuild: true 521 | dev: true 522 | optional: true 523 | 524 | /furina@1.0.3: 525 | resolution: {integrity: sha512-kGY0Roq6Y49XtWPYdubUzwDTybhc9opzUDF1HsVhwIaMO6sY7jqoktudu6d9rHB4b1BbrMyhSV3IM4G9Lx6U8g==} 526 | dev: false 527 | 528 | /glsl-token-functions@1.0.1: 529 | resolution: {integrity: sha512-EigGhp1g+aUVeUNY7H1o5tL/bnwIB3/FcRREPr2E7Du+/UDXN24hDkaZ3e4aWHDjHr9lJ6YHXMISkwhUYg9UOg==} 530 | dev: false 531 | 532 | /glsl-token-string@1.0.1: 533 | resolution: {integrity: sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg==} 534 | dev: false 535 | 536 | /glsl-tokenizer@2.1.5: 537 | resolution: {integrity: sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==} 538 | dependencies: 539 | through2: 0.6.5 540 | dev: false 541 | 542 | /gsap@3.12.5: 543 | resolution: {integrity: sha512-srBfnk4n+Oe/ZnMIOXt3gT605BX9x5+rh/prT2F1SsNJsU1XuMiP0E2aptW481OnonOGACZWBqseH5Z7csHxhQ==} 544 | dev: false 545 | 546 | /howler@2.2.4: 547 | resolution: {integrity: sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==} 548 | dev: false 549 | 550 | /imagesloaded@5.0.0: 551 | resolution: {integrity: sha512-/0JGSubc1MTCoDKVmonLHgbifBWHdyLkun+R/151E1c5n79hiSxcd7cB7mPXFgojYu8xnRZv7GYxzKoxW8BetQ==} 552 | dependencies: 553 | ev-emitter: 2.1.2 554 | dev: false 555 | 556 | /inherits@2.0.4: 557 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 558 | dev: false 559 | 560 | /isarray@0.0.1: 561 | resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} 562 | dev: false 563 | 564 | /kokomi.js@1.9.99(three@0.162.0): 565 | resolution: {integrity: sha512-8ZF+PUny8h0P/VFOo9FmCa1ipk1tzLBw7PD6pDeomuErqEcoxq+V7Ld0cLahykK9j9U9q129qKr/xmx/VBpwPw==} 566 | peerDependencies: 567 | three: '>=0.137' 568 | dependencies: 569 | blueimp-md5: 2.19.0 570 | camera-controls: 2.8.3(three@0.162.0) 571 | cannon-es: 0.20.0 572 | gsap: 3.12.5 573 | imagesloaded: 5.0.0 574 | maku.js: 1.0.8(three@0.162.0) 575 | marcher.js: 1.4.3 576 | mitt: 3.0.1 577 | nipplejs: 0.10.2 578 | simplex-noise: 4.0.1 579 | stats.js: 0.17.0 580 | three: 0.162.0 581 | three-custom-shader-material: 5.4.0(three@0.162.0) 582 | three-stdlib: 2.30.1(three@0.162.0) 583 | three.interactive: 1.7.0(three@0.162.0) 584 | troika-three-text: 0.49.1(three@0.162.0) 585 | transitivePeerDependencies: 586 | - '@react-three/fiber' 587 | - react 588 | dev: false 589 | 590 | /lil-gui@0.19.2: 591 | resolution: {integrity: sha512-nU8j4ND702ouGfQZoaTN4dfXxacvGOAVK0DtmZBVcUYUAeYQXLQAjAN50igMHiba3T5jZyKEjXZU+Ntm1Qs6ZQ==} 592 | dev: false 593 | 594 | /lygia@1.1.3: 595 | resolution: {integrity: sha512-CCcfEeETtYOHSHXQqdhHOgPvQ655CBcF7sijna9o/AVhUimT4PKtil4lmrXgLeebwzPUaUlEfV3IvkP2sXb85A==} 596 | dev: false 597 | 598 | /maku.js@1.0.8(three@0.162.0): 599 | resolution: {integrity: sha512-YkLU0GVmalDSyGqe8X08Fdf3BQ4U0z4xwJ/vCorscIzsxlHZw8KMFxdVMdu4lg1KshJuN2KwrTVBw6qCWVd3lg==} 600 | peerDependencies: 601 | three: '>=0.122.0' 602 | dependencies: 603 | three: 0.162.0 604 | dev: false 605 | 606 | /marcher.js@1.4.3: 607 | resolution: {integrity: sha512-59XN/v9mYbFUzDQkFJtP47AHTLD1lNGcZF4b29VzC+UzuQ4DWHm5s61xnokZc0tfTvRAa8furTytxvHKgeDrtg==} 608 | dev: false 609 | 610 | /meshoptimizer@0.18.1: 611 | resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==} 612 | dev: true 613 | 614 | /mitt@3.0.1: 615 | resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} 616 | dev: false 617 | 618 | /nanoid@3.3.7: 619 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 620 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 621 | hasBin: true 622 | dev: true 623 | 624 | /nipplejs@0.10.2: 625 | resolution: {integrity: sha512-XGxFY8C2DOtobf1fK+MXINTzkkXJLjZDDpfQhOUZf4TSytbc9s4bmA0lB9eKKM8iDivdr9NQkO7DpIQfsST+9g==} 626 | dev: false 627 | 628 | /object-hash@3.0.0: 629 | resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} 630 | engines: {node: '>= 6'} 631 | dev: false 632 | 633 | /picocolors@1.0.1: 634 | resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} 635 | dev: true 636 | 637 | /picomatch@2.3.1: 638 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 639 | engines: {node: '>=8.6'} 640 | dev: true 641 | 642 | /postcss@8.4.38: 643 | resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} 644 | engines: {node: ^10 || ^12 || >=14} 645 | dependencies: 646 | nanoid: 3.3.7 647 | picocolors: 1.0.1 648 | source-map-js: 1.2.0 649 | dev: true 650 | 651 | /postprocessing@6.35.4(three@0.162.0): 652 | resolution: {integrity: sha512-U4Uk+wOHRbdlMV8zhn843K3bZyiWGKnWXWSsDXa8IW6NAiAP/YJtf6DHs4UFo1gLnNnRGpgJPc2Xxai9O/HoLg==} 653 | engines: {node: '>= 0.13.2'} 654 | peerDependencies: 655 | three: '>= 0.152.0 < 0.165.0' 656 | dependencies: 657 | three: 0.162.0 658 | dev: false 659 | 660 | /potpack@1.0.2: 661 | resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} 662 | dev: false 663 | 664 | /readable-stream@1.0.34: 665 | resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} 666 | dependencies: 667 | core-util-is: 1.0.3 668 | inherits: 2.0.4 669 | isarray: 0.0.1 670 | string_decoder: 0.10.31 671 | dev: false 672 | 673 | /require-from-string@2.0.2: 674 | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 675 | engines: {node: '>=0.10.0'} 676 | dev: false 677 | 678 | /rollup@4.18.0: 679 | resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} 680 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 681 | hasBin: true 682 | dependencies: 683 | '@types/estree': 1.0.5 684 | optionalDependencies: 685 | '@rollup/rollup-android-arm-eabi': 4.18.0 686 | '@rollup/rollup-android-arm64': 4.18.0 687 | '@rollup/rollup-darwin-arm64': 4.18.0 688 | '@rollup/rollup-darwin-x64': 4.18.0 689 | '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 690 | '@rollup/rollup-linux-arm-musleabihf': 4.18.0 691 | '@rollup/rollup-linux-arm64-gnu': 4.18.0 692 | '@rollup/rollup-linux-arm64-musl': 4.18.0 693 | '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 694 | '@rollup/rollup-linux-riscv64-gnu': 4.18.0 695 | '@rollup/rollup-linux-s390x-gnu': 4.18.0 696 | '@rollup/rollup-linux-x64-gnu': 4.18.0 697 | '@rollup/rollup-linux-x64-musl': 4.18.0 698 | '@rollup/rollup-win32-arm64-msvc': 4.18.0 699 | '@rollup/rollup-win32-ia32-msvc': 4.18.0 700 | '@rollup/rollup-win32-x64-msvc': 4.18.0 701 | fsevents: 2.3.3 702 | dev: true 703 | 704 | /simplex-noise@4.0.1: 705 | resolution: {integrity: sha512-zl/+bdSqW7HJOQ0oDbxrNYaF4F5ik0i7M6YOYmEoIJNtg16NpvWaTTM1Y7oV/7T0jFljawLgYPS81Uu2rsfo1A==} 706 | dev: false 707 | 708 | /source-map-js@1.2.0: 709 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} 710 | engines: {node: '>=0.10.0'} 711 | dev: true 712 | 713 | /stats.js@0.17.0: 714 | resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} 715 | dev: false 716 | 717 | /string_decoder@0.10.31: 718 | resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} 719 | dev: false 720 | 721 | /three-custom-shader-material@5.4.0(three@0.162.0): 722 | resolution: {integrity: sha512-Yn1lFlKOk3Vul3npEGAmbbFUZ5S2+yjPgM2XqJEZEYRSUUH2vk+WVYrtTB6Bcq15wa7hLUXAKoctAvbRmBmbYA==} 723 | peerDependencies: 724 | '@react-three/fiber': '>=8.0' 725 | react: '>=18.0' 726 | three: '>=0.154' 727 | peerDependenciesMeta: 728 | '@react-three/fiber': 729 | optional: true 730 | react: 731 | optional: true 732 | dependencies: 733 | glsl-token-functions: 1.0.1 734 | glsl-token-string: 1.0.1 735 | glsl-tokenizer: 2.1.5 736 | object-hash: 3.0.0 737 | three: 0.162.0 738 | dev: false 739 | 740 | /three-stdlib@2.30.1(three@0.162.0): 741 | resolution: {integrity: sha512-3WHpc6rB5aiqkrbVA0h09NcwwCdcZ/bTN/01BbjcxzLQLjclhi163JUA02VZ93jR5zN7und6gfrWwewNHQTMog==} 742 | peerDependencies: 743 | three: '>=0.128.0' 744 | dependencies: 745 | '@types/draco3d': 1.4.10 746 | '@types/offscreencanvas': 2019.7.3 747 | '@types/webxr': 0.5.16 748 | draco3d: 1.5.7 749 | fflate: 0.6.10 750 | potpack: 1.0.2 751 | three: 0.162.0 752 | dev: false 753 | 754 | /three.interactive@1.7.0(three@0.162.0): 755 | resolution: {integrity: sha512-WuJijcJUT8cxiU3iP7FbqjN9EtU4xuVH/YR+jmEV4dG5ijNE8KeZcQtFRuK2dlJk4AGwCFte1GPUxAR7hYyo3g==} 756 | peerDependencies: 757 | three: '>= 0.122.0' 758 | dependencies: 759 | three: 0.162.0 760 | dev: false 761 | 762 | /three@0.162.0: 763 | resolution: {integrity: sha512-xfCYj4RnlozReCmUd+XQzj6/5OjDNHBy5nT6rVwrOKGENAvpXe2z1jL+DZYaMu4/9pNsjH/4Os/VvS9IrH7IOQ==} 764 | dev: false 765 | 766 | /through2@0.6.5: 767 | resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==} 768 | dependencies: 769 | readable-stream: 1.0.34 770 | xtend: 4.0.2 771 | dev: false 772 | 773 | /troika-three-text@0.49.1(three@0.162.0): 774 | resolution: {integrity: sha512-lXGWxgjJP9kw4i4Wh+0k0Q/7cRfS6iOME4knKht/KozPu9GcFA9NnNpRvehIhrUawq9B0ZRw+0oiFHgRO+4Wig==} 775 | peerDependencies: 776 | three: '>=0.125.0' 777 | dependencies: 778 | bidi-js: 1.0.3 779 | three: 0.162.0 780 | troika-three-utils: 0.49.0(three@0.162.0) 781 | troika-worker-utils: 0.49.0 782 | webgl-sdf-generator: 1.1.1 783 | dev: false 784 | 785 | /troika-three-utils@0.49.0(three@0.162.0): 786 | resolution: {integrity: sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==} 787 | peerDependencies: 788 | three: '>=0.125.0' 789 | dependencies: 790 | three: 0.162.0 791 | dev: false 792 | 793 | /troika-worker-utils@0.49.0: 794 | resolution: {integrity: sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==} 795 | dev: false 796 | 797 | /typescript@5.4.5: 798 | resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} 799 | engines: {node: '>=14.17'} 800 | hasBin: true 801 | dev: true 802 | 803 | /vite-plugin-glsl@1.3.0(vite@5.2.11): 804 | resolution: {integrity: sha512-SzEoLet9Bp5VSozjrhUiSc3xX1+u7rCTjXAsq4qWM3u8UjilI76A9ucX/T+CRGQCe25j50GSY+9mKSGUVPET1w==} 805 | engines: {node: '>= 16.15.1', npm: '>= 8.11.0'} 806 | peerDependencies: 807 | vite: ^3.0.0 || ^4.0.0 || ^5.0.0 808 | dependencies: 809 | '@rollup/pluginutils': 5.1.0 810 | vite: 5.2.11 811 | transitivePeerDependencies: 812 | - rollup 813 | dev: true 814 | 815 | /vite@5.2.11: 816 | resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} 817 | engines: {node: ^18.0.0 || >=20.0.0} 818 | hasBin: true 819 | peerDependencies: 820 | '@types/node': ^18.0.0 || >=20.0.0 821 | less: '*' 822 | lightningcss: ^1.21.0 823 | sass: '*' 824 | stylus: '*' 825 | sugarss: '*' 826 | terser: ^5.4.0 827 | peerDependenciesMeta: 828 | '@types/node': 829 | optional: true 830 | less: 831 | optional: true 832 | lightningcss: 833 | optional: true 834 | sass: 835 | optional: true 836 | stylus: 837 | optional: true 838 | sugarss: 839 | optional: true 840 | terser: 841 | optional: true 842 | dependencies: 843 | esbuild: 0.20.2 844 | postcss: 8.4.38 845 | rollup: 4.18.0 846 | optionalDependencies: 847 | fsevents: 2.3.3 848 | dev: true 849 | 850 | /webgl-sdf-generator@1.1.1: 851 | resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==} 852 | dev: false 853 | 854 | /xtend@4.0.2: 855 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} 856 | engines: {node: '>=0.4'} 857 | dev: false 858 | -------------------------------------------------------------------------------- /public/audio/bgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/audio/bgm.mp3 -------------------------------------------------------------------------------- /public/audio/roadBgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/audio/roadBgm.mp3 -------------------------------------------------------------------------------- /public/draco/README.md: -------------------------------------------------------------------------------- 1 | # Draco 3D Data Compression 2 | 3 | Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics. 4 | 5 | [Website](https://google.github.io/draco/) | [GitHub](https://github.com/google/draco) 6 | 7 | ## Contents 8 | 9 | This folder contains three utilities: 10 | 11 | * `draco_decoder.js` — Emscripten-compiled decoder, compatible with any modern browser. 12 | * `draco_decoder.wasm` — WebAssembly decoder, compatible with newer browsers and devices. 13 | * `draco_wasm_wrapper.js` — JavaScript wrapper for the WASM decoder. 14 | 15 | Each file is provided in two variations: 16 | 17 | * **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco). 18 | * **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension). 19 | 20 | Either variation may be used with `THREE.DRACOLoader`: 21 | 22 | ```js 23 | var dracoLoader = new THREE.DRACOLoader(); 24 | dracoLoader.setDecoderPath('path/to/decoders/'); 25 | dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support. 26 | ``` 27 | 28 | Further [documentation on GitHub](https://github.com/google/draco/tree/master/javascript/example#static-loading-javascript-decoder). 29 | 30 | ## License 31 | 32 | [Apache License 2.0](https://github.com/google/draco/blob/master/LICENSE) 33 | -------------------------------------------------------------------------------- /public/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /public/draco/gltf/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/draco/gltf/draco_decoder.wasm -------------------------------------------------------------------------------- /public/draco/gltf/draco_wasm_wrapper.js: -------------------------------------------------------------------------------- 1 | var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(h){var n=0;return function(){return n>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE? 7 | $jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))}; 8 | $jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,u){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)}; 9 | var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q=y}},"es6","es3"); 19 | $jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(kp;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3"); 20 | $jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); 21 | $jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); 22 | var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(){var e=ja.buffer;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e); 24 | e="Aborted("+e+")";da(e);sa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");ka(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(ma)return ma(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(ta||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)}); 25 | if(na)return new Promise(function(e,b){na(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function u(e){for(;0>2]=b};this.get_type=function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+ 26 | 12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c);this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+ 27 | 16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(ua(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function F(){function e(){if(!la&&(la=!0,a.calledRun=!0,!sa)){va=!0;u(oa);wa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)xa.unshift(a.postRun.shift());u(xa)}}if(!(0=d?b++:2047>=d?b+=2:55296<=d&&57343>= 29 | d?(b+=4,++c):b+=3}b=Array(b+1);c=0;d=b.length;if(0=t){var aa=e.charCodeAt(++g);t=65536+((t&1023)<<10)|aa&1023}if(127>=t){if(c>=d)break;b[c++]=t}else{if(2047>=t){if(c+1>=d)break;b[c++]=192|t>>6}else{if(65535>=t){if(c+2>=d)break;b[c++]=224|t>>12}else{if(c+3>=d)break;b[c++]=240|t>>18;b[c++]=128|t>>12&63}b[c++]=128|t>>6&63}b[c++]=128|t&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function Z(e){if("object"=== 30 | typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=za();w(S)[this.ptr]=this}function Q(){this.ptr=Aa();w(Q)[this.ptr]=this}function V(){this.ptr=Ba();w(V)[this.ptr]=this}function x(){this.ptr=Ca();w(x)[this.ptr]=this}function D(){this.ptr=Da();w(D)[this.ptr]=this}function G(){this.ptr=Ea();w(G)[this.ptr]=this}function H(){this.ptr=Fa();w(H)[this.ptr]=this}function E(){this.ptr=Ga();w(E)[this.ptr]= 31 | this}function T(){this.ptr=Ha();w(T)[this.ptr]=this}function C(){throw"cannot construct a Status, no constructor in IDL";}function I(){this.ptr=Ia();w(I)[this.ptr]=this}function J(){this.ptr=Ja();w(J)[this.ptr]=this}function K(){this.ptr=Ka();w(K)[this.ptr]=this}function L(){this.ptr=La();w(L)[this.ptr]=this}function M(){this.ptr=Ma();w(M)[this.ptr]=this}function N(){this.ptr=Na();w(N)[this.ptr]=this}function O(){this.ptr=Oa();w(O)[this.ptr]=this}function z(){this.ptr=Pa();w(z)[this.ptr]=this}function m(){this.ptr= 32 | Qa();w(m)[this.ptr]=this}n=void 0===n?{}:n;var a="undefined"!=typeof n?n:{},wa,ka;a.ready=new Promise(function(e,b){wa=e;ka=b});var Ra=!1,Sa=!1;a.onRuntimeInitialized=function(){Ra=!0;if(Sa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Sa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3=e[1]?!0:0!=e[0]||10< 33 | e[1]?!1:!0};var Ta=Object.assign({},a),ta="object"==typeof window,fa="function"==typeof importScripts,Ua="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,U="";if(Ua){var Va=require("fs"),pa=require("path");U=fa?pa.dirname(U)+"/":__dirname+"/";var Wa=function(e,b){e=e.startsWith("file://")?new URL(e):pa.normalize(e);return Va.readFileSync(e,b?void 0:"utf8")};var ma=function(e){e=Wa(e,!0);e.buffer||(e=new Uint8Array(e));return e};var na=function(e, 34 | b,c){e=e.startsWith("file://")?new URL(e):pa.normalize(e);Va.readFile(e,function(d,g){d?c(d):b(g.buffer)})};1>>=0;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{d=ja.buffer;try{ja.grow(g-d.byteLength+65535>>>16);l();var t=1;break a}catch(aa){}t=void 0}if(t)return!0}return!1}};(function(){function e(g,t){a.asm=g.exports;ja=a.asm.e;l();oa.unshift(a.asm.f);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==qa&&(clearInterval(qa),qa=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)} 38 | function c(g){return q().then(function(t){return WebAssembly.instantiate(t,d)}).then(function(t){return t}).then(g,function(t){da("failed to asynchronously prepare wasm: "+t);y(t)})}var d={a:qd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){da("Module.instantiateWasm callback failed with error: "+g),ka(g)}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")|| 39 | P.startsWith("file://")||Ua||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(t){da("wasm streaming compile failed: "+t);da("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ka);return{}})();var Xa=a._emscripten_bind_VoidPtr___destroy___0=function(){return(Xa=a._emscripten_bind_VoidPtr___destroy___0=a.asm.h).apply(null,arguments)},za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0= 40 | function(){return(za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.i).apply(null,arguments)},Ya=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(Ya=a._emscripten_bind_DecoderBuffer_Init_2=a.asm.j).apply(null,arguments)},Za=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(Za=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.k).apply(null,arguments)},Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0= 41 | a.asm.l).apply(null,arguments)},$a=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return($a=a._emscripten_bind_AttributeTransformData_transform_type_0=a.asm.m).apply(null,arguments)},ab=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(ab=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.n).apply(null,arguments)},Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0= 42 | a.asm.o).apply(null,arguments)},bb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(bb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.p).apply(null,arguments)},Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.q).apply(null,arguments)},cb=a._emscripten_bind_PointAttribute_size_0=function(){return(cb=a._emscripten_bind_PointAttribute_size_0=a.asm.r).apply(null,arguments)},db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0= 43 | function(){return(db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.s).apply(null,arguments)},eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return(eb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.t).apply(null,arguments)},fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(fb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.u).apply(null,arguments)},gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(gb=a._emscripten_bind_PointAttribute_num_components_0= 44 | a.asm.v).apply(null,arguments)},hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(hb=a._emscripten_bind_PointAttribute_normalized_0=a.asm.w).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ib=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.x).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(jb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.y).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_unique_id_0= 45 | function(){return(kb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.z).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return(lb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.A).apply(null,arguments)},Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.B).apply(null,arguments)},mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1= 46 | function(){return(mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.C).apply(null,arguments)},nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.D).apply(null,arguments)},ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.E).apply(null,arguments)},pb= 47 | a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(pb=a._emscripten_bind_AttributeQuantizationTransform_range_0=a.asm.F).apply(null,arguments)},qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.G).apply(null,arguments)},Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0= 48 | a.asm.H).apply(null,arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return(rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.I).apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.J).apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(tb= 49 | a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.K).apply(null,arguments)},Fa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return(Fa=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.L).apply(null,arguments)},ub=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(ub=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.M).apply(null,arguments)},vb=a._emscripten_bind_PointCloud_num_points_0=function(){return(vb=a._emscripten_bind_PointCloud_num_points_0=a.asm.N).apply(null, 50 | arguments)},wb=a._emscripten_bind_PointCloud___destroy___0=function(){return(wb=a._emscripten_bind_PointCloud___destroy___0=a.asm.O).apply(null,arguments)},Ga=a._emscripten_bind_Mesh_Mesh_0=function(){return(Ga=a._emscripten_bind_Mesh_Mesh_0=a.asm.P).apply(null,arguments)},xb=a._emscripten_bind_Mesh_num_faces_0=function(){return(xb=a._emscripten_bind_Mesh_num_faces_0=a.asm.Q).apply(null,arguments)},yb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(yb=a._emscripten_bind_Mesh_num_attributes_0= 51 | a.asm.R).apply(null,arguments)},zb=a._emscripten_bind_Mesh_num_points_0=function(){return(zb=a._emscripten_bind_Mesh_num_points_0=a.asm.S).apply(null,arguments)},Ab=a._emscripten_bind_Mesh___destroy___0=function(){return(Ab=a._emscripten_bind_Mesh___destroy___0=a.asm.T).apply(null,arguments)},Ha=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ha=a._emscripten_bind_Metadata_Metadata_0=a.asm.U).apply(null,arguments)},Bb=a._emscripten_bind_Metadata___destroy___0=function(){return(Bb=a._emscripten_bind_Metadata___destroy___0= 52 | a.asm.V).apply(null,arguments)},Cb=a._emscripten_bind_Status_code_0=function(){return(Cb=a._emscripten_bind_Status_code_0=a.asm.W).apply(null,arguments)},Db=a._emscripten_bind_Status_ok_0=function(){return(Db=a._emscripten_bind_Status_ok_0=a.asm.X).apply(null,arguments)},Eb=a._emscripten_bind_Status_error_msg_0=function(){return(Eb=a._emscripten_bind_Status_error_msg_0=a.asm.Y).apply(null,arguments)},Fb=a._emscripten_bind_Status___destroy___0=function(){return(Fb=a._emscripten_bind_Status___destroy___0= 53 | a.asm.Z).apply(null,arguments)},Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=a.asm._).apply(null,arguments)},Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.$).apply(null,arguments)},Hb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Hb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.aa).apply(null,arguments)},Ib= 54 | a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ib=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ba).apply(null,arguments)},Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return(Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.ca).apply(null,arguments)},Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.da).apply(null,arguments)},Kb=a._emscripten_bind_DracoInt8Array_size_0= 55 | function(){return(Kb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.ea).apply(null,arguments)},Lb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Lb=a._emscripten_bind_DracoInt8Array___destroy___0=a.asm.fa).apply(null,arguments)},Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ga).apply(null,arguments)},Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1= 56 | a.asm.ha).apply(null,arguments)},Nb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Nb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ia).apply(null,arguments)},Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ja).apply(null,arguments)},La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.ka).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt16Array_GetValue_1= 57 | function(){return(Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.la).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt16Array_size_0=a.asm.ma).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.na).apply(null,arguments)},Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0= 58 | a.asm.oa).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.pa).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.qa).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return(Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.ra).apply(null,arguments)},Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0= 59 | function(){return(Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.sa).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ta).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt32Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt32Array_size_0=a.asm.ua).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt32Array___destroy___0= 60 | a.asm.va).apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=a.asm.wa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.xa).apply(null,arguments)},Zb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.ya).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt32Array___destroy___0= 61 | function(){return($b=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.za).apply(null,arguments)},Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return(Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Aa).apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ba).apply(null,arguments)},bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2= 62 | a.asm.Ca).apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=a.asm.Da).apply(null,arguments)},dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Ea).apply(null,arguments)},ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Fa).apply(null, 63 | arguments)},fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ga).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ha).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(hc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ia).apply(null,arguments)},Qa=a._emscripten_bind_Decoder_Decoder_0= 64 | function(){return(Qa=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ja).apply(null,arguments)},ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.Ka).apply(null,arguments)},jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.La).apply(null,arguments)},kc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(kc=a._emscripten_bind_Decoder_GetAttributeId_2= 65 | a.asm.Ma).apply(null,arguments)},lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=a.asm.Na).apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Oa).apply(null,arguments)},nc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(nc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Pa).apply(null,arguments)}, 66 | oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Qa).apply(null,arguments)},pc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(pc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Ra).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Sa).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3= 67 | function(){return(rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ta).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return(sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Ua).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Va).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(uc= 68 | a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Wa).apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Xa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Ya).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3= 69 | a.asm.Za).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm._a).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3= 70 | a.asm.ab).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return(Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.cb).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3= 71 | a.asm.db).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return(Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.eb).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.fb).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1= 72 | a.asm.gb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return(Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.hb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.ib).apply(null,arguments)},Jc=a._emscripten_bind_Decoder___destroy___0=function(){return(Jc=a._emscripten_bind_Decoder___destroy___0=a.asm.jb).apply(null,arguments)},Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM= 73 | function(){return(Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=a.asm.kb).apply(null,arguments)},Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.lb).apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM= 74 | a.asm.mb).apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return(Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.nb).apply(null,arguments)},Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.ob).apply(null,arguments)},Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION= 75 | a.asm.pb).apply(null,arguments)},Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return(Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.qb).apply(null,arguments)},Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.rb).apply(null,arguments)},Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD= 76 | a.asm.sb).apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return(Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.tb).apply(null,arguments)},Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return(Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.ub).apply(null,arguments)},Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD= 77 | a.asm.vb).apply(null,arguments)},Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return(Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.wb).apply(null,arguments)},Xc=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(Xc=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.xb).apply(null,arguments)},Yc=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(Yc=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.yb).apply(null,arguments)},Zc= 78 | a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(Zc=a._emscripten_enum_draco_DataType_DT_UINT8=a.asm.zb).apply(null,arguments)},$c=a._emscripten_enum_draco_DataType_DT_INT16=function(){return($c=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Ab).apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(ad=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Bb).apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(bd=a._emscripten_enum_draco_DataType_DT_INT32= 79 | a.asm.Cb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return(cd=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Db).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Eb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Fb).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_FLOAT32= 80 | function(){return(fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Gb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Hb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(hd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Ib).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT= 81 | a.asm.Jb).apply(null,arguments)},jd=a._emscripten_enum_draco_StatusCode_OK=function(){return(jd=a._emscripten_enum_draco_StatusCode_OK=a.asm.Kb).apply(null,arguments)},kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Lb).apply(null,arguments)},ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Mb).apply(null,arguments)},md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER= 82 | function(){return(md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=a.asm.Nb).apply(null,arguments)},nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Ob).apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Pb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Qb).apply(null,arguments)}; 83 | a._free=function(){return(a._free=a.asm.Rb).apply(null,arguments)};var ua=function(){return(ua=a.asm.Sb).apply(null,arguments)};a.___start_em_js=11660;a.___stop_em_js=11758;var la;ha=function b(){la||F();la||(ha=b)};if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0=r.size?(0>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;gb.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule); 117 | -------------------------------------------------------------------------------- /public/font/AlimamaFangYuanTiVF-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/font/AlimamaFangYuanTiVF-Thin.ttf -------------------------------------------------------------------------------- /public/font/ali.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/font/ali.woff -------------------------------------------------------------------------------- /public/font/ali.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/font/ali.woff2 -------------------------------------------------------------------------------- /public/mesh/2024-Model3-d.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/2024-Model3-d.glb -------------------------------------------------------------------------------- /public/mesh/Driving.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/Driving.fbx -------------------------------------------------------------------------------- /public/mesh/city_road.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/city_road.glb -------------------------------------------------------------------------------- /public/mesh/line.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/line.glb -------------------------------------------------------------------------------- /public/mesh/road-d.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/road-d.glb -------------------------------------------------------------------------------- /public/mesh/road.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/road.glb -------------------------------------------------------------------------------- /public/mesh/sm_car_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_data.bin -------------------------------------------------------------------------------- /public/mesh/sm_car_img0.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img0.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img1.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img2.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img3.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img4.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img5.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img6.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img7.webp -------------------------------------------------------------------------------- /public/mesh/sm_car_img8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_car_img8.webp -------------------------------------------------------------------------------- /public/mesh/sm_speedup.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "generator": "glTF-Transform v3.10.1", 4 | "version": "2.0" 5 | }, 6 | "accessors": [ 7 | { 8 | "type": "SCALAR", 9 | "componentType": 5123, 10 | "count": 2592, 11 | "normalized": false, 12 | "byteOffset": 0, 13 | "bufferView": 0 14 | }, 15 | { 16 | "type": "VEC2", 17 | "componentType": 5126, 18 | "count": 586, 19 | "normalized": false, 20 | "byteOffset": 0, 21 | "bufferView": 1 22 | }, 23 | { 24 | "type": "VEC3", 25 | "componentType": 5120, 26 | "count": 586, 27 | "normalized": true, 28 | "byteOffset": 0, 29 | "bufferView": 2 30 | }, 31 | { 32 | "type": "VEC3", 33 | "componentType": 5122, 34 | "count": 586, 35 | "max": [ 36 | 32767, 37 | 892, 38 | 1800 39 | ], 40 | "min": [ 41 | -32767, 42 | -892, 43 | -1800 44 | ], 45 | "normalized": true, 46 | "byteOffset": 4688, 47 | "bufferView": 1 48 | } 49 | ], 50 | "bufferViews": [ 51 | { 52 | "buffer": 0, 53 | "byteOffset": 0, 54 | "byteLength": 5184, 55 | "target": 34963, 56 | "extensions": { 57 | "EXT_meshopt_compression": { 58 | "buffer": 0, 59 | "byteOffset": 0, 60 | "byteLength": 986, 61 | "mode": "TRIANGLES", 62 | "byteStride": 2, 63 | "count": 2592 64 | } 65 | } 66 | }, 67 | { 68 | "buffer": 0, 69 | "byteOffset": 5184, 70 | "byteLength": 2164, 71 | "target": 34962, 72 | "byteStride": 8, 73 | "extensions": { 74 | "EXT_meshopt_compression": { 75 | "buffer": 0, 76 | "byteOffset": 988, 77 | "byteLength": 5541, 78 | "mode": "ATTRIBUTES", 79 | "byteStride": 8, 80 | "count": 1172 81 | } 82 | } 83 | }, 84 | { 85 | "buffer": 0, 86 | "byteOffset": 7348, 87 | "byteLength": 0, 88 | "target": 34962, 89 | "byteStride": 4, 90 | "extensions": { 91 | "EXT_meshopt_compression": { 92 | "buffer": 0, 93 | "byteOffset": 6532, 94 | "byteLength": 814, 95 | "mode": "ATTRIBUTES", 96 | "filter": "OCTAHEDRAL", 97 | "byteStride": 4, 98 | "count": 586 99 | } 100 | } 101 | } 102 | ], 103 | "buffers": [ 104 | { 105 | "uri": "sm_speedup_data.bin", 106 | "byteLength": 7348 107 | } 108 | ], 109 | "meshes": [ 110 | { 111 | "name": "Plane.032", 112 | "primitives": [ 113 | { 114 | "attributes": { 115 | "TEXCOORD_0": 1, 116 | "NORMAL": 2, 117 | "POSITION": 3 118 | }, 119 | "mode": 4, 120 | "indices": 0 121 | } 122 | ] 123 | } 124 | ], 125 | "nodes": [ 126 | { 127 | "name": "加速.002", 128 | "translation": [ 129 | 0, 130 | 3.334592640399933, 131 | -0.0000049173831939697266 132 | ], 133 | "scale": [ 134 | 115.93985748291016, 135 | 115.93985748291016, 136 | 115.93985748291016 137 | ], 138 | "mesh": 0 139 | } 140 | ], 141 | "scenes": [ 142 | { 143 | "name": "Scene", 144 | "nodes": [ 145 | 0 146 | ] 147 | } 148 | ], 149 | "scene": 0, 150 | "extensionsUsed": [ 151 | "KHR_mesh_quantization", 152 | "EXT_meshopt_compression" 153 | ], 154 | "extensionsRequired": [ 155 | "KHR_mesh_quantization", 156 | "EXT_meshopt_compression" 157 | ] 158 | } -------------------------------------------------------------------------------- /public/mesh/sm_speedup_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_speedup_data.bin -------------------------------------------------------------------------------- /public/mesh/sm_startroom.raw.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "generator": "Khronos glTF Blender I/O v3.5.30", 4 | "version": "2.0" 5 | }, 6 | "extensionsUsed": [ 7 | "KHR_materials_specular", 8 | "KHR_materials_ior" 9 | ], 10 | "scene": 0, 11 | "scenes": [ 12 | { 13 | "name": "Scene", 14 | "nodes": [ 15 | 0, 16 | 1 17 | ] 18 | } 19 | ], 20 | "nodes": [ 21 | { 22 | "mesh": 0, 23 | "name": "light.001", 24 | "rotation": [ 25 | 0, 26 | -1, 27 | 0, 28 | 1.6292068494294654e-7 29 | ], 30 | "translation": [ 31 | 0, 32 | 2.87214994430542, 33 | 0 34 | ] 35 | }, 36 | { 37 | "mesh": 1, 38 | "name": "ReflecFloor", 39 | "rotation": [ 40 | 0, 41 | -1, 42 | 0, 43 | 2.821299744937278e-7 44 | ], 45 | "translation": [ 46 | 11.865281105041504, 47 | 0.006904084701091051, 48 | 0 49 | ] 50 | } 51 | ], 52 | "materials": [ 53 | { 54 | "doubleSided": true, 55 | "name": "light", 56 | "pbrMetallicRoughness": {} 57 | }, 58 | { 59 | "doubleSided": true, 60 | "extensions": { 61 | "KHR_materials_specular": { 62 | "specularColorFactor": [ 63 | 0, 64 | 0, 65 | 0 66 | ] 67 | }, 68 | "KHR_materials_ior": { 69 | "ior": 1.4500000476837158 70 | } 71 | }, 72 | "name": "floor", 73 | "pbrMetallicRoughness": { 74 | "metallicFactor": 0.41709843277931213, 75 | "roughnessFactor": 0.14507770538330078 76 | } 77 | } 78 | ], 79 | "meshes": [ 80 | { 81 | "name": "Plane.023", 82 | "primitives": [ 83 | { 84 | "attributes": { 85 | "POSITION": 0, 86 | "TEXCOORD_0": 1, 87 | "NORMAL": 2 88 | }, 89 | "indices": 3, 90 | "material": 0 91 | } 92 | ] 93 | }, 94 | { 95 | "name": "Plane.020", 96 | "primitives": [ 97 | { 98 | "attributes": { 99 | "POSITION": 4, 100 | "TEXCOORD_0": 5, 101 | "TEXCOORD_1": 6, 102 | "NORMAL": 7 103 | }, 104 | "indices": 8, 105 | "material": 1 106 | } 107 | ] 108 | } 109 | ], 110 | "accessors": [ 111 | { 112 | "bufferView": 0, 113 | "componentType": 5126, 114 | "count": 4, 115 | "max": [ 116 | 2.9542529582977295, 117 | 0.05927114188671112, 118 | 1.4155222177505493 119 | ], 120 | "min": [ 121 | -2.9542529582977295, 122 | 0.0592702180147171, 123 | -1.4155222177505493 124 | ], 125 | "type": "VEC3" 126 | }, 127 | { 128 | "bufferView": 1, 129 | "componentType": 5126, 130 | "count": 4, 131 | "type": "VEC2" 132 | }, 133 | { 134 | "bufferView": 2, 135 | "componentType": 5126, 136 | "count": 4, 137 | "type": "VEC3" 138 | }, 139 | { 140 | "bufferView": 3, 141 | "componentType": 5123, 142 | "count": 6, 143 | "type": "SCALAR" 144 | }, 145 | { 146 | "bufferView": 4, 147 | "componentType": 5126, 148 | "count": 8, 149 | "max": [ 150 | 127.80513000488281, 151 | 0, 152 | 15.004532814025879 153 | ], 154 | "min": [ 155 | -104.07454681396484, 156 | 0, 157 | -15.004525184631348 158 | ], 159 | "type": "VEC3" 160 | }, 161 | { 162 | "bufferView": 5, 163 | "componentType": 5126, 164 | "count": 8, 165 | "type": "VEC2" 166 | }, 167 | { 168 | "bufferView": 6, 169 | "componentType": 5126, 170 | "count": 8, 171 | "type": "VEC2" 172 | }, 173 | { 174 | "bufferView": 7, 175 | "componentType": 5126, 176 | "count": 8, 177 | "type": "VEC3" 178 | }, 179 | { 180 | "bufferView": 8, 181 | "componentType": 5123, 182 | "count": 18, 183 | "type": "SCALAR" 184 | } 185 | ], 186 | "bufferViews": [ 187 | { 188 | "buffer": 0, 189 | "byteLength": 48, 190 | "byteOffset": 0, 191 | "target": 34962 192 | }, 193 | { 194 | "buffer": 0, 195 | "byteLength": 32, 196 | "byteOffset": 48, 197 | "target": 34962 198 | }, 199 | { 200 | "buffer": 0, 201 | "byteLength": 48, 202 | "byteOffset": 80, 203 | "target": 34962 204 | }, 205 | { 206 | "buffer": 0, 207 | "byteLength": 12, 208 | "byteOffset": 128, 209 | "target": 34963 210 | }, 211 | { 212 | "buffer": 0, 213 | "byteLength": 96, 214 | "byteOffset": 140, 215 | "target": 34962 216 | }, 217 | { 218 | "buffer": 0, 219 | "byteLength": 64, 220 | "byteOffset": 236, 221 | "target": 34962 222 | }, 223 | { 224 | "buffer": 0, 225 | "byteLength": 64, 226 | "byteOffset": 300, 227 | "target": 34962 228 | }, 229 | { 230 | "buffer": 0, 231 | "byteLength": 96, 232 | "byteOffset": 364, 233 | "target": 34962 234 | }, 235 | { 236 | "buffer": 0, 237 | "byteLength": 36, 238 | "byteOffset": 460, 239 | "target": 34963 240 | } 241 | ], 242 | "buffers": [ 243 | { 244 | "uri": "sm_startroom.raw_data.bin", 245 | "byteLength": 496 246 | } 247 | ] 248 | } -------------------------------------------------------------------------------- /public/mesh/sm_startroom.raw_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/mesh/sm_startroom.raw_data.bin -------------------------------------------------------------------------------- /public/texture/decal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/decal.png -------------------------------------------------------------------------------- /public/texture/t_car_body_AO.raw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_car_body_AO.raw.jpg -------------------------------------------------------------------------------- /public/texture/t_env_light.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_env_light.hdr -------------------------------------------------------------------------------- /public/texture/t_env_night.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_env_night.hdr -------------------------------------------------------------------------------- /public/texture/t_floor_normal.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_floor_normal.webp -------------------------------------------------------------------------------- /public/texture/t_floor_roughness.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_floor_roughness.webp -------------------------------------------------------------------------------- /public/texture/t_startroom_ao.raw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_startroom_ao.raw.jpg -------------------------------------------------------------------------------- /public/texture/t_startroom_light.raw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varrff/Model3ThreeJsExpo/5dad2fba7187303e8c2d3096b1ef36785f890e32/public/texture/t_startroom_light.raw.jpg -------------------------------------------------------------------------------- /src/Experience/Debug.ts: -------------------------------------------------------------------------------- 1 | import * as dat from "lil-gui"; 2 | 3 | export default class Debug { 4 | active: boolean; 5 | ui: dat.GUI | null; 6 | constructor() { 7 | this.active = window.location.hash === "#debug"; 8 | 9 | this.ui = null; 10 | 11 | if (this.active) { 12 | this.ui = new dat.GUI(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Experience/Experience.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | 4 | import World from "./World/World"; 5 | 6 | import Debug from "./Debug"; 7 | 8 | import Postprocessing from "./Postprocessing"; 9 | 10 | import { resources } from "./resources"; 11 | 12 | export default class Experience extends kokomi.Base { 13 | params; 14 | controls: kokomi.CameraControls; 15 | world: World; 16 | debug: Debug; 17 | am: kokomi.AssetManager; 18 | post: Postprocessing; 19 | constructor(sel = "#sketch") { 20 | super(sel, { 21 | autoAdaptMobile: true, 22 | }); 23 | 24 | (window as any).experience = this; 25 | 26 | this.params = { 27 | speed: 0, 28 | cameraPos: { 29 | // x: 0, 30 | // y: 0.8, 31 | // z: -11, 32 | x: 0, 33 | y: 20.33, 34 | z: 0.01, 35 | }, 36 | isCameraMoving: false, 37 | lightAlpha: 0, 38 | lightIntensity: 0, 39 | envIntensity: 0, 40 | envWeight: 0, 41 | reflectIntensity: 0, 42 | lightOpacity: 1, 43 | floorLerpColor: 0, 44 | carBodyEnvIntensity: 1, 45 | cameraShakeIntensity: 0, 46 | bloomLuminanceSmoothing: 1.6, 47 | bloomIntensity: 1, 48 | speedUpOpacity: 0, 49 | cameraFov: 33.4, 50 | furinaLerpColor: 0, 51 | isRushing: false, 52 | disableInteract: false, 53 | isFurina: window.location.hash === "#furina", 54 | }; 55 | 56 | this.debug = new Debug(); 57 | 58 | this.renderer.toneMapping = THREE.CineonToneMapping; 59 | 60 | let resourcesToLoad = resources; 61 | if (!this.params.isFurina) { 62 | resourcesToLoad = resourcesToLoad.filter( 63 | (item) => !["driving", "decal"].includes(item.name) 64 | ); 65 | } 66 | console.log(resourcesToLoad); 67 | 68 | this.am = new kokomi.AssetManager(this, resourcesToLoad, { 69 | useMeshoptDecoder: true, 70 | useDracoLoader:true 71 | }); 72 | 73 | const camera = this.camera as THREE.PerspectiveCamera; 74 | camera.fov = this.params.cameraFov; 75 | camera.updateProjectionMatrix(); 76 | const cameraPos = new THREE.Vector3( 77 | this.params.cameraPos.x, 78 | this.params.cameraPos.y, 79 | this.params.cameraPos.z 80 | ); 81 | camera.position.copy(cameraPos); 82 | const lookAt = new THREE.Vector3(0, 0.8, 0); 83 | camera.lookAt(lookAt); 84 | 85 | const controls = new kokomi.CameraControls(this); 86 | controls.controls.setTarget(lookAt.x, lookAt.y, lookAt.z); 87 | this.controls = controls; 88 | 89 | this.world = new World(this); 90 | 91 | this.post = new Postprocessing(this); 92 | 93 | // this.update(() => { 94 | // const target = new THREE.Vector3(); 95 | // console.log(JSON.stringify(controls.controls.getPosition(target))); 96 | // }); 97 | 98 | this.update(() => { 99 | // console.log(this.camera.position) 100 | if (this.params.isCameraMoving) { 101 | this.controls.controls.enabled = false; 102 | this.controls.controls.setPosition( 103 | this.params.cameraPos.x, 104 | this.params.cameraPos.y, 105 | this.params.cameraPos.z 106 | ); 107 | } else { 108 | this.controls.controls.enabled = true; 109 | } 110 | }); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Experience/Postprocessing.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as POSTPROCESSING from "postprocessing"; 3 | 4 | import type Experience from "./Experience"; 5 | 6 | export default class Postprocessing extends kokomi.Component { 7 | declare base: Experience; 8 | params; 9 | bloom: POSTPROCESSING.BloomEffect; 10 | constructor(base: Experience) { 11 | super(base); 12 | 13 | this.params = {}; 14 | 15 | const composer = new POSTPROCESSING.EffectComposer(this.base.renderer, { 16 | multisampling: 8, 17 | }); 18 | // @ts-ignore 19 | this.base.composer = composer; 20 | 21 | composer.addPass( 22 | new POSTPROCESSING.RenderPass(this.base.scene, this.base.camera) 23 | ); 24 | 25 | const bloom = new POSTPROCESSING.BloomEffect({ 26 | blendFunction: POSTPROCESSING.BlendFunction.ADD, 27 | mipmapBlur: true, 28 | luminanceThreshold: 0, 29 | luminanceSmoothing: this.base.params.bloomLuminanceSmoothing, 30 | }); 31 | this.bloom = bloom; 32 | 33 | const effectPass = new POSTPROCESSING.EffectPass(this.base.camera, bloom); 34 | composer.addPass(effectPass); 35 | } 36 | setLuminanceSmoothing(value: number) { 37 | this.bloom.luminanceMaterial.smoothing = value; 38 | } 39 | setIntensity(value: number) { 40 | this.bloom.intensity = value; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Experience/Shaders/DynamicEnv/frag.glsl: -------------------------------------------------------------------------------- 1 | uniform float iTime; 2 | uniform vec3 iResolution; 3 | uniform vec4 iMouse; 4 | 5 | varying vec2 vUv; 6 | 7 | uniform sampler2D uEnvmap1; 8 | uniform sampler2D uEnvmap2; 9 | uniform float uWeight; 10 | uniform float uIntensity; 11 | 12 | void main(){ 13 | vec2 uv=vUv; 14 | vec3 envmap1=texture(uEnvmap1,uv).xyz; 15 | vec3 envmap2=texture(uEnvmap2,uv).xyz; 16 | vec3 col=mix(envmap1,envmap2,uWeight)*uIntensity; 17 | gl_FragColor=vec4(col,1.); 18 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/DynamicEnv/vert.glsl: -------------------------------------------------------------------------------- 1 | uniform float iTime; 2 | uniform vec3 iResolution; 3 | uniform vec4 iMouse; 4 | 5 | varying vec2 vUv; 6 | 7 | void main(){ 8 | vec3 p=position; 9 | gl_Position=vec4(p,1.); 10 | 11 | vUv=uv; 12 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/ReflecFloor/frag.glsl: -------------------------------------------------------------------------------- 1 | #include "/node_modules/lygia/lighting/fresnel.glsl" 2 | #include "/node_modules/lygia/sample/bicubic.glsl" 3 | #include "/node_modules/furina/sample/packedTexture2DLOD.glsl" 4 | 5 | uniform float iTime; 6 | uniform vec2 iResolution; 7 | uniform vec2 iMouse; 8 | 9 | varying vec2 vUv_; 10 | varying vec4 vWorldPosition; 11 | 12 | uniform vec3 uColor; 13 | uniform float uSpeed; 14 | uniform mat4 uReflectMatrix; 15 | uniform sampler2D uReflectTexture; 16 | uniform float uReflectIntensity; 17 | uniform vec2 uMipmapTextureSize; 18 | 19 | void main(){ 20 | vec2 p=vUv_; 21 | 22 | vec2 surfaceNormalUv=vWorldPosition.xz; 23 | surfaceNormalUv.x+=iTime*uSpeed; 24 | vec3 surfaceNormal=texture(normalMap,surfaceNormalUv).rgb*2.-1.; 25 | surfaceNormal=surfaceNormal.rbg; 26 | surfaceNormal=normalize(surfaceNormal); 27 | 28 | vec3 viewDir=vViewPosition; 29 | float d=length(viewDir); 30 | viewDir=normalize(viewDir); 31 | 32 | vec2 distortion=surfaceNormal.xz*(.001+1./d); 33 | 34 | vec4 reflectPoint=uReflectMatrix*vWorldPosition; 35 | reflectPoint=reflectPoint/reflectPoint.w; 36 | 37 | // vec3 reflectionSample=texture(uReflectTexture,reflectPoint.xy+distortion).xyz; 38 | vec2 roughnessUv=vWorldPosition.xz; 39 | roughnessUv.x+=iTime*uSpeed; 40 | float roughnessValue=texture(roughnessMap,roughnessUv).r; 41 | roughnessValue=roughnessValue*(1.7-.7*roughnessValue); 42 | roughnessValue*=4.; 43 | float level=roughnessValue; 44 | vec2 finalUv=reflectPoint.xy+distortion; 45 | vec3 reflectionSample=packedTexture2DLOD(uReflectTexture,finalUv,level,uMipmapTextureSize).rgb; 46 | reflectionSample*=uReflectIntensity; 47 | 48 | vec3 col=uColor; 49 | // col+=reflectionSample; 50 | col*=3.; 51 | vec3 fres=fresnel(vec3(0.),vNormal,viewDir); 52 | col=mix(col,reflectionSample,fres); 53 | 54 | csm_DiffuseColor=vec4(col,1.); 55 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/ReflecFloor/vert.glsl: -------------------------------------------------------------------------------- 1 | uniform float iTime; 2 | uniform vec2 iResolution; 3 | uniform vec2 iMouse; 4 | 5 | varying vec2 vUv_; 6 | varying vec4 vWorldPosition; 7 | 8 | void main(){ 9 | vec3 p=position; 10 | 11 | csm_Position=p; 12 | 13 | vUv_=uv; 14 | vWorldPosition=modelMatrix*vec4(p,1); 15 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/Speedup/frag.glsl: -------------------------------------------------------------------------------- 1 | #include "/node_modules/furina/generative/simplex.glsl" 2 | #include "/node_modules/lygia/generative/random.glsl" 3 | #include "/node_modules/lygia/math/saturate.glsl" 4 | #include "/node_modules/lygia/math/map.glsl" 5 | #include "/node_modules/lygia/color/palette.glsl" 6 | 7 | uniform float iTime; 8 | uniform vec3 iResolution; 9 | uniform vec4 iMouse; 10 | 11 | varying vec2 vUv; 12 | 13 | uniform float uSpeed; 14 | uniform float uOpacity; 15 | 16 | vec3 pos2col(vec2 i){ 17 | i+=vec2(9.,0.); 18 | 19 | float r=random(i+vec2(12.,2.)); 20 | float g=random(i+vec2(7.,5.)); 21 | float b=random(i); 22 | 23 | vec3 col=vec3(r,g,b); 24 | return col; 25 | } 26 | 27 | vec3 colorNoise(vec2 uv){ 28 | vec2 size=vec2(1.); 29 | vec2 pc=uv*size; 30 | vec2 base=floor(pc); 31 | 32 | vec3 v1=pos2col((base+vec2(0.,0.))/size); 33 | vec3 v2=pos2col((base+vec2(1.,0.))/size); 34 | vec3 v3=pos2col((base+vec2(0.,1.))/size); 35 | vec3 v4=pos2col((base+vec2(1.,1.))/size); 36 | 37 | vec2 f=fract(pc); 38 | 39 | f=smoothstep(0.,1.,f); 40 | 41 | vec3 px1=mix(v1,v2,f.x); 42 | vec3 px2=mix(v3,v4,f.x); 43 | vec3 v=mix(px1,px2,f.y); 44 | return v; 45 | } 46 | 47 | void main(){ 48 | vec2 uv=vUv; 49 | 50 | vec3 col=vec3(1.); 51 | 52 | float mask=1.; 53 | 54 | vec2 noiseUv=uv; 55 | noiseUv.x+=-iTime*.5; 56 | float noiseValue=noise(noiseUv*vec2(3.,100.)); 57 | mask=noiseValue; 58 | mask=map(mask,-1.,1.,0.,1.); 59 | mask=pow(saturate(mask-.1),11.); 60 | mask=smoothstep(0.,.04,mask); 61 | 62 | // col=palette(mask,vec3(.5),vec3(.5),vec3(1.),vec3(0.,.33,.67)); 63 | col=colorNoise(noiseUv*vec2(10.,100.)); 64 | col*=vec3(1.5,1.,400.); 65 | // mask=1.; 66 | mask*=smoothstep(.02,.5,uv.x)*smoothstep(.02,.5,1.-uv.x); 67 | mask*=smoothstep(.01,.1,uv.y)*smoothstep(.01,.1,1.-uv.y); 68 | mask*=smoothstep(1.,10.,uSpeed); 69 | 70 | gl_FragColor=vec4(col,mask*uOpacity); 71 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/Speedup/vert.glsl: -------------------------------------------------------------------------------- 1 | uniform float iTime; 2 | uniform vec3 iResolution; 3 | uniform vec4 iMouse; 4 | 5 | varying vec2 vUv; 6 | 7 | void main(){ 8 | vec3 p=position; 9 | gl_Position=projectionMatrix*modelViewMatrix*vec4(p,1.); 10 | 11 | vUv=uv; 12 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/TestObject/frag.glsl: -------------------------------------------------------------------------------- 1 | uniform float iTime; 2 | uniform vec3 iResolution; 3 | uniform vec4 iMouse; 4 | 5 | varying vec2 vUv; 6 | 7 | void main(){ 8 | vec2 uv=vUv; 9 | gl_FragColor=vec4(uv,0.,1.); 10 | } -------------------------------------------------------------------------------- /src/Experience/Shaders/TestObject/vert.glsl: -------------------------------------------------------------------------------- 1 | #include "/node_modules/lygia/generative/cnoise.glsl" 2 | 3 | uniform float iTime; 4 | uniform vec3 iResolution; 5 | uniform vec4 iMouse; 6 | 7 | varying vec2 vUv; 8 | 9 | uniform float uDistort; 10 | 11 | vec3 distort(vec3 p){ 12 | float noise=cnoise(p+iTime); 13 | p+=noise*normal*.3*uDistort; 14 | return p; 15 | } 16 | 17 | void main(){ 18 | vec3 p=position; 19 | p=distort(p); 20 | gl_Position=projectionMatrix*modelViewMatrix*vec4(p,1.); 21 | 22 | vUv=uv; 23 | } -------------------------------------------------------------------------------- /src/Experience/Utils/meshReflectorMaterial.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | 4 | export interface MeshReflectorMaterialConfig { 5 | resolution: number; 6 | ignoreObjects: THREE.Object3D[]; 7 | } 8 | 9 | class MeshReflectorMaterial extends kokomi.Component { 10 | parent: THREE.Mesh; 11 | ignoreObjects: THREE.Object3D[]; 12 | _camera: THREE.PerspectiveCamera; 13 | reflectPlane: THREE.Plane; 14 | _reflectMatrix: THREE.Matrix4; 15 | _renderTexture: kokomi.FBO; 16 | mipmapper: kokomi.PackedMipMapGenerator; 17 | mirrorFBO: THREE.WebGLRenderTarget; 18 | mipmapFBO: kokomi.FBO; 19 | constructor( 20 | base: kokomi.Base, 21 | parent: THREE.Mesh, 22 | config: Partial = {} 23 | ) { 24 | super(base); 25 | 26 | this.parent = parent; 27 | 28 | let { resolution = 256, ignoreObjects = [] } = config; 29 | 30 | this.ignoreObjects = ignoreObjects; 31 | 32 | this._camera = new THREE.PerspectiveCamera(); 33 | this.reflectPlane = new THREE.Plane(); 34 | this._reflectMatrix = new THREE.Matrix4(); 35 | this._renderTexture = new kokomi.FBO(this.base, { 36 | width: resolution, 37 | height: resolution, 38 | options: { 39 | type: THREE.UnsignedByteType, 40 | }, 41 | }); 42 | 43 | const mipmapper = new kokomi.PackedMipMapGenerator(); 44 | this.mipmapper = mipmapper; 45 | const mirrorFBO = this._renderTexture.rt; 46 | this.mirrorFBO = mirrorFBO; 47 | const mipmapFBO = new kokomi.FBO(this.base); 48 | this.mipmapFBO = mipmapFBO; 49 | } 50 | update(): void { 51 | this.beforeRender(); 52 | 53 | this.mipmapper.update( 54 | this.mirrorFBO.texture, 55 | this.mipmapFBO.rt, 56 | this.base.renderer 57 | ); 58 | } 59 | beforeRender() { 60 | this.reflectPlane.set(new THREE.Vector3(0, 1, 0), 0); 61 | this.reflectPlane.applyMatrix4(this.parent.matrixWorld); 62 | // @ts-ignore 63 | this._camera.copy(this.base.camera); 64 | const r = new THREE.Vector3(0, 0, 1).clone().negate(); 65 | const o = this.base.camera.getWorldPosition(new THREE.Vector3()); 66 | r.reflect(this.reflectPlane.normal); 67 | const p = new THREE.Vector3(); 68 | this.reflectPlane.projectPoint(o, p); 69 | const y = p.clone(); 70 | y.sub(o), y.add(p), this._camera.position.copy(y); 71 | const d = new THREE.Vector3(0, 0, -1); 72 | d.applyQuaternion( 73 | this.base.camera.getWorldQuaternion(new THREE.Quaternion()) 74 | ); 75 | d.add(o); 76 | const E = new THREE.Vector3(); 77 | this.parent.getWorldPosition(E); 78 | E.sub(d); 79 | E.reflect(this.reflectPlane.normal).negate(); 80 | E.add(this.parent.getWorldPosition(new THREE.Vector3())); 81 | this._camera.up.set(0, 1, 0); 82 | this._camera.applyQuaternion( 83 | this.base.camera.getWorldQuaternion(new THREE.Quaternion()) 84 | ); 85 | this._camera.up.reflect(this.reflectPlane.normal); 86 | this._camera.lookAt(E); 87 | this._camera.updateMatrixWorld(); 88 | const L = new THREE.Matrix4(); 89 | L.set(0.5, 0, 0, 0.5, 0, 0.5, 0, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 1); 90 | L.multiply(this._camera.projectionMatrix); 91 | L.multiply(this._camera.matrixWorldInverse); 92 | this._reflectMatrix.copy(L); 93 | this.reflectPlane.applyMatrix4(this._camera.matrixWorldInverse); 94 | const k = new THREE.Vector4( 95 | this.reflectPlane.normal.x, 96 | this.reflectPlane.normal.y, 97 | this.reflectPlane.normal.z, 98 | this.reflectPlane.constant 99 | ); 100 | const X = this._camera.projectionMatrix; 101 | const $ = new THREE.Vector4(); 102 | $.x = (Math.sign(k.x) + X.elements[8]) / X.elements[0]; 103 | $.y = (Math.sign(k.y) + X.elements[9]) / X.elements[5]; 104 | $.z = -1; 105 | $.w = (1 + X.elements[10]) / X.elements[14]; 106 | k.multiplyScalar(2 / k.dot($)); 107 | X.elements[2] = k.x; 108 | X.elements[6] = k.y; 109 | X.elements[10] = k.z + 1; 110 | X.elements[14] = k.w; 111 | const Z = this.base.renderer.getRenderTarget(); 112 | this.base.renderer.setRenderTarget(this._renderTexture.rt); 113 | this.base.renderer.state.buffers.depth.setMask(true); 114 | this.base.renderer.autoClear === false && this.base.renderer.clear(); 115 | this.ignoreObjects.forEach((be) => (be.visible = false)); 116 | this.base.renderer.render(this.base.scene, this._camera); 117 | this.ignoreObjects.forEach((be) => (be.visible = true)); 118 | this.base.renderer.setRenderTarget(Z); 119 | } 120 | } 121 | 122 | export { MeshReflectorMaterial }; 123 | -------------------------------------------------------------------------------- /src/Experience/World/CameraShake.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | import gsap from "gsap"; 4 | import * as STDLIB from "three-stdlib"; 5 | import { createNoise2D } from "simplex-noise"; 6 | 7 | import type Experience from "../Experience"; 8 | 9 | // 创建一个 2D simplex 噪声对象 10 | const noise2d = createNoise2D(); 11 | 12 | // Fractal Brownian Motion(分形布朗运动)函数 13 | const fbm = ({ 14 | octave = 3, // 八度数 15 | frequency = 2, // 频率 16 | amplitude = 0.5, // 振幅 17 | lacunarity = 2, // 空隙度 18 | persistance = 0.5, // 持续度 19 | } = {}) => { 20 | let value = 0; 21 | for (let i = 0; i < octave; i++) { 22 | // 根据参数计算噪声值 23 | const noiseValue = noise2d(frequency, frequency); 24 | value += noiseValue * amplitude; 25 | frequency *= lacunarity; 26 | amplitude *= persistance; 27 | } 28 | return value; 29 | }; 30 | 31 | // 相机震动配置接口 32 | export interface CameraShakeConfig { 33 | intensity: number; // 震动强度 34 | } 35 | 36 | // 相机震动类 37 | export default class CameraShake extends kokomi.Component { 38 | declare base: Experience; 39 | tweenedPosOffset: THREE.Vector3; // 缓动的位置偏移向量 40 | intensity: number; // 震动强度 41 | constructor(base: Experience, config: Partial = {}) { 42 | super(base); 43 | 44 | // 解构配置参数,设置默认值 45 | const { intensity = 1 } = config; 46 | this.intensity = intensity; 47 | 48 | // 创建缓动的位置偏移向量 49 | const tweenedPosOffset = new THREE.Vector3(0, 0, 0); 50 | this.tweenedPosOffset = tweenedPosOffset; 51 | } 52 | 53 | // 更新函数 54 | update(): void { 55 | const t = this.base.clock.elapsedTime; // 获取当前时间 56 | // 计算随机位置偏移 57 | const posOffset = new THREE.Vector3( 58 | fbm({ 59 | frequency: t * 0.5 + THREE.MathUtils.randFloat(-10000, 0), // 在 x 方向上的噪声 60 | amplitude: 2, // 振幅 61 | }), 62 | fbm({ 63 | frequency: t * 0.5 + THREE.MathUtils.randFloat(-10000, 0), // 在 y 方向上的噪声 64 | amplitude: 2, // 振幅 65 | }), 66 | fbm({ 67 | frequency: t * 0.5 + THREE.MathUtils.randFloat(-10000, 0), // 在 z 方向上的噪声 68 | amplitude: 2, // 振幅 69 | }) 70 | ); 71 | posOffset.multiplyScalar(0.1 * this.intensity); // 乘以震动强度 72 | // 使用 GSAP 库创建动画,平滑过渡相机位置 73 | gsap.to(this.tweenedPosOffset, { 74 | x: posOffset.x, 75 | y: posOffset.y, 76 | z: posOffset.z, 77 | duration: 1.2, // 动画持续时间 78 | }); 79 | 80 | // 将震动位置偏移应用到相机位置 81 | this.base.camera.position.add(this.tweenedPosOffset); 82 | } 83 | 84 | // 设置震动强度 85 | setIntensity(value: number) { 86 | this.intensity = value; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/Experience/World/Car.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | import * as STDLIB from "three-stdlib"; 4 | 5 | import type Experience from "../Experience"; 6 | 7 | // 定义 Car 类,继承自 kokomi.Component 8 | export default class Car extends kokomi.Component { 9 | declare base: Experience; 10 | model: STDLIB.GLTF; // 模型 11 | modelParts: THREE.Object3D[]; // 模型部件 12 | bodyMat!: THREE.MeshStandardMaterial; // 车身材质 13 | wheelModel!: THREE.Group; // 轮胎模型 14 | 15 | // 构造函数,接受一个 Experience 实例作为参数 16 | constructor(base: Experience) { 17 | super(base); 18 | 19 | // 从资源管理器中获取汽车模型 20 | const model = this.base.am.items["sm_car"] as STDLIB.GLTF; 21 | this.model = model; 22 | this.model.scene.position.y = 0.75; 23 | this.model.scene.rotation.y += -(Math.PI / 2); // 90 度用弧度表示为 Math.PI / 2 24 | // this.model.scene.scale.set(0.01, 0.01, 0.01); 25 | 26 | 27 | // 扁平化模型,获取模型的所有部件 28 | const modelParts = kokomi.flatModel(model.scene); 29 | kokomi.printModel(modelParts); 30 | this.modelParts = modelParts; 31 | 32 | // // 处理模型 33 | // this.handleModel(); 34 | } 35 | 36 | // 添加已存在的模型到容器中 37 | addExisting() { 38 | this.container.add(this.model.scene); 39 | } 40 | 41 | // 更新函数 42 | update(): void { 43 | // 根据速度旋转车轮模型 44 | this.wheelModel?.children.forEach((item) => { 45 | item.rotateZ(-this.base.params.speed * 0.03); 46 | }); 47 | } 48 | 49 | // 处理模型函数 50 | handleModel() { 51 | // 获取车身部件 52 | const body = this.modelParts[2] as THREE.Mesh; 53 | // 获取车身材质 54 | const bodyMat = body.material as THREE.MeshStandardMaterial; 55 | this.bodyMat = bodyMat; 56 | // 设置车身颜色 57 | bodyMat.color = new THREE.Color("#26d6e9"); 58 | // 如果是 Furina 模式,则更改车身材质和贴图 59 | if (this.base.params.isFurina) { 60 | bodyMat.color = new THREE.Color("white"); 61 | bodyMat.map = this.base.am.items["decal"]; 62 | } 63 | 64 | // 遍历模型的所有部件 65 | // @ts-ignore 66 | this.modelParts.forEach((item: THREE.Mesh) => { 67 | // 如果部件是网格 68 | if (item.isMesh) { 69 | // 设置环境光遮蔽贴图 70 | const mat = item.material as THREE.MeshStandardMaterial; 71 | mat.aoMap = this.base.am.items["ut_car_body_ao"]; 72 | } 73 | }); 74 | 75 | // 获取车轮模型 76 | const Wheel = this.modelParts[35] as THREE.Group; 77 | this.wheelModel = Wheel; 78 | } 79 | 80 | // 设置车身环境贴图强度 81 | setBodyEnvmapIntensity(value: number) { 82 | if (this.bodyMat) { 83 | this.bodyMat.envMapIntensity = value; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Experience/World/City.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as STDLIB from "three-stdlib"; 3 | // import { clone } from "three/examples/jsm/utils/SkeletonUtils"; 4 | import gsap from "gsap"; 5 | import { Mesh, MeshStandardMaterial } from "three"; 6 | 7 | import type Experience from "../Experience"; 8 | import * as THREE from "three"; 9 | 10 | export default class City extends kokomi.Component { 11 | declare base: Experience; 12 | model: any; 13 | isRun!: boolean; 14 | road!: any; 15 | controlPoints: THREE.Vector3[]; 16 | animationLoop: any; 17 | group:any; 18 | 19 | constructor(base: Experience) { 20 | super(base); 21 | this.controlPoints = []; 22 | } 23 | 24 | addExisting() { 25 | this.isRun = true; 26 | const model = this.base.am.items["city_road"] as STDLIB.GLTF; 27 | this.model = model; 28 | this.model.scene.position.y = -3; 29 | this.model.scene.position.z = 51.5; 30 | this.model.scene.position.x = 10; 31 | this.model.scene.scale.set(2, 2, 2); 32 | this.container.add(this.model.scene); 33 | this.createRoad(); 34 | this.runRoad(); 35 | } 36 | 37 | setCar() { 38 | const model = this.base.am.items["sm_car"] as STDLIB.GLTF; 39 | } 40 | 41 | createRoad() { 42 | const points = [ 43 | new THREE.Vector3(0, 0, 0), 44 | new THREE.Vector3(0, 0, 5), 45 | new THREE.Vector3(0, 0, 10), 46 | new THREE.Vector3(-20, 0, 10), 47 | ]; 48 | this.controlPoints = points; 49 | 50 | this.updateRoadGeometry(); 51 | 52 | // 使用GSAP进行过渡动画 53 | gsap.to(this.road.material, { 54 | duration: 2, 55 | opacity: 1, 56 | onComplete: () => { 57 | 58 | }, 59 | }); 60 | } 61 | 62 | updateRoadGeometry() { 63 | if (!this.controlPoints || this.controlPoints.length === 0) { 64 | 65 | return; 66 | } 67 | 68 | const curve = new THREE.CatmullRomCurve3(this.controlPoints); 69 | const tubularSegments = 100; 70 | const radius = 1; 71 | const radialSegments = 8; 72 | const closed = false; 73 | 74 | const geometry = new THREE.TubeGeometry( 75 | curve, 76 | tubularSegments, 77 | radius, 78 | radialSegments, 79 | closed 80 | ); 81 | 82 | const positionAttribute = geometry.attributes.position; 83 | const vertex = new THREE.Vector3(); 84 | 85 | for (let i = 0; i < positionAttribute.count; i++) { 86 | vertex.fromBufferAttribute(positionAttribute, i); 87 | vertex.y *= 0.1; 88 | positionAttribute.setXYZ(i, vertex.x, vertex.y, vertex.z); 89 | } 90 | 91 | const canvas = document.createElement("canvas"); 92 | canvas.width = 256; 93 | canvas.height = 1; 94 | 95 | const context = canvas.getContext("2d") as CanvasRenderingContext2D; 96 | const gradient = context.createLinearGradient(0, 0, canvas.width, 0); 97 | gradient.addColorStop(0, "#2076ff"); 98 | gradient.addColorStop(1, "#abcbff"); 99 | 100 | context.fillStyle = gradient; 101 | context.fillRect(0, 0, canvas.width, canvas.height); 102 | 103 | const gradientTexture = new THREE.CanvasTexture(canvas); 104 | 105 | const material = new THREE.MeshBasicMaterial({ 106 | map: gradientTexture, 107 | side: THREE.DoubleSide, 108 | opacity: 0, 109 | transparent: true, 110 | }); 111 | 112 | if (this.road) { 113 | this.road.geometry.dispose(); 114 | this.road.geometry = geometry; 115 | } else { 116 | this.road = new THREE.Mesh(geometry, material); 117 | this.road.rotation.y = Math.PI / 2; 118 | this.container.add(this.road); 119 | } 120 | } 121 | 122 | updateControlPoint( 123 | index: number, 124 | xValue: number | null = null, 125 | xStep: number | null = 0, 126 | zValue: number | null = null, 127 | zStep: number | null = 0 128 | ): void { 129 | if (!this.controlPoints || this.controlPoints.length <= index) { 130 | console.error(`Control point at index ${index} is not defined.`); 131 | return; 132 | } 133 | 134 | const point = this.controlPoints[index].clone(); 135 | 136 | if (xValue !== null && xStep !== null) { 137 | if (point.x < xValue) { 138 | point.setX(point.x + xStep); 139 | } else if (point.x > xValue) { 140 | point.setX(point.x - xStep); 141 | } 142 | } 143 | 144 | if (zValue !== null && zStep !== null) { 145 | if (point.z >= zValue) { 146 | point.setZ(point.z - zStep); 147 | } else if (point.z < zValue) { 148 | point.setZ(point.z + zStep); 149 | } 150 | } 151 | 152 | this.controlPoints[index] = point; 153 | this.updateRoadGeometry(); 154 | } 155 | 156 | runRoad() { 157 | const t1 = gsap.to(this.model.scene.position, { 158 | x: 1, 159 | duration: 3, 160 | delay: 2, 161 | onComplete: () => {}, 162 | }); 163 | const t2 = gsap.to(this.model.scene.position, { 164 | z: 52, 165 | duration: 3, 166 | delay: 2.5, 167 | onComplete: () => { 168 | t4(); 169 | console.log("Road added to scene with smooth transition."); 170 | }, 171 | }); 172 | 173 | const car = this.base.am.items["sm_car"] as STDLIB.GLTF; 174 | const group = new THREE.Group(); 175 | group.add(this.model.scene); 176 | group.position.copy(car.scene.position); 177 | this.group = group 178 | this.container.add(this.group); 179 | const t3LINE = () => { 180 | const animateControlPoints = () => { 181 | this.updateControlPoint(3, 0, 0.03, 15, 0.055); //-20, 0, 10 182 | // this.updateControlPoint(4, 0, 0.007, null,null); 183 | // this.animationLoop = requestAnimationFrame(animateControlPoints); 184 | requestAnimationFrame(animateControlPoints); 185 | }; 186 | 187 | animateControlPoints(); 188 | }; 189 | setTimeout(() => { 190 | t3LINE(); 191 | }, 1000); 192 | const t3 = gsap.to(group.rotation, { 193 | y: Math.PI / 2, 194 | duration: 6, 195 | delay: 2.5, 196 | onComplete: () => { 197 | 198 | }, 199 | }); 200 | const t4 = () => { 201 | gsap.to(this.model.scene.position, { 202 | x: 0, 203 | z: 45, 204 | duration: 3, 205 | onComplete: () => { 206 | t5(); 207 | cancelAnimationFrame(this.animationLoop); 208 | 209 | }, 210 | }); 211 | }; 212 | 213 | const t5 = () => { 214 | gsap.to(this.model.scene.position, { 215 | x: 0, 216 | z: 10, 217 | duration: 10, 218 | onComplete: () => { 219 | 220 | }, 221 | }); 222 | }; 223 | } 224 | removeAllModelsAndAnimations() { 225 | this.container.remove(this.road); 226 | this.model.scene.position.y = -3; 227 | this.model.scene.position.z = 51.5; 228 | this.model.scene.position.x = 10; 229 | // 取消动画循环 230 | if (this.animationLoop) { 231 | // cancelAnimationFrame(this.animationLoop); 232 | this.animationLoop = null; 233 | } 234 | // 移除道路模型 235 | if (this.model) { 236 | this.container.remove(this.model.scene); 237 | // 释放资源 238 | this.model = null; 239 | } 240 | this.group 241 | if ( this.group) { 242 | this.container.remove( this.group); 243 | // 释放资源 244 | this.group = null; 245 | } 246 | // 移除 tube 对象 247 | if (this.road) { 248 | this.container.remove(this.road); 249 | // 释放资源 250 | this.road.geometry.dispose(); 251 | this.road.material.dispose(); 252 | this.road = null; 253 | } 254 | } 255 | playAuto() { 256 | const bgm = new Howl({ 257 | src: "audio/roadBgm.mp3", 258 | loop: false, 259 | }); 260 | bgm.play(); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/Experience/World/DynamicEnv.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | import gsap from "gsap"; 4 | 5 | import type Experience from "../Experience"; 6 | 7 | import dynamicEnvVertexShader from "../Shaders/DynamicEnv/vert.glsl"; 8 | import dynamicEnvFragmentShader from "../Shaders/DynamicEnv/frag.glsl"; 9 | 10 | export interface DynamicEnvConfig { 11 | envmap1: THREE.Texture; 12 | envmap2: THREE.Texture; 13 | } 14 | 15 | const t1 = gsap.timeline(); 16 | 17 | export default class DynamicEnv extends kokomi.Component { 18 | declare base: Experience; 19 | fbo: kokomi.FBO; 20 | material: THREE.ShaderMaterial; 21 | quad: kokomi.FullScreenQuad; 22 | constructor(base: Experience, config: Partial = {}) { 23 | super(base); 24 | 25 | const { envmap1, envmap2 } = config; 26 | 27 | const envData = envmap1?.source.data; 28 | 29 | const fbo = new kokomi.FBO(this.base, { 30 | width: envData.width, 31 | height: envData.height, 32 | }); 33 | this.fbo = fbo; 34 | 35 | this.envmap.mapping = THREE.CubeUVReflectionMapping; 36 | 37 | const material = new THREE.ShaderMaterial({ 38 | vertexShader: dynamicEnvVertexShader, 39 | fragmentShader: dynamicEnvFragmentShader, 40 | uniforms: { 41 | uEnvmap1: { 42 | value: envmap1, 43 | }, 44 | uEnvmap2: { 45 | value: envmap2, 46 | }, 47 | uWeight: { 48 | value: 0, 49 | }, 50 | uIntensity: { 51 | value: 1, 52 | }, 53 | }, 54 | }); 55 | this.material = material; 56 | 57 | const quad = new kokomi.FullScreenQuad(material); 58 | this.quad = quad; 59 | } 60 | update() { 61 | this.base.renderer.setRenderTarget(this.fbo.rt); 62 | this.quad.render(this.base.renderer); 63 | this.base.renderer.setRenderTarget(null); 64 | } 65 | get envmap() { 66 | return this.fbo.rt.texture; 67 | } 68 | setWeight(value: number) { 69 | this.material.uniforms.uWeight.value = value; 70 | } 71 | setIntensity(value: number) { 72 | this.material.uniforms.uIntensity.value = value; 73 | } 74 | lerpWeight(value: number, duration: number) { 75 | // t1.timeScale(0.2); 76 | t1.to(this.material.uniforms.uWeight, { 77 | value, 78 | duration, 79 | ease: "power2.out", 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Experience/World/Furina.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | 4 | import type Experience from "../Experience"; 5 | 6 | export default class Furina extends kokomi.Component { 7 | declare base: Experience; 8 | model: THREE.Group; 9 | realModel: THREE.Group; 10 | modelParts: THREE.Object3D[]; 11 | mixer: THREE.AnimationMixer; 12 | actions: Record; 13 | currentAction: THREE.AnimationAction | null; 14 | isPaused: boolean; 15 | constructor(base: Experience) { 16 | super(base); 17 | 18 | const model = new THREE.Group(); 19 | this.model = model; 20 | 21 | // const realModel = this.base.am.items["furina"] as THREE.Group; 22 | const realModel = this.base.am.items["driving"] as THREE.Group; 23 | this.realModel = realModel; 24 | 25 | this.model.add(this.realModel); 26 | 27 | const modelParts = kokomi.flatModel(this.realModel); 28 | // kokomi.printModel(modelParts); 29 | this.modelParts = modelParts; 30 | 31 | this.handleModel(); 32 | 33 | const mixer = new THREE.AnimationMixer(this.model); 34 | this.mixer = mixer; 35 | 36 | this.actions = {}; 37 | 38 | this.currentAction = null; 39 | 40 | this.addAction("driving", "driving"); 41 | 42 | this.playAction("driving"); 43 | 44 | this.mixer.update(1); 45 | this.isPaused = true; 46 | } 47 | addExisting() { 48 | this.container.add(this.model); 49 | } 50 | update(): void { 51 | if (this.isPaused) { 52 | return; 53 | } 54 | 55 | this.mixer.update(this.base.clock.deltaTime); 56 | } 57 | handleModel() { 58 | this.model.scale.setScalar(0.074); 59 | 60 | this.model.rotation.y = Math.PI * 0.5; 61 | 62 | this.model.position.set(0.225, 0.15, -0.4); 63 | 64 | // @ts-ignore 65 | this.modelParts.forEach((item: THREE.Mesh) => { 66 | if (item.isMesh) { 67 | if ((item.material as THREE.MeshPhongMaterial).isMeshPhongMaterial) { 68 | const newMat = new THREE.MeshBasicMaterial({ 69 | transparent: true, 70 | // @ts-ignore 71 | map: item.material.map || null, 72 | // color: new THREE.Color("#666666"), 73 | }); 74 | item.material = newMat; 75 | } 76 | } 77 | }); 78 | } 79 | addAction(assetName: string, name: string) { 80 | const animation = (this.base.am?.items[assetName] as THREE.Group) 81 | .animations[0]; 82 | const action = this.mixer.clipAction(animation); 83 | this.actions[name] = action; 84 | } 85 | playAction(name: string) { 86 | if (this.currentAction) { 87 | this.currentAction.fadeOut(0.5); 88 | } 89 | const action = this.actions[name]; 90 | action.weight = 1; 91 | action.reset().fadeIn(0.5).play(); 92 | this.currentAction = action; 93 | return action; 94 | } 95 | setColor(color: THREE.Color) { 96 | // @ts-ignore 97 | this.modelParts.forEach((item: THREE.Mesh) => { 98 | if (item.isMesh) { 99 | const mat = item.material as THREE.MeshBasicMaterial; 100 | mat.color.set(color); 101 | } 102 | }); 103 | } 104 | pause() { 105 | this.isPaused = true; 106 | } 107 | drive() { 108 | this.isPaused = false; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Experience/World/Road.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as STDLIB from "three-stdlib"; 3 | // @ts-ignore 4 | import { clone } from "three/examples/jsm/utils/SkeletonUtils"; 5 | import gsap from "gsap"; 6 | import { Mesh, MeshStandardMaterial } from "three"; 7 | import { Howl } from "howler"; 8 | import type Experience from "../Experience"; 9 | import * as THREE from "three"; 10 | 11 | export default class Road extends kokomi.Component { 12 | declare base: Experience; 13 | model: any; 14 | isRun!: boolean; 15 | carShield: Mesh | null = null; 16 | lineMesh: Mesh | null = null; 17 | controlPoints!: Array; 18 | tube: any; 19 | animationLoop: any; 20 | newCar: any; 21 | AnimationFrame: any; 22 | 23 | constructor(base: Experience) { 24 | super(base); 25 | } 26 | 27 | addExisting() { 28 | this.isRun = true; 29 | const model = this.base.am.items["road"] as STDLIB.GLTF; 30 | this.model = model; 31 | this.model.scene.position.z = -2.5; 32 | this.model.scene.scale.set(3, 3, 3); 33 | this.container.add(this.model.scene); 34 | this.run(); 35 | } 36 | 37 | run() { 38 | this.carRun(); 39 | const animate = () => { 40 | if (!this.isRun) { 41 | return; // 如果标志为false,停止动画 42 | } 43 | requestAnimationFrame(animate); 44 | 45 | // 模型移动速度 46 | const moveSpeed = 0.1; 47 | 48 | this.model.scene.position.x -= moveSpeed; 49 | }; 50 | 51 | // 初始调用animate,启动递归动画循环 52 | animate(); 53 | } 54 | 55 | carRun() { 56 | // 确保每次都是新的克隆对象 57 | const model = this.base.am.items["sm_car"] as STDLIB.GLTF; 58 | this.newCar = clone(model.scene); 59 | console.log(model) 60 | 61 | // 创建一个新的标准材质,支持光照和反射 62 | const newMaterial = new MeshStandardMaterial({ 63 | color: "#8a8886", 64 | metalness: 0.8, 65 | roughness: 0.8, 66 | }); // 这里设置你想要的颜色和材质属性 67 | 68 | // 遍历模型并替换所有材质 69 | this.newCar.traverse( 70 | (child: { isMesh: any; material: MeshStandardMaterial }) => { 71 | if (child.isMesh) { 72 | child.material = newMaterial; 73 | } 74 | } 75 | ); 76 | 77 | this.createShield(); 78 | 79 | this.container.add(this.newCar); 80 | 81 | // 动画参数 82 | const initialX = -1; 83 | const initialZ = 5; 84 | const forwardDistance = 3; // 向前移动的距离 85 | const sideDistance = 5; // 超车时横向移动的距离 86 | const duration = 5000; // 动画持续时间(毫秒) 87 | const pauseDuration = 1500; // 停顿时间(毫秒) 88 | 89 | let startTime: number | null = null; 90 | 91 | // 动画函数 92 | const animateCar = (time: number) => { 93 | if (!startTime) startTime = time; 94 | const elapsedTime = time - startTime; 95 | 96 | if (elapsedTime < duration / 2) { 97 | // 前半段,向前移动 98 | const progress = elapsedTime / (duration / 2); 99 | this.newCar.position.x = initialX + progress * forwardDistance; 100 | this.newCar.position.z = initialZ; 101 | } else if (elapsedTime < duration) { 102 | // 后半段,向斜前方移动 103 | const progress = (elapsedTime - duration / 2) / (duration / 2); 104 | this.newCar.position.x = 105 | initialX + forwardDistance + progress * sideDistance; 106 | this.newCar.position.z = initialZ - progress * sideDistance; 107 | } else if (elapsedTime < duration + pauseDuration) { 108 | // 停顿时间 109 | // 不进行任何操作,保持车辆静止 110 | } else { 111 | // 加速向前移动 112 | const progress = (elapsedTime - duration - pauseDuration) / 2000; // 加速时间为2秒 113 | this.newCar.position.x = 114 | initialX + forwardDistance + sideDistance + progress * 10; // 加速移动的距离为10 115 | this.newCar.position.z = initialZ - sideDistance; 116 | if (this.newCar.position.x > 20) { 117 | // 超出场景范围,移除车辆 118 | this.container.remove(this.newCar); 119 | const father = document.querySelector(".line") as Element; 120 | //@ts-ignore 121 | father.style.display = "flex"; // 设置元素 display 为 none 122 | cancelAnimationFrame(this.AnimationFrame); // 结束动画 123 | } 124 | } 125 | 126 | this.AnimationFrame = requestAnimationFrame(animateCar); 127 | }; 128 | 129 | // 启动动画 130 | requestAnimationFrame(animateCar); 131 | } 132 | 133 | createShield() { 134 | const controlPoints = [ 135 | new THREE.Vector3(3, 1, 1), 136 | new THREE.Vector3(2.96, 1, 1.5), 137 | new THREE.Vector3(3, 1, 1.7), 138 | new THREE.Vector3(2.65, 1, 2.7), 139 | new THREE.Vector3(2, 1, 2.65), 140 | new THREE.Vector3(1, 1, 2.7), 141 | new THREE.Vector3(0.5, 1, 2.8), 142 | ]; 143 | this.controlPoints = controlPoints; 144 | // Create a Catmull-Rom spline curve 145 | const curve = new THREE.CatmullRomCurve3(this.controlPoints); 146 | 147 | // Create TubeGeometry from the curve 148 | const tubeGeometry = new THREE.TubeGeometry(curve, 100, 0.025, 32, false); 149 | 150 | // 创建画布 151 | const canvas = document.createElement("canvas"); 152 | canvas.width = 256; 153 | canvas.height = 1; 154 | 155 | // 获取画布上下文 156 | const context = canvas.getContext("2d") as CanvasRenderingContext2D; 157 | 158 | // 创建线性渐变 159 | const gradient = context.createLinearGradient(0, 0, canvas.width, 0); 160 | gradient.addColorStop(0, "#ffA500"); // 橙色 161 | gradient.addColorStop(1, "#ff0000"); // 红色 162 | 163 | // 填充画布 164 | context.fillStyle = gradient; 165 | context.fillRect(0, 0, canvas.width, canvas.height); 166 | 167 | // 创建渐变纹理 168 | const gradientTexture = new THREE.CanvasTexture(canvas); 169 | 170 | // 创建材质 171 | const tubeMaterial = new THREE.MeshBasicMaterial({ 172 | map: gradientTexture, 173 | side: THREE.DoubleSide, // 如果需要双面渲染,可以添加这一行 174 | }); 175 | // 设置初始透明度为 0 176 | tubeMaterial.opacity = 0; 177 | tubeMaterial.transparent = true; 178 | const tube = new THREE.Mesh(tubeGeometry, tubeMaterial); 179 | // Position the tube 180 | tube.position.z = -1.2; 181 | tube.position.y = -0.5; 182 | this.tube = tube; 183 | this.container.add(this.tube); 184 | 185 | // 定义动画持续时间 186 | const duration = 2; // 5 秒 187 | 188 | setTimeout(() => { 189 | let count = 0; 190 | const intervalId = setInterval(() => { 191 | // 执行的任务 192 | console.log("任务执行"); 193 | this.playAuto(); 194 | // 增加计数器 195 | count++; 196 | 197 | // 如果计数器达到3次,则清除定时器 198 | if (count === 2) { 199 | clearInterval(intervalId); // 清除定时器 200 | } 201 | }, 1000); // 每秒执行一次 202 | }, 500); 203 | 204 | gsap.to(tubeMaterial, { 205 | duration: 0.5, 206 | opacity: 1, // 设置目标透明度为 1,即完全不透明 207 | delay: 2.6, // 延迟 1 秒后开始播放动画 208 | ease: "power1.inOut", // 缓动函数,可以根据需要进行调整 209 | onComplete: () => { 210 | // 启动动画函数 211 | animateControlPoints(); 212 | 213 | // 创建一个新的标准材质,支持光照和反射 214 | const newMaterial = new MeshStandardMaterial({ 215 | color: "#b00000", 216 | metalness: 0.8, 217 | roughness: 0.8, 218 | }); // 这里设置你想要的颜色和材质属性 219 | 220 | // 遍历模型并替换所有材质 221 | this.newCar.traverse( 222 | (child: { isMesh: any; material: MeshStandardMaterial }) => { 223 | if (child.isMesh) { 224 | child.material = newMaterial; 225 | } 226 | } 227 | ); 228 | 229 | let countA = 0; 230 | const intervalIdA = setInterval(() => { 231 | // 执行的任务 232 | console.log("任务执行2"); 233 | this.playAuto(); 234 | // 增加计数器 235 | countA++; 236 | 237 | // 如果计数器达到3次,则清除定时器 238 | if (countA === 5) { 239 | clearInterval(intervalIdA); 240 | } 241 | }, 500); // 每秒执行一次 242 | 243 | gsap.to(this.tube.position, { 244 | duration: 1, 245 | x: 0.2, // 设置 x 轴的目标位置 246 | z: -1, // 设置 z 轴的目标位置 247 | ease: "power1.inOut", // 缓动函数,可以根据需要进行调整 248 | delay: 3.1, // 延迟 1 秒后开始播放动画 249 | onComplete: () => { 250 | // 在动画完成后执行的操作 251 | 252 | // 创建一个新的标准材质,支持光照和反射 253 | const newMaterial = new MeshStandardMaterial({ 254 | color: "#8a8886", 255 | metalness: 0.8, 256 | roughness: 0.8, 257 | }); // 这里设置你想要的颜色和材质属性 258 | 259 | // 遍历模型并替换所有材质 260 | this.newCar.traverse( 261 | (child: { isMesh: any; material: MeshStandardMaterial }) => { 262 | if (child.isMesh) { 263 | child.material = newMaterial; 264 | } 265 | } 266 | ); 267 | console.log("Animation completed!"); 268 | gsap.to(tubeMaterial, { 269 | duration: 0.6, 270 | opacity: 0, // 271 | ease: "power1.inOut", // 缓动函数,可以根据需要进行调整 272 | }); 273 | cancelAnimationFrame(this.animationLoop); 274 | }, 275 | }); 276 | }, 277 | }); 278 | 279 | // 动画函数 280 | const animateControlPoints = () => { 281 | this.updateControlPoint(3, 2.85, 0.007, 2, 0.007); 282 | this.updateControlPoint(4, null, null, 2.45, 0.0055); //(2, 1, 2.65), 283 | this.updateControlPoint(5, 1.2, 0.003, 2.45, 0.003); 284 | 285 | // new THREE.Vector3(0.5, 1, 2.8), 286 | this.updateControlPoint(6, 1, 0.003, 2.45, 0.0035); 287 | // 更新曲线和几何体 288 | curve.points = this.controlPoints; 289 | tube.geometry.dispose(); 290 | tube.geometry = new THREE.TubeGeometry(curve, 100, 0.025, 32, false); 291 | 292 | this.animationLoop = requestAnimationFrame(animateControlPoints); 293 | }; 294 | } 295 | 296 | updateControlPoint( 297 | index: number, 298 | xValue: number | null = null, 299 | xStep: number | null = 0, 300 | zValue: number | null = null, 301 | zStep: number | null = 0 302 | ): void { 303 | const point = this.controlPoints[index].clone(); 304 | 305 | if (xValue !== null && xStep !== null) { 306 | if (point.x < xValue) { 307 | point.setX(point.x + xStep); // 递增操作 308 | } else if (point.x > xValue) { 309 | point.setX(point.x - xStep); // 递减操作 310 | } 311 | } 312 | 313 | if (zValue !== null && zStep !== null) { 314 | if (point.z >= zValue) { 315 | point.setZ(point.z - zStep); // 递减操作 316 | } else if (point.z < zValue) { 317 | point.setZ(point.z + zStep); // 递增操作 318 | } 319 | } 320 | 321 | this.controlPoints[index] = point; 322 | } 323 | 324 | removeAllModelsAndAnimations() { 325 | this.isRun = false; 326 | 327 | // 移除道路模型 328 | if (this.model) { 329 | this.container.remove(this.model.scene); 330 | this.model = null; 331 | } 332 | 333 | // 移除 tube 对象 334 | if (this.tube) { 335 | this.container.remove(this.tube); 336 | this.tube.geometry.dispose(); 337 | this.tube.material.dispose(); 338 | this.tube = null; 339 | } 340 | 341 | // 移除汽车模型 342 | if (this.newCar) { 343 | this.container.remove(this.newCar); 344 | this.newCar = null; 345 | } 346 | 347 | // 停止所有动画循环 348 | if (this.AnimationFrame) { 349 | cancelAnimationFrame(this.AnimationFrame); 350 | this.AnimationFrame = null; 351 | } 352 | if (this.animationLoop) { 353 | cancelAnimationFrame(this.animationLoop); 354 | this.animationLoop = null; 355 | } 356 | } 357 | 358 | 359 | playAuto() { 360 | const bgm = new Howl({ 361 | src: "audio/roadBgm.mp3", 362 | loop: false, 363 | }); 364 | bgm.play(); 365 | } 366 | } 367 | -------------------------------------------------------------------------------- /src/Experience/World/Speedup.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | import * as STDLIB from "three-stdlib"; 4 | 5 | import type Experience from "../Experience"; 6 | 7 | import speedUpVertexShader from "../Shaders/Speedup/vert.glsl"; 8 | import speedUpFragmentShader from "../Shaders/Speedup/frag.glsl"; 9 | 10 | export default class Speedup extends kokomi.Component { 11 | declare base: Experience; 12 | model: STDLIB.GLTF; 13 | uj: kokomi.UniformInjector; 14 | material: THREE.ShaderMaterial; 15 | constructor(base: Experience) { 16 | super(base); 17 | 18 | const model = this.base.am.items["sm_speedup"] as STDLIB.GLTF; 19 | this.model = model; 20 | 21 | const modelParts = kokomi.flatModel(model.scene); 22 | // kokomi.printModel(modelParts); 23 | 24 | const uj = new kokomi.UniformInjector(this.base); 25 | this.uj = uj; 26 | const material = new THREE.ShaderMaterial({ 27 | vertexShader: speedUpVertexShader, 28 | fragmentShader: speedUpFragmentShader, 29 | transparent: true, 30 | depthWrite: false, 31 | uniforms: { 32 | ...uj.shadertoyUniforms, 33 | uSpeed: { 34 | value: this.base.params.speed, 35 | }, 36 | uOpacity: { 37 | value: this.base.params.speedUpOpacity, 38 | }, 39 | }, 40 | }); 41 | this.material = material; 42 | 43 | const speedupMesh = modelParts[1] as THREE.Mesh; 44 | speedupMesh.material = material; 45 | } 46 | addExisting() { 47 | this.container.add(this.model.scene); 48 | } 49 | update(): void { 50 | this.uj.injectShadertoyUniforms(this.material.uniforms); 51 | 52 | this.material.uniforms.uSpeed.value = this.base.params.speed; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Experience/World/StartRoom.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | import * as STDLIB from "three-stdlib"; 4 | 5 | import type Experience from "../Experience"; 6 | 7 | import reflecFloorVertexShader from "../Shaders/ReflecFloor/vert.glsl"; 8 | import reflecFloorFragmentShader from "../Shaders/ReflecFloor/frag.glsl"; 9 | 10 | import { MeshReflectorMaterial } from "../Utils/meshReflectorMaterial"; 11 | 12 | export default class StartRoom extends kokomi.Component { 13 | declare base: Experience; 14 | model: STDLIB.GLTF; 15 | uj: kokomi.UniformInjector; 16 | lightMat: THREE.MeshStandardMaterial; 17 | customFloorMat: kokomi.CustomShaderMaterial; 18 | constructor(base: Experience) { 19 | super(base); 20 | 21 | const model = this.base.am.items["sm_startroom"] as STDLIB.GLTF; 22 | this.model = model; 23 | 24 | const modelParts = kokomi.flatModel(model.scene); 25 | // kokomi.printModel(modelParts); 26 | 27 | const light001 = modelParts[1] as THREE.Mesh; 28 | const lightMat = light001.material as THREE.MeshStandardMaterial; 29 | this.lightMat = lightMat; 30 | lightMat.emissive = new THREE.Color("white"); 31 | lightMat.emissiveIntensity = 1; 32 | lightMat.toneMapped = false; 33 | lightMat.transparent = true; 34 | this.lightMat.alphaTest = 0.1; 35 | 36 | const ReflecFloor = modelParts[2] as THREE.Mesh; 37 | const floorMat = ReflecFloor.material as THREE.MeshPhysicalMaterial; 38 | floorMat.aoMap = this.base.am.items["ut_startroom_ao"]; 39 | floorMat.lightMap = this.base.am.items["ut_startroom_light"]; 40 | floorMat.normalMap = this.base.am.items["ut_floor_normal"]; 41 | floorMat.roughnessMap = this.base.am.items["ut_floor_roughness"]; 42 | floorMat.envMapIntensity = 0; 43 | 44 | // const reflectPlane = new THREE.Mesh( 45 | // new THREE.PlaneGeometry(100, 100), 46 | // new THREE.MeshBasicMaterial() 47 | // ); 48 | // reflectPlane.rotation.x = -Math.PI / 2; 49 | // this.container.add(reflectPlane); 50 | // const reflectMat = new kokomi.MeshReflectorMaterial( 51 | // this.base, 52 | // reflectPlane, 53 | // { 54 | // resolution: 1024, 55 | // blur: [1000, 1000], 56 | // mixBlur: 4, 57 | // mixStrength: 1, 58 | // mirror: 1, 59 | // } 60 | // ); 61 | // // @ts-ignore 62 | // reflectPlane.material = reflectMat.material; 63 | // ReflecFloor.visible = false; 64 | 65 | const uj = new kokomi.UniformInjector(this.base); 66 | this.uj = uj; 67 | 68 | const customFloorMat = new kokomi.CustomShaderMaterial({ 69 | baseMaterial: floorMat, 70 | vertexShader: reflecFloorVertexShader, 71 | fragmentShader: reflecFloorFragmentShader, 72 | uniforms: { 73 | ...uj.shadertoyUniforms, 74 | uColor: { 75 | value: new THREE.Color("#ffffff"), 76 | }, 77 | uSpeed: { 78 | value: this.base.params.speed, 79 | }, 80 | uReflectMatrix: { 81 | value: new THREE.Matrix4(), 82 | }, 83 | uReflectTexture: { 84 | value: null, 85 | }, 86 | uReflectIntensity: { 87 | value: 25, 88 | }, 89 | uMipmapTextureSize: { 90 | value: new THREE.Vector2(window.innerWidth, window.innerHeight), 91 | }, 92 | }, 93 | }); 94 | this.customFloorMat = customFloorMat; 95 | ReflecFloor.material = customFloorMat; 96 | 97 | this.base.resizer.on("resize", () => { 98 | this.customFloorMat.uniforms.uMipmapTextureSize.value = new THREE.Vector2( 99 | window.innerWidth, 100 | window.innerHeight 101 | ); 102 | }); 103 | 104 | // const reflectMat = new kokomi.MeshReflectorMaterial( 105 | // this.base, 106 | // ReflecFloor, 107 | // { 108 | // resolution: 1024, 109 | // blur: [1000, 1000], 110 | // mixBlur: 4, 111 | // mixStrength: 1, 112 | // mirror: 1, 113 | // ignoreObjects: [ReflecFloor], 114 | // } 115 | // ); 116 | // customFloorMat.uniforms.uReflectMatrix.value = 117 | // reflectMat.material._textureMatrix.value; 118 | // customFloorMat.uniforms.uReflectTexture.value = 119 | // reflectMat.material._tDiffuse.value; 120 | 121 | const reflectMat = new MeshReflectorMaterial(this.base, ReflecFloor, { 122 | resolution: 1024, 123 | ignoreObjects: [light001, ReflecFloor], 124 | }); 125 | customFloorMat.uniforms.uReflectMatrix.value = reflectMat._reflectMatrix; 126 | // customFloorMat.uniforms.uReflectTexture.value = 127 | // reflectMat._renderTexture.rt.texture; 128 | customFloorMat.uniforms.uReflectTexture.value = 129 | reflectMat.mipmapFBO.rt.texture; 130 | } 131 | addExisting() { 132 | this.container.add(this.model.scene); 133 | } 134 | toggleModelVisibility(isShow:boolean) { 135 | this.model.scene.visible = isShow; 136 | } 137 | update(): void { 138 | this.uj.injectShadertoyUniforms(this.customFloorMat.uniforms); 139 | 140 | this.customFloorMat.uniforms.uSpeed.value = this.base.params.speed; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Experience/World/TestObject.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | 4 | import type Experience from "../Experience"; 5 | 6 | import testObjectVertexShader from "../Shaders/TestObject/vert.glsl"; 7 | import testObjectFragmentShader from "../Shaders/TestObject/frag.glsl"; 8 | 9 | export default class TestObject extends kokomi.Component { 10 | declare base: Experience; 11 | material: THREE.ShaderMaterial; 12 | mesh: THREE.Mesh; 13 | uj: kokomi.UniformInjector; 14 | constructor(base: Experience) { 15 | super(base); 16 | 17 | const params = { 18 | uDistort: { 19 | value: 1, 20 | }, 21 | }; 22 | 23 | const geometry = new THREE.SphereGeometry(2, 64, 64); 24 | // const geometry = new THREE.PlaneGeometry(4, 4); 25 | const material = new THREE.ShaderMaterial({ 26 | vertexShader: testObjectVertexShader, 27 | fragmentShader: testObjectFragmentShader, 28 | }); 29 | this.material = material; 30 | const mesh = new THREE.Mesh(geometry, material); 31 | this.mesh = mesh; 32 | 33 | const uj = new kokomi.UniformInjector(this.base); 34 | this.uj = uj; 35 | material.uniforms = { 36 | ...material.uniforms, 37 | ...uj.shadertoyUniforms, 38 | ...params, 39 | }; 40 | 41 | const debug = this.base.debug; 42 | if (debug.active) { 43 | const debugFolder = debug.ui?.addFolder("testObject"); 44 | debugFolder 45 | ?.add(params.uDistort, "value") 46 | .min(0) 47 | .max(2) 48 | .step(0.01) 49 | .name("distort"); 50 | } 51 | } 52 | addExisting() { 53 | this.container.add(this.mesh); 54 | } 55 | update() { 56 | this.uj.injectShadertoyUniforms(this.material.uniforms); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Experience/World/World.ts: -------------------------------------------------------------------------------- 1 | import * as kokomi from "kokomi.js"; 2 | import * as THREE from "three"; 3 | import gsap from "gsap"; 4 | // import { Howl } from "howler"; 5 | import TWEEN from "three/examples/jsm/libs/tween.module.js"; 6 | import type Experience from "../Experience"; 7 | 8 | import TestObject from "./TestObject"; 9 | import DynamicEnv from "./DynamicEnv"; 10 | import StartRoom from "./StartRoom"; 11 | import Car from "./Car"; 12 | import Speedup from "./Speedup"; 13 | import CameraShake from "./CameraShake"; 14 | import Furina from "./Furina"; 15 | import Road from "./Road"; 16 | import City from "./City"; 17 | export default class World extends kokomi.Component { 18 | declare base: Experience; 19 | testObject: TestObject | null; 20 | dynamicEnv!: DynamicEnv; 21 | startRoom!: StartRoom; 22 | car!: Car; 23 | road!: Road; 24 | city!: City; 25 | furina!: Furina; 26 | speedup!: Speedup; 27 | environment!: kokomi.Environment; 28 | cameraShake!: CameraShake; 29 | isWheels: boolean; 30 | currentIndex: number; 31 | ambientLight: any; 32 | t1!: ReturnType; 33 | t2!: ReturnType; 34 | t3!: ReturnType; 35 | t4!: ReturnType; 36 | t5!: ReturnType; 37 | t6!: ReturnType; 38 | t7!: ReturnType; 39 | t8!: ReturnType; 40 | t9!: ReturnType; 41 | constructor(base: Experience) { 42 | super(base); 43 | 44 | this.testObject = null; 45 | this.isWheels = false; 46 | this.currentIndex = 0; 47 | this.base.am.on("ready", () => { 48 | this.handleAssets(); 49 | this.setLine(); 50 | // this.testObject = new TestObject(this.base); 51 | // this.testObject.addExisting(); 52 | 53 | const t1 = gsap.timeline(); 54 | this.t1 = t1; 55 | const t2 = gsap.timeline(); 56 | this.t2 = t2; 57 | const t3 = gsap.timeline(); 58 | this.t3 = t3; 59 | const t4 = gsap.timeline(); 60 | this.t4 = t4; 61 | const t5 = gsap.timeline(); 62 | this.t5 = t5; 63 | const t6 = gsap.timeline(); 64 | this.t6 = t6; 65 | const t7 = gsap.timeline(); 66 | this.t7 = t7; 67 | const t8 = gsap.timeline(); 68 | this.t8 = t8; 69 | const t9 = gsap.timeline(); 70 | this.t9 = t9; 71 | 72 | this.base.scene.background = new THREE.Color("black"); 73 | 74 | const envmap1 = kokomi.getEnvmapFromHDRTexture( 75 | this.base.renderer, 76 | this.base.am.items["ut_env_night"] 77 | ); 78 | const envmap2 = kokomi.getEnvmapFromHDRTexture( 79 | this.base.renderer, 80 | this.base.am.items["ut_env_light"] 81 | ); 82 | const dynamicEnv = new DynamicEnv(this.base, { 83 | envmap1, 84 | envmap2, 85 | }); 86 | this.dynamicEnv = dynamicEnv; 87 | this.base.scene.environment = dynamicEnv.envmap; 88 | dynamicEnv.setWeight(1); 89 | // dynamicEnv.lerpWeight(1, 4); 90 | 91 | console.log(this.base.controls.controls); 92 | this.base.controls.controls.maxDistance = 30; 93 | const startRoom = new StartRoom(this.base); 94 | this.startRoom = startRoom; 95 | startRoom.addExisting(); 96 | 97 | const car = new Car(this.base); 98 | this.car = car; 99 | car.addExisting(); 100 | 101 | const road = new Road(this.base); 102 | this.road = road; 103 | const city = new City(this.base); 104 | this.city = city; 105 | if (this.base.params.isFurina) { 106 | const furina = new Furina(this.base); 107 | this.furina = furina; 108 | furina.addExisting(); 109 | } 110 | 111 | const speedup = new Speedup(this.base); 112 | this.speedup = speedup; 113 | speedup.addExisting(); 114 | 115 | const environment = new kokomi.Environment(this.base, { 116 | resolution: 512, 117 | scene: this.base.scene, 118 | options: { 119 | minFilter: THREE.LinearMipMapLinearFilter, 120 | anisotropy: 0, 121 | depthBuffer: false, 122 | generateMipmaps: true, 123 | }, 124 | textureType: THREE.UnsignedByteType, 125 | ignoreObjects: [this.car.model.scene], 126 | }); 127 | this.environment = environment; 128 | 129 | const cameraShake = new CameraShake(this.base); 130 | this.cameraShake = cameraShake; 131 | cameraShake.setIntensity(0); 132 | 133 | this.base.interactionManager.add(car.model.scene); 134 | car.model.scene.addEventListener("click", () => { 135 | if (this.currentIndex == 0) { 136 | this.rush(); 137 | } 138 | }); 139 | 140 | this.on("enter", () => { 141 | this.base.params.disableInteract = false; 142 | }); 143 | 144 | this.enter(); 145 | // this.enterDirectly(); 146 | 147 | // const bgm = new Howl({ 148 | // src: "audio/bgm.mp3", 149 | // loop: true, 150 | // }); 151 | // bgm.play(); 152 | }); 153 | } 154 | handleAssets() { 155 | const items = this.base.am.items; 156 | (items["ut_car_body_ao"] as THREE.Texture).flipY = false; 157 | (items["ut_car_body_ao"] as THREE.Texture).colorSpace = 158 | THREE.LinearSRGBColorSpace; 159 | (items["ut_car_body_ao"] as THREE.Texture).minFilter = THREE.NearestFilter; 160 | (items["ut_car_body_ao"] as THREE.Texture).magFilter = THREE.NearestFilter; 161 | (items["ut_car_body_ao"] as THREE.Texture).channel = 1; 162 | (items["ut_startroom_ao"] as THREE.Texture).flipY = false; 163 | (items["ut_startroom_ao"] as THREE.Texture).colorSpace = 164 | THREE.LinearSRGBColorSpace; 165 | (items["ut_startroom_ao"] as THREE.Texture).channel = 1; 166 | (items["ut_startroom_light"] as THREE.Texture).flipY = false; 167 | (items["ut_startroom_light"] as THREE.Texture).colorSpace = 168 | THREE.SRGBColorSpace; 169 | (items["ut_startroom_light"] as THREE.Texture).channel = 1; 170 | (items["ut_floor_normal"] as THREE.Texture).flipY = false; 171 | (items["ut_floor_normal"] as THREE.Texture).colorSpace = 172 | THREE.LinearSRGBColorSpace; 173 | (items["ut_floor_normal"] as THREE.Texture).wrapS = THREE.RepeatWrapping; 174 | (items["ut_floor_normal"] as THREE.Texture).wrapT = THREE.RepeatWrapping; 175 | (items["ut_floor_roughness"] as THREE.Texture).flipY = false; 176 | (items["ut_floor_roughness"] as THREE.Texture).colorSpace = 177 | THREE.LinearSRGBColorSpace; 178 | (items["ut_floor_roughness"] as THREE.Texture).wrapS = THREE.RepeatWrapping; 179 | (items["ut_floor_roughness"] as THREE.Texture).wrapT = THREE.RepeatWrapping; 180 | 181 | if (this.base.params.isFurina) { 182 | (items["decal"] as THREE.Texture).flipY = false; 183 | (items["decal"] as THREE.Texture).colorSpace = THREE.LinearSRGBColorSpace; 184 | } 185 | } 186 | clearAllTweens() { 187 | this.t1.clear(); 188 | this.t2.clear(); 189 | this.t3.clear(); 190 | this.t4.clear(); 191 | this.t5.clear(); 192 | this.t6.clear(); 193 | this.t7.clear(); 194 | this.t8.clear(); 195 | this.t9.clear(); 196 | } 197 | enter() { 198 | if (this.currentIndex == 0) { 199 | this.startRoom.lightMat.opacity = 0; 200 | this.rush(); 201 | const options = { x: 0.23, y: 2.85, z: -11.5 }; 202 | this.moveCameraToPosition( 203 | options, 204 | () => { 205 | this.rushDone(); 206 | this.VisibilityTitle1(true); 207 | }, 208 | 4 209 | ); 210 | } 211 | 212 | this.base.params.disableInteract = true; 213 | this.dynamicEnv.setWeight(0); 214 | this.startRoom.lightMat.emissive.set(new THREE.Color("#000000")); 215 | this.startRoom.lightMat.emissiveIntensity = 0; 216 | this.dynamicEnv.setIntensity(0); 217 | this.startRoom.customFloorMat.uniforms.uColor.value.set( 218 | new THREE.Color("#000000") 219 | ); 220 | this.startRoom.customFloorMat.uniforms.uReflectIntensity.value = 0; 221 | this.furina?.setColor(new THREE.Color("#000000")); 222 | 223 | document.querySelector(".loader-screen")?.classList.add("hollow"); 224 | 225 | this.base.params.isCameraMoving = true; 226 | // this.t1.to(this.base.params.cameraPos, { 227 | // x: 0.23, 228 | // y: 2.85, 229 | // z: -11.5, 230 | // duration: 0.1, 231 | // ease: "power2.inOut", 232 | // onComplete: () => { 233 | // this.base.params.isCameraMoving = false; 234 | // this.emit("enter"); 235 | // }, 236 | // }); 237 | const lightColor = new THREE.Color(); 238 | const blackColor = new THREE.Color("#000000"); 239 | const whiteColor = new THREE.Color("#ffffff"); 240 | this.t2.to(this.base.params, { 241 | lightAlpha: 1, 242 | lightIntensity: 1, 243 | reflectIntensity: 25, 244 | furinaLerpColor: 1, 245 | duration: 4, 246 | delay: 1, 247 | ease: "power2.inOut", 248 | onUpdate: () => { 249 | lightColor 250 | .copy(blackColor) 251 | .lerp(whiteColor, this.base.params.lightAlpha); 252 | 253 | this.startRoom.lightMat.emissive.set(lightColor); 254 | this.startRoom.lightMat.emissiveIntensity = 255 | this.base.params.lightIntensity; 256 | 257 | this.startRoom.customFloorMat.uniforms.uColor.value.set(lightColor); 258 | this.startRoom.customFloorMat.uniforms.uReflectIntensity.value = 259 | this.base.params.reflectIntensity; 260 | 261 | this.furina?.setColor(lightColor); 262 | }, 263 | }); 264 | this.t3 265 | .to(this.base.params, { 266 | envIntensity: 1, 267 | duration: 4, 268 | delay: 0.5, 269 | ease: "power2.inOut", 270 | onUpdate: () => { 271 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 272 | }, 273 | }) 274 | .to( 275 | this.base.params, 276 | { 277 | envWeight: 1, 278 | duration: 4, 279 | ease: "power2.inOut", 280 | onUpdate: () => { 281 | this.dynamicEnv.setWeight(this.base.params.envWeight); 282 | }, 283 | }, 284 | "-=2.5" 285 | ); 286 | } 287 | enterDirectly() { 288 | document.querySelector(".loader-screen")?.classList.add("hollow"); 289 | this.base.params.isCameraMoving = false; 290 | this.base.controls.controls.setPosition(0, 0.8, -7); 291 | this.base.params.envIntensity = 1; 292 | this.emit("enter"); 293 | } 294 | async rush() { 295 | if (this.currentIndex !== 0) { 296 | return; 297 | } 298 | if (this.base.params.isRushing) { 299 | this.rushDone(); 300 | return; 301 | } 302 | 303 | if (this.base.params.disableInteract) { 304 | return; 305 | } 306 | this.isWheels = true; 307 | this.wheels(); 308 | this.base.params.disableInteract = true; 309 | this.clearAllTweens(); 310 | // this.base.controls.controls.setPosition(6.4, 1, -3); 311 | const floorColor = new THREE.Color(); 312 | const blackColor = new THREE.Color("#000000"); 313 | const camera = this.base.camera as THREE.PerspectiveCamera; 314 | 315 | const furinaColor = new THREE.Color(); 316 | const furinaFadeColor = new THREE.Color("#666666"); 317 | 318 | this.furina?.drive(); 319 | 320 | this.t4 321 | .to(this.base.params, { 322 | speed: 4, 323 | duration: 2, 324 | ease: "power2.out", 325 | onComplete: () => { 326 | this.base.params.isRushing = true; 327 | this.base.params.disableInteract = false; 328 | }, 329 | }) 330 | .to(this.base.params, { 331 | speed: 10, 332 | duration: 4, 333 | ease: "power2.out", 334 | }); 335 | this.t5.to(this.base.params, { 336 | lightOpacity: 0, 337 | duration: 1, 338 | ease: "power2.out", 339 | onUpdate: () => { 340 | //隐藏灯光板 341 | this.startRoom.lightMat.opacity = this.base.params.lightOpacity; 342 | }, 343 | }); 344 | this.t6.fromTo( 345 | this.base.params, 346 | { 347 | floorLerpColor: 0, 348 | furinaLerpColor: 0, 349 | }, 350 | { 351 | floorLerpColor: 1, 352 | furinaLerpColor: 1, 353 | duration: 4, 354 | ease: "none", 355 | onUpdate: () => { 356 | floorColor.lerp(blackColor, this.base.params.floorLerpColor); 357 | this.startRoom.customFloorMat.uniforms.uColor.value.set(floorColor); 358 | 359 | furinaColor.lerp(furinaFadeColor, this.base.params.furinaLerpColor); 360 | this.furina?.setColor(furinaColor); 361 | }, 362 | } 363 | ); 364 | this.t7.to(this.base.params, { 365 | envIntensity: 0.01, 366 | duration: 1, 367 | ease: "power2.out", 368 | onUpdate: () => { 369 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 370 | }, 371 | }); 372 | this.t8.to(this.base.params, { 373 | speedUpOpacity: 1, 374 | cameraFov: 36, 375 | duration: 2, 376 | ease: "power2.out", 377 | onUpdate: () => { 378 | this.speedup.material.uniforms.uOpacity.value = 379 | this.base.params.speedUpOpacity; 380 | 381 | camera.fov = this.base.params.cameraFov; 382 | camera.updateProjectionMatrix(); 383 | }, 384 | }); 385 | await kokomi.sleep(1000); 386 | this.base.scene.environment = this.environment.texture; 387 | this.t9.to(this.base.params, { 388 | carBodyEnvIntensity: 10, 389 | cameraShakeIntensity: 1, 390 | bloomLuminanceSmoothing: 0.4, 391 | bloomIntensity: 2, 392 | duration: 4, 393 | ease: "power2.out", 394 | onUpdate: () => { 395 | this.car.setBodyEnvmapIntensity(this.base.params.carBodyEnvIntensity); 396 | this.cameraShake.setIntensity(this.base.params.cameraShakeIntensity); 397 | this.base.post.setLuminanceSmoothing( 398 | this.base.params.bloomLuminanceSmoothing 399 | ); 400 | this.base.post.setIntensity(this.base.params.bloomIntensity); 401 | }, 402 | }); 403 | } 404 | // 车轮滚动 405 | wheels() { 406 | this.VisibilityMenu(false); 407 | // 从资源管理器中获取汽车模型 408 | const carModel = this.base.am.items["sm_car"]; 409 | const wheelFrontLeft = this.findObjectByName( 410 | carModel.scene, 411 | "wheels001_wheels6_0" 412 | ); 413 | const wheelFrontRight = this.findObjectByName( 414 | carModel.scene, 415 | "wheels_wheels6_0" 416 | ); 417 | // 确保所有车轮对象都存在 418 | if (wheelFrontLeft && wheelFrontRight) { 419 | // 渲染循环 420 | const animate = () => { 421 | if (!this.isWheels) { 422 | this.VisibilityMenu(true); 423 | return; // 如果标志为false,停止动画 424 | } 425 | requestAnimationFrame(animate); 426 | // 旋转车轮 427 | const rotationSpeed = 0.1; // 车轮旋转速度 428 | wheelFrontLeft.rotation.x -= rotationSpeed; 429 | wheelFrontRight.rotation.x -= rotationSpeed; 430 | }; 431 | 432 | animate(); 433 | } else { 434 | console.log("找不到所有车轮对象"); 435 | } 436 | } 437 | 438 | // 查找车轮对象 439 | findObjectByName( 440 | obj: { name: any; children: string | any[] }, 441 | name: string 442 | ): any { 443 | if (obj.name === name) { 444 | return obj; 445 | } 446 | for (let i = 0; i < obj.children.length; i++) { 447 | const result = this.findObjectByName(obj.children[i], name); 448 | if (result) { 449 | return result; 450 | } 451 | } 452 | return null; 453 | } 454 | rushDone() { 455 | if (this.base.params.disableInteract) { 456 | return; 457 | } 458 | 459 | this.base.params.disableInteract = true; 460 | this.clearAllTweens(); 461 | const floorColor = new THREE.Color(); 462 | const whiteColor = new THREE.Color("#ffffff"); 463 | const camera = this.base.camera as THREE.PerspectiveCamera; 464 | 465 | const furinaColor = new THREE.Color(); 466 | const furinaOriginalColor = new THREE.Color("#ffffff"); 467 | 468 | this.furina?.pause(); 469 | 470 | this.t4.to(this.base.params, { 471 | speed: 0, 472 | duration: 2, 473 | ease: "power2.out", 474 | onComplete: () => { 475 | this.base.params.isRushing = false; 476 | this.base.params.disableInteract = false; 477 | }, 478 | }); 479 | this.t5.to(this.base.params, { 480 | lightOpacity: 1, 481 | duration: 1, 482 | ease: "power2.out", 483 | onUpdate: () => { 484 | this.startRoom.lightMat.opacity = this.base.params.lightOpacity; 485 | }, 486 | }); 487 | this.t6.fromTo( 488 | this.base.params, 489 | { floorLerpColor: 0, furinaLerpColor: 0 }, 490 | { 491 | floorLerpColor: 1, 492 | furinaLerpColor: 1, 493 | duration: 4, 494 | ease: "none", 495 | onUpdate: () => { 496 | floorColor.lerp(whiteColor, this.base.params.floorLerpColor); 497 | this.startRoom.customFloorMat.uniforms.uColor.value.set(floorColor); 498 | 499 | furinaColor.lerp( 500 | furinaOriginalColor, 501 | this.base.params.furinaLerpColor 502 | ); 503 | this.furina?.setColor(furinaColor); 504 | }, 505 | } 506 | ); 507 | this.t7.to(this.base.params, { 508 | envIntensity: 1, 509 | duration: 1, 510 | ease: "power2.out", 511 | onUpdate: () => { 512 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 513 | }, 514 | }); 515 | this.t8.to(this.base.params, { 516 | speedUpOpacity: 0, 517 | cameraFov: 33.4, 518 | duration: 2, 519 | ease: "power2.out", 520 | onUpdate: () => { 521 | this.speedup.material.uniforms.uOpacity.value = 522 | this.base.params.speedUpOpacity; 523 | 524 | camera.fov = this.base.params.cameraFov; 525 | camera.updateProjectionMatrix(); 526 | }, 527 | }); 528 | this.t9.to(this.base.params, { 529 | carBodyEnvIntensity: 1, 530 | cameraShakeIntensity: 0, 531 | bloomLuminanceSmoothing: 1.6, 532 | bloomIntensity: 1, 533 | duration: 4, 534 | ease: "power2.out", 535 | onUpdate: () => { 536 | this.car.setBodyEnvmapIntensity(this.base.params.carBodyEnvIntensity); 537 | this.cameraShake.setIntensity(this.base.params.cameraShakeIntensity); 538 | this.base.post.setLuminanceSmoothing( 539 | this.base.params.bloomLuminanceSmoothing 540 | ); 541 | this.base.post.setIntensity(this.base.params.bloomIntensity); 542 | }, 543 | }); 544 | this.base.scene.environment = this.dynamicEnv.envmap; 545 | setTimeout(() => { 546 | this.isWheels = false; 547 | const father = document.querySelector(".line") as Element; 548 | //@ts-ignore 549 | father.style.display = "flex"; // 设置元素 display 为 none 550 | }, 1500); 551 | } 552 | rush3() { 553 | this.city.addExisting(); 554 | setTimeout(() => { 555 | const targetPosition = { x: -31.82, y: 56.71, z: 3.61 }; 556 | this.moveCameraToPosition(targetPosition, null, 5); 557 | setTimeout(() => { 558 | const targetPosition2 = { x: -14.53, y: 8.41, z: 0.01 }; 559 | this.moveCameraToPosition( 560 | targetPosition2, 561 | () => { 562 | const father = document.querySelector(".line") as Element; 563 | //@ts-ignore 564 | father.style.display = "flex"; // 设置元素 display 为 none 565 | }, 566 | 2 567 | ); 568 | }, 5000); 569 | }, 2000); 570 | this.isWheels = true; 571 | this.wheels(); 572 | this.base.params.disableInteract = true; 573 | this.clearAllTweens(); 574 | setTimeout(() => { 575 | this.VisibilityMenu(true); 576 | this.VisibilityTitle3(true); 577 | }, 7000); 578 | // this.base.controls.controls.setPosition(6.4, 1, -3); 579 | const floorColor = new THREE.Color(); 580 | const blackColor = new THREE.Color("#000000"); 581 | const camera = this.base.camera as THREE.PerspectiveCamera; 582 | camera.near = 0.1; // 将近剪切面调近 583 | camera.far = 100; // 根据场景实际情况调整远剪切面 584 | camera.updateProjectionMatrix(); 585 | 586 | const furinaColor = new THREE.Color(); 587 | const furinaFadeColor = new THREE.Color("#666666"); 588 | 589 | this.furina?.drive(); 590 | const ambientLight = new THREE.AmbientLight("0xffffff", 0.1); // 第一个参数是颜色,第二个参数是光强度 // 第一个参数是颜色,第二个参数是光强度 591 | ambientLight.position.y = ambientLight.position.y + 2; // 设置灯光的位置 592 | this.ambientLight = ambientLight; 593 | this.container.add(this.ambientLight); 594 | this.t4 595 | .to(this.base.params, { 596 | speed: 4, 597 | duration: 2, 598 | ease: "power2.out", 599 | onComplete: () => { 600 | this.base.params.isRushing = true; 601 | this.base.params.disableInteract = false; 602 | }, 603 | }) 604 | .to(this.base.params, { 605 | speed: 10, 606 | duration: 4, 607 | ease: "power2.out", 608 | }); 609 | this.t5.to(this.base.params, { 610 | lightOpacity: 0, 611 | duration: 1, 612 | ease: "power2.out", 613 | onUpdate: () => { 614 | //隐藏灯光板 615 | this.startRoom.lightMat.opacity = this.base.params.lightOpacity; 616 | }, 617 | }); 618 | this.t6.fromTo( 619 | this.base.params, 620 | { 621 | floorLerpColor: 0, 622 | furinaLerpColor: 0, 623 | }, 624 | { 625 | floorLerpColor: 1, 626 | furinaLerpColor: 1, 627 | duration: 4, 628 | ease: "none", 629 | onUpdate: () => { 630 | floorColor.lerp(blackColor, this.base.params.floorLerpColor); 631 | this.startRoom.customFloorMat.uniforms.uColor.value.set(floorColor); 632 | 633 | furinaColor.lerp(furinaFadeColor, this.base.params.furinaLerpColor); 634 | // this.furina?.setColor(furinaColor); 635 | }, 636 | } 637 | ); 638 | 639 | // ---- 640 | this.startRoom.toggleModelVisibility(false); 641 | 642 | // ---- 643 | this.t7.to(this.base.params, { 644 | envIntensity: 0.01, 645 | duration: 1, 646 | ease: "power2.out", 647 | onUpdate: () => { 648 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 649 | }, 650 | }); 651 | // ---- 652 | } 653 | setLine() { 654 | const lines = document.querySelectorAll(".child"); 655 | lines.forEach((line, index) => { 656 | line.addEventListener("click", () => { 657 | const oldIndex = Array.from(lines).findIndex((line) => 658 | line.classList.contains("act") 659 | ); 660 | if (oldIndex == index ) { 661 | return; 662 | } 663 | // 获取已经存在act类的元素索引值 664 | const father = document.querySelector(".line") as Element; 665 | //@ts-ignore 666 | father.style.display = "none"; 667 | if (oldIndex == 1) { 668 | this.rushDone2(); 669 | } 670 | if (oldIndex == 2) { 671 | this.rushDone3(); 672 | } 673 | if (this.currentIndex !== null) { 674 | lines.forEach((e, index) => { 675 | lines[index].classList.remove("act"); 676 | }); 677 | } 678 | line.classList.add("act"); 679 | // 根据索引设置不同的目标位置 680 | let targetPosition; 681 | switch (index) { 682 | case 0: 683 | this.VisibilityTitle1(true); 684 | targetPosition = { x: 0.23, y: 2.85, z: -11.5 }; 685 | this.moveCameraToPosition(targetPosition, () => { 686 | //@ts-ignore 687 | father.style.display = "flex"; 688 | }); 689 | break; 690 | case 1: 691 | this.VisibilityTitle1(false); 692 | targetPosition = { x: -23.4, y: 15.05, z: -0.04 }; 693 | this.moveCameraToPosition(targetPosition, this.rush2()); 694 | break; 695 | case 2: 696 | this.VisibilityTitle1(false); 697 | targetPosition = { x: -49.54, y: 41.86, z: 3.49 }; 698 | this.moveCameraToPosition(targetPosition, this.rush3()); 699 | break; 700 | // 添加其他 case 以处理其他索引的目标位置 701 | default: 702 | break; 703 | } 704 | 705 | this.currentIndex = index; 706 | }); 707 | }); 708 | } 709 | rushDone3() { 710 | this.city.removeAllModelsAndAnimations(); 711 | this.VisibilityTitle3(false); 712 | this.startRoom.toggleModelVisibility(true); 713 | this.container.remove(this.ambientLight); 714 | this.VisibilityTitle2(false); 715 | 716 | this.base.params.disableInteract = true; 717 | this.clearAllTweens(); 718 | const floorColor = new THREE.Color(); 719 | const whiteColor = new THREE.Color("#ffffff"); 720 | const camera = this.base.camera as THREE.PerspectiveCamera; 721 | 722 | const furinaColor = new THREE.Color(); 723 | const furinaOriginalColor = new THREE.Color("#ffffff"); 724 | 725 | this.furina?.pause(); 726 | 727 | this.t4.to(this.base.params, { 728 | speed: 0, 729 | duration: 2, 730 | ease: "power2.out", 731 | onComplete: () => { 732 | this.base.params.isRushing = false; 733 | this.base.params.disableInteract = false; 734 | }, 735 | }); 736 | this.t5.to(this.base.params, { 737 | lightOpacity: 1, 738 | duration: 1, 739 | ease: "power2.out", 740 | onUpdate: () => { 741 | this.startRoom.lightMat.opacity = this.base.params.lightOpacity; 742 | }, 743 | }); 744 | this.t6.fromTo( 745 | this.base.params, 746 | { floorLerpColor: 0, furinaLerpColor: 0 }, 747 | { 748 | floorLerpColor: 1, 749 | furinaLerpColor: 1, 750 | duration: 4, 751 | ease: "none", 752 | onUpdate: () => { 753 | floorColor.lerp(whiteColor, this.base.params.floorLerpColor); 754 | this.startRoom.customFloorMat.uniforms.uColor.value.set(floorColor); 755 | 756 | furinaColor.lerp( 757 | furinaOriginalColor, 758 | this.base.params.furinaLerpColor 759 | ); 760 | this.furina?.setColor(furinaColor); 761 | }, 762 | } 763 | ); 764 | this.t7.to(this.base.params, { 765 | envIntensity: 1, 766 | duration: 1, 767 | ease: "power2.out", 768 | onUpdate: () => { 769 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 770 | }, 771 | }); 772 | this.t8.to(this.base.params, { 773 | speedUpOpacity: 0, 774 | cameraFov: 33.4, 775 | duration: 2, 776 | ease: "power2.out", 777 | onUpdate: () => { 778 | this.speedup.material.uniforms.uOpacity.value = 779 | this.base.params.speedUpOpacity; 780 | 781 | camera.fov = this.base.params.cameraFov; 782 | camera.updateProjectionMatrix(); 783 | }, 784 | }); 785 | this.t9.to(this.base.params, { 786 | carBodyEnvIntensity: 1, 787 | cameraShakeIntensity: 0, 788 | bloomLuminanceSmoothing: 1.6, 789 | bloomIntensity: 1, 790 | duration: 4, 791 | ease: "power2.out", 792 | onUpdate: () => { 793 | this.car.setBodyEnvmapIntensity(this.base.params.carBodyEnvIntensity); 794 | this.cameraShake.setIntensity(this.base.params.cameraShakeIntensity); 795 | this.base.post.setLuminanceSmoothing( 796 | this.base.params.bloomLuminanceSmoothing 797 | ); 798 | this.base.post.setIntensity(this.base.params.bloomIntensity); 799 | }, 800 | }); 801 | this.base.scene.environment = this.dynamicEnv.envmap; 802 | setTimeout(() => { 803 | this.isWheels = false; 804 | }, 8000); 805 | } 806 | VisibilityMenu(show: boolean) { 807 | const menu = document.querySelector(".line") as HTMLElement; 808 | if (!show) { 809 | menu.style.opacity = "0"; 810 | } else { 811 | menu.style.opacity = "1"; 812 | } 813 | } 814 | VisibilityTitle1(show: boolean) { 815 | const title1 = document.querySelector(".title1") as HTMLElement; 816 | if (!show) { 817 | title1.style.opacity = "0"; 818 | } else { 819 | title1.style.opacity = "1"; 820 | } 821 | } 822 | VisibilityTitle2(show: boolean) { 823 | const title1 = document.querySelector(".safety") as HTMLElement; 824 | if (!show) { 825 | title1.style.opacity = "0"; 826 | } else { 827 | title1.style.opacity = "1"; 828 | } 829 | } 830 | VisibilityTitle3(show: boolean) { 831 | const title1 = document.querySelector(".fsd") as HTMLElement; 832 | if (!show) { 833 | title1.style.opacity = "0"; 834 | } else { 835 | title1.style.opacity = "1"; 836 | } 837 | } 838 | async rush2() { 839 | this.isWheels = true; 840 | this.wheels(); 841 | this.base.params.disableInteract = true; 842 | this.clearAllTweens(); 843 | setTimeout(() => { 844 | this.VisibilityMenu(true); 845 | }, 10000); 846 | // this.base.controls.controls.setPosition(6.4, 1, -3); 847 | const floorColor = new THREE.Color(); 848 | const blackColor = new THREE.Color("#000000"); 849 | const camera = this.base.camera as THREE.PerspectiveCamera; 850 | camera.near = 0.1; // 将近剪切面调近 851 | camera.far = 100; // 根据场景实际情况调整远剪切面 852 | camera.updateProjectionMatrix(); 853 | 854 | const furinaColor = new THREE.Color(); 855 | const furinaFadeColor = new THREE.Color("#666666"); 856 | 857 | this.furina?.drive(); 858 | const ambientLight = new THREE.AmbientLight("0xffffff", 0.5); // 第一个参数是颜色,第二个参数是光强度 // 第一个参数是颜色,第二个参数是光强度 859 | ambientLight.position.y = ambientLight.position.y + 2; // 设置灯光的位置 860 | this.ambientLight = ambientLight; 861 | this.container.add(this.ambientLight); 862 | this.t4 863 | .to(this.base.params, { 864 | speed: 4, 865 | duration: 2, 866 | ease: "power2.out", 867 | onComplete: () => { 868 | this.base.params.isRushing = true; 869 | this.base.params.disableInteract = false; 870 | }, 871 | }) 872 | .to(this.base.params, { 873 | speed: 10, 874 | duration: 4, 875 | ease: "power2.out", 876 | }); 877 | this.t5.to(this.base.params, { 878 | lightOpacity: 0, 879 | duration: 1, 880 | ease: "power2.out", 881 | onUpdate: () => { 882 | //隐藏灯光板 883 | this.startRoom.lightMat.opacity = this.base.params.lightOpacity; 884 | }, 885 | }); 886 | this.t6.fromTo( 887 | this.base.params, 888 | { 889 | floorLerpColor: 0, 890 | furinaLerpColor: 0, 891 | }, 892 | { 893 | floorLerpColor: 1, 894 | furinaLerpColor: 1, 895 | duration: 4, 896 | ease: "none", 897 | onUpdate: () => { 898 | floorColor.lerp(blackColor, this.base.params.floorLerpColor); 899 | this.startRoom.customFloorMat.uniforms.uColor.value.set(floorColor); 900 | 901 | furinaColor.lerp(furinaFadeColor, this.base.params.furinaLerpColor); 902 | // this.furina?.setColor(furinaColor); 903 | }, 904 | } 905 | ); 906 | 907 | // ---- 908 | this.startRoom.toggleModelVisibility(false); 909 | this.road.addExisting(); 910 | this.VisibilityTitle2(true); 911 | // ---- 912 | this.t7.to(this.base.params, { 913 | envIntensity: 0.01, 914 | duration: 1, 915 | ease: "power2.out", 916 | onUpdate: () => { 917 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 918 | }, 919 | }); 920 | } 921 | rushDone2() { 922 | this.road.removeAllModelsAndAnimations(); 923 | this.startRoom.toggleModelVisibility(true); 924 | this.container.remove(this.ambientLight); 925 | this.VisibilityTitle2(false); 926 | 927 | this.base.params.disableInteract = true; 928 | this.clearAllTweens(); 929 | const floorColor = new THREE.Color(); 930 | const whiteColor = new THREE.Color("#ffffff"); 931 | const camera = this.base.camera as THREE.PerspectiveCamera; 932 | 933 | const furinaColor = new THREE.Color(); 934 | const furinaOriginalColor = new THREE.Color("#ffffff"); 935 | 936 | this.furina?.pause(); 937 | 938 | this.t4.to(this.base.params, { 939 | speed: 0, 940 | duration: 2, 941 | ease: "power2.out", 942 | onComplete: () => { 943 | this.base.params.isRushing = false; 944 | this.base.params.disableInteract = false; 945 | }, 946 | }); 947 | this.t5.to(this.base.params, { 948 | lightOpacity: 1, 949 | duration: 1, 950 | ease: "power2.out", 951 | onUpdate: () => { 952 | this.startRoom.lightMat.opacity = this.base.params.lightOpacity; 953 | }, 954 | }); 955 | this.t6.fromTo( 956 | this.base.params, 957 | { floorLerpColor: 0, furinaLerpColor: 0 }, 958 | { 959 | floorLerpColor: 1, 960 | furinaLerpColor: 1, 961 | duration: 4, 962 | ease: "none", 963 | onUpdate: () => { 964 | floorColor.lerp(whiteColor, this.base.params.floorLerpColor); 965 | this.startRoom.customFloorMat.uniforms.uColor.value.set(floorColor); 966 | 967 | furinaColor.lerp( 968 | furinaOriginalColor, 969 | this.base.params.furinaLerpColor 970 | ); 971 | this.furina?.setColor(furinaColor); 972 | }, 973 | } 974 | ); 975 | this.t7.to(this.base.params, { 976 | envIntensity: 1, 977 | duration: 1, 978 | ease: "power2.out", 979 | onUpdate: () => { 980 | this.dynamicEnv.setIntensity(this.base.params.envIntensity); 981 | }, 982 | }); 983 | this.t8.to(this.base.params, { 984 | speedUpOpacity: 0, 985 | cameraFov: 33.4, 986 | duration: 2, 987 | ease: "power2.out", 988 | onUpdate: () => { 989 | this.speedup.material.uniforms.uOpacity.value = 990 | this.base.params.speedUpOpacity; 991 | 992 | camera.fov = this.base.params.cameraFov; 993 | camera.updateProjectionMatrix(); 994 | }, 995 | }); 996 | this.t9.to(this.base.params, { 997 | carBodyEnvIntensity: 1, 998 | cameraShakeIntensity: 0, 999 | bloomLuminanceSmoothing: 1.6, 1000 | bloomIntensity: 1, 1001 | duration: 4, 1002 | ease: "power2.out", 1003 | onUpdate: () => { 1004 | this.car.setBodyEnvmapIntensity(this.base.params.carBodyEnvIntensity); 1005 | this.cameraShake.setIntensity(this.base.params.cameraShakeIntensity); 1006 | this.base.post.setLuminanceSmoothing( 1007 | this.base.params.bloomLuminanceSmoothing 1008 | ); 1009 | this.base.post.setIntensity(this.base.params.bloomIntensity); 1010 | }, 1011 | }); 1012 | this.base.scene.environment = this.dynamicEnv.envmap; 1013 | setTimeout(() => { 1014 | this.isWheels = false; 1015 | }, 1500); 1016 | } 1017 | moveCameraToPosition( 1018 | targetPosition: any, 1019 | onCompleteCallback?: any, 1020 | duration = 2, 1021 | ease = "power2.inOut" 1022 | ) { 1023 | // 获取当前控制器的位置 1024 | const currentPosition = this.base.controls.controls.getPosition( 1025 | new THREE.Vector3() 1026 | ); 1027 | 1028 | // 使用 gsap 平滑移动到目标位置 1029 | gsap.to(currentPosition, { 1030 | x: targetPosition.x, 1031 | y: targetPosition.y, 1032 | z: targetPosition.z, 1033 | duration: duration, // 动画持续时间 1034 | ease: ease, 1035 | onUpdate: () => { 1036 | // 更新控制器位置 1037 | this.base.controls.controls.setPosition( 1038 | currentPosition.x, 1039 | currentPosition.y, 1040 | currentPosition.z 1041 | ); 1042 | // 更新渲染 1043 | this.base.renderer.render(this.base.scene, this.base.camera); 1044 | }, 1045 | onComplete: () => { 1046 | this.base.params.isCameraMoving = false; 1047 | if (onCompleteCallback) { 1048 | console.log(onCompleteCallback); 1049 | 1050 | onCompleteCallback(); 1051 | } 1052 | }, 1053 | }); 1054 | 1055 | this.base.params.isCameraMoving = true; 1056 | } 1057 | } 1058 | -------------------------------------------------------------------------------- /src/Experience/resources.ts: -------------------------------------------------------------------------------- 1 | import type * as kokomi from "kokomi.js"; 2 | 3 | export const resources: kokomi.ResourceItem[] = [ 4 | { 5 | name: "roadBgm", 6 | type: "audio", 7 | path: "audio/roadBgm.mp3", 8 | }, 9 | { 10 | name: "sm_car", 11 | type: "gltfModel", 12 | path: "mesh/2024-Model3-d.glb", 13 | }, 14 | { 15 | name: "sm_startroom", 16 | type: "gltfModel", 17 | path: "mesh/sm_startroom.raw.gltf", 18 | }, 19 | { 20 | name: "road", 21 | type: "gltfModel", 22 | path: "mesh/road-d.glb", 23 | }, 24 | { 25 | name: "city_road", 26 | type: "gltfModel", 27 | path: "mesh/city_road.glb", 28 | }, 29 | { 30 | name: "sm_speedup", 31 | type: "gltfModel", 32 | path: "mesh/sm_speedup.gltf", 33 | }, 34 | { 35 | name: "ut_car_body_ao", 36 | type: "texture", 37 | path: "texture/t_car_body_AO.raw.jpg", 38 | }, 39 | { 40 | name: "ut_startroom_ao", 41 | type: "texture", 42 | path: "texture/t_startroom_ao.raw.jpg", 43 | }, 44 | { 45 | name: "ut_startroom_light", 46 | type: "texture", 47 | path: "texture/t_startroom_light.raw.jpg", 48 | }, 49 | { 50 | name: "ut_floor_normal", 51 | type: "texture", 52 | path: "texture/t_floor_normal.webp", 53 | }, 54 | { 55 | name: "ut_floor_roughness", 56 | type: "texture", 57 | path: "texture/t_floor_roughness.webp", 58 | }, 59 | { 60 | name: "ut_env_night", 61 | type: "hdrTexture", 62 | path: "texture/t_env_night.hdr", 63 | }, 64 | { 65 | name: "ut_env_light", 66 | type: "hdrTexture", 67 | path: "texture/t_env_light.hdr", 68 | }, 69 | { 70 | name: "driving", 71 | type: "fbxModel", 72 | path: "mesh/Driving.fbx", 73 | }, 74 | { 75 | name: "decal", 76 | type: "texture", 77 | path: "texture/decal.png", 78 | }, 79 | ]; 80 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.glsl" { 2 | const value: string; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import "./style.css"; 2 | 3 | import { adaptMobileDOM } from "kokomi.js"; 4 | 5 | import Experience from "./Experience/Experience"; 6 | 7 | document.querySelector("#app")!.innerHTML = ` 8 |
9 |
10 |
11 |
12 | L 13 | O 14 | A 15 | D 16 | I 17 | N 18 | G 19 |
20 |
21 |
22 | `; 23 | 24 | const app = document.querySelector("#app")! as HTMLElement; 25 | 26 | adaptMobileDOM(app); 27 | window.addEventListener("resize", () => { 28 | adaptMobileDOM(app); 29 | }); 30 | 31 | 32 | 33 | new Experience("#sketch"); 34 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | .hollow { 6 | opacity: 0; 7 | pointer-events: none; 8 | } 9 | 10 | #app { 11 | position: absolute; 12 | top: 0; 13 | left: 0; 14 | width: 100%; 15 | height: 100%; 16 | } 17 | 18 | #sketch { 19 | position: absolute; 20 | top: 0; 21 | left: 0; 22 | width: 100%; 23 | height: 100%; 24 | overflow: hidden; 25 | } 26 | 27 | .loader-screen { 28 | position: fixed; 29 | z-index: 5; 30 | top: 0; 31 | left: 0; 32 | width: 100%; 33 | height: 100%; 34 | transition: 0.3s; 35 | background: black; 36 | } 37 | 38 | .loading-container { 39 | position: absolute; 40 | top: 50%; 41 | left: 50%; 42 | transform: translate(-50%, -50%); 43 | } 44 | 45 | .loading { 46 | color: white; 47 | font-size: 1.875rem; 48 | letter-spacing: 0.1em; 49 | } 50 | 51 | .loading span { 52 | animation: blur 1.5s calc(var(--i) / 5 * 1s) alternate infinite; 53 | } 54 | 55 | @keyframes blur { 56 | to { 57 | filter: blur(2px); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | /* font-family: 'AliFont'; 3 | src: url('http://model.newhao2021.top/model3/ali.woff') format('woff'), */ 4 | /* url('/public/font/ali.woff') format('woff') */ 5 | /* url('/public/font/ali.woff2') format('woff2'); */ 6 | } 7 | 8 | * { 9 | transition: all .5s; 10 | } 11 | 12 | body { 13 | width: 100vw; 14 | height: 100vh; 15 | background-color: black; 16 | overflow: hidden; 17 | } 18 | 19 | .line { 20 | position: absolute; 21 | bottom: 5vh; 22 | left: 50%; 23 | opacity: 0; 24 | transform: translateX(-50%); 25 | width: 700px; 26 | height: 3px; 27 | background-color: rgba(255, 255, 255, 0.4); 28 | display: flex; 29 | justify-content: space-between; 30 | align-items: center; 31 | transition: all .5s; 32 | } 33 | 34 | .line .child { 35 | width: 15px; 36 | height: 15px; 37 | border-radius: 50%; 38 | background-color: rgb(173, 173, 173); 39 | /* transform: translateX(-50%); */ 40 | position: relative; 41 | cursor: pointer; 42 | /* font-family: "AliFont"; */ 43 | } 44 | 45 | .line .child.act { 46 | background-color: #3271ae; 47 | } 48 | 49 | .line .child.act .text { 50 | color: #fff; 51 | } 52 | 53 | .line .child .text { 54 | position: absolute; 55 | top: -25px; 56 | transform: translateX(-10%); 57 | width: 100px; 58 | color: #ffffff96; 59 | } 60 | 61 | .title1 { 62 | position: absolute; 63 | top: 10vh; 64 | left: 50%; 65 | transform: translateX(-50%); 66 | font-size: 3vw; 67 | color: #fff; 68 | opacity: 0; 69 | } 70 | 71 | .safety { 72 | position: absolute; 73 | top: 1vh; 74 | left: 5%; 75 | /* transform: translateX(-50%); */ 76 | font-size: 3vw; 77 | color: #fff; 78 | opacity: 0; 79 | 80 | h1 { 81 | font-size: 3vw; 82 | } 83 | 84 | h3 { 85 | font-size: .8vw; 86 | } 87 | } 88 | 89 | .fsd { 90 | position: absolute; 91 | top: 1vh; 92 | left: 50%; 93 | transform: translateX(-50%); 94 | /* transform: translateX(-50%); */ 95 | font-size: 3vw; 96 | color: #fff; 97 | opacity: 0; 98 | 99 | h1 { 100 | font-size: 3vw; 101 | } 102 | 103 | h3 { 104 | font-size: 1vw; 105 | } 106 | } 107 | 108 | @media screen and (max-width: 927px) { 109 | .fsd { 110 | top: 45vh; 111 | left: 87%; 112 | width: 800px; 113 | text-align: center; 114 | transform: translateX(-50%) rotate(90deg); 115 | h1{ 116 | font-size: 28px; 117 | } 118 | h3{ 119 | font-size: 12px; 120 | } 121 | } 122 | 123 | .safety { 124 | top: 10vh; 125 | left: 78%; 126 | transform: translateX(-50%) rotate(90deg); 127 | 128 | h1 { 129 | font-size: 28px; 130 | } 131 | 132 | h3 { 133 | width: 300px; 134 | font-size: 9px; 135 | } 136 | } 137 | 138 | .title1 { 139 | top: 47vh; 140 | left: 85%; 141 | transform: translateX(-50%) rotate(90deg); 142 | font-size: 30px; 143 | width: 500px; 144 | text-align: center; 145 | } 146 | 147 | .line { 148 | bottom: 50vh; 149 | left: 12%; 150 | transform: translateX(-50%) rotate(90deg); 151 | width: 550px; 152 | } 153 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": false, 18 | "noUnusedParameters": false, 19 | "noFallthroughCasesInSwitch": true, 20 | "noEmit": true, 21 | "noEmitOnError": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import glsl from "vite-plugin-glsl"; 4 | 5 | export default defineConfig({ 6 | server: { 7 | open: true, 8 | }, 9 | plugins: [glsl()], 10 | }); 11 | --------------------------------------------------------------------------------