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

如何在ThreeJS中仅将选区内的球体设置为红色?

问题根源

你的代码中球体屏幕坐标的转换逻辑错误,导致坐标偏移计算反向,同时未处理重复选区的颜色重置,这两个问题共同造成了非选区内球体被误设为红色的情况。

解决方案

1. 修正坐标转换逻辑

替换mouseup函数中的坐标计算部分,确保球体的3D位置正确转换为与鼠标坐标统一的文档坐标系:

function mouseup(e) {
    if (!isOrbitControlEnabled) {
        var box = document.getElementById("sel_box");
        var mxy = getCursorPosition(e);
        box.style.display = "none";
        box.style.width = "0";
        box.style.height = "0";
        document.onmousemove = function () {};
        document.onmouseup = function () {};

        mouseUpCoords.x = mxy[0];
        mouseUpCoords.y = mxy[1];
        console.log("up x y: " + mouseUpCoords.x + " " + mouseUpCoords.y);

        // 获取容器的文档位置与尺寸
        const container = document.getElementById("scene-container1");
        const containerRect = container.getBoundingClientRect();
        const containerWidth = container.clientWidth;
        const containerHeight = container.clientHeight;

        // 重置之前选中球体的颜色(可选,按需启用)
        selectedMeshes.forEach(sphere => {
            sphere.material.color.set(defaultMaterial.color);
        });
        selectedMeshes = [];

        // 遍历球体判断是否在选区内
        spheres.forEach((sphere) => {
            const spherePosition = sphere.position.clone();
            const screenPosition = spherePosition.clone().project(camera);

            // 将标准化设备坐标转换为容器内相对坐标
            const containerX = (screenPosition.x + 1) / 2 * containerWidth;
            const containerY = (-screenPosition.y + 1) / 2 * containerHeight;

            // 转换为文档坐标(与鼠标坐标坐标系统一)
            const domX = containerRect.left + containerX + window.scrollX;
            const domY = containerRect.top + containerY + window.scrollY;

            // 定义选区边界
            const minX = Math.min(mouseDownCoords.x, mouseUpCoords.x);
            const maxX = Math.max(mouseDownCoords.x, mouseUpCoords.x);
            const minY = Math.min(mouseDownCoords.y, mouseUpCoords.y);
            const maxY = Math.max(mouseDownCoords.y, mouseUpCoords.y);

            // 判断是否在选区内
            if (
                domX >= minX &&
                domX <= maxX &&
                domY >= minY &&
                domY <= maxY
            ) {
                console.log("sphere x y: " + domX + " " + domY);
                sphere.material.color.set(0xff0000);
                selectedMeshes.push(sphere);
            }
        });
    }
}

2. 简化鼠标坐标获取函数

getCursorPosition可以直接使用原生pageX/pageY属性,避免手动计算的误差:

function getCursorPosition(e) {
    e = e || window.event;
    return [e.pageX, e.pageY];
}

关键说明

  • 坐标统一:鼠标事件获取的是文档坐标,球体坐标必须转换为同一坐标系才能准确对比;
  • 容器适配:使用容器自身的宽高代替窗口尺寸,确保容器非全屏时坐标计算依然准确;
  • 颜色重置:每次选区操作前恢复之前选中球体的默认颜色,避免重复选区导致的颜色残留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 00:43:18