通过 GUI 采样拾取瓦片(Sample Pick Tiles Through GUI)
- 英文原标题:Sample Pick Tiles Through GUI
- 英文原作者:meded90
- 原始链接:https://discourse.threejs.org/t/sample-pick-tiles-through-gui/93514
- 发布板块:Showcase
- 标签:
textures/materials
一、原帖内容概述
原帖内容非常精简,作者 meded90 在 three.js 官方论坛的 Showcase 板块发布了该演示,并在 2026-08-15 与 2026-08-17 两次更新。两次更新均以视频演示为主,正文没有附加大段文字说明,也没有贴出可直接复制运行的代码段。
从标题、标签以及视频缩略内容来看,该演示的核心是:
在 three.js 场景中,通过 GUI(图形用户界面) 来采样/拾取(pick)瓦片(tiles),并实时切换或应用不同的 纹理(textures) 与 材质(materials)。
原帖 HTML 中的视频占位符对应以下视频资源(仅作存档,无需翻译):
- 帖子 1 视频 1:
.../7778d046413f47a68cc162ef484fe7adc45010b2.mp4 - 帖子 1 视频 2:
.../5efe4e564e471f3b3a0c6c9fe40df861dfcb35c4.mp4 - 帖子 2 视频 1:
.../43dfb42b8bb4c5923b8685ed1c888e57d9fc525b.mp4 - 帖子 2 视频 2:
.../9c9eeef27b62516933994890b650f7cd6f1dfc18.mp4
二、核心代码说明
原文正文未包含任何可直接提取的核心代码片段,两次帖子均只有视频占位与 “Updated” 文本。因此,本次深度解读无法“保留原帖中的核心代码”,因为原帖并未以文本形式提供代码。
不过,从标题、标签和相关主题讨论可以推断,该实现通常涉及以下技术点:
- 瓦片/图块(tiles)的纹理管理与切换
- GUI 控件驱动材质参数或 UV 偏移
- 鼠标拾取(picking)选择特定瓦片
- 纹理图集(texture atlas)或纹理数组(texture array)优化
下面以常见的 three.js / WebGL 实现思路为例,给出补充性伪代码,不属于原帖代码,仅供理解实现方向。
三、3 个核心优化要点
1. 使用纹理图集 / 纹理数组,减少纹理绑定切换
如果每个瓦片都单独上传一张纹理,会频繁切换 GPU 纹理绑定,导致性能下降。更优做法是:
- 将所有瓦片合并到一张 纹理图集(Texture Atlas) 中
- 或使用 纹理数组(Texture Array) / 纹理矩阵
- 在着色器中通过 UV 偏移与缩放来选择不同瓦片
补充 GLSL 示例(仅示意,非原帖代码):
uniform sampler2D uAtlas;
uniform vec2 uTileScale; // 例如 1/8, 1/8
uniform vec2 uTileOffset; // 例如第 3 列第 2 行
varying vec2 vUv;
void main() {
vec2 tileUV = fract(vUv * uTileScale + uTileOffset);
vec4 color = texture2D(uAtlas, tileUV);
gl_FragColor = color;
}
术语提示:在 GLSL 3.0 及以上版本中,
texture2D应使用texture;在 WebGL2 中建议用texture(uAtlas, tileUV)。
2. 使用 GPU 拾取(颜色编码 / ID 渲染)代替 CPU 遍历
当瓦片数量较多时,用 CPU 端射线投射逐瓦片检测拾取效率较低。常见优化是:
- 创建一个离屏渲染目标(
WebGLRenderTarget) - 为每个瓦片分配唯一颜色 ID
- 渲染到离屏目标后,用
readPixels读取鼠标位置的颜色,反查瓦片 ID
补充 JS 示例(仅示意,非原帖代码):
const pickingRT = new THREE.WebGLRenderTarget(width, height);
// 1. 使用 ID 材质渲染
scene.overrideMaterial = pickingMaterial;
renderer.setRenderTarget(pickingRT);
renderer.render(scene, camera);
// 2. 读取鼠标位置像素
const pixel = new Uint8Array(4);
renderer.readRenderTargetPixels(pickingRT, mouseX, mouseY, 1, 1, pixel);
// 3. 由颜色反推瓦片 ID
const tileID = (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
// 4. 恢复默认渲染
scene.overrideMaterial = null;
renderer.setRenderTarget(null);
这种 GPU 拾取 的优点是无需复杂几何遍历,拾取速度与瓦片数量几乎无关;代价是需要额外的离屏渲染与分析通道。
3. 复用几何体与材质实例,避免频繁创建/销毁
如果 GUI 只是在不同瓦片之间切换纹理或颜色,而不是修改网格拓扑,建议:
- 多个瓦片共享同一个
BufferGeometry或PlaneGeometry - 使用
InstancedMesh(实例化网格)减少 draw call - 材质参数变更时,只更新
uniforms或纹理offset/repeat,不要反复new THREE.MeshStandardMaterial()
补充 JS 示例(仅示意,非原帖代码):
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshStandardMaterial({
map: atlasTexture,
});
const mesh = new THREE.InstancedMesh(geometry, material, tileCount);
// GUI 只更新 uniform 或 UV offset
material.map.offset.set(uOff, vOff);
material.map.repeat.set(uScale, vScale);
material.map.updateMatrix();
通过缓存纹理单元、复用材质实例,可显著降低 CPU 与 GPU 端的分配/释放开销。
四、GLSL / WebGL 专业术语检查
原文中直接出现的技术标签为:
textures— 纹理materials— 材质
在相关主题与推断实现中,涉及术语应统一为:
| 英文术语 | 推荐中文译名 | 备注 |
|---|---|---|
| tiles | 瓦片 / 图块 | 在地形、纹理图集、3D Tiles 语境下不宜译为“瓷砖” |
| picking | 拾取 | 不要译为“采摘” |
| GUI | 图形用户界面 | 三.js 社区常直接用 “GUI” |
| texture atlas | 纹理图集 | 也称“纹理图册” |
| texture array | 纹理数组 | WebGL2 支持的数组纹理 |
| UV coordinates | UV 坐标 | UV 不翻译是通用做法 |
| raycasting | 射线投射 / 光线投射 | three.js 中 Raycaster 常保留英文 |
| render target | 渲染目标 | WebGLRenderTarget 是核心类 |
| readPixels | 读取像素 | 对应 readRenderTargetPixels |
| instanced mesh | 实例化网格 | THREE.InstancedMesh |
| draw call | 绘制调用 | 不译为宜 |
| shader | 着色器 | 顶点/片元着色器 |
| spritesheet | 精灵表 / 雪碧图 | 与 texture atlas 类似 |
| cube map | 立方体贴图 | 环境映射常用 |
| transparency | 透明度 | 材质属性 |
| shadow material | 阴影材质 | 用于阴影映射 |
原帖并未直接出现 GLSL 着色器代码,因此没有可校正的 GLSL 语法问题。以上检查主要针对相关讨论中可能出现的术语翻译一致性。
五、延伸阅读
原帖页面还列出了若干相关主题,可作为同类技术参考:
- Procedure generating terrain tile / only background at this moment
《程序化生成地形瓦片 / 目前仅有背景》 - Change floor image in canvas 3D
《在 Canvas 3D 中更换地面图片》 - High-Resolution Multiscale Panoramic from Tile Zoom Cameras
《来自瓦片变焦相机的高分辨率多尺度全景》 - 3d-Tiles-Renderer: A 3D Tiles implementation for three.js from NASA JPL
《3d-Tiles-Renderer:来自 NASA JPL 的 three.js 3D Tiles 实现》 - How to use spritesheet in this special case?
《如何在这种特殊情况下使用精灵表?》
这些相关主题可以帮助理解该演示在纹理、材质、瓦片拾取和性能优化方面的技术脉络。
六、结语
meded90 的原帖以视频为主,并未提供可直接复制的核心代码,因此本文没有“保留核心代码”的内容。不过,通过标题、标签和相关讨论,可以合理推断其实现方向为:GUI 驱动 + 瓦片拾取 + 纹理/材质切换,并由此提炼出三条通用性能优化路径。
如果你需要落地类似功能,建议优先考虑:
- 纹理图集 / 纹理数组
- GPU 拾取通道
- 几何体与材质实例复用
这三点能够在保证交互体验的同时,有效控制 WebGL 渲染压力。
