Is it possible to consolidate geometry in each frame during the rendering process using three.js?

Having recently delved into three.js, I've been experimenting with some concepts. My current challenge involves creating a line in the scene and using it as a reference for cloning and transforming. The goal is to display the cloned lines in a sequential transformation within the scene.

The basic code structure looks like this:

var line, scene, camera, light, renderer;
var frame = 0;
var random_degree = Math.round(Math.random() * 360);
var container = document.getElementById( 'container' );
init();
animate();

function init() {
   renderer = new THREE.WebGLRenderer();
   renderer.setSize( window.innerWidth, window.innerHeight );
   container.appendChild( renderer.domElement );

   scene = new THREE.Scene();

   camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
    scene.add( camera );

    camera.position.x = 0;
    camera.position.y = 0;
    camera.position.z = 200;

   var material = new THREE.LineBasicMaterial({
      transparent: true,
      color: 0x0000ff
   });

   var geometry = new THREE.Geometry();
   geometry.vertices.push(
     new THREE.Vector3( -100, 0, 0 ),
     new THREE.Vector3( 0, 100, 0 ),
     new THREE.Vector3( 100, 0, 0 )
   );
   line = new THREE.Line( geometry, material );
   //Code adapted from http://threejs.org/docs/#Reference/Objects/Line 
   //simplified for demonstration
}

function animate() {
    requestAnimationFrame( animate );
    frame ++;
    if( frame < 1500){
        var newCurve = line.clone();
        newCurve.rotation.x = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
        newCurve.rotation.y = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
        newCurve.rotation.z = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
        newCurve.material.opacity = 0.2;
        scene.add(newCurve);
    }
    renderer.render( scene, camera );
}

The HTML section simply consists of:

<div id='container'></div>

Although everything is functioning as intended, a limitation arises when the number of lines exceeds 2000, resulting in a significant drop in FPS. In an attempt to address this, I experimented with merging the lines during initialization:

var totalGeometry  = new THREE.Geometry();
....
function init(){
....
    for(var i=0; i< 1500; i++){
        var newCurve = line.clone();
        newCurve.rotation.x = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
        newCurve.rotation.y = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
        newCurve.rotation.z = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
        newCurve.updateMatrix();
        totalGeometry.merge(newCurve.geometry, newCurve.matrix);
    }
    var totalLine = new THREE.Line(totalGeometry, material);
....
}    

However, I encountered a limitation as I could only merge the lines during initialization and not during the rendering process. When attempting to merge the lines within the function animate(), only a single line is rendered instead of a group:

function animate(){
    .....
    if( frame < 1500){
       var newCurve = curve1.clone();
       newCurve.rotation.x = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
       newCurve.rotation.y = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
       newCurve.rotation.z = ((random_degree + frame * 0.25) % 360) * Math.PI / 180;
       newCurve.material.opacity = 0.2;
       newCurve.updateMatrix();
       totalGeo.merge(newCurve.geometry, newCurve.matrix);
       totalMesh = new THREE.Line(totalGeo, newCurve.material);

       scene.add(totalMesh);
     }
}

If anyone has suggestions or solutions to this challenge, I would greatly appreciate it. Thank you.

Answer №1

To efficiently update the geometry of your line without combining geometries or introducing new line objects, consider using a THREE.BufferGeometry. This approach helps conserve memory and achieve the desired effect.

I have made adjustments to your fiddle here to showcase this.

Begin by creating a buffer geometry in the getBufferGeometry function:

/**
 * Create a buffer geometry
 * Positions attribute with 3 vertices per point
 */
function getBufferGeometry() {
    var geometry = new THREE.BufferGeometry();

    positions = new Float32Array(total * 3);
    geometry.addAttribute(
        'position', new THREE.BufferAttribute(positions, 3)
    );
    return geometry;
}

The real magic happens in the addLine function:

/**
 * Add a new line to the geometry on each call
 */
function addLine() {
    if (count < total) {
        vertices = getVertices();

        var index = count * 9;
        positions[index] = vertices[0].x;
        positions[index++] = vertices[0].y;
        positions[index++] = vertices[0].z;
        positions[index++] = vertices[1].x;
        positions[index++] = vertices[1].y;
        positions[index++] = vertices[1].z;
        positions[index++] = vertices[2].x;
        positions[index++] = vertices[2].y;
        positions[index++] = vertices[2].z;

        var start = count * 3;
        var end = start + 3;

        bufferGeometry.addGroup(start, end);
        line.geometry.attributes.position.needsUpdate = true
        count++;
    }
}

This method is inspired by @WestLangley's answer in a related question here.

Remember to define the maximum number of points - in this example, it is set as total at the beginning of the code.

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

Challenges with Incorporating Stripe

I am currently working on integrating Stripe into a school project. Despite following the documentation and instructions provided, I keep encountering a POST 500 (INTERNAL SERVER ERROR) along with an error message stating "Error fetching payment intent: Er ...

What could be causing my recursive function to skip over certain parts of my JSON data?

UPDATED TO BE MORE CONCISE Hello, I'm looking for assistance with a recursive function that's not returning the expected values from a JSON object. The goal is to retrieve all "Flow" object IDs where the "Type" is either "Standard" or "Block". T ...

Unable to modify document value in MongoDB using Node.js

Currently, I am attempting to fetch the value of a field form that is being sent to a subroute and utilize it to update a database collection. My ability to retrieve the form value and manipulate it is working fine; however, I encounter an issue when I sol ...

Exploring the animation potential of HTML5 canvas and Javascript through utilizing putImageData with animated gifs

I am interested in modifying the image data of each frame in an animated gif while it is playing in a web browser, using HTML5 canvas and Javascript. For instance, I would like to convert every frame to grayscale dynamically as the gif plays. Is this achie ...

Despite being deployed on Vercel, the process.env variables in Nextjs are still not functioning as expected

I'm currently working on a project that involves using 4 api keys that I need to keep hidden: STORYBLOK_API_KEY= EMAILJS_SERVICE_ID= EMAILJS_USER_ID= EMAILJS_TEMPLATE_ID= All of these keys are being accessed using process.env.XXX. What's inte ...

Defeat the all-powerful !important tag and enable dialog customization for positioning

I am currently developing a browser extension and I am encountering an issue with using JQueryUI to display a modal dialog. The problem arises when certain websites, for example espn.com, also utilize JQueryUI but do not properly scope their own elements. ...

Issues with calculating SUM in MySQL within a Node.js Express application using EJS template

I am currently working on developing a dashboard for my Node.js project. The aim is to calculate the sum of certain values for an overview. While the SELECT statement works fine in my MySQL database, when I incorporate it into my Node project, I do not rec ...

Obtain the name of the client's computer within a web-based application

I am working on a Java web application that requires the computer name of clients connecting to it. Initially, I attempted to retrieve this information using JavaScript and store it in a hidden form field. However, I discovered that JavaScript does not hav ...

What's the most effective method for transferring data to different components?

How can I efficiently pass a user info object to all low-level components, even if they are grandchildren? Would using @input work or is there another method to achieve this? Here is the code for my root component: constructor(private _state: GlobalSta ...

Having trouble with npm and unable to find a solution that works. Any suggestions on how to fix it?

I've been working on a JavaScript project that requires me to import a library, but I keep running into errors with npm every time I try to use it. Here is the error message: npm WARN deprecated <a href="/cdn-cgi/l/email-protection" class="__cf_em ...

The pause button will still function, even if the scrolling feature is enabled

I've successfully implemented a feature that pauses and plays the video on scroll when it reaches a certain pixel height. However, I'm facing an issue where the code automatically plays the video whenever the scroll position is more than 13500px ...

Relaying event arguments from client-side JavaScript to server-side code-behind through ClientScript.GetPostBackEventReference

My goal is to initiate a postback using JavaScript and also pass event arguments. While I have managed to trigger the postback successfully, I am facing issues with passing event args. The function below is not functioning as expected. It seems to be enco ...

Clicking on an embedded YouTube video will automatically redirect you to the video's

Hey there, I've added an embedded video to my website and I'm wondering if it's possible to redirect users to a new site when they click the play button? Thanks in advance! ...

Exploring the benefits of leveraging TypeScript with AWS NodeJS for improved stacktrace visibility over traditional JavaScript

I'm contemplating the idea of transitioning my existing JavaScript codebase to incorporate TypeScript in NodeJS. One aspect that I am concerned about is being able to view the stack trace in AWS CloudWatch (request log) in case an error occurs during ...

Exploring GLTF models with Threejs - just a click away!

I am currently developing a project in three.js where I aim to load a GLTF file consisting of geometric shapes. My goal is to extract information, specifically the name, of the shapes that are clicked within the GLTF file. At this stage, I am using console ...

Smooth Div Scroll experiencing display issues

Trying to integrate the smooth div scroll, specifically the "Clickable Logo Parade" found at: Successfully implemented it on a blank page exactly as desired, but encountering issues when inserting it into the current layout. Could something be causing int ...

Excessive image display | HTML and CSS synergize

I am having some trouble with my image gallery. Each image is displayed as a vertical column and has zooming effects when hovered over. Clicking on an image should show it in full screen with a caption. The problem arises when dealing with images that are ...

What is the process for triggering a PHP function when a form element is clicked in a webpage?

Currently, I am trying to implement a jQuery colorbox on my webpage which appears over a <select> drop-down list. My goal is to trigger an AJAX call every time a new option is selected from the drop-down. Even though I have written the following cod ...

The Javafx WebEngine's executescript() function is unable to send a multiline string

Issue: I'm struggling to make the JavaFX WebEngine trigger a JavaScript function when using a Java String object with multiple lines. If I input the following example in HTML: "asd" ENTER "qwe" into the textArea, and then click the send button, the f ...

Encountering an issue such as "Exceeding the maximum number of re-renders. React restricts the amount of renders to avoid

Currently, I am attempting to update the state within the request data method for a string variable as shown below: const ViewChangeRequest = () => { const [requestStageValue, setRequestStage] = useState(''); const { data: request ...