What is the fastest way to efficiently refresh a substantial BufferGeometry?

When using a BufferGeometry to render thousands of cubes forming terrain, I encountered difficulty in updating the geometry when changing the position of a single cube. For instance, this is the code used to initialize the geometry: (My tests are based on an updated version of this example)

// 12 triangles per cube (6 quads)
var triangles = 12 * 150000;

var geometry = new THREE.BufferGeometry();
geometry.attributes = {

    position: {
        itemSize: 3,
        array: new Float32Array( triangles * 3 * 3 ),
        numItems: triangles * 3 * 3
    },

    normal: {
        itemSize: 3,
        array: new Float32Array( triangles * 3 * 3 ),
        numItems: triangles * 3 * 3
    },

    color: {
        itemSize: 3,
        array: new Float32Array( triangles * 3 * 3 ),
        numItems: triangles * 3 * 3
    }
}

positions = geometry.attributes.position.array;
normals = geometry.attributes.normal.array;
colors = geometry.attributes.color.array;

After moving a cube, I have to set:

geometry.attributes.position.needsUpdate = true;

This operation causes a drop in FPS during the update process. I am looking for alternate methods to achieve this. It seems unnecessary for minor changes to one cube (12 triangles/36 vertices). I assume that setting `needsUpdate` sends the array to the shader again.

One solution I considered was dividing the geometry into separate smaller BufferGeometries, but I am unsure about the impact on overall performance. As far as I know, more geometries lead to lower FPS.

If anyone has any suggestions or ideas on how to tackle this issue, I would appreciate the assistance! Despite the update concerns, BufferGeometry appears to be the ideal solution for my needs. Thank you!

Answer №1

From version r71 onwards, threejs now includes support for bufferSubData.

To make use of this feature, utilize a DynamicBufferAttribute, (or adjust the updateRange setting accordingly)

var positionAttr = geometry.attributes.position 
// if not using DynamicBufferAttribute initialize updateRange:
// positionAttr.updateRange = {};
positionAttr.updateRange.offset = 0; // specify starting point for updates
positionAttr.updateRange.count = 1; // indicate number of vertices to update
positionAttr.needsUpdate = true;

Answer №2

I encountered a similar issue with a sizable BufferGeometry while updating specific vertices within it.

One workaround is to utilize _gl.bufferSubData instead of _gl.bufferData to modify only a portion of the buffer. (It's worth noting that three.js exclusively uses _gl.bufferData).

Therefore, when updating positions, you should:

// Create a view of the data to update from index offsetSub to offsetSubEnd
var view = geometry.attributes.position.array.subarray(offsetSub, offsetSubEnd);

// Bind the buffer for positions (get the gl context with webglrenderer)
_gl.bindBuffer(_gl.ARRAY_BUFFER, geometry.attributes.position.buffer);

// Insert the new values at the appropriate index in the GPU buffer (offsetGeometry is in bytes)
_gl.bufferSubData(_gl.ARRAY_BUFFER, offsetGeometry, view);

It's important to note that this approach may be slower when modifying a significant portion of the buffer vertices compared to using _gl.bufferData.

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

Using Angular to create a dynamic form with looping inputs that reactively responds to user

I need to implement reactive form validation for a form that has dynamic inputs created through looping data: This is what my form builder setup would be like : constructor(private formBuilder: FormBuilder) { this.userForm = this.formBuilder.group({ ...

I have always wondered about the meaning of " + i + " in Javascript. Can you explain it to

<script> var x,xmlhttp,xmlDoc xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", "cd_catalog.xml", false); xmlhttp.send(); xmlDoc = xmlhttp.responseXML; x = xmlDoc.getElementsByTagName("CD"); table="<tr><th>Artist</th><th>Ti ...

When attempting to log out of Keycloak, a TypeError occurs in the front-end application stating that it cannot read properties of undefined related to the action of logging out

I've been trying to implement a logout feature in my front-end application using Keycloak, but I'm encountering difficulties. Most of the examples I found online are for older versions of Keycloak and use 'auth' and 'redirectURI&ap ...

Traverse through the nested JSON array using a loop

Exploring a JSON object: { "date_price": [ { "date": "Jan 2000", "price": 1394.46 }, { "date": "Feb 2000", "price": 1366.42 }, { "date": "Mar 2000", "price": 1498.58 }, { "date": "Apr ...

Tips for retaining a number even when the page is refreshed

Is there a way to keep the number increasing even after refreshing the webpage? Currently, the number resets every time the page is refreshed. Any suggestions on how to fix this? Here is the number <form method="POST"> &l ...

What is the best way to remove the left margin from a MuiTreeItem-group?

I'm working with the MUI tree component and I want to remove the left margin of the second layer of MuiTreeItem-group I attempted to use makeStyles to address this issue, but it didn't have the desired effect const useStyles = makeStyles(() => ...

Configuring .env files for both production and development environments in Node.js

As I observed, there were various approaches to setting up environments in NodeJS - some seemed straightforward while others appeared more intricate. Is it possible to utilize package.json scripts to manage environment variables? If so, what is the best p ...

Implementing JavaScript functionality based on a specific body class

Is there a way to execute this script only on a specific page with a particular body class? For example, if the page has <body class="category-type-plp"> How can I target my script to work specifically for "category-type-plp"? plpSpaceRemove: fun ...

The function 'toBlob' on 'HTMLCanvasElement' cannot be executed in react-image-crop because tainted canvases are not allowed to be exported

Currently, I am utilizing the react-image-crop npm package for image cropping purposes. Everything works perfectly when I pass a local image as props to the module. However, an issue arises when I try to pass a URL of an image fetched from the backend - th ...

Utilizing Vue.js to set the instance global property as the default value for a component prop

Is it possible to access a global property from my vue instance when setting a default prop value in my component? This is what I would like to achieve props: { id: { type: String, default: this.$utils.uuid } } I attempted to use an arrow fun ...

The white PNG image loaded as a texture in ThreeJS, applied as a material and displayed as a plane, is showing noticeable grey edges

I'm encountering an issue with rendering a white material in ThreeJS version 87. Follow these steps to recreate the problem: Load a white PNG image as a texture Use this texture to create a MeshBasicMaterial (passed as a parameter map) Combine the ...

While attempting to upload a file in my Mocha Node.js test, I encountered the message: "Received [Object null prototype] { file: { ... }}"

Everywhere I find the solution in white : app.use(bodyParser.urlencoded({extended: true})); I can use JSON.stringify(req.files) However, I am sure there is a way to fix my problem. My Mocha test : it('handles file upload', async function () { ...

The function is not functioning properly due to an issue with the HTTP request

I am working with an AngularJS Framework controller. var app = angular.module('myApp', []); app.controller('myCtrl', function($scope, $http) { var locations =[]; var map; var markers = []; $scope.mappa = function(){ map = new g ...

Tips for controlling the camera using mouse movement rather than clicking on the mouse

I recently encountered an issue while using the react-three-fiber package. I wanted to add camera movement based on mouse movement instead of mouse clicks, similar to what is seen on roundme.com where the camera moves towards the position of the pointer as ...

Utilizing VUE with Socket.io or vue-socket.io Integration

I've been working on connecting using socket.io (client) and websocket.org (server) with vue.js. Despite going through all the examples, I can establish a connection to the socket but when I emit the event BOARD_ID, I don't receive any response. ...

How can we programmatically trigger a click action on an element obtained through an HTTP request with the help of Set

window.addEventListener("load" , () => { setInterval(() => { let xhttp = new XMLHttpRequest(); xhttp.open("GET", "./messagedUsers.php", true); xhttp.onload = () => { if(xhttp.re ...

Removing various data entries based on timestamp and additional fields in Firebase Firestore

I stumbled upon a similar query before. Being new to coding, I am attempting to remove all documents in the "users" collection that are older than 1 month and not marked as premium. The deletion criteria involve checking if the "user_online" field is at le ...

Guide to displaying a particular item in Vue 3

Currently, I am embarking on a project that requires the functionality to print a specific element of my webpage. After some research, I came across a mixin/plugin known as VueHtmlToPaper which seems to be the perfect solution for what I need. However, I a ...

What is the correct method for launching a modal window in wagtail-admin?

I am currently working on enhancing my wagtail-admin interface, but I have hit a roadblock when trying to open a modal window. While I could create a div with a close button, I believe there must be a more appropriate method for achieving this. It seems th ...

``Changing the value of the radio button does not update the ng-model variable

I have encountered an issue with my code. Upon page load, the radio button is checked but the ng-model value session.payment does not get updated automatically. I have to manually select it again for the update to take effect. <li ng-repeat="method i ...