I believe NodeMaterial could support an expressive instancing API, without requiring users to modify builtin shaders. The instancing • lambert example shows the simplest pre-existing approach, and is still complex enough that users will find it challenging to instance a 3D model created in a DCC tool.
Proposal:
import * as THREE from 'three';
import {
StandardNodeMaterial,
InstanceTransformNode,
AttributeNode,
FloatNode,
OperatorNode,
TextureNode
} from 'three/js/nodes/THREE.Nodes';
var material = new StandardNodeMaterial();
// Configure shared material properties as usual.
material.metalness = new FloatNode( 0 );
// Configure material.instanceTransform to reference 1-3 InstancedBufferAttribute nodes.
material.instanceTransform = THREE.InstanceTransformNode(
new AttributeNode( 'instancePosition', 'vec3' ),
new AttributeNode( 'instanceQuaternion', 'vec4' ),
new AttributeNode( 'instanceScale', 'vec3' )
);
// Configure per-instance material properties using node expressions and InstancedBufferAttribute.
material.roughness = new AttributeNode( 'instanceRoughness' );
material.color = new OperatorNode(
new TextureNode( baseColorTexture ),
new AttributeNode( 'instanceColor' ),
OperatorNode.MUL
);
With this API, and as loaders enable the NodeMaterial system, instancing models created in DCC tools becomes much easier:
var treePositions = new Float32Array( [
0, 0, 0,
10, 0, 0,
20, 0, 0
] );
var loader = new THREE.GLTFLoader();
loader
.setUseNodes( true )
.load( 'tree.glb', ( gltf ) => {
var model = gltf.scene.children[ 0 ];
model.geometry = new THREE.InstancedBufferGeometry().fromBufferGeometry( model.geometry );
model.geometry.addAttribute( 'instancePosition', new THREE.InstancedBufferAttribute( treePositions, 3 );
model.material.instanceTransfom = new THREE.InstanceTransformNode( THREE.AttributeNode( 'instancePosition' ) );
scene.add( model );
} );
This idea is based loosely on noticing recently that Unity plans to add instancing support to its Shader Graph master nodes.
/cc @sunag
I can make an example as soon as possible.