如何动态隐藏THREE.js Points对象中的单个点?
如何动态隐藏THREE.js Points中的单个点?
当然可以实现,针对你的场景,这里有两种实用方案:
方案一:利用顶点颜色的Alpha通道控制可见性
既然你已经在使用顶点颜色,最简单的方式是把颜色格式从RGB扩展为RGBA,通过修改单个点的Alpha值来控制透明度(设为0即隐藏)。
步骤:
转换颜色属性为RGBA格式:
原来的color属性是每个点3个值(R、G、B),需要扩展为4个值(增加Alpha通道):const oldColorArray = pointsObj.geometry.attributes.color.array; const rgbaArray = new Float32Array(oldColorArray.length * 4 / 3); // 遍历原RGB数据,填充RGBA数组,初始Alpha设为1(完全可见) for (let i = 0; i < oldColorArray.length; i += 3) { const rgbaIndex = (i / 3) * 4; rgbaArray[rgbaIndex] = oldColorArray[i]; rgbaArray[rgbaIndex + 1] = oldColorArray[i + 1]; rgbaArray[rgbaIndex + 2] = oldColorArray[i + 2]; rgbaArray[rgbaIndex + 3] = 1; } // 更新几何体的color属性,itemSize设为4 pointsObj.geometry.setAttribute('color', new THREE.BufferAttribute(rgbaArray, 4));配置材质支持顶点颜色与透明:
pointsObj.material.vertexColors = true; pointsObj.material.transparent = true; // 若出现透明点排序问题,可尝试关闭depthWrite,但可能影响深度表现 // pointsObj.material.depthWrite = false;动态控制单个点的可见性:
// 隐藏指定索引的点 function hidePoint(index) { const colorAttr = pointsObj.geometry.attributes.color; // 保留原RGB值,仅修改Alpha为0 colorAttr.setXYZW(index, colorAttr.getX(index), colorAttr.getY(index), colorAttr.getZ(index), 0); colorAttr.needsUpdate = true; // 通知Three.js更新GPU数据 } // 显示指定索引的点 function showPoint(index) { const colorAttr = pointsObj.geometry.attributes.color; colorAttr.setXYZW(index, colorAttr.getX(index), colorAttr.getY(index), colorAttr.getZ(index), 1); colorAttr.needsUpdate = true; }
方案二:使用自定义着色器材质(ShaderMaterial)
如果点数量极大,或者不想处理透明排序问题,自定义着色器是更高效的选择——通过新增一个visibility顶点属性,在片元着色器里直接丢弃不可见的点。
步骤:
添加visibility顶点属性:
const pointCount = pointsObj.geometry.attributes.position.count; const visibilityArray = new Float32Array(pointCount); visibilityArray.fill(1); // 初始所有点可见 pointsObj.geometry.setAttribute('visibility', new THREE.BufferAttribute(visibilityArray, 1));创建自定义着色器材质:
const shaderMat = new THREE.ShaderMaterial({ vertexShader: ` attribute float visibility; varying float vVisibility; void main() { vVisibility = visibility; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); gl_PointSize = 3.0; // 可根据需求调整点大小,或用uniform传递动态值 } `, fragmentShader: ` varying float vVisibility; // 如果需要使用顶点颜色,需添加varying vec3 vColor;并在顶点着色器传递 void main() { // 若visibility小于0.5,直接丢弃该像素(不渲染) if(vVisibility < 0.5) discard; // 这里可以自定义点的颜色,比如用顶点颜色: // gl_FragColor = vec4(vColor, 1.0); gl_FragColor = vec4(1.0, 0.6, 0.2, 1.0); // 示例颜色 } `, // 不需要开启透明,性能更优 transparent: false }); // 替换原PointsMaterial pointsObj.material = shaderMat;动态切换点的可见性:
function togglePointVisibility(index, isVisible) { const visAttr = pointsObj.geometry.attributes.visibility; visAttr.setX(index, isVisible ? 1 : 0); visAttr.needsUpdate = true; }
方案对比
- 方案一:无需编写着色器,上手快;但大量点修改时可能有轻微性能损耗,且透明点存在排序问题(部分点可能被错误遮挡)。
- 方案二:性能更高,无透明排序问题,控制更灵活;需要掌握基础的GLSL着色器知识。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

