To optimize performance, it is recommended to avoid raycasting on every single frame and instead set up a specific interval for raycasting. This can be achieved by using functions like setTimeout
or setInterval
, or by checking the timing within the update loop.
onUpdate() {
// Code that runs once per frame
// Check if enough time has passed to perform raycast
if (Date.now() - this.lastRaycast > this.raycastInterval && this.qRaycast) {
this.handleRaycast();
this.lastRaycast = Date.now();
this.qRaycast = false;
}
requestAnimationFrame( () => this.onUpdate() );
}
In addition, consider queuing up raycasts only when the mouse moves, as there's no need to continuously raycast when the mouse is stationary. Also, disable raycasting during panning movements to prevent any jitter during such actions.
// Event Handlers
// Record mouse position for raycast
onMouseMove(e) {
this.mouse.x = (e.clientX / window.innerWidth ) * 2 - 1;
this.mouse.y = -((e.clientY - 50) / window.innerHeight ) * 2 + 1;
// Do not queue raycast if panning
this.qRaycast = !this.mouseState.held;
}
// Disable raycast during panning
onMouseDown(e) {
this.mouseState.lastClick = Date.now();
this.mouseState.clicked = false;
this.mouseState.held = true;
}
onMouseUp(e) {
this.mouseState.held = false;
}
Once the conditions are met, handling the raycast like so:
// Handling Raycast
handleRaycast() {
let hits = null;
let hitcount = 0;
if (UI.raycast && meshObj) {
this.raygun.setFromCamera(this.mouse, this.camera);
hits = this.raygun.intersectObject(meshObj, false);
hitcount = hits.length;
}
if (hitcount > 0) {
// Actions with the raycast results
}
}
If further optimization is needed, consider breaking down the loop function into smaller parts to allow UI updates in between iterations:
An example could be sorting through all hits to find the closest point to the cursor:
// Optimization
let startTime = 0;
let maxTime = 75; // maximum time in ms
let dist = 1;
let hitIndex;
let i = 0;
function findClosest() {
return new Promise((resolve) => {
function loop() {
startTime = performance.now();
while (i < hitcount) {
// Break loop after max time
let currentTime = performance.now();
if ((currentTime - startTime) > maxTime) {
console.log('Loop exceeded max time: ' +
(currentTime - startTime).toFixed(3) );
startTime = currentTime;
break;
}
// Finding the closest raycast point to cursor
dist = hits[i].distanceToRay;
if (dist < smallestDist) {
smallestDist = dist;
smallestPointIndex = hits[i].index;
}
i++;
}
if (i < hitcount) {
// Update UI and continue looping
setTimeout(loop, 1);
} else {
resolve(smallestPointIndex);
}
}
loop();
});
}
findClosest().then(result => {
// Handle result here
}
Additionally, reducing the number of objects being raycasted to can also help improve performance significantly.