Is it possible to duplicate the mesh thousands of times and animate it without causing significant performance issues

I have created a demo with numerous cubes that share the same geometry and texture:

texture  = THREE.ImageUtils.loadTexture ...
material = new THREE.MeshLambertMaterial( map: texture )
geometry = new THREE.BoxGeometry( 1, 1, 1 )

cubes = []
for i in [0..1000]
  cubes.push new THREE.Mesh geometry, material

... on each frame

for cube in cubes
  // perform actions on each cube

After generating all the cubes, I begin moving them around the screen.

Although the cubes have identical textures and sizes, the computer struggles to render them all when there are hundreds of cubes.

Is there a way to inform Three.js / WebGL that these cubes are essentially the same object, just in different positions?

I've heard about BufferGeometry and Geometry2 potentially improving performance in this scenario, but I'm unsure of the best approach to take.

Thank you

Answer №1

Is there a way to inform Three.js / WebGL that all these objects are essentially the same object, just placed in different positions?

Unfortunately, there is no automatic way to optimize render calls in this scenario. It would be great if there was.

I've heard about BufferGeometry and Geometry2 potentially improving performance in this situation, but I'm unsure of the best approach to take.

The key here is that the standard THREE.Geometry class in three.js is designed for developer convenience and is not optimized for how WebGL handles data. The DirectGeometry (previously Geometry2) and BufferGeometry classes are specifically for this purpose. BufferGeometry aligns with how WebGL expects data for draw calls, utilizing typed arrays for geometry attributes. The conversion from Geometry to BufferGeometry occurs automatically when geometry.verticesNeedsUpdate is set to true.

If attributes are not modified, this conversion occurs once per geometry, which is fine since you only have one geometry. Moving to BufferGeometry won't provide further optimization since you are already using it.

The main challenge with multiple geometries is the increased number of draw calls needed for rendering. Each instance of THREE.Mesh results in a draw call, and multiple draw calls can impact performance significantly. Combining meshes or geometries into a single entity can reduce draw calls, although it may not be practical for dynamic positioning and rotation.

What you may be interested in is geometry instancing in WebGL, allowing for rendering multiple objects in a single draw call. Each instance shares a common geometry while special attributes like InstancedBufferAttribute enable unique values for each instance. This approach can streamline rendering for multiple objects.

Examples of geometry instancing can be found here:

The challenge with instancing lies in creating a custom vertex shader to handle per-instance attributes in the material. This customization is crucial for applying unique transformations to each instance during rendering.

Answer №2

Since you're working with a webgl tag, I'll provide an alternative approach that doesn't involve using Three.js.

One effective method is to create a float texture array that contains model transform matrix data (or just vec3 positions if that's all you need). Then, you can allocate a mesh chunk that holds all the cube data. Introduce an additional attribute called modelTransform index, which corresponds to the correct offset in the model transform data texture for each "cube instance" in the mesh chunk.

During each frame, calculate the appropriate model transform data for all the cubes and update the model transform data texture with the correct offsets before uploading it to the GPU. In the vertex shader, access the model transform data using the modelTransform index attribute and the float texture.

This method has proved effective in my own engine, especially for small objects like cubes. However, keep in mind that updating 150,000 cubes at 60 FPS will likely consume a significant amount of your CPU resources. This limitation is inherent in any instancing scheme you choose.

For cubes with fixed motion or animation, consider uploading a velocity attribute and initial creation time stamp attribute for each cube instance. Each frame, pass the current time as a uniform and calculate the position using the formula

"pos += attr_velocity * getDeltaTime(attr_initTime, unif_currentTime);"
. This approach eliminates CPU workload entirely and enables you to render a larger number of cubes more efficiently.

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

What is the best method for deleting a portion of a string following the final instance of a particular character?

I have a single string that looks like this: "Opportunity >> Source = Email >> Status = New >> Branch = Mumbai" My goal is to truncate the string from the last occurrence of >>. Essentially, I want the resulting string to be: "Op ...

Issues with Bootstrap Contact Form submission

I found a helpful tutorial for creating a form at the following link: After following the tutorial, I added these scripts to the bottom of my contact form HTML: <script src='https://code.jquery.com/jquery-1.12.0.min.js'></script> ...

The webpage continues to refresh after executing a JavaScript function triggered by the AJAX response

I have experimented with various solutions for calling a JavaScript function returned from an AJAX response. While each method worked to some extent, I found that using an alert within the refreshResults function was necessary in order to display the resul ...

The NextJs router encountered an unknown key passed through the urlObject during the push operation

I have a Next.js/React application where I am utilizing the Next Router to include some queries in my URL. However, when using the following function, the Chrome Dev Console displays numerous warnings: const putTargetsToQueryParams = (targets: IFragrance ...

Experiencing difficulty in updating GitHub pages with React application

Looking for help updating my deployed active react app on GitHub pages with newer code, such as color changes and text updates. The updated code has been pushed to the main branch of my GitHub repo but the live GitHub page is not reflecting the changes. De ...

Exploring the World with AngularJS and Google Maps API through ngGeolocation

Having some difficulty displaying my geolocation on Google Maps API using a marker. I am utilizing the ng controller ngGeolocation and the http://angular-ui.github.io/angular-google-maps/ Previously, I hardcoded the marker and map location without any is ...

The custom validation function in jQuery is not triggering

I am facing an issue with my HTML and JavaScript setup, which looks like this: <html> <head> <title>Validation Test</title> <script src="https://code.jquery.com/jquery-3.4.1.js"></script> <script src="htt ...

How can I incorporate a standalone Vuetify component into my Nuxt.js project?

Using Vuetify with nuxt.js specifically for the dashboard layout - how can I achieve this in my nuxt.config.js file? modules: [ //['nuxt-leaflet', { /* module options */}], 'bootstrap-vue/nuxt', '@nuxtjs/ax ...

JavaScript loop used to create markers on Google Maps

I am currently in the process of developing a basic Google map which includes markers and involves looping through the data source for the markers. When I replace key.lng or key.lat with hardcoded values in the code below, everything functions correctly. ...

Experiencing a 404 ERROR while attempting to submit an API POST request for a Hubspot form within a Next.js application

Currently, I am in the process of developing a Hubspot email submission form using nextjs and typescript. However, I am encountering a couple of errors that I need help with. The first error pertains to my 'response' constant, which is declared b ...

Generate a fresh row in a table with user inputs and save the input values when the "save" button is

HTML: <tbody> <tr id="hiddenRow"> <td> <button id="saveBtn" class="btn btn-success btn-xs">save</button> </td> <td id="firstName"> <input id="first" type="tex ...

What is the best way to enhance a tool-tip with images or legends?

Currently, I have implemented a tool-tip feature which works for a text box. However, the issue is that users are unaware of the presence of the tool-tip for the text box until they hover over it. My question is, how can I make it more obvious to users t ...

Adjust the size of the logo as the user scrolls

Currently, I am implementing a JavaScript feature that allows my logo to shrink when the user scrolls down and grow when they scroll up. To achieve this effect, I am utilizing the jQuery functions addClass and removeClass. However, I have encountered som ...

Using jQuery to select the next table cell vertically

Is there a way to utilize jQuery to access the cell (td) directly below a given cell in a traditional grid-layout HTML table (where each cell spans only one row and column)? I understand that the code below will assign nextCell to the cell immediately to ...

Is there a way to prevent the text in my text boxes from staying there when I refresh the page?

Currently working on an HTML5 project with Javascript, here is a snippet of my code: Your inquiry <textarea type="text" name="phrase" id="phrase" cols="50" rows="5" placeholder="Write your text here. . ."></textarea> I am looking for a way ...

Getting POST data in Next.js is a common task that requires understanding of how the

I am currently working on a form validation project using the App Router within Next.js. // app/register/page.tsx export default function Register(context: any) { console.log("Register page", context.params, context.searchParams); return ...

Issue with React component not displaying in the browser.Here are some

I am currently following a React tutorial on and I'm facing an issue where the Counter component is not displaying on the page. The generated HTML looks like this: <html> <head> <script src="/bundle.js" ></script> </he ...

The $.get jQuery function is unexpectedly retrieving an entire HTML page instead of the expected JSON data

Currently, I am in the process of developing a web application and have opted to use PHP as the server-side language. Below is the PHP script responsible for returning JSON data: <?php require_once "connection.php"; if (isset($_GET['take'])) ...

steps to extract routing into its own component

Is it possible to extract this routing logic into a separate component? I attempted to use map but it didn't work I want to have only a single route, and change the 'path' when a specific link is clicked const Home = ({ code }) => { re ...

JavaScript heap ran out of memory near heap limit during mark-compacts, rendering the allocation ineffective, resulting in a failed Ionic 3 production build

While attempting to build a production version of my Ionic 3 app, I encountered the following error: "FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory". To troubleshoot this issue, I duplicated the en ...