Three.js中IFC模型instanceColor设置后无法恢复颜色求助
IFC模型元素闪烁功能:颜色重置失效及部分元素着色不可靠问题
我正在处理一个加载完成的带自定义属性的IFC模型,已实现搜索框功能,目标是用户输入自定义标识后,对应元素可闪烁以在屏幕中被识别。搜索框及元素识别功能已开发完成,相关搜索函数如下:
function performSearchIfc() { let searchInput = document.getElementById("uuidsearchinput").value; let expressId = designatorToExpressId.get(searchInput); let arrayOfParts = loadedFragmentsGroup.data.get(expressId)[0]; console.log(arrayOfParts); for (let i = 0; i < arrayOfParts.length; i++) { let partId = arrayOfParts[i]; let children = loadedFragmentsGroup.children; let item = children.find(item => item.id === partId); if (!item) { console.log("Skipping item: " + partId); continue; } console.log(item); (async () => { //颜色设置存在问题 - 缩放功能正常 try { let r = item.instanceColor.array[0] + 1 - 1; let g = item.instanceColor.array[1] + 1 - 1; let b = item.instanceColor.array[2] + 1 - 1; let copyOfOrigColor = new Float32Array([r, g, b]); let intenseGreen = new Float32Array([0, 1, 0]); while (true) { console.log("Setting color to " + intenseGreen); item.instanceColor.set(intenseGreen); item.scale.set(2.2, 2.2, 2.2); await sleep(1000); console.log("Setting color to " + copyOfOrigColor); item.instanceColor.set(copyOfOrigColor); item.scale.set(1, 1, 1); await sleep(1000); } } catch (error) { console.error(error); } })(); } }
目前遇到两个核心问题:
- 元素可被正确找到,缩放功能正常,颜色能设置为亮绿色,但重置为原颜色时失效,元素保持绿色。
- 有时仅部分元素会被着色,整个着色方法不可靠。
问题原因分析
1. 颜色重置失效的核心原因
- 原颜色复制逻辑错误:你用
item.instanceColor.array[0] +1 -1的冗余操作毫无意义,更关键的是item.instanceColor.array大概率是共享数组引用。当调用item.instanceColor.set(intenseGreen)时,会直接修改这个共享数组的内容,导致之前保存的copyOfOrigColor已经被后续操作污染,根本不是真正的原始颜色。 - 未触发渲染更新:修改
instanceColor数组后,基于Three.js的IFC.js需要标记颜色属性为needsUpdate = true,否则渲染器不会重新绘制颜色变化,看起来就像颜色没重置。
2. 部分元素着色不可靠的原因
- 并发闪烁冲突:循环中每个元素都启动独立的异步无限循环,多个元素的颜色修改操作可能互相干扰,比如一个元素正在重置颜色时,另一个元素的修改覆盖了共享资源。
- 元素匹配效率低且易出错:每次循环都调用
children.find遍历子元素,不仅性能差,还可能因为ID重复或数据异常导致部分元素匹配失败。 - 无闪烁状态管理:用户多次触发搜索时,会为同一元素启动多个闪烁循环,颜色状态被反复覆盖,出现部分元素着色异常。
解决方案
修复颜色重置问题
- 正确复制原始颜色:直接深拷贝原始颜色数组,避免引用共享问题:
// 替换原颜色复制逻辑 const copyOfOrigColor = new Float32Array(item.instanceColor.array);
- 触发渲染更新:修改颜色后标记属性需要更新:
item.instanceColor.needsUpdate = true;
解决部分元素着色不可靠问题
- 添加闪烁状态标记:避免为同一元素重复启动闪烁循环:
if (item.isBlinking) return; item.isBlinking = true;
- 预创建元素ID映射:提升元素匹配的准确性和性能:
// 循环外创建ID到元素的映射 const idToItem = new Map(); loadedFragmentsGroup.children.forEach(child => idToItem.set(child.id, child)); // 循环内直接通过映射获取元素 const item = idToItem.get(partId);
- 用状态控制循环:避免无限循环无法终止,同时在异常时清除状态:
while (item.isBlinking) { // 用状态控制循环启停 // 高亮逻辑... }
完整修复后的代码
function performSearchIfc() { const searchInput = document.getElementById("uuidsearchinput").value; const expressId = designatorToExpressId.get(searchInput); const arrayOfParts = loadedFragmentsGroup.data.get(expressId)?.[0]; if (!arrayOfParts) return; // 处理空数据情况 // 预创建元素ID映射,提升匹配效率 const idToItem = new Map(); loadedFragmentsGroup.children.forEach(child => idToItem.set(child.id, child)); // 可选:先停止所有正在闪烁的元素 loadedFragmentsGroup.children.forEach(child => { child.isBlinking = false; }); for (const partId of arrayOfParts) { const item = idToItem.get(partId); if (!item) { console.log("Skipping item: " + partId); continue; } if (item.isBlinking) continue; // 避免重复启动闪烁 item.isBlinking = true; (async () => { try { const copyOfOrigColor = new Float32Array(item.instanceColor.array); const intenseGreen = new Float32Array([0, 1, 0]); while (item.isBlinking) { // 设置高亮 item.instanceColor.set(intenseGreen); item.instanceColor.needsUpdate = true; item.scale.set(2.2, 2.2, 2.2); await sleep(1000); // 恢复原状 item.instanceColor.set(copyOfOrigColor); item.instanceColor.needsUpdate = true; item.scale.set(1, 1, 1); await sleep(1000); } } catch (error) { console.error(error); } finally { item.isBlinking = false; // 清除闪烁状态 } })(); } } // 确保sleep函数存在 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
内容的提问来源于stack exchange,提问作者monamona
相关产品推荐
相关产品推荐

