You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js中如何选择Mesh、Group或Object3D并实现高亮切换?

解决Three.js选中Mesh后恢复初始颜色的问题

核心思路

要实现再次选中时恢复树木初始颜色,需要记录树木的原始颜色,同时跟踪当前选中的树木对象。点击时判断是选中新树木、取消当前选中,还是重复点击同一棵树,再分别执行高亮或颜色恢复操作。

具体修改步骤

1. 保存树木的初始颜色

在创建树木的代码中,给每个树木的子Mesh添加initialColor属性(存在userData中,避免和内置属性冲突),保存初始颜色:

// 示例:创建树木时保存初始颜色
function createTree() {
  const tree = new Object3D();
  tree.name = "tree";

  // 假设这里已经创建了树干、树枝等子Mesh
  tree.children.forEach(child => {
    if (child.children.length > 0) {
      child.children.forEach(c2 => {
        // 克隆初始颜色,避免后续修改影响原始值
        c2.userData.initialColor = c2.material.color.clone();
      });
    } else {
      child.userData.initialColor = child.material.color.clone();
    }
  });

  return tree;
}

2. 修改MouseController跟踪选中状态

新增_selectedTree变量记录当前选中的树木,添加颜色重置方法,并优化选中逻辑:

import MouseControllerInput from "./input.js";

export default class MouseController {
  constructor(SceneEntity, CameraEntity) {
    this._scene = SceneEntity;
    this._camera = CameraEntity;
    this._input = new MouseControllerInput();
    this._selectedTree = null; // 跟踪当前选中的树木
  }

  // 恢复树木初始颜色的方法
  #resetTreeColor(tree) {
    tree.children.forEach(c => {
      if (c.children.length > 0) {
        c.children.forEach(c2 => {
          c2.material.color.copy(c2.userData.initialColor);
        });
      } else {
        c.material.color.copy(c.userData.initialColor);
      }
    });
  }

  // 高亮树木的方法
  #highlightTree(tree) {
    tree.children.forEach(c => {
      if (c.children.length > 0) {
        c.children.forEach(c2 => c2.material.color.set(0xff0000));
      } else {
        c.material.color.set(0xff0000);
      }
    });
  }

  Update() {
    if (this._input.active) {
      this._input.raycaster.setFromCamera(this._input.pointer, this._camera);
      // 第二个参数设为true,递归检测所有子对象
      const intersects = this._input.raycaster.intersectObject(this._scene, true);

      let targetTree = null;
      // 从相交结果中找到最顶层的tree对象
      for (const intersect of intersects) {
        const obj = intersect.object;
        if (obj.parent.name === "terrain") continue;

        // 向上遍历父对象,找到名为tree的节点
        let current = obj;
        while (current && current.name !== "tree") {
          current = current.parent;
        }
        if (current) {
          targetTree = current;
          break; // 只处理第一个相交的树木
        }
      }

      // 处理选中逻辑
      if (targetTree) {
        if (this._selectedTree === targetTree) {
          // 重复点击同一棵树,恢复颜色并取消选中
          this.#resetTreeColor(targetTree);
          this._selectedTree = null;
        } else {
          // 先取消之前选中树的高亮
          if (this._selectedTree) {
            this.#resetTreeColor(this._selectedTree);
          }
          // 高亮新选中的树
          this.#highlightTree(targetTree);
          this._selectedTree = targetTree;
        }
      } else {
        // 点击空白处,取消当前选中
        if (this._selectedTree) {
          this.#resetTreeColor(this._selectedTree);
          this._selectedTree = null;
        }
      }

      this._input.active = false; // 处理完点击后重置状态,避免重复触发
    }
  }
}

3. 修复MouseControllerInput的事件绑定问题

原代码中事件绑定会立即执行函数,且mouseup事件会导致状态混乱,修改如下:

export default class MouseControllerInput {
  constructor() {
    this.#_init();
    this._raycaster = new Raycaster();
    this._pointer = new Vector2();
    this._active = false;
  }
  get pointer() {
    return this._pointer;
  }
  get raycaster() {
    return this._raycaster;
  }
  get active() {
    return this._active;
  }
  #_init() {
    // 传递函数引用,而非立即执行
    document.addEventListener("mousedown", this.#_onClick());
    // 移除mouseup事件,仅在点击按下时触发逻辑
  }
  #_onClick() {
    return (v) => {
      this._active = true; // 设置为true,而非取反,避免状态异常
      this._pointer.x = (v.clientX / window.innerWidth) * 2 - 1;
      this._pointer.y = -(v.clientY / window.innerHeight) * 2 + 1;
    };
  }
}

关键说明

  • 使用userData存储初始颜色:Three.js内置的userData属性专门用于存放自定义数据,不会和框架内置属性冲突。
  • 跟踪选中状态:通过_selectedTree变量记录当前选中的树木,避免重复高亮或遗漏颜色恢复。
  • 递归检测子对象:intersectObject的第二个参数设为true,可以自动检测所有嵌套子对象,简化tree节点的查找逻辑。

内容的提问来源于stack exchange,提问作者ask4you

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 14:46:07