The rendering of a Points geometry in THREE.js is not displaying when points are dynamically added

I am currently utilizing Three.js version r83.

My goal is to dynamically incorporate points into a geometry, but for some reason, the scene doesn't update.

The following code successfully achieves this:

var tmaterial = new THREE.PointsMaterial({
    color: 0xff0000,
    size: 5,
    opacity: 1
});

var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);

for(var i = 0; i< 1000; i++) {
    x = (Math.random() * 200) - 100;
    y = (Math.random() * 200) - 100;
    z = (Math.random() * 200) - 100;
    tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.computeVertexNormals();

scene.add(pointCloud);

However, the following code does not achieve the desired result:

var tmaterial = new THREE.PointsMaterial({
    color: 0xff0000,
    size: 5,
    opacity: 1
});

var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
scene.add(pointCloud);

for(var i = 0; i< 1000; i++) {
    x = (Math.random() * 200) - 100;
    y = (Math.random() * 200) - 100;
    z = (Math.random() * 200) - 100;
    tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.elementsNeedUpdate = true;
tgeometry.computeVertexNormals();
renderer.render(scene, camera);

The only difference between the two codes is that in the second one, scene.add(pointCloud); was added before the vertices.

What am I overlooking?

You can access a working example on this JSFiddle link. Thanks to @hectate for sharing it.

To observe the issue, simply swap out:

init(); setPoints(); animate();

with:

init(); animate(); setPoints();

Answer №1

It's unclear why the THREE.Geometry object isn't updating Points after the initial rendering, but switching to a THREE.BufferGeometry solved the issue.

A big thank you to @Hectate for providing a functional fiddle and @WestLangley for pointing me in the right direction. Check out the working fiddle here.

The BufferGeometry has a fixed number of vertices, but you can control how many are rendered by utilizing

geometry.attributes.position.needsUpdate = true;
and
geometry.setDrawRange( 0, nbPointsYouWantToDisplay );

var MAX_POINTS = 1000000;
var geometry = new THREE.BufferGeometry();
var positions = new Float32Array( MAX_POINTS * 3 );
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

Create your cloudpoints and add them to the scene:

// material and scene defined in original post
pointCloud = new THREE.Points(geometry, material);
scene.add(pointCloud);

Now the goal is to add and render 500 new points every 10 milliseconds.

var nbPoints = 500;
var INTERVAL_DURATION = 10;

Simply do the following:

var interval = setInterval(function() {
  setPoints();
}, INTERVAL_DURATION)

function setPoints() {

  var positions = pointCloud.geometry.attributes.position.array;

  var x, y, z, index;

  var l  = currentPoints + nbPoints;
  if(l >= MAX_POINTS) {
    clearInterval(interval);
  }

  for ( var i = currentPoints; i < l; i ++ ) {
    x = ( Math.random() - 0.5 ) * 300;
    y = ( Math.random() - 0.5 ) * 300;
    z = ( Math.random() - 0.5 ) * 300;
    positions[ currentPointsIndex ++ ] = x;
    positions[ currentPointsIndex ++ ] = y;
    positions[ currentPointsIndex ++ ] = z;
  }
  currentPoints = l;
  pointCloud.geometry.attributes.position.needsUpdate = true;
  pointCloud.geometry.setDrawRange( 0, currentPoints );
  controls.update();
  renderer.render(scene, camera);

}

Answer №2

Check out this fiddle containing your initial setup: https://jsfiddle.net/87wg5z27/236/

var scene, renderer, camera;
var cube;
var controls;

initialize();
startAnimating();

function initialize()
{
    renderer = new THREE.WebGLRenderer( {antialias:true} );
    var width = window.innerWidth;
    var height = window.innerHeight;
    renderer.setSize (width, height);
    document.body.appendChild (renderer.domElement);

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera (45, width/height, 1, 10000);
    camera.position.y = 160;
    camera.position.z = 400;
    camera.lookAt (new THREE.Vector3(0,0,0));

    controls = new THREE.OrbitControls (camera, renderer.domElement);

    var tmaterial = new THREE.PointsMaterial({
        color: 0xff0000,
        size: 5,
        opacity: 1
    });

    var tgeometry = new THREE.Geometry();
    var pointCloud = new THREE.Points(tgeometry, tmaterial);

    for(var i = 0; i< 1000; i++) {
        x = (Math.random() * 200) - 100;
        y = (Math.random() * 200) - 100;
        z = (Math.random() * 200) - 100;
        tgeometry.vertices.push(new THREE.Vector3(x, y, z));
    }
    tgeometry.verticesNeedUpdate = true;
    tgeometry.computeVertexNormals();

    scene.add(pointCloud);

    window.addEventListener ('resize', adjustWindowSize, false);
}

function adjustWindowSize ()
{
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function startAnimating()
{
    controls.update();
    requestAnimationFrame( startAnimating );  
    renderer.render(scene, camera);
}

This is the link to the second setup on a fiddle: https://jsfiddle.net/87wg5z27/237/

var scene, renderer, camera;
var cube;
var controls;

initialize();
startAnimating();

function initialize()
{
    renderer = new THREE.WebGLRenderer( {antialias:true} );
    var width = window.innerWidth;
    var height = window.innerHeight;
    renderer.setSize(width, height);
    document.body.appendChild(renderer.domElement);

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(45, width/height, 1, 10000);
    camera.position.y = 160;
    camera.position.z = 400;
    camera.lookAt(new THREE.Vector3(0,0,0));

    controls = new THREE.OrbitControls(camera, renderer.domElement);

    var tmaterial = new THREE.PointsMaterial({
        color: 0xff0000,
        size: 5,
        opacity: 1
    });

    var tgeometry = new THREE.Geometry();
    var pointCloud = new THREE.Points(tgeometry, tmaterial);
    scene.add(pointCloud);

    for(var i = 0; i< 1000; i++) {
        x = (Math.random() * 200) - 100;
        y = (Math.random() * 200) - 100;
        z = (Math.random() * 200) - 100;
        tgeometry.vertices.push(new THREE.Vector3(x, y, z));
    }
    tgeometry.verticesNeedUpdate = true;
    tgeometry.elementsNeedUpdate = true;
    tgeometry.computeVertexNormals();
    renderer.render(scene, camera);

    window.addEventListener('resize', adjustWindowSize, false);
}

function adjustWindowSize ()
{
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function startAnimating()
{
    controls.update();
    requestAnimationFrame(startAnimating);  
    renderer.render(scene, camera);
}

I can see the point cloud displaying correctly in both scenarios (version 82). It's possible that you might be missing something else or forgetting to render an element at some point. One observation is that the first example does not specify where render() is being called. Hopefully, this information proves useful!

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

Leveraging Express.js alongside websockets

I am currently working on an application that is built on Expressjs and Angularjs. I am looking to incorporate a few two-way calls in addition to the existing HTTP calls. While I have gone through some websocket chat tutorials, none of them seem to be inte ...

Exploring the art of reading and writing to a file with JavaScript and NodeJS

I am currently working on creating a function that will scan a file and remove all content below a specific line before adding new lines to the file. So far, I have successfully read the file and identified the target line: function analyze() { lineRe ...

Minimize data once more using various key criteria

In my current setup, I have created a view that counts reports for different cities. function (doc) { if(doc.type == "report") { emit(doc.city_name, null); } } Using the _count reduce function, I get the following values: {'key': &a ...

What could be the reason for scope.$watch failing to function properly?

My AngularJS directive has a template with two tags - an input and an empty list. I am trying to watch the input value of the first input tag. However, the $watch() method only gets called once during initialization of the directive and any subsequent chan ...

Passing parameters to an external function in order to display a message is proving difficult. An error of type TypeError is being encountered, specifying that the Class constructor AlertMessage cannot be called without using the

Every time I attempt to pass a message as an argument to the showAlert() function, an error is triggered: Error: An instance of the AlertMessage class cannot be created without using 'new' image: https://i.sstatic.net/d0GGD.jpg I am simply tryi ...

Does my method need adjustments or is it fundamentally flawed?

<html><head></head> <body><script> function calculateGreatestCommonDivisor(a, b) { if (a == 0) { return b; } return calculateGreatestCommonDivisor(b % a, a); } function getDifference(array) { for ( ...

What sets apart the following: ( import React from "react"; ) and ( import React from 'react'; )?

When it comes to imports, is there a distinction between using single quotes (') versus double quotes ("), for example in import React from 'react'; and import React from "react";? Are there any notable differences? ...

Creating a feature in Angular JS that allows for each item in a list to be toggled individually

Looking for a more efficient way to toggle individual buttons without updating all at once? Check out this basic example where each button toggles independently by using ng-click="selected = !selected". Instead of updating all buttons at once, you can achi ...

Tips for inserting a row component into a table using Angular 7

I am currently using the latest version of Angular (7.2.0). I have created a custom tr component as follows: import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-table-row', templateUrl: './table- ...

What steps can I take to troubleshoot and fix the height of a div/span element?

Here is my HTML code: <div> <span style="display: inline-block;height:20px">20</span> <span style="display: inline-block;"><img src="img/ex.png"/></span> </div> The image I have in the second span is sized at ...

Tailwind Component Grid in Action

I'm trying to arrange a list of JavaScript components in a grid with one row and twelve columns. I want to use only six columns for the actual elements, while having three columns of padding on each side of the grid. My goal is to place three elements ...

Shut down jquery modal

I have successfully imported Jquery Modal using the following two links (js and css) <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cl ...

What is the best location to create the content for a sidebar?

Currently in the process of building my new website using express. The layout consists of various "sections" such as a blog, project information, and more. I want to have a unique sidebar next to the main content for each section. For instance, in the "blo ...

Issues with Displaying Components Generated from an Array in JSX

I have a task variable which has the structure as follows: [ team_id_1: { task_id_1: { description: ... }, task_id_2: { description: ... } }, team_id_2: { ... } ] When trying ...

Webpack loaders or plugins: understanding the distinction

Can you explain the distinction between loaders and plugins in webpack? I found on the documentation for plugins that it states: Plugins are used to incorporate extra functionalities usually related to bundles within webpack. While I understand that b ...

Combining Vue.js with Laravel Blade

I've encountered an issue while trying to implement a Basic Vue script within my Laravel blade template. The error message I am getting reads: app.js:32753 [Vue warn]: Property or method "message" is not defined on the instance but referenc ...

How to showcase information stored in Firebase Realtime Database within an Ionic application

Looking to list all children of "Requests" from my firebase realtime database in a structured format. Here's a snapshot of how the database is organized: https://i.stack.imgur.com/5fKQP.png I have successfully fetched the data from Firebase as JSON: ...

Reverting to the original order in jQuery DataTables after dropping a row

Recently, I've been attempting to utilize jQuery DataTables in conjunction with the Row Ordering plugin. At first, everything seemed to be functioning properly until a javascript error popped up indicating an unrecognized expression. After researching ...

Issues with React useState persisting new values between useEffect intervalsHere is a rephrased

I am attempting to store jokes and log a new value every time the interval runs (triggered by a get call) after 5 seconds. However, for some reason, the value is not rendering anything after each interval. I'm not certain if the jokes are actually bei ...

Exploring Javascript/JQuery parameters based on data types

I'm a bit confused about whether the title accurately reflects my question. I need help understanding how jQuery deals with functions that are called with different argument combinations, such as ("Some String", true, function(){}) and ("Some String", ...