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);
}

三个核心优化要点

  1. 实例化渲染(Instanced Rendering)降低 draw call
    大量相同几何体的体素块如果逐个创建 Mesh,会导致 draw call 数量急剧上升。使用 THREE.InstancedMesh 将同一类方块(如石头、泥土、木板)合并为一次 draw call,可显著提升帧率,尤其适合 Minecraft 风格的场景。

  2. 视锥剔除 + 区块动态加载/卸载(Frustum Culling + Chunk Streaming)
    只渲染相机视锥(frustum)内的区块,远处或背后的区块不提交 GPU。同时按玩家/用户交互位置流式加载附近区块、卸载远处区块,避免内存与 GPU 负担无限增长。这是开放体素世界流畅运行的关键。

  3. 遮挡面剔除 + 纹理图集合并(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面剔除移除不可见的面(背面/遮挡面)
GLSLOpenGL 着色器语言用于编写顶点/片段着色器
WebGL2Web 图形库 2.0支持更多高级特性,如实例化

以上术语均符合 WebGL/GLSL 规范,无明显错误。


结语

BLOCKSMITH 用“页面组装自己”的隐喻,展示了 Web3D 在创意页面与体素世界之间构建交互体验的可能性。虽然原帖只有一句俄语简介,但其背后的技术思路——实例化、视锥剔除、纹理图集——正是 Minecraft 风格 Web 体验能够流畅运行的核心。如果你计划复现类似效果,优先实现这三个优化,就能在浏览器中稳定呈现数千个体素块而不掉帧。