Here I get a 3D model with a sphere as shown in the figure. My goal is to use a selection area to turn the spheres in this area red. However, while doing this, I cannot paint the spheres in the exact area I selected.
Spheres in straight alignment in the area I have chosen should be painted. In other words, if the x,y axis matches, all spheres in the z axis must be red.
As can be seen in this image, the area I selected from above decreases downwards. However, it should land straight and every sphere within the area should be red.
Camera:
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
This is how to create select area box and color spheres:
// Select area and spheres
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
var selectedMeshes = [];
var selectionBox = document.getElementById("sel_box");
let isOrbitControlEnabled = true;
document.getElementById('forceareaadd').addEventListener('click', onPickAreaClick, false);
var mouseDownCoords = { x: 0, y: 0 };
var mouseUpCoords = { x: 0, y: 0 };
function onPickAreaClick() {
isOrbitControlEnabled = !isOrbitControlEnabled;
controls.enabled = isOrbitControlEnabled;
if (!isOrbitControlEnabled) {
}
}
document.getElementById('clearselectedsphere').addEventListener('click', clearSelectedSpheres, false);
// Function to clear selected spheres
function clearSelectedSpheres() {
// Iterate through selectedMeshes and reset their colors
selectedMeshes.forEach((sphere) => {
sphere.material.color.set(0x00ff00);
});
// Clear the selectedMeshes array
selectedMeshes = [];
console.log("selected meshes after clear: " + selectedMeshes);
}
function getCursorPosition(e) {
e = e || window.event;
if (e) {
if (e.pageX || e.pageX == 0) return [e.pageX, e.pageY];
var dE = document.documentElement || {};
var dB = document.body || {};
if ((e.clientX || e.clientX == 0) && ((dB.scrollLeft || dB.scrollLeft == 0) || (dE.clientLeft || dE.clientLeft == 0))) return [e.clientX + (dE.scrollLeft || dB.scrollLeft || 0) - (dE.clientLeft || 0), e.clientY + (dE.scrollTop || dB.scrollTop || 0) - (dE.clientTop || 0)];
}
return null;
}
function mousedown(e) {
if (!isOrbitControlEnabled) {
var mxy = getCursorPosition(e);
var box = document.getElementById("sel_box");
mouseDownCoords.x = mxy[0];
mouseDownCoords.y = mxy[1];
box.orig_x = mxy[0];
box.orig_y = mxy[1];
box.style.left = mxy[0] + "px";
box.style.top = mxy[1] + "px";
box.style.display = "block";
document.onmousemove = mousemove;
document.onmouseup = mouseup;
console.log("down x y: " + mouseDownCoords.x + " " + mouseDownCoords.y);
}
}
function mousemove(e) {
if (!isOrbitControlEnabled) {
var mxy = getCursorPosition(e);
var box = document.getElementById("sel_box");
if (mxy[0] - box.orig_x < 0) {
box.style.left = mxy[0] + "px";
}
if (mxy[1] - box.orig_y < 0) {
box.style.top = mxy[1] + "px";
}
box.style.width = Math.abs(mxy[0] - box.orig_x) + "px";
box.style.height = Math.abs(mxy[1] - box.orig_y) + "px";
}
}
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 = null;
document.onmouseup = null;
mouseUpCoords.x = mxy[0];
mouseUpCoords.y = mxy[1];
console.log("up x y: " + mouseUpCoords.x + " " + mouseUpCoords.y);
const designPartContainer = document.querySelector('.design-part');
const containerRect = designPartContainer.getBoundingClientRect();
// Account for potential scroll offsets
const scrollX = window.scrollX || window.pageXOffset;
const scrollY = window.scrollY || window.pageYOffset;
// Calculate the depth range based on the camera's near and far planes
const near = camera.near;
const far = camera.far;
spheres.forEach((sphere) => {
const spherePosition = sphere.position.clone();
const screenPosition = spherePosition.clone().project(camera);
// Convert screen position to DOM coordinates within the design-part class
const domX = (screenPosition.x + 1) / 2 * containerRect.width + containerRect.left + scrollX;
const domY = (-screenPosition.y + 1) / 2 * containerRect.height + containerRect.top + scrollY;
// Check if the sphere is within the selection box and within the depth range
const isInsideSelectionBox =
domX >= Math.min(mouseDownCoords.x, mouseUpCoords.x) &&
domX <= Math.max(mouseDownCoords.x, mouseUpCoords.x) &&
domY >= Math.min(mouseDownCoords.y, mouseUpCoords.y) &&
domY <= Math.max(mouseDownCoords.y, mouseUpCoords.y);
const isWithinDepthRange = screenPosition.z >= 0 && screenPosition.z <= 1;
if (isInsideSelectionBox && isWithinDepthRange) {
console.log("sphere x y: " + domX + " " + domY);
sphere.material.color.set(0xff0000); // Set to red color
selectedMeshes.push(sphere);
}
});
// Center the camera on the selected area
const centerX = (mouseDownCoords.x + mouseUpCoords.x) / 2;
const centerY = (mouseDownCoords.y + mouseUpCoords.y) / 2;
const centerScreenPosition = new THREE.Vector3(
(centerX - containerRect.left - scrollX) / containerRect.width * 2 - 1,
-(centerY - containerRect.top - scrollY) / containerRect.height * 2 + 1,
0.5 // Adjust this value based on the depth range of your scene
);
const centerWorldPosition = centerScreenPosition.unproject(camera);
camera.lookAt(centerWorldPosition);
}
}
document.onmousedown = mousedown;