ThreeJS MeshSurfaceSampler无法采样变换后平面的有效点问题
解决MeshSurfaceSampler采样点不匹配变换后地形的问题
问题根源很直接:MeshSurfaceSampler是基于几何体的原始顶点数据进行采样的,你给Mesh设置的position/rotation/scale这些变换属于"世界空间变换",只会在渲染阶段生效,不会改变几何体本身的顶点数据,所以采样出来的点自然还是原始平面上的位置。
下面给两种实用的解决思路:
思路1:直接修改几何体顶点数据(推荐)
把旋转、位移变换直接应用到几何体的顶点上,让几何体本身的顶点就是变换后的位置,这样采样时自然就会取到正确的点。
代码示例(React+TS环境):
import { PlaneGeometry, Mesh, MeshStandardMaterial, Matrix4, Vector3 } from 'three'; // 假设你有噪声库,比如simplex-noise import { createNoise2D } from 'simplex-noise'; const noise2D = createNoise2D(); // 1. 创建平面几何体并生成地形高度 const planeGeometry = new PlaneGeometry(100, 100, 128, 128); const positions = planeGeometry.attributes.position; for (let i = 0; i < positions.count; i++) { const x = positions.getX(i); const y = positions.getY(i); // 用噪声生成地形高度,可自行调整参数 const height = noise2D(x * 0.05, y * 0.05) * 8; positions.setZ(i, height); } // 2. 创建变换矩阵(旋转+位移) const transformMatrix = new Matrix4(); // 比如绕X轴旋转90度,让平面从XY面转到XZ面 transformMatrix.makeRotationX(Math.PI / 2); // 再设置位移 transformMatrix.setPosition(new Vector3(0, -5, 0)); // 3. 将变换应用到几何体顶点 transformMatrix.applyToBufferAttribute(positions); // 4. 更新几何体状态 positions.needsUpdate = true; planeGeometry.computeVertexNormals(); // 5. 创建地形Mesh const terrainMesh = new Mesh(planeGeometry, new MeshStandardMaterial({ color: 0x7cb342 })); // 6. 现在采样就是变换后的点了 const sampler = new MeshSurfaceSampler(terrainMesh).build(); const treePos = new Vector3(); sampler.sample(treePos); // treePos就是地形上的正确位置,用来放置树木模型即可
思路2:采样后对点位应用变换
如果不想修改几何体原始数据,也可以先采样原始平面的点,再用Mesh的matrixWorld(世界变换矩阵)把采样点转换到世界空间的正确位置。
代码示例:
// 假设已经创建好带变换的terrainMesh const sampler = new MeshSurfaceSampler(terrainMesh).build(); const rawSamplePoint = new Vector3(); sampler.sample(rawSamplePoint); // 应用世界矩阵变换,得到真实地形上的点 const treePos = rawSamplePoint.clone().applyMatrix4(terrainMesh.matrixWorld);
两种思路的对比
- 思路1更推荐:采样结果完全匹配地形,后续对地形的任何操作(比如碰撞检测)也更准确,缺点是修改了几何体数据,无法恢复原始状态(如果需要的话可以提前克隆一份)。
- 思路2适合临时需求:不用改动几何体,但如果地形有缩放变换,采样的密度会和原始平面一致,可能出现分布不均的情况。
内容的提问来源于stack exchange,提问作者Jakob B
相关产品推荐
相关产品推荐

