3D世界制作过程:从空白平面到可交互场景
这次 3D 世界的改动,最开始只是想把“只有人物”的页面变成一个真正可以停留、可以互动的小空间。做着做着,它就从一个模型展示页,变成了一个带水面、树环境、角色拖动、AI 对话和模型投放区的网页场景。

最初的目标
原来的 3D 世界更像是“把角色放到网页上”。这次我想让它更接近一个站点里的小舞台:
- 左侧是主要的 3D 世界,占界面的大部分空间。
- 右侧保留模型投放区,以后可以继续加入更多模型。
- 场景里固定有角色和环境,但只有角色可以拖动。
- 点击角色后,可以进入之前已经搭好的 AI 对话。
- 访客拖入模型后,可以继续调整模型的 X、Y、Z 位置。
这个目标听起来很直接,但真正做的时候,最麻烦的不是“写一个 3D 页面”,而是不断判断:模型到底没加载,还是加载了但看不到?是坐标问题、缩放问题、光照问题,还是浏览器 WebGL 和脚本执行层的问题?
从 Blender 文件到网页模型
一开始我尝试直接使用 Blender 文件里的角色和环境。后来发现 .blend 文件并不适合直接放到网页里展示,真正适合网页加载的是 .glb 模型。于是流程变成:
- 在 Blender 中整理角色、树、木屋、水井等对象。
- 导出为
.glb。 - 通过 Three.js 的
GLTFLoader加载模型。 - 在网页里重新处理缩放、位置、光照和交互。
这里踩过一个很典型的坑:Blender 里看起来正常的场景,到了网页里可能会非常大、非常远,或者刚好被相机视角错过。后来我把页面改成可以直接调整相机 X、Y、Z 参数,这样就不用每次都猜“是不是相机没对准”。
先保证能看见
调 3D 页面最重要的一步,是先让页面出现一个最简单、最确定的东西。之前角色、树、地面都看不到时,继续猜模型问题很容易绕圈。所以我先把页面退回到一个基础状态:
- 只显示一个平面。
- 检查 WebGL 是否正常。
- 检查脚本是否真正执行。
- 再逐步加回角色、树、水面和投放区。
这个过程很像搭积木:先确认地板存在,再放角色,再放环境,最后才加倒影和控制面板。只要某一步坏了,就知道问题大概出现在哪里。
水面和倒影
地面最后没有继续做成普通颜色平面,而是改成了水面。水面用了 Three.js 的反射效果,让角色、树和投放模型可以在下方出现倒影。
这个效果对 3D 世界很关键。普通平面只是“站在地上”,水面会让整个空间变得更有层次:
- 上方是角色和树。
- 下方有镜像倒影。
- 场景边缘有淡淡的圆形水纹。
- 背景颜色、太阳光颜色和水面颜色都可以在右侧调整。
后来我把这些参数都放进了控制区,这样不用改代码也能调气氛。
角色交互和边界限制
角色使用犬夜叉模型。它不仅要显示出来,还要能拖动,并且不能被拖出正方形世界边缘。
这里做了几个小规则:
- 角色可以用鼠标在水面范围内拖动。
- 拖动时会限制在世界边界里。
- 点击角色会打开 AI 对话框。
- 对话框尺寸调小,避免挡住太多 3D 场景。
- 环境树不能被拖动,避免访客把整个场景拖乱。
这让角色从“摆在网页上的模型”变成了一个真正的交互入口。
模型投放区
右侧 20% 的区域现在是模型投放区。当前放进去的模型包括小王子、水井和小木屋。
投放区的逻辑是:
- 每一种模型最多只能投放一个。
- 投放后的模型可以取消。
- 投放后的模型可以调整 X、Y、Z 坐标。
- 简单物理碰撞会阻止模型之间完全重叠。
这部分其实是在给后续功能预留入口。以后如果有更多模型,可以继续加到右侧,不需要重做整个 3D 世界结构。
环境树的处理
树环境一开始尝试直接用很大的 GLB 文件加载,但文件太大,线上部署和浏览器加载都会变慢。最后我把环境改成程序生成的树阵列:
- 不再上传超大的树环境模型。
- 用代码生成树干和树冠。
- 控制树的数量、位置、颜色和整体范围。
- 保留“有森林背景”的视觉效果,但大幅降低部署压力。
这一步很重要。网站不是本地演示,最终还是要能稳定打开、能上线、能让访客访问。
上线时遇到的问题
本地能打开,不代表线上一定能打开。最后上线时遇到的主要问题,是 EdgeOne 云端构建在大模型文件上失败。解决方式是把思路拆开:
- 页面代码和轻量资源由 EdgeOne 部署。
- 大模型文件从 GitHub 静态地址加载。
- 树环境用程序生成,不再依赖超大 GLB。
- 每次上线后验证
/world/页面、world-app.js脚本和模型地址。
这样页面终于成功部署到正式域名,3D 世界也能在站点里稳定展示。
这次做完后的样子
现在打开 3D 世界,应该能看到:
- 一个 80% 宽度的 3D 舞台。
- 水面和倒影。
- 犬夜叉角色。
- 周围树环境。
- 右侧模型投放区。
- 小王子、水井、小木屋模型卡片。
- 相机、灯光、水面颜色等调节项。
- 点击角色进入 AI 对话。
它不只是一个“模型页”了,更像是站点里开出来的一小块空间。
后续想法
接下来可以继续往这个方向扩展:
- 增加更多可投放模型。
- 保存访客调整后的模型位置。
- 给模型增加更细的碰撞范围。
- 增加天气、昼夜或音乐联动。
- 把 3D 世界变成站点的一个长期互动入口。
这次最有意思的地方,是整个过程并不是一次写完的,而是边看效果边修正:看不到,就先做平面;角色太大,就缩小;树太重,就程序生成;上线失败,就拆开资源部署。最后这个 3D 世界也带着这种试出来的痕迹——不是一下子从图纸变出来,而是一点一点被调亮、缩放、拖动、部署,最后站到了站点里。