I'm testing the use of Three.js for my project (http://agentscript.org) and the first test seems quite slow:
https://asx-vqnhxlahpe.now.sh/test.html?three0
(note: the site can take a while, it "sleeps" after a period of non-use)
This is apparently due to my using way too many draws, one per agent.
renderer.info.render
Object {calls: 10002, vertices: 60090, faces: 20000, points: 0}
I believe using a BufferGeometry would solve this, but I don't know how to use one and still be able to access each individual agent so that my step/animate function can modify (move, rotate) them.
How would I do this?
I realize I could simply go to using my own Shader, and plan to do so, but I'd prefer to have an intermediate solution or two first.
You want to reduce the number of draw calls in your Agent simulation and get something working relatively easily. You can do that by representing your collection of agents as THREE.Points
.
// geometry
var geometry = new THREE.BufferGeometry();
// attributes
var positions = new Float32Array( numAgents * 3 ); // 3 values per vertex
var rotations = new Float32Array( numAgents * 1 ); // 1 values per vertex
for ( var i = 0; i < numAgents; i ++ ) {
positions[ i ] = 0;
positions[ i + 1 ] = 0;
positions[ i + 2 ] = 0;
rotations[ i ] = 2 * Math.PI * Math.random();
}
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.addAttribute( 'rotation', new THREE.BufferAttribute( rotations, 1 ) );
// material
var material = new THREE.PointsMaterial( {
color: 0xff0000,
size: 4,
map: null
} );
// points
points = new THREE.Points( geometry, material );
scene.add( points );
This will render in a single draw call and you can update the positions on the CPU and push the data to the GPU each frame. You should be able to render 100,000 agents easily.
fiddle: http://jsfiddle.net/730ffn4x/
If you want to represent your points as an arrow with direction, you would need to provide texture with an arrow image and a custom ShaderMaterial
to rotate each point.
InstancedBufferGeometry
is appropriate if each agent must be represented as a Mesh
. Here is a fine example by @MartinSchuhfuß that is similar to what you want to do.
For intense simulations, you would use GPGPU. See the three.js examples. In GPGPU, the simulation runs entirely on the GPU, and the CPU typically does minimal work.
three.js r.84
In your case, instancing is the best way to reduce geometries and draw calls. Three.js
supports instancing through ANGLE_instanced_arrays
extension.
Take a look at this -
https://threejs.org/docs/#api/core/InstancedBufferGeometry
Also here is an example on how to do instancing in Three.js
-
https://threejs.org/examples/webgl_buffergeometry_instancing.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With