基于Three.js实现六边形体素地图的问题求助
六边形体素地图适配方案(Three.js)
针对第一种方案的修复(生成六边形体素并定位)
你提到第一种方案仅生成网格定位,核心问题是没把六边形体素与网格坐标绑定。可以按以下步骤修改:
- 创建六边形柱体几何:用
CylinderGeometry生成标准六边形,调整参数适配体素尺寸,再旋转使其垂直于地面:// 生成六边形柱体(外接圆半径1,高度2,6段边) const hexVoxelGeo = new THREE.CylinderGeometry(1, 1, 2, 6); // 旋转90度让柱体立在XY平面上 hexVoxelGeo.rotateX(Math.PI / 2); - 绑定网格坐标与体素位置:遍历HexGrid的每个网格,用
getCenter或hexToWorld获取世界坐标,创建并放置六边形体素:const hexGrid = new THREE.HexGrid(2); // 网格间距2 // 遍历目标范围内的六边形坐标 for (let q = -5; q <= 5; q++) { for (let r = -5; r <= 5; r++) { const hex = new THREE.HexGrid.Hex(q, r); const worldPos = hexGrid.hexToWorld(hex); // 生成体素网格并设置位置 const voxel = new THREE.Mesh(hexVoxelGeo, yourMaterial); voxel.position.set(worldPos.x, 0, worldPos.y); // y轴作为高度可后续调整 scene.add(voxel); } } - 性能优化:如果体素数量多,改用
InstancedMesh批量渲染,减少Draw Call。
针对第二种方案的VoxelWorld类适配
第二种方案生成了六边形但不兼容自定义VoxelWorld,核心是要重构VoxelWorld的坐标系统和体素管理逻辑:
- 重构坐标存储:把原立方体的笛卡尔坐标(x,y,z)替换为六边形轴向坐标(q,r)+ 高度y,用Map存储体素:
class VoxelWorld { private voxels = new Map<string, THREE.Mesh>(); private hexGrid = new THREE.HexGrid(2); // 网格间距与体素尺寸匹配 // 添加体素:传入六边形坐标(q,r)和高度y addVoxel(q: number, r: number, y: number) { const key = `${q},${r},${y}`; if (this.voxels.has(key)) return; const hex = new THREE.HexGrid.Hex(q, r); const worldPos = this.hexGrid.hexToWorld(hex); worldPos.y = y * 2; // 体素高度2,按层堆叠 const voxel = new THREE.Mesh(hexVoxelGeo, yourMaterial); voxel.position.copy(worldPos); this.scene.add(voxel); this.voxels.set(key, voxel); } // 获取体素:通过六边形坐标查询 getVoxel(q: number, r: number, y: number) { return this.voxels.get(`${q},${r},${y}`); } } - 适配拾取与交互:原立方体的射线检测逻辑要修改,先用
worldToHex把鼠标射线交点转换成六边形坐标,再查询对应体素:function onMouseClick(event: MouseEvent) { const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1 ); raycaster.setFromCamera(mouse, camera); // 先获取地面交点,转换为六边形坐标 const groundPlane = new THREE.Plane(new THREE.Vector3(0,1,0), 0); const intersectionPoint = new THREE.Vector3(); raycaster.ray.intersectPlane(groundPlane, intersectionPoint); const hex = hexGrid.worldToHex(new THREE.HexGrid.Hex(), intersectionPoint.x, intersectionPoint.z); // 查询该坐标下的体素 const voxel = voxelWorld.getVoxel(hex.q, hex.r, 0); // 后续交互逻辑... } - 邻接逻辑调整:如果需要实现体素的相邻检测(比如自动合并、挖除),要适配六边形的6个邻接方向,替换原立方体的上下左右前后逻辑。
内容的提问来源于stack exchange,提问作者drPapus
相关产品推荐
相关产品推荐

