Why is the Geometry faster than BufferGeometry?

Because I was not sure if my extensive code (THREEf.js) has influence on the test, I have made a very simple example. Except for the differences between Geometry and BufferGeometry, the code is the same.

Try out
http://sandbox.threejs.hofk.de/Geometry_BufferGeometry/speedtestSimple.html

But again, Geometry is faster.

Memory consumption and speed are usually in the reverse ratio.

So if Geometry is omitted, then you have to use even more complicated things than BufferGeometry instead of simpler Geometry (to get speed)?

If Geometry is eliminated, it will be much harder for beginners to enter three.js. Many simple examples currently use Geometry. I understand, however, that the focus is on the professional programmers.

I can not fully understand the internals of three.js, maybe there is a way to solve the speed problem?

The code:

segments 
<input type="text" size="5" id="hs" value="100" >  x  
<input type="text" size="5" id="rs" value="100" > :  
	
<input type="radio" name="geom" id="Geometry" checked="checked" > Geometry
<input type="radio" name="geom" id="BufferGeometry" > indexed BufferGeometry 

<input type="radio" name="color" id="multicolor" checked="checked" > multicolor	
<input type="radio" name="color" id="monochrome" > monochrome

<button type="button" id="show">  -> show new mesh </button> 

script src=“three.min.86.js”
script src=“OrbitControls.js”
script src=“THREEx.WindowResize.js”

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 200000 );
camera.position.set( 400, 600, 1000 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xeeeeee, 1 );
var container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement ); 
THREEx.WindowResize( renderer, camera );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = true;
var clock  = new THREE.Clock( true );
var t; // time
var	g; // Geometry or BufferGeometry
var mesh;
var hs; // height segment count ( y direction)
var rs; // radial segment count (here in test  x direction)
var hss; // hs + 1
var rss; // rs + 1
var vertexCount;
var vIdx;	// vertex Index
var faceCount;
var fIdx;	// face index
var j0, j1; // j index 
var a, b1, c1, c2; // vertex indices,  b2 equals c1
var ni, nj; // relative counter variable
var posIdx; // position Index
var x, y, z; // position coordinates
var materialSegment;
var multicolor = null;;

var showGeo = false;

// materials
var uvTex			= new THREE.TextureLoader().load( "uvgrid01.png" );
var waterlilyTex	= new THREE.TextureLoader().load( "waterlily.png" );
// var earthTex		= new THREE.TextureLoader().load( "earth_nasa_map_900.png" );
var side = THREE.DoubleSide;

var materials = [
																						// material index:
    new THREE.MeshBasicMaterial( { color: 0x000000,transparent: true, opacity: 0.6,	side: side } ),	//  0 transparent
	new THREE.MeshBasicMaterial( { map: uvTex, 							side: side } ),	//  1 uv grid
	new THREE.MeshPhongMaterial( { color: 0xff0000, emissive: 0xff0000, side: side } ),	//  2 red
	new THREE.MeshPhongMaterial( { color: 0x00ff00, emissive: 0x00ff00, side: side } ),	//  3 green
	new THREE.MeshPhongMaterial( { color: 0x0000ff, emissive: 0x0000ff, side: side } ),	//  4 blue
	new THREE.MeshPhongMaterial( { color: 0xffff00, emissive: 0xffff00, side: side } ),	//  5 yellow
	new THREE.MeshPhongMaterial( { color: 0xff00ff, emissive: 0xff00ff, side: side } ),	//  6 mgenta
	new THREE.MeshPhongMaterial( { color: 0x00ffff, emissive: 0x00ffff, side: side } ),	//  7 cyan	
	new THREE.MeshBasicMaterial( { map: waterlilyTex,					side: side } ),	//  8 photo waterlily (free)
	new THREE.MeshPhongMaterial( { color: 0x7755ff, emissive: 0x4433dd, side: side } ),	//  9 color
	new THREE.MeshPhongMaterial( { color: 0x444444, emissive: 0x333333, side: side } )		// 10 grey
	
];

// var material = new THREE.MeshBasicMaterial( { color: 0x880088, side: side, wireframe: true } );
// var material = new THREE.MeshBasicMaterial( { map: earthTex,	side: side } );

document.getElementById( "show" ).onclick = showNewMesh;

animate();

function showNewMesh() {

	if ( mesh ) {
	
		scene.remove( mesh );
		g.dispose();
		showGeo = false;
		
		multicolor = null;
				
	}
	
	hs = Math.floor( document.getElementById( "hs" ).value );
	rs = Math.floor( document.getElementById( "rs" ).value );
	
	hss = hs + 1;
	rss = rs + 1;
	
	vertexCount = hss * rss;
	faceCount =  hs * rs * 2;
	
	multicolor = document.getElementById( "multicolor" ).checked;
	
	// Geometry or BufferGeometry
	
	if ( document.getElementById( "Geometry" ).checked ) g = new THREE.Geometry();
	if ( document.getElementById( "BufferGeometry" ).checked ) g = new THREE.BufferGeometry();
		
	// mesh
	
	mesh = new THREE.Mesh( g, materials );
	scene.add( mesh );
	
	//configure
	
	if ( g.isGeometry ) {
		
		for ( var i = 0; i < vertexCount; i ++ ) { 
			
			g.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); 
		
		}
		
	}	
		
	if ( g.isBufferGeometry ) {
	
		var idxCount = 0;
		
		g.faceIndices = new Uint32Array( faceCount * 3 );
		g.vertices = new Float32Array( vertexCount * 3 );  
				
		g.setIndex( new THREE.BufferAttribute( g.faceIndices, 1 ) );	
		g.addAttribute( 'position', new THREE.BufferAttribute( g.vertices, 3 ).setDynamic( true ) );
		
		for ( var f = 0, p = 0; f < faceCount; f ++, p += 3 ) {
			
			g.addGroup( p, 3, 0 );  // write group for multi material
			
		}
		
	}
	
	for ( var j = 0; j < rs; j ++ ) {
	
		j0 = hss * j; 
		j1 = hss * ( j + 1 );
		
		for ( var i = 0; i < hs; i ++ ) {
			
			// 2 faces / segment,  3 vertex indices
			a =  j0 + i;
			b1 = j1 + i;			// right-bottom
			c1 = j1 + 1 + i;
			// b2 = j1 + 1 + i; =c1	// left-top 
			c2 = j0 + 1 + i;
			
			if ( g.isGeometry ) {
				
				g.faces.push( new THREE.Face3( a, b1, c1 ) ); // right-bottom
				g.faces.push( new THREE.Face3( a, c1, c2 ) ); // left-top
				
			}
			
			if ( g.isBufferGeometry ) {
			
				g.faceIndices[ idxCount     ] = a; // right-bottom
				g.faceIndices[ idxCount + 1 ] = b1;
				g.faceIndices[ idxCount + 2 ] = c1; 
				
				g.faceIndices[ idxCount + 3 ] = a; // left-top
				g.faceIndices[ idxCount + 4 ] = c1,
				g.faceIndices[ idxCount + 5 ] = c2; 
				
				idxCount += 6;
				
			}
						
		}
		
	}
	
	showGeo = true;	 // start animation
	
}

function move( t ) {
	
	if ( g.isGeometry ) g.verticesNeedUpdate  = true;
	if ( g.isBufferGeometry ) g.attributes.position.needsUpdate = true;
	
	for ( var j = 0; j < rss; j ++ ) {
		
		nj = j / rs;
		
		y = 400 * nj;							// calculate y
		
		for ( var i = 0; i < hss; i ++ ) {
			
			ni   = i / hs;
			
			x = 400 * ni;						// calculate x
			
			z =  400 * Math.sin( t + ni + nj );	// calculate z
			
			vIdx = hss * j + i; 
			
			if ( g.isGeometry ) g.vertices[ vIdx ].set( x, y, z );
			
			if ( g.isBufferGeometry ) {
			
				posIdx = vIdx * 3;
				
				g.vertices[ posIdx ]  = x;		
				g.vertices[ posIdx + 1 ]  = y;
				g.vertices[ posIdx + 2 ]  = z;
				
			}	
			
		}
		
	}
	
	if ( multicolor ) {
	
		g.groupsNeedUpdate = true;	// to change materialIndex for multi material
	
		for ( var j = 0; j < rs ; j ++ ) {
			
			for ( var i = 0; i < hs; i ++ ) {
				
				materialSegment = Math.floor( 5 * ( 1 + Math.cos( 0.2 * t + i * i + 2 * j ) ) ); // calculate material
				
				fIdx = 2 * hs * j + 2 * i;
				
				if ( g.isGeometry ) {
					
					g.faces[ fIdx ].materialIndex = materialSegment;
					g.faces[ fIdx + 1 ].materialIndex = materialSegment;
					
				}
				
				if ( g.isBufferGeometry ) {
					
					g.groups[ fIdx ].materialIndex = materialSegment;
					g.groups[ fIdx + 1 ].materialIndex = materialSegment;
					
				}
				
			}
			
		}
		
	}	
	
}

function animate() {
	
	requestAnimationFrame( animate );
	t = clock.getElapsedTime();
	
	if ( showGeo ) move( t );
	 
	renderer.render( scene, camera );
	controls.update();
	
}