Scene graph level abstraction for three.js InstancedBufferGeometry
npm install three-instanced-meshTHREE.InstancedBufferGeometry for three.js. For a webgl level overview check out TojiCode. For a more in depth overview on how this works, i've written an article more or less on how to build this from scratch.
THREE.InstancedBufferAttribute changed with version R96. ~0.96.0 of this package should work with >= R96, the previous one with the older.~ 0.96.1 should work with all versions of three.
attributeName is omitted all of the attributes will be marked for updates. Valid names are position, quaternion, scale, colors._
myInstanceMesh.material = material the material will be cloned and decorated with the instancing flags. This is supposed to make it simple to use, but is quite a side effect._
THREE.InstancedBufferGeometry, allows for the instancing attributes to be setup by a "placement function" and converts a regular buffer geometry to instanced. This is a modified example running 30k objects instead of 5. All of the objects should be drawn with one draw call, thus speeding things up. It does a simple transformation of normals to view space if the instances are known to be uniformly scaled. If not, it does a mat3 inversion on the gpu (yikes!) but it works.
THREE.InstancedMesh constructor. This will also patch different shader chunks to attach the instancing logic to THREE.ShaderChunks{} (overrides certain chunks).
THREE.InstancedBufferGeometry is instantiated and the provided THREE.BufferGeometry argument copied into it (instancing only works on InstancedBufferGeometry).
dynamic, uniformScale and colors are set. These should only be provided upon construction. color would instantiate another buffer which is wasteful if not used, uniform would require a shader recompilation (when false it uses a branch in glsl to do a heavy matrix computation), dynamic sets a buffer of a different type and is a property of THREE.BufferGeometry.
instancePosition,instanceQuaternion and instanceScale are always created, instanceColor depends on the flag). Their arrays are not instantiated. The idea behind this is noble, why do any work you are going to make reduntant right away. Scale on the other hand can likely be just 1,1,1, maybe an optional method to "init" the mesh should be provided? Please give feedback
customDistanceMaterial and customDepthMaterial in order to allow for instancing to interact with the rest of three's rendering logic that relies on depth (shadows, AO...). Three manages the default materials under the hood of THREE.WebGLRenderer. Internally it holds a cache of shader programs which are created based on the properties of a Material (and other stuff like lights). In order to not alter the renderer. This is all done here through a fancy .material setter, which is not the most elegant solution. Please provide feedback and use cases.
javascript
//var InstancedMesh = require('three-instanced-mesh')( THREE ); //should replace shaders on first call
//or just patch three
require( 'three-instanced-mesh' )(THREE);
//geometry to be instanced
var boxGeometry = new THREE.BoxBufferGeometry(2,2,2,1,1,1);
//material that the geometry will use
var material = new THREE.MeshPhongMaterial();
//the instance group
var cluster = new THREE.InstancedMesh(
boxGeometry, //this is the same
material,
10000, //instance count
false, //is it dynamic
false //does it have color
true, //uniform scale, if you know that the placement function will not do a non-uniform scale, this will optimize the shader
);
var _v3 = new THREE.Vector3();
var _q = new THREE.Quaternion();
for ( var i = 0 ; i < 10000 ; i ++ ) {
cluster.setQuaternionAt( i , _q );
cluster.setPositionAt( i , _v3.set( Math.random() , Math.random(), Math.random() ) );
cluster.setScaleAt( i , _v3.set(1,1,1) );
}
scene.add( cluster );
``