I have a raycaster function that works well on the first attachment to a scene.
See below, as the mouse moves, the mesh is filled appropriately.
After updating my scene though with some clicks on the 3d plots, there are some hard to reproduce fringe cases where the fill is no longer occurring, notice a few of the blue triangles not being filled on hover.
My raycaster function is this:
export function setupRaycastingForResults(scene, camera, renderer) {
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
let hoveredObject = null;
let hoveredRebar = null;
let originalRebarColor = new THREE.Color();
function updateRaycaster(event) {
const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
return raycaster.intersectObjects(scene.children, true); // ✅ Always get fresh objects
}
// ✅ Mouse Move Event - Highlight Object on Hover
renderer.domElement.addEventListener('mousemove', (event) => {
let intersects = updateRaycaster(event);
let meshFound = false;
let rebarFound = false;
for (const intersect of intersects) {
const object = intersect.object;
if (object instanceof THREE.Mesh && !meshFound) {
if (hoveredObject !== object) {
if (hoveredObject) hoveredObject.material.wireframe = true;
hoveredObject = object;
hoveredObject.material.wireframe = false;
}
meshFound = true;
}
if (object instanceof THREE.Points && !rebarFound) {
if (hoveredRebar !== object) {
if (hoveredRebar) hoveredRebar.material.color.set(originalRebarColor);
originalRebarColor.copy(object.material.color);
object.material.color.set(0x00FF00); // Highlight rebar as green
hoveredRebar = object;
}
rebarFound = true;
}
}
// ✅ Restore previous properties when mouse leaves
if (!meshFound && hoveredObject) {
hoveredObject.material.wireframe = true;
hoveredObject = null;
}
if (!rebarFound && hoveredRebar) {
hoveredRebar.material.color.set(originalRebarColor);
hoveredRebar = null;
}
});
My scene being update is shown in the following code, essentially I am updating the position and colors of the mesh objects when selecting a point on the 3d plot.
// ✅ Add Click Event Listener
document.getElementById("pmPlot").on('plotly_click', (data) => {
let clickedIndex = data.points[0].customdata; // Extract strain profile index
window.selectedStrainProfileIndex = clickedIndex;
window.selectedConcShape.generate3dStressPlot(window.selectedAngle, selectedConcShape.strainProfiles[window.selectedAngle][window.selectedStrainProfileIndex]);
// ✅ Reinitialize raycasting since scene was modified
setTimeout(() => {
console.log("🔄 Reinitializing raycasting after PMM selection...");
setupRaycastingForResults(scene, camera, renderer);
}, 100);
});
Part of the updating in generate3dStressPlot function
this.FEMmesh.forEach((object) => {
if (!object.geometry || !object.geometry.attributes.position) return;
let positions = object.geometry.attributes.position.array;
let stress = calculateStress(object, strainProfile, angle, concreteMat);
let zOffset = (stress / 4000) * concreteScaleFactor;
for (let i = 2; i < positions.length; i += 9) {
let newZ = zOffset;
minZ = Math.min(minZ, newZ);
maxZ = Math.max(maxZ, newZ);
}
});
// Second pass to update position and apply colors
this.FEMmesh.forEach((object) => {
let positions = object.geometry.attributes.position.array;
let colors = object.geometry.attributes.color.array;
let stress = calculateStress(object, strainProfile, angle, concreteMat);
let zOffset = (stress / 4000) * concreteScaleFactor;
for (let i = 0; i < positions.length; i += 3) { // Loop through ALL vertices
positions[i + 2] = zOffset; // Modify Z-coordinate
let normalizedZ = (positions[i + 2] - minZ) / (maxZ - minZ);
// Assign color per vertex
colors[i] = 1 - normalizedZ; // Red channel
colors[i + 1] = 0; // Green channel
colors[i + 2] = normalizedZ; // Blue channel
}
object.geometry.attributes.position.needsUpdate = true;
object.geometry.attributes.color.needsUpdate = true;
});
Any ideas on why the raycaster might not be working as intended?
Thanks!