BLOCKSMITH — 一个 Minecraft 风格构建者在你面前组装页面
英文原作者:Paladei
原始链接:https://discourse.threejs.org/t/blocksmith-a-page-that-a-minecraft-style-builder-assembles-in-front-of-you/93508
原文编译
原文(俄语)如下:
BLOCKSMITH — сайт, который строит себя
Живая смета, которую можно потянуть, и мир, который живёт под чертежом, — страница собирает себя у вас на глазах.
编译为中文:
BLOCKSMITH —— 一个自我构建的网站
一份可以拖动的实时预算,以及一个生活在蓝图之下的世界 —— 页面就在你眼前组装自己。
原帖正文非常简短,没有附带核心代码。但结合标题与简介,可以还原出该案例的技术路径:这是一个基于 three.js 的 Minecraft 风格体素(voxel)页面构建器,用户拖动“预算/清单”(смета)时,下方世界会像蓝图展开一样动态生成、逐块“组装”成完整页面。这类效果在 Web3D 中通常依赖 实例化渲染、体素几何合并、视锥剔除和动态区块加载 等优化手段。
核心代码参考
由于原帖未提供可运行代码,以下代码是根据该案例所呈现的 Minecraft 风格交互效果,还原出的典型 three.js + GLSL 实现思路,不作为原帖原文摘录。
1. 使用 InstancedMesh 批量渲染体素块
// 核心:使用 InstancedMesh 合并同类型体素块的 draw call
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({
map: atlasTexture, // 纹理图集,避免多材质切换
});
const maxBlocks = 10000;
const mesh = new THREE.InstancedMesh(geometry, material, maxBlocks);
const dummy = new THREE.Object3D();
let index = 0;
for (const block of visibleBlocks) {
dummy.position.set(block.x, block.y, block.z);
dummy.rotation.set(0, 0, 0); // 体素块通常无旋转
dummy.scale.set(1, 1, 1);
dummy.updateMatrix();
mesh.setMatrixAt(index++, dummy.matrix);
}
mesh.instanceMatrix.needsUpdate = true;
scene.add(mesh);
2. 自定义实例化顶点着色器(GLSL)
// instancedVoxel.vert
attribute vec3 offset; // 每个实例的偏移量
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
vec4 worldPosition = modelViewMatrix * vec4(position + offset, 1.0);
gl_Position = projectionMatrix * worldPosition;
}
实际 three.js
InstancedMesh内部会使用instanceMatrix属性,无需手动声明offset。此处仅为展示 GLSL 层面的实例化思路。
3. 纹理图集 UV 映射(片段着色器)
// voxel.frag
uniform sampler2D atlasTexture;
varying vec2 vUv;
varying float vBlockType; // 由 CPU 传入的块类型
void main() {
// 假设图集为 4x4,共 16 种方块纹理
float tileX = mod(vBlockType, 4.0) / 4.0;
float tileY = floor(vBlockType / 4.0) / 4.0;
vec2 atlasUv = vec2(
tileX + vUv.x / 4.0,
tileY + vUv.y / 4.0
);
gl_FragColor = texture2D(atlasTexture, atlasUv);
}
三个核心优化要点
-
实例化渲染(Instanced Rendering)降低 draw call
大量相同几何体的体素块如果逐个创建Mesh,会导致 draw call 数量急剧上升。使用THREE.InstancedMesh将同一类方块(如石头、泥土、木板)合并为一次 draw call,可显著提升帧率,尤其适合 Minecraft 风格的场景。 -
视锥剔除 + 区块动态加载/卸载(Frustum Culling + Chunk Streaming)
只渲染相机视锥(frustum)内的区块,远处或背后的区块不提交 GPU。同时按玩家/用户交互位置流式加载附近区块、卸载远处区块,避免内存与 GPU 负担无限增长。这是开放体素世界流畅运行的关键。 -
遮挡面剔除 + 纹理图集合并(Face Culling + Texture Atlas)
在构建几何体阶段,剔除完全被相邻方块遮挡的面,避免渲染不可见的多边形。配合纹理图集(texture atlas)将所有方块纹理合并到一张纹理中,减少纹理切换与材质状态变更,进一步提升渲染效率。
GLSL / WebGL 专业术语检查
原文未直接出现 GLSL 术语,但根据案例扩展解读中涉及的术语,核查如下:
| 术语 | 中文对应 | 说明 |
|---|---|---|
| Instanced Rendering | 实例化渲染 | 一次 draw call 绘制多个相同几何体 |
| InstancedMesh | 实例化网格 | three.js 中的实例化对象 |
| Draw Call | 绘制调用 | CPU 向 GPU 提交的一次渲染指令 |
| Frustum Culling | 视锥剔除 | 移除视锥体外的对象,减少渲染负载 |
| Chunk | 区块 | 体素世界中的空间分区单位 |
| Texture Atlas | 纹理图集 | 多张纹理合并为一张大图 |
| Voxel | 体素 | 三维空间中的体积像素 |
| Face Culling | 面剔除 | 移除不可见的面(背面/遮挡面) |
| GLSL | OpenGL 着色器语言 | 用于编写顶点/片段着色器 |
| WebGL2 | Web 图形库 2.0 | 支持更多高级特性,如实例化 |
以上术语均符合 WebGL/GLSL 规范,无明显错误。
结语
BLOCKSMITH 用“页面组装自己”的隐喻,展示了 Web3D 在创意页面与体素世界之间构建交互体验的可能性。虽然原帖只有一句俄语简介,但其背后的技术思路——实例化、视锥剔除、纹理图集——正是 Minecraft 风格 Web 体验能够流畅运行的核心。如果你计划复现类似效果,优先实现这三个优化,就能在浏览器中稳定呈现数千个体素块而不掉帧。
