The performance of Three.js significantly decreases when utilizing onMouseMove in conjunction with RayCaster

I am currently working on an application using three.js, but I am encountering serious performance issues. This particular part of the application is inspired by the Voxel Painter example. In my version, the user initiates placement by clicking on a cell, drags the cursor to the desired end point, and then clicks again to complete the placement.

function onDocumentMouseMove(event) {
    //setting up mouse and raycaster
    event.preventDefault();
    mouse.set((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1);
    raycaster.setFromCamera(mouse, camera);

    switch (buildMode) {
        case buildModes.CORRIDOR:
            scene.add(rollOverFloor);

            var intersects = raycaster.intersectObjects(gridObject);
            if (intersects.length > 0) {

                var intersect = intersects[0];

                if (beginPlace == true) {
                    //storing the intersection position
                    var endPlace = new THREE.Vector3(0, 0, 0);
                    endPlace.copy(intersect.point).add(intersect.face.normal);
                    endPlace.divideScalar(step).floor().multiplyScalar(step).addScalar(step / step);
                    endPlace.set(endPlace.x, 0, endPlace.z);

                    corridorDrag(endPlace);

                }
                else {
                    //showing temporary wall on the grid
                    rollOverFloor.position.copy(intersect.point).add(intersect.face.normal);
                    rollOverFloor.position.divideScalar(step).floor().multiplyScalar(step).addScalar(step / step);
                    rollOverFloor.position.set(rollOverFloor.position.x, 0, rollOverFloor.position.z);
                }
            }
            break;

    }
    render();
}

This function is triggered when the user moves the mouse (there are various build modes in the main application, but they are not included here). The function essentially determines the start and end points, with the corridorDrag() function filling in the cells between these points:

function corridorDrag(endPlace) {
    deleteFromScene(stateType.CORRIDOR_DRAG);

    var startPoint = startPlace;
    var endPoint = endPlace;
    var zIntersect = new THREE.Vector3(startPoint.x, 0, endPoint.z);
    var xIntersect = new THREE.Vector3(endPoint.x, 0, startPoint.z);

    var differenceZ = Math.abs(startPlace.z - zIntersect.z);
    var differenceX = Math.abs(startPlace.x - xIntersect.x);

    var mergedGeometry = new THREE.Geometry();

    for (var i = 0; i <= (differenceZ / step); i++) {
        for (var j = 0; j <= (differenceX / step); j++) {
            var x = startPlace.x;
            var y = startPlace.y;
            var z = startPlace.z;

            //Calculating the position of each cell
            if (endPoint.x <= (startPlace.x )) {
                if (endPoint.z <= (startPlace.z)) {
                    x = x - (step * j);
                    z = z - (step * i);
                }
                else if (endPoint.z >= (startPlace.z)) {
                    x = x - (step * j);
                    z = z + (step * i);
                }
            } else if (endPoint.x >= (startPlace.x)) {
                if (endPoint.z <= (startPlace.z)) {
                    x = x + (step * j);
                    z = z - (step * i);
                }
                else if (endPoint.z >= (startPlace.z)) {
                    x = x + (step * j);
                    z = z + (step * i);
                }
            }

            floorGeometry.translate(x, y, z);
            mergedGeometry.merge(floorGeometry);
            floorGeometry.translate(-x, -y, -z);
        }
    }

    var voxel = new THREE.Mesh(mergedGeometry, tempMaterial);
    voxel.state = stateType.CORRIDOR_DRAG;

    scene.add(voxel);
    tempObjects.push(voxel);
}

Initially, the deleteFromScene() function removes all highlighted cells from the scene (see below). The code should then create multiple meshes based on the start and end points, and add them to the scene.

 function deleteFromScene(state) {
    tempObjects = [];
    var i = scene.children.length;
    while (i--) {
        if (scene.children[i].state != undefined)
            if (scene.children[i].state == state)
                scene.children.splice(i, 1);
    }
}

Unfortunately, the performance is severely affected and there seems to be a large number of vertices being added to the renderer, as indicated in the WebGLRenderer stats window. I am unsure why it is adding so many vertices, but I suspect this is the cause of the slow rendering.

You can view the application here - the issue can be observed by clicking on a cell, dragging the cursor to the other end of the grid, and noting the time taken to fill in the cells.

Thank you for your help, I am turning to this as a final resort.

Answer №1

Not long ago, Twitter released an update that included the feature of infinite scrolling. However, this new feature caused major issues as it was crashing users' browsers upon its launch. After conducting a thorough investigation, Twitter engineers discovered that the frequent firing of the scroll event was the root cause of the problem.

It is important to note that mouse events have the potential to fire multiple times in a single second, leading to excessive code execution and ultimately slowing down or crashing the browser. To address this issue, Twitter implemented a simple solution: event polling.

Within your mousemove event handler, it is recommended to check if a certain amount of time has elapsed since the last move event before executing your code.

var lastMove = Date.now();

function onDocumentMouseMove(event) {
    if (Date.now() - lastMove < 31) { // aiming for 32 frames per second
        return;
    } else {
        lastMove = Date.now();
    }

    // insert your code here
}

I trust this explanation serves you well!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React throws a "ReferenceError: indexedDB is not defined" but surprisingly, it still manages to function properly

I utilized yarn to install idb-keyval By utilizing the following code, I imported it: import { set } from 'idb-keyval'; Then, I assigned a value to a variable using the following code snippet: set('hello', 'world'); Althou ...

Divide HTML elements every two words

Can you use CSS to break up HTML content after every 2 words, ensuring it works for any word combination? Example: // Original HTML content The cat is sleeping // Desired result: The cat is sleeping ...

Is it possible to modify the numerical values within TimeCircles.js?

I have integrated the TimeCircles.js plugin into a Persian website and need to convert Persian numbers to English. I already have a function that replaces each digit with the appropriate English number. I am able to successfully convert the text inside t ...

What are some javascript libraries that can be used to develop a mobile image gallery for both Android and iPhone

I currently have the touch gallery system in place, but unfortunately it isn't functioning properly on Android devices. ...

Guide to indicating the chosen filter in React using Material UI

I'm currently working on a blog that includes a filter feature. The filtering functionality is working perfectly, but I am trying to specify which filter option is currently selected. Here is the code snippet: {cardCategories.map((cat) => { retu ...

Switching the mouse cursor when the mousedown event occurs

I'm trying to implement a feature where holding down the mouse will change the cursor to an image, and when releasing the mouse it should revert back to its default. However, the code I have isn't working properly - you have to right click then l ...

"Encountering an issue where the route function in Passport and ExpressJS is not being

When using passport for admin authentication, I am facing an issue where the redirect is not calling my function. Consequently, all that gets printed on login is [object Object] Here is my code: app.get('/admin', isLoggedIn, Routes.admin); ...

Setting the Date in Angular.js: A Step-by-Step Guide

Make maxDate selectable as today at the latest (past days are clickable but not tomorrow). The range between minDay and maxDay should not exceed 365 days, allowing for fewer days to be selected. $scope.dateOptions = { formatYear: " ...

Ways to determine the vertical size of a React component

Currently, I am dynamically generating a list of Symbol(react.element) by utilizing the map function to iterate through an array and incorporate each element's HTML tags. My question is: How can I determine the height of each individual rendered Symbo ...

A new long polling AJAX request is triggered whenever there is a change in the parameter

function AjaxRequest(params, url) { if (params) { this.params = params; this.type = "GET"; this.url = url; // this.contentType = "multipart/form-data"; this.contentLength = params.length;; } } AjaxRequ ...

What is the most efficient way to add an attribute in jQuery - using the attr() method, passing attributes as a key-value object, or directly?

There are three ways that I am aware of for adding a href attribute with a relative link in jQuery: using (1) .attr(), (2) attributes as key-value pair in an argument, or (3) direct writing (if you know other methods, please share in your response so I can ...

Working with JSON objects in AngularJS

I have a JSON dataset in the following structure. I need to extract information from the JSON and display it on an HTML table. [region: [name:"", code:""IntradayBalance:{ currency:,Time:,Balance: }.... ], acccountcurrencyBalance:[{ c ...

Sending an email through Node.js with SendGrid is not a challenge

I've got this Mailer.js file const sendgrid = require('sendgrid'); const helper = sendgrid.mail; const keys = require('../config/keys'); class Mailer extends helper.Mail { constructor({ subject, recipients ...

Easily move a group of HTML elements at the same time with a simple

Exploring HTML5 Drag and Drop with Multiple Elements When it comes to dragging and dropping multiple elements in HTML5, there seems to be a limitation with the default draggable attribute. This attribute allows only one element to be dragged at a time, ma ...

Tips for preventing multiple button clicks until the completion of the initial click event

I created a clock that tells the time every quarter as per the professor's request. However, there is an issue - when I click multiple times, the clock keeps telling the time repeatedly until the number of tellings matches the number of clicks. I thou ...

Learn how to dynamically insert an element into an angular scope using a click event

Currently, I am working on a function called onGroundUserClick within the Scope passedScope. The goal is to have a function triggered upon the completion of loading the iframe that will establish ng-click. var $tdName = $("<td/>", { ...

Error message found: "Uncaught TypeError: e[n] is undefined while setting up redux store in a reactjs application

Delving into the world of Redux for the first time, I decided to tackle the Todo List example from the official redux.js.org website. After testing the code, everything seemed to be working fine with the redux store initialized only with the reducer as a p ...

Javascript: object continuously moving despite key being released

When I leave the keyword new on line: var myGamePiece = new makeComponent(myContext, 30, 30, "red", 10, 120); The red square continues to move even when I release the arrow key. However, if I remove the new element from that line, the square stops moving ...

Changing the data type of a column in an Excel file from XLSX to

I am currently working with the XLSX npm package and attempting to download a sample Excel file, add some data to it, and then upload it back. The fields in the file include MOBILE NUMBER, DATE, TIME, and NAME. When I upload the file, the values for the DA ...

Verifying the format of an object received from an HTTP service using a TypeScript interface

Ensuring that the structure of the http JSON response aligns with a typescript interface/type is crucial for our javascript integration tests against the backend. Take, for example, our CurrentUser interface: export interface CurrentUser { id: number; ...