ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Three.js 3D作品集网站5MB体积优化实战指南

Three.js 3D作品集网站5MB体积优化实战指南 最近在看到一位开发者的分享他花了 2.5 年时间打磨自己的 3D 作品集网站并最终把所有资源体积控制在了 5MB 以内。这个数字乍看没什么但如果你做过 Web 3D 项目就会明白一个包含模型、纹理、交互逻辑的 3D 页面光是一个高模 GLB 文件就可能超过 20MB能做到 5MB 以内需要非常系统的体积管理意识。这篇文章不打算复述那个项目的每个细节而是把它当作一个典型工程案例拆解背后的技术思路3D 作品集网站该怎么做、为什么把体积控制在 5MB 以内是有意义的、Three.js 场景如何搭建、模型和纹理如何压缩、代码如何分包按需加载以及移动端体验和性能优化需要注意哪些坑。无论你是想做个人 3D 主页还是在业务项目里引入一个 3D 展示模块这套方法都可以直接复用。1. 3D 作品集网站的价值与核心挑战1.1 为什么值得花时间做一个 3D 作品集网站传统个人主页通常是“头像 自我介绍 项目列表 外链”的静态页面信息传达效率高但同质化严重。3D 作品集网站把“展示”变成了一种体验用户通过旋转、缩放、点击交互来探索页面这种参与感是平面截图无法替代的。对于视觉设计师、游戏开发者、前端工程师、3D 建模师这类人群一个 3D 作品集本身就是最好的名片。从技术角度看3D 作品集网站也是 Web 3D 技术的综合演练场。你需要处理 3D 场景搭建、模型加载、相机控制、灯光材质、动画交互、资源压缩、性能优化等一系列问题几乎每一环都是前端工程能力的体现。即使最终页面只有几个场景和模型整个项目链路也足够帮助你建立对 WebGL、GPU 渲染和资源管理的系统认知。不过做 3D 作品集网站很容易陷入“好看但进不去”的误区。很多个人项目在 PC 上运行流畅换到手机端就白屏、卡顿或者加载十几秒。原因通常不是设备性能差而是资源体积失控、绘制调用过多、没有做移动端适配。因此真正值得研究的不是“能不能做出来”而是“如何在有限体积和性能预算内做出来”。1.2 5MB 体积约束意味着什么我们说的“5MB”通常指网站首次访问时需要下载的核心资源总量包括 HTML、CSS、JavaScript、3D 模型、纹理图片、字体文件、音频等静态资源。它不包含运行时缓存的按需加载资源但一个好的作品集网站应该尽量让首屏资源整体落在预算之内。5MB 是一个什么概念我们可以做一个粗略的资源分配一个压缩后的 GLB 模型可能占 2 到 3MB一套 1024x1024 的纹理经过 WebP 或 KTX2 压缩后大约 200 到 500KBThree.js 框架核心代码压缩后大约几百 KB再加上业务 JS、CSS 和字体整体很容易逼近甚至超过 5MB。换句话说5MB 预算要求你在“画面表现力”和“资源体积”之间做严格的取舍。体积控制的意义直接反映在用户体验上。移动网络环境下一个 5MB 页面和 50MB 页面的首屏等待时间是数量级的差距Lighthouse 等性能评分工具也会对“总传输体积”和“首次内容绘制时间”给出严格评估。把体积作为硬性指标其实是在逼迫自己采用更高效的模型拓扑、更合理的纹理尺寸和更精细的代码分割策略这些都是工程能力的体现。2. 技术选型与开发环境准备2.1 技术栈选择Three.js 仍然是 Web 3D 首选做 Web 3D 的技术方案并不少原生 WebGL 过于底层Babylon.js 功能丰富但生态和资料相对少而 Three.js 是目前最主流、资料最全、社区最活跃的选择。官方文档和示例非常完善npm 包直接集成到 Vite、Webpack 项目里都很方便。对于 3D 作品集网站这种“中小型场景 丰富交互 需要快速迭代”的项目Three.js 的性价比是最高的。如果你熟悉 Vue 或 React也可以选择 React Three Fiber 这类声明式封装它用组件思想管理 Three.js 场景适合组件化程度高的项目。但要注意封装层会引入额外依赖在体积预算紧张的时候需要评估是否值得。对于一个以展示为核心的作品集直接使用 Three.js 反而更轻量、更可控这也是很多开发者最终选择原生 Three.js 的原因。有一个容易混淆的概念需要说明Three.js 并不是唯一负责“体积”的变量。Three.js 本身是一个核心库场景最终表现取决于模型资产、纹理设计、着色器代码和业务逻辑。体积优化的重心往往不在框架而在资产管线Asset Pipeline也就是模型从建模软件导出到浏览器展示的过程。2.2 开发环境与项目结构搭建一个 Three.js Vite 项目成本很低。Vite 提供了快速的开发服务器和生产构建能力可以轻松处理模块化 JavaScript 和静态资源。示例环境建议如下操作系统Windows / macOS / Linux 均可运行环境Node.js 18 或更高版本包管理工具npm 或 pnpm构建工具Vite技术栈原生 Three.js。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。由于 Three.js 迭代速度较快安装时建议以 npm 实际拉取到的稳定版本为准并锁定版本号避免后续升级带来的破坏性变更。项目结构推荐采用下面的方式3d-portfolio/ ├── index.html ├── package.json ├── vite.config.js └── src/ ├── main.js # 场景入口 ├── scenes/ # 各场景模块 ├── models/ # 静态模型资源目录 ├── textures/ # 纹理资源目录 └── style.css把模型、纹理和场景代码分开是为了让资源和逻辑的边界更清晰。后续做体积分析和按需加载时你可以一眼看出哪些资源属于首屏哪些属于延迟加载。3. 3D 场景搭建的核心原理3.1 场景、相机、渲染器的关系Three.js 的核心概念可以概括为三句话Scene场景是存放物体、灯光、相机的容器Camera相机决定了从哪个位置、以什么角度观察场景Renderer渲染器负责把场景里的物体通过相机“画”到浏览器画布上。初学者很容易在第一步就出现问题场景里有模型但相机朝向不对所以画面一片空白。看一个最小的场景初始化代码import * as THREE from three; const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera( 45, // 视角角度单位是度 window.innerWidth / window.innerHeight, // 宽高比 0.1, // 近裁剪面 100 // 远裁剪面 ); camera.position.set(0, 2, 6); // 把相机放在模型前方偏上位置 camera.lookAt(0, 0, 0); // 相机看向原点 const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement); function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate();这里有一个特别值得注意的参数renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))。手机屏幕的设备像素比DPR常常是 3如果不设置上限GPU 会渲染大量无效像素导致帧率明显下降。限制到 2 之后画面没有肉眼可见的损失性能却会好很多。3.2 为什么选择 glTF 格式作为模型标准3D 模型的文件格式很多OBJ、FBX、STL、glTF 都有各自的适用场景。对 Web 端来说glTFGL Transmission Format是当前最推荐的格式它专门为实时传输和渲染而设计支持 PBR 材质、骨骼动画、变形目标、相机灯光等完整信息。它的二进制版本 .glb 把所有资源打包到一个文件里非常适合网络传输。在 3D 作品集项目中你应该尽量在 Blender、3ds Max、C4D 中完成建模和材质设置然后导出为 .glb。导出前还要做几个关键操作清掉项目里没用的节点、材质和动画轨道把模型面数控制在合理范围贴图尽量使用 2 的幂次尺寸如 1024x1024、512x512方便 GPU 采样和压缩。你可能在项目里也会遇到 .fbx 或 .obj 格式的老模型。建议不要直接用 Three.js 加载它们而是先用 Blender 做一次“格式转换 清理优化”再导出成 glTF。这样做的收益非常大导入导出的过程中可以清理无效多边形、重新烘焙贴图、调整单位比例和坐标轴朝向从源头上减少浏览器端的解析压力。3.3 决定渲染性能的三个关键指标判断一个 3D 页面是否流畅不能只看模型“看起来精不精细”要关注三个核心指标Draw Call 数量、几何体三角面数、纹理内存占用。Draw Call 是指 CPU 向 GPU 发送一次绘制命令的过程。每调用一次GPU 就要切换渲染状态Draw Call 越多CPU 开销越大。一个典型的移动端中低端设备合理预算大约是几百次 Draw Call。同一个场景里如果有很多结构相同但位置不同的物体比如书架上的书、草地上的花优先使用 InstancedMesh实例化网格它可以用一次 Draw Call 绘制大量重复几何体。三角面数影响 GPU 的顶点处理压力。桌面浏览器正确处理几十万三角面没有问题但移动端在复杂场景下很容易掉帧。优化思路包括减少模型细节、使用 LODLevel of Detail多级细节技术、远处物体用低模替代。纹理内存则和纹理尺寸强相关。一张 2048x2048 的 RGBA 贴图在显存里约占 16MB两张就是 32MB移动端 GPU 的显存是有限的大纹理很容易导致闪退或严重掉帧。后面会专门讲纹理优化。4. 5MB 体积优化实战4.1 用 Draco 压缩模型几何数据模型文件往往占据 3D 网站体积的大头。一个包含高细节雕塑、家具、角色的作品集场景几何数据可能有好几十MB。如果不做任何优化体积预算直接爆了。Google 开源的 Draco 是当前最常用的几何压缩方案。它通过重新编码顶点坐标、法线和纹理坐标把几何数据压缩到原来的十分之一甚至更低浏览器端通过 WebAssembly 解码器快速恢复数据。在 Three.js 中使用 Draco 主要分两步引入 DRACOLoader然后设置解码器路径。import { GLTFLoader } from three/examples/jsm/loaders/GLTFLoader.js; import { DRACOLoader } from three/examples/jsm/loaders/DRACOLoader.js; const dracoLoader new DRACOLoader(); // 将 three 包内的解码器复制到 public 目录 dracoLoader.setDecoderPath(/draco/); const loader new GLTFLoader(); loader.setDRACOLoader(dracoLoader); loader.load(/models/main-scene.glb, (gltf) { scene.add(gltf.scene); hideLoading(); });解码器文件来自node_modules/three/examples/jsm/libs/draco你需要把它们复制到项目的public/draco目录避免依赖第三方 CDN加载路径更可控。如果你用 gltf-transform 这类工具也可以在构建阶段直接对 GLB 做压缩处理常见的命令示例如下npx gltf-transform/cli optimize main-scene.glb main-scene-optimized.glb --compress draco --texture-compress webp值得提醒的是Draco 压缩适合静态几何不适合动画骨骼或需要频繁修改顶点的场景。压缩后的模型需要在每次加载时解码因此模型越大解码耗时越长。实际项目中建议先压缩再在弱设备上测试解码耗时必要时对模型做 LOD 分级。4.2 纹理压缩与尺寸控制很多开发者在压缩模型几何之后才发现纹理才是体积膨胀的隐形推手。一个高精度 PBR 材质通常包含基础色贴图、法线贴图、粗糙度贴图、金属度贴图甚至环境光遮蔽贴图每一种贴图都是 1024 或 2048 像素的图片。多个材质叠加后纹理资源体积很容易超过模型本身。处理纹理的第一条原则是能用 512 就绝不使用 1024能用 1024 就绝不使用 2048。对于占据屏幕面积不大的物体512 纹理在视觉上几乎看不出区别但体积差异是 4 倍。你可以在开发时先放 1024 纹理观察效果确定视觉可接受的最低分辨率后再统一导出。第二条原则是使用支持 GPU 直接压缩的纹理格式。KTX2 / Basis Universal 是基于 GPU 压缩的纹理方案加载后直接以压缩格式驻留显存相比 PNG/JPEG 能进一步降低纹理内存和加载体积。Three.js 使用 KTX2Loader 加载再配合纹理转码器使用。不过 KTX2 的创建和加载链路稍复杂适合对纹理体积要求较高的项目。第三条原则是控制纹理数量。多个物体各用一张独立贴图不如把零散贴图合并成一张纹理图集Texture Atlas这样可以减少纹理切换次数也能降低 Draw Call。图集在导出模型时就可以在 Blender 中通过 UV 重拓扑实现。4.3 代码分包与按需加载5MB 预算内业务代码同样是资源的一部分。现代前端项目普遍采用模块化开发很容易把不需要的库打进首屏包。例如有些页面只展示了模型场景却把 UI 库、图表库、动画库全部加载进来了体积自然失控。Vite 生产构建默认会做代码分割但默认策略并不一定满足你的体积要求。你可以在vite.config.js里通过manualChunks控制分包策略把 Three.js 这类体积较大的核心库拆成独立 chunk利用浏览器缓存减少重复加载。import { defineConfig } from vite; export default defineConfig({ build: { chunkSizeWarningLimit: 1500, rollupOptions: { output: { manualChunks: { three: [three] } } } } });更重要的思路是“按需加载”。作品集网站通常有多个展示场景例如“关于我”“项目作品”“联系方式”。如果所有场景的代码和模型都在首屏加载体积就失去了控制。合理的做法是首屏只加载主场景和关键 UI其他场景通过用户交互动态加载。// 点击“项目作品”按钮时再加载项目场景模块 document.getElementById(project-btn).addEventListener(click, async () { const { createProjectScene } await import(./scenes/project-scene.js); const group await createProjectScene(); scene.add(group); });动态import()会让 Vite 自动把这些代码拆成独立 chunk只有用户真的想看作品场景时才会下载对应资源和模型。这种“首屏精简、后续按需”的模式是控制 5MB 预算最有效的工程手段。4.4 资源加载进度与首屏体验体积控制得再好资源加载也需要时间。如果用户打开页面后长时间看到白屏体验会非常糟糕所以 3D 作品集网站必须做好加载反馈。GLTFLoader 提供了onProgress回调可以读取当前加载进度配合一个简单的进度条就能显著改善感知性能。loader.load( /models/main-scene.glb, (gltf) { scene.add(gltf.scene); hideLoading(); }, (event) { if (event.total) { const percent Math.round((event.loaded / event.total) * 100); document.getElementById(progress-bar).style.width percent %; } }, (error) { console.error(模型加载失败, error); showErrorTip(); } );进度条之外还可以考虑在加载阶段展示一段简洁的启动动画、静态背景或文字说明让用户感受到页面正在运行而不是卡死。加载完成后通过一个淡入动画把主场景暴露出来观感会比瞬间切换好很多。这个“加载过渡”环节经常被忽略但对 3D 作品集这种重型页面来说反而非常重要。5. 完整示例搭建一个 3D 作品集页面骨架5.1 创建项目入口下面从零搭建一个最小可运行的 3D 作品集页面骨架包含场景、灯光、控制器、模型加载和体积构建。先创建package.json{ name: 3d-portfolio, private: true, version: 1.0.0, type: module, scripts: { dev: vite, build: vite build, preview: vite preview }, dependencies: { three: ^0.160.0 }, devDependencies: { vite: ^5.0.0 } }版本号请以安装时的实际环境为准这里只是示例。然后创建index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / title3D Portfolio/title style * { margin: 0; padding: 0; } body { overflow: hidden; background: #0a0a0a; } #loading { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #fff; font-family: Arial, sans-serif; z-index: 10; } #progress-bar { width: 0%; height: 4px; background: linear-gradient(90deg, #ff6633, #33aaff); transition: width 0.2s ease; } /style /head body div idloading pLoading 3D Scene.../p div idprogress-bar/div /div script typemodule src/src/main.js/script /body /html5.2 编写 Three.js 场景代码创建src/main.js这里包含完整场景逻辑。为了让示例不依赖外部模型文件我们先用一个TorusKnotGeometry作为占位物体它会告诉你场景、灯光、相机、动画循环是如何配合的import * as THREE from three; import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 100 ); camera.position.set(0, 2, 6); camera.lookAt(0, 0, 0); const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement); const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true; controls.dampingFactor 0.05; // 环境光提供基础照明 const ambientLight new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); // 两束彩色点光源增强立体感 const light1 new THREE.PointLight(0xff6633, 2, 10); light1.position.set(-4, 3, 4); scene.add(light1); const light2 new THREE.PointLight(0x33aaff, 2, 10); light2.position.set(4, 3, 4); scene.add(light2); // 占位模型环形几何体用来验证场景可渲染 const geometry new THREE.TorusKnotGeometry(1, 0.35, 128, 16); const material new THREE.MeshStandardMaterial({ color: 0xffffff, metalness: 0.3, roughness: 0.4 }); const mesh new THREE.Mesh(geometry, material); scene.add(mesh); function animate() { requestAnimationFrame(animate); controls.update(); mesh.rotation.x 0.003; mesh.rotation.y 0.005; renderer.render(scene, camera); } animate(); // 隐藏加载浮层 document.getElementById(loading).style.display none; window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });模型加载部分可以替换成前面介绍过的 GLTFLoader 方案。实际作品集里你的main-scene.glb可能是房间、雕塑或抽象几何组合加载后放到场景中即可其他代码结构不变。5.3 创建 Vite 配置与构建验证创建vite.config.jsimport { defineConfig } from vite; export default defineConfig({ server: { host: true, open: true }, build: { chunkSizeWarningLimit: 1500, assetsInlineLimit: 4 * 1024, rollupOptions: { output: { manualChunks: { three: [three] } } } } });安装依赖后执行构建npm install npm run build构建完成后使用du或文件管理器查看dist目录的体积du -sh dist这个命令会显示整个静态站点的体积。如果你的实际资源超过了 5MB可以用下面的思路逐步排查先看dist下哪些文件最大模型 GLB 是否已经压缩纹理是否还有压缩空间哪些 chunk 被重复加载。体积分析是 3D 项目中最容易被跳过、但价值最高的环节。6. 常见问题与排查思路3D 作品集网站开发过程中有几个高频问题几乎每个开发者都会遇到。下面整理了一份排查表格方便你快速定位。问题现象常见原因解决思路页面打开后一片空白相机位置朝向错误或灯光缺失检查相机position和lookAt临时添加GridHelper辅助网格确认场景朝向模型加载后颜色发灰、失真贴图色彩空间设置错误将颜色贴图的texture.colorSpace设置为THREE.SRGBColorSpace移动端滑动、旋转卡顿DPR 过高、Draw Call 过多设置renderer.setPixelRatio(Math.min(devicePixelRatio, 2))合并几何体使用 InstancedMesh打包后体积超出预算模型未压缩、纹理过大、代码未分包使用 Draco 压缩 GLB纹理转为 WebP/KTX2检查产物体积并拆分按需加载模型加载很慢缺少缓存策略、资源未走 CDN配置 CDN、gzip/brotli 压缩、HTTP 缓存首屏资源优先加载其他延迟加载透明物体渲染错乱未启用透明排序或深度写入异常检查材质transparent和depthWrite配置必要时拆分透明渲染队列点击交互不生效射线检测只检测到空气使用Raycaster后检查射线与物体包围盒的计算范围确保物体已加入场景且包围盒更新正确第一行的白屏问题是最常见的。多数情况下并不是模型没有加载而是相机在一个错误的位置观察场景。建议在开发初期就开启GridHelper和AxesHelper用可视化的方式确认坐标系朝向这样能立刻看出物体是否位于相机视野内。第二个常见痛点是色彩空间。Three.js 在新版本中默认使用 sRGB 输出但如果你加载的纹理没有标记为 sRGB渲染结果就会偏灰偏暗。只需要在加载贴图后补一行配置const texture await new THREE.TextureLoader().loadAsync(/textures/color.jpg); texture.colorSpace THREE.SRGBColorSpace;注意法线贴图、粗糙度贴图这类数据贴图不要设置 sRGB它们应当保持线性色彩空间否则材质表现会非常奇怪。7. 最佳实践与工程建议7.1 建立资源体积预算表做 3D 作品集网站最好在一开始就确定“钱花在哪里”。下面是一个可以参考的预算分配表你可以根据实际场景调整资源类型预算比例说明HTML/CSS/JS10%框架代码和业务逻辑注意代码分包3D 模型50%使用 Draco 压缩控制顶点数和动画骨数纹理贴图30%使用 WebP/KTX2 压缩控制分辨率和数量字体、音频、徽标10%优先使用系统字体图标用 SVG 代替图片预算表的价值在于让每个决策都变得可衡量。当你纠结“要不要给模型加一层高精度金属划痕贴图”时看一眼预算表就知道答案纹理预算已经用完那这层细节就不值得加。7.2 模型导出前的清理规范很多体积问题不是压缩能解决的而是源头就没清理干净。在 Blender 或建模软件中导出 glTF 前建议按顺序执行一遍清理流程删除场景中未使用的对象、材质、UV 贴图、顶点组和骨骼动画合并同一物体的多个子网格如果不需要独立动画把不常用的属性烘焙到纹理重新计算法线并检查是否有无意义的高模细分。这个流程在项目初期就要建立否则每次导出模型都会带回一堆无用数据。7.3 移动端体验优先3D 作品集网站的访问者很可能多数来自手机因此移动端性能是核心指标而不是“附加项”。除了限制 DPR、控制 Draw Call 之外还有几个方向交互上使用单指旋转、双指缩放避免依赖右键或滚轮UI 元素要适配安全区域避免被刘海屏遮挡加载过程中保留静态封面让用户感觉页面立刻有内容。7.4 建立降级策略WebGL 不是所有设备和浏览器都支持尤其是部分低端手机、旧浏览器或开启了硬件加速关闭策略的环境。为了避免一打开就是白屏应该检测 WebGL 支持情况不支持的场景降级到静态图像或 2D 页面。const canvas document.createElement(canvas); const gl canvas.getContext(webgl); if (!gl) { // 显示静态作品集封面或跳转简化版页面 showFallbackContent(); }这个兜底逻辑成本很低但能救回很大一部分被硬件挡住的用户。做作品集是为了让更多人看到你的内容而不是让一部分人打不开所以在技术表现和可访问性之间需要找一个平衡点。7.5 接入性能监控与持续优化网站上线不是终点。浏览器 DevTools 的 Performance 面板可以看到真实的帧率、渲染耗时和 GPU 占用Lighthouse 可以生成性能报告如果项目规模更大还可以接入性能监控平台实时了解用户的加载时间和报错信息。建议在 CI 构建流程中加入体积门槛例如dist总大小超过 5MB 时构建失败从制度上保证体积不会随着迭代失控。8. 总结回到开头那个“2.5 年打磨、体积控制在 5MB 以内”的项目它真正值得学习的地方并不是“用了多久”而是那种把每一个 KB、每一个 Draw Call、每一次交互都纳入预算的工程态度。3D 作品集网站不是把几个模型堆在页面上就完成了它需要你在技术选型、模型管线、纹理规范、代码分割、加载体验、移动端适配等多个维度作系统决策。本文从 3D 作品集的价值和挑战出发介绍了 Three.js 场景搭建的基础原理详细拆解了 Draco 模型压缩、纹理优化、代码分包和加载进度等体积控制手段并给出了一个可运行的 Vite Three.js 项目示例。如果你正打算构建自己的 3D 个人主页建议按这个顺序动手先做出一个能跑的最小场景然后把模型和纹理压缩工程化最后再打磨交互和移动端体验。下一步你可以继续学习的内容包括PBR 材质的原理与贴图制作、Blender 建模与 UV 展开、KTX2 纹理压缩方案、InstancedMesh 在重复物体场景中的用法以及 WebGL 渲染管线的底层知识。实际项目中优先关注的仍然是体积和性能模型能不用的面就不要用纹理能小一点就小一点代码能按需加载就按需加载这些细节叠加起来就是“5MB 以内”这个数字背后真正的工程价值。做 3D 作品集网站的过程其实是一次完整的 Web 3D 项目训练从设计、建模、导出、编码到上线每一步都会踩坑但每一步都能学到东西。如果你也想做一个让人印象深刻的个人主页不妨先设定一个体积预算然后在这个预算内发挥你的创造力。
返回列表