不知道大家有没有同样的感觉:
今年的 “金三银四”,似乎没有想象中那么热闹。
尤其是 前端岗位,不少公司都在收缩,机会明显少了很多。
我最近也参加了几场大厂面试(我面的是 AI 全栈开发岗)。
有一件事让我挺意外的。
某度的面试官在面试完后加微信聊天的时候说:
“刚看到你简历上的个人网站时,就明显感觉到你是一个有技术追求的同学,还让 hr 赶快联系一下面试。”
然后就把这个网站发到分享到小红书上,b站上去了(之前看过类似的效果,特地复刻了一版),反响很不错,所以特此非常以下里面的技术细节。
效果如下:
点击跳转在线地址
同时,欢迎大家关注我的微信公众号:ai超级个人,会有更多的炫酷网页分享
这篇文章会稍微偏技术一些。
如果你:
- 对网页动效感兴趣
- 或者几乎没有 Three.js 基础
- 甚至不太懂 3D
这些思路依然很有价值。
尤其是在 你让 AI 帮你调试代码、改造项目的时候,理解这些结构会非常有帮助。
如果你想系统学习 Three.js,我只推荐一套教程:
Three.js Journey(点击跳转 B 站)
这是我心中目前全球范围内,从 0 到 1 最完美的 Three.js 课程。说实话,市面上很多所谓的基础教程,且不说是否存在“割韭菜”的行为,单是乏味的教学逻辑就在浪费你的学习生命。
好了,回到正文。今天我们要深度拆解上面网站效果,以及解决如下三个核心问题:
1. 空间定位:如何在网页中调试模型位置?
在 3D 世界里,任何模型都有它的坐标。以下面这个电脑模型为例:
模型默认被放置在原点 $(0, 0, 0)$,这通常没问题。但真正的痛点在于:摄像机应该架在哪?
打个比方,这就好比现实中的人像摄影:
- 被拍的人 → 相当于 3D 模型
- 摄影师 → 相当于 Camera(相机)
模型在那不动,但摄影师的位置(Position)和对焦的方向(LookAt)决定了最终的画面。
而且我们能不能像在 Blender(知名的 3D 图形软件)里一样,在网页端也能直观地旋转、调整远近,从而找到那个最完美的视觉角度?如下图是 blender 的界面:
2. 跨次元融合:如何将真实网页嵌入 3D 场景?
请看下图:
在这台 3D 电脑模型的屏幕中央,其实嵌套了一个真实的网页(前端术语叫 iframe)。
所以问题来了,在 three.js 中如何嵌套一个别的网站的网页呢?
3. 精准对位:如何调试 iframe 的 3D 坐标?
这是上一个问题的延伸。iframe(网页) 作为一个平面,在 3D 空间中同样拥有自己的坐标和旋转参数。但问题是:
你很难凭直觉盲猜出电脑模型那块屏幕的精确数值。
因此,我们需要一套可视化的调试界面。然后配合我们第一步提到的工具,让我们可以在页面上手动微调 iframe 的位置,直到它与模型屏幕完美贴合。
最后,直接将调试好的坐标参数“写死”在代码里就能保证初始化电脑模型和网页都在合适的坐标上。
接下来,我们一步一步,从 0 到 1 实现这个过程:
网页中调整相机位置小技巧
初始的时候,我们假设有如下代码(精简后的 demo )。代码主要做的是将电脑的模型贴图加载进来。
如果你有不了解的代码块可以借助 ai 了解详细信息,因为已经是最基础的 three.js 代码,如果缺乏必要的基础,建议学习上面的教程。
注:代码使用了 react 框架,你也可以让 ai 改造为你的熟悉的技术栈,例如 vue 或者 html:- import * as THREE from "three";import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";export interface Computer3DConfig { container: HTMLElement; modelPath: string; texturePath: string; modelScale?: number;}export class Computer3D { private scene: THREE.Scene = new THREE.Scene(); private camera: THREE.PerspectiveCamera; private renderer: THREE.WebGLRenderer; private container: HTMLElement; private config: Computer3DConfig; constructor(config: Computer3DConfig) { this.config = { ...config }; this.container = config.container; // 1. 初始化相机 const aspect = window.innerWidth / window.innerHeight; this.camera = new THREE.PerspectiveCamera(35, aspect, 10, 100000); // 2. 初始化渲染器 (WebGL) this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this.renderer.domElement.style.position = "absolute"; this.renderer.domElement.style.top = "0"; this.renderer.domElement.style.zIndex = "1"; this.container.appendChild(this.renderer.domElement); this.render(); } // 加载模型与贴图 public async load(): Promise { const loader = new GLTFLoader(); const textureLoader = new THREE.TextureLoader(); // 并行加载模型和贴图 const [gltf, texture] = await Promise.all([ loader.loadAsync(this.config.modelPath), textureLoader.loadAsync(this.config.texturePath), ]); // 贴图配置 texture.flipY = false; texture.colorSpace = THREE.SRGBColorSpace; const material = new THREE.MeshBasicMaterial({ map: texture }); // 遍历模型应用材质 gltf.scene.traverse((child: any) => { if (child instanceof THREE.Mesh) { child.material = material; } }); this.scene.add(gltf.scene); } // 渲染循环 private render(): void { requestAnimationFrame(this.render.bind(this)); this.renderer.render(this.scene, this.camera); } // 处理窗口大小调整(建议添加) public onWindowResize(): void { const width = window.innerWidth; const height = window.innerHeight; this.camera.aspect = width / height; this.camera.updateProjectionMatrix(); this.renderer.setSize(width, height); }}export default Computer3D;
复制代码 避坑指南:为什么初始化你的 3D 世界是一团黑?
很多同学在加载代码后,满怀期待地打开页面,结果发现是一片漆黑。例如我们上面的代码。
别担心,并不是模型消失了,只是你正“站在模型肚子里”!(模型内部)默认情况下,相机的初始坐标在 (0, 0, 0)。而模型加载进来也通常在原点。
这种“合二为一”的状态让你什么也看不见。为了解决这个问题,我们需要像真正的摄影师一样,完成以下三个层层递进的步骤。
首先就是让相机能够完整的看到电脑模型:
第一步:开启“自动对焦”,给模型一个完美的全身照
首先模型的大小是不可控的,有的只有几厘米,有的却有几百米。
所以我们需要一个通用的“自动对焦”函数,让相机自动根据模型的大小调整距离,起码能看清楚模型的全身,然后再后续微调相机位置。
核心逻辑: 用一个隐形的方框把模型包起来(Box3),测量它的尺寸,然后把相机推到足够远的地方。
[code]/** * ✅ 自动对焦:不仅要移相机,还要移控制器的目标点 */private autoFitCamera(object: THREE.Object3D): void { // 1. 计算模型的包围盒 const box = new THREE.Box3().setFromObject(object); const size = box.getSize(new THREE.Vector3()); // 获取模型长宽高 const center = box.getCenter(new THREE.Vector3()); // 获取模型的中心点 // 2. 根据模型大小计算相机距离 const maxDim = Math.max(size.x, size.y, size.z); const fov = this.camera.fov * (Math.PI / 180); // 视角转弧度 // 数学公式:距离 = 对边 / tan(角度) const cameraDistance = Math.abs(maxDim / 2 / Math.tan(fov / 2)) * 1.5; // 3. 移动相机位置:稍微偏一点,让画面有立体感 this.camera.position.set( center.x + maxDim * 0.2, center.y + maxDim * 0.3, center.z + cameraDistance, ); // 4.
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |