THREE.js динамически добавляет точки к геометрии Points, которая не отображается

Я использую Three.js r83.

Я пытаюсь динамически добавлять точки в геометрию, но сцена никогда не обновляется.

Это работает :

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);

Это не работает:

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);

Как видите, единственная разница заключается в том, что я добавляю scene.add(pointCloud); перед добавлением вершин.

Что мне не хватает?

Вы можете найти скрипту благодаря @hectate

Чтобы понять, что я имею в виду, просто замените

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

by

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


person Ant    schedule 16.12.2016    source источник
comment
Какая у вас версия three.js? Ознакомьтесь также с документацией здесь о том, как обновлять вещи...   -  person Wilt    schedule 16.12.2016
comment
См. stackoverflow.com/questions/36699389/ и stackoverflow .com/questions/31399856/.   -  person WestLangley    schedule 18.12.2016
comment
@WestLangley В настоящее время я изучаю BufferGeometry, но, похоже, количество точек фиксировано.   -  person Ant    schedule 18.12.2016
comment
Максимальное количество есть. Отображенный номер - нет. Изучите вторую ссылку, которую я разместил.   -  person WestLangley    schedule 18.12.2016
comment
@WestLangley Спасибо - у меня все работает с максимальным количеством баллов и BufferGeometry. Обновление и написание ответа сейчас.   -  person Ant    schedule 18.12.2016
comment
Методом проб и ошибок запрос кадра анимации перед рендерингом этого — это худшее, что вы можете сделать, просто неправильно, на свой страх и риск. а если правда, то почему никто не заметил?   -  person greenthings    schedule 07.08.2020
comment
@greenthings Я думаю, вы, вероятно, правы - я не прикасался к 3.js более 3 лет - поэтому я не могу вспомнить.   -  person Ant    schedule 14.08.2020


Ответы (2)


Я не уверен, почему объект THREE.Geometry не обновляет точки после первоначального рендеринга, но вместо этого я заставил его работать с THREE.BufferGeometry.

Спасибо @Hectate, который дал мне рабочую скрипку, и @WestLangley, который направил меня к подсказкам, вот рабочая скрипка< /а>

BufferGeometry имеет фиксированное количество вершин, но вы можете решить, сколько из них вы хотите визуализировать. Хитрость заключается в том, чтобы использовать geometry.attributes.position.needsUpdate = true; и 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 ) );

Затем вы можете создать свои облачные точки и добавить их на сцену:

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

Теперь я хочу добавлять и отображать 500 новых точек каждые 10 миллисекунд.

var nbPoints = 500;
var INTERVAL_DURATION = 10;

Все, что мне нужно сделать, это:

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);

}
person Ant    schedule 18.12.2016
comment
Как вы уже выяснили, three.js отошел от Geometry в пользу BufferGeometry. Конечно, мне легко говорить об этом в 2021 году ( ; - person Jacksonkr; 14.05.2021

Вот скрипт с установленной первой установкой: https://jsfiddle.net/87wg5z27/236/

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

init();
animate();

function init()
{
    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', onWindowResize, false);
}

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

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

Вот один со вторым: https://jsfiddle.net/87wg5z27/237/

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

init();
animate();

function init()
{
    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', onWindowResize, false);
}

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

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

В обоих случаях облако точек у меня отображается отлично (версия 82). Возможно, что-то еще отсутствует, когда вы пренебрегаете рендерингом чего-то? Я заметил, что ваш первый пример не показывает, на каком этапе вы вызываете render(). Надеюсь, это поможет!

person Hectate    schedule 16.12.2016
comment
Привет @Hectate, большое спасибо за скрипку, я должен был создать ее - большое спасибо. Я сделал еще одну скрипку, которая показывает мою проблему - см. обновленный вопрос. jsfiddle.net/jjjaLv3e/2 Я хочу обновить PointCloud после его визуализации. - person Ant; 18.12.2016