Can I merge geometry in every frame in rendering process using three.js?

怎甘沉沦 提交于 2019-12-11 12:58:13

问题


I'm new to three.js and just tried some ideas. Now the problem is I created a line in the scene and used it as a base to clone and transform. So that the cloned ones will be shown as a sequence of transformation in the scene.

The simplified code is like:

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 );
   //borrowed the code from http://threejs.org/docs/#Reference/Objects/Line 
   //just wanted to make it simple
}

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

and The html part is just <div id='container'></div>

It is all working well, but as you can see that I can only limit the new line numbers to 1500, when the line number is over 2000, I started to get rendering problem, the the fps drops quickly after then when the number of lines increasing.

I tried to merge like:

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

But I can only merge in the init process not in the rendering process. If I use the above code in function animate(), It only render one line instead of a whole group of lines:

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

Anyone got suggestions? Thanks.


回答1:


You can use a THREE.BufferGeometry to update your line geometry without merging geometries or adding new line objects to your scene. Like this you will save a lot of memory and it will allow you to get the same effect.

I updated your fiddle here to demonstrate.

First you need to create a buffer geometry (done 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;
}

And then the magic happens here 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 solution is based on @WestLangley his answer on another related question here.

You will still need to set an maximum amount of points in the example this value is set as total at the top of the code.



来源:https://stackoverflow.com/questions/36906891/can-i-merge-geometry-in-every-frame-in-rendering-process-using-three-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!