🤯 前言:降维打击你的竞争对手
想象一下,面试官打开你的主页:
- 普通版:白底黑字,一张证件照,几行 HTML/CSS 写的技能条。
- 你的版本:霓虹闪烁的雨夜,高耸入云的赛博大厦,鼠标滑动时镜头穿梭在城市森林中,点击全息广告牌弹出你的 GitHub 项目。
这不仅展示了你的代码能力,更展示了你的技术审美和对前沿技术(AI + 3D)的整合能力。
🏗️ 一、 技术架构:AI 负责“皮囊”,代码负责“灵魂”
我们不需要成为 3D 建模师。我们的思路是:用简单的几何体(盒子)构建城市,用 AI 生成的复杂纹理赋予它细节。
工作流 (Mermaid):
🎨 二、 Step 1: 用 AI 生成“赛博建筑”皮肤
我们要解决的核心痛点是:如何不建模,却让立方体看起来像高科技大楼?
答案:UV 贴图欺诈。
1. 生成无缝贴图 (Seamless Texture)
打开 Midjourney 或 Stable Diffusion。
关键参数:--tile(MJ) 或Tiling(SD)。这能保证图片上下左右拼接时没有缝隙。
MJ Prompt 参考:
Prompt:cyberpunk skyscraper facade texture, windows, neon lights, metal panels, seamless, flat view, high detail, 8k, dark atmosphere --tile --v 5.2
你将得到一张类似这样的图:哪怕只贴在一个平面上,看起来也像有凹凸感的大楼表面。
2. 生成法线贴图 (Normal Map)
光有颜色图(Diffuse)是不够的,光照上去会很假。
我们需要一张紫色的法线贴图来模拟凹凸感。
- 工具:将 AI 生成的图上传到 NormalMap-Online。
- 产出:下载生成的 Normal Map。
💻 三、 Step 2: Three.js 代码实战
1. 搭建基础场景
我们需要一个黑色的背景和雾气,营造赛博朋克的神秘感。
import*asTHREEfrom'three';// 场景初始化constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x000510);// 深蓝黑色// 雾气:实现“远处不可见”的效果,增加景深scene.fog=newTHREE.FogExp2(0x000510,0.002);constcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(0,10,20);constrenderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);2. 加载 AI 纹理
constloader=newTHREE.TextureLoader();// 加载 AI 生成的图constbaseTexture=loader.load('textures/cyber_building.jpg');constnormalTexture=loader.load('textures/cyber_normal.png');// 材质定义constbuildingMaterial=newTHREE.MeshStandardMaterial({map:baseTexture,normalMap:normalTexture,roughness:0.2,// 光滑一点,模拟玻璃/金属metalness:0.8});3. 生成城市森林 (InstancedMesh)
面试加分点:不要用for循环创建 1000 个Mesh,那会卡死浏览器。
使用InstancedMesh,一次 GPU 绘制调用(Draw Call)就能渲染成千上万个相同的物体。
constcount=1000;constgeometry=newTHREE.BoxGeometry(1,1,1);// 关键:实例化网格constcity=newTHREE.InstancedMesh(geometry,buildingMaterial,count);constdummy=newTHREE.Object3D();constspread=100;// 城市范围for(leti=0;i<count;i++){// 随机位置dummy.position.set((Math.random()-0.5)*spread,0,(Math.random()-0.5)*spread);// 随机高度 (Y轴拉伸)constheight=Math.random()*10+2;dummy.scale.set(1,height,1);dummy.position.y=height/2;// 调整中心点,使其立在地面上dummy.updateMatrix();city.setMatrixAt(i,dummy.matrix);}scene.add(city);✨ 四、 Step 3: 注入灵魂 —— 后处理 (Post-Processing)
没有“辉光”的赛博朋克是没有灵魂的。我们需要UnrealBloomPass。
import{EffectComposer}from'three/examples/jsm/postprocessing/EffectComposer.js';import{RenderPass}from'three/examples/jsm/postprocessing/RenderPass.js';import{UnrealBloomPass}from'three/examples/jsm/postprocessing/UnrealBloomPass.js';constrenderScene=newRenderPass(scene,camera);// 辉光参数:强度、半径、阈值constbloomPass=newUnrealBloomPass(newTHREE.Vector2(window.innerWidth,window.innerHeight),1.5,0.4,0.85);bloomPass.threshold=0;bloomPass.strength=1.2;// 强度bloomPass.radius=0.5;constcomposer=newEffectComposer(renderer);composer.addPass(renderScene);composer.addPass(bloomPass);// 动画循环functionanimate(){requestAnimationFrame(animate);// 缓慢旋转城市,制造动态感city.rotation.y+=0.001;// 使用 composer 渲染而不是 renderercomposer.render();}animate();🚀 五、 优化与交互:让 HR 眼前一亮
为了让这个 Demo 变成一个真正的“产品”,你还需要做两件事:
- 交互性 (Raycaster):
添加鼠标悬停事件。当鼠标划过某栋大楼时,大楼变色,并弹出一个 HTML Tooltip(例如:“点击查看我的 Vue 项目”)。
原理:使用THREE.Raycaster检测鼠标与InstancedMesh的碰撞。 - 性能优化 (Performance):
- 纹理压缩:将 JPG/PNG 转为.webp甚至.ktx2格式,减少加载时间。
- LOD (Level of Detail):虽然 InstancedMesh 很快,但如果场景过大,考虑引入 Fog 剔除远处的渲染计算。
🎯 总结
通过这个项目,你向面试官证明了:
- 工程能力:你懂 WebGL 性能优化(InstancedMesh)。
- 前沿视野:你会利用 AI 工具(Stable Diffusion)解决资源瓶颈。
- 视觉审美:你懂 Post-Processing 和光影氛围的营造。
这就是所谓的**“全栈视觉工程师”**,也是未来前端最有竞争力的方向之一。
Next Step:
现在的城市是静止的。试着加入“雨滴粒子系统”(Particle System),让整个场景变成一个下着雨的赛博朋克夜晚,氛围感绝对拉满!