Can one use layers for instances of an instanced mesh?

I want to dynamically show or hide instances of an instansed mesh. This works by changing the position of each instance as desired. I set the position so that the camera does not show the instance. So further than far (Camera frustum far plane) or behind the camera.

I also found examples for color change. See
three.js/webgl_instancing_raycast.html at 95ef309c79158aa506f3f7ddeab769e7c4908187 · mrdoob/three.js · GitHub
Line 67 mesh.setColorAt( i, color );

But I did not find anything in the docs for .setColorAt. It is sometimes quite difficult
to find special details there or I get a little clumsy. :confused:

I also found this. Raycast Highlight with InstancedMesh - #3 by prisoner849


A test example “BinaryMemory”. threejs.hofk.de section -Test- CPU-Simulation or directly BinaryMemory Code below.

In the documentation and with research I could not find out, if it is possible to define and dynamically change layers for instances of an instanced mesh instead of changing the position. If so, is this more efficient?

I am thankful for any hint. :slightly_smiling_face:


<!DOCTYPE html>
<!--  -->
<head>
	<title> BinaryMemory </title>
	<meta charset="utf-8" />
	<style>
	body {
	overflow: hidden;
	margin: 0;
	}
	</style>
</head>
<body> </body>

<script src="../js/three.min.121.js"></script>
<script src="../js/OrbitControls.121.js"></script>

<script>

'use strict'

const visible = 0;
const invisible = -8000;

const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, -invisible / 2 );
camera.position.set( 0, 0, 300 );

const scene = new THREE.Scene();

const renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.setClearColor( 0xeeeed3, 1 );

const light = new THREE.DirectionalLight( );
light.intensity = 0.2;
light.position.set( 200 , 1500 , 1500 );
scene.add( light );	

new THREE.OrbitControls( camera, renderer.domElement );

const RAM = new THREE.Object3D();
const countRAM = 2048; // = 256 * 8;  256 Byte RAM
const transform = new THREE.Object3D();
	
const geoBox = new THREE.BoxBufferGeometry( 5, 8.5, 3 ); 
const matBox = new THREE.MeshBasicMaterial({color: 0xaaaaaa,  transparent: true,  opacity: 0.25 } );
const instMeshBox = new THREE.InstancedMesh( geoBox, matBox, countRAM );
positionInst( instMeshBox, visible );
RAM.add( instMeshBox );

const matDig = new THREE.MeshPhongMaterial( );
matDig.emissive.setRGB( 0, 0, 0 ); 
matDig.specular.setRGB( 0.4, 0.4, 0.4 );

const geoDig0 = new THREE.TorusBufferGeometry( 2, 0.5, 36, 36 ); 
const instMeshDig0 = new THREE.InstancedMesh( geoDig0, matDig, countRAM );
positionInst( instMeshDig0, visible );
RAM.add( instMeshDig0 );

const geoDig1 = new THREE.CylinderBufferGeometry( 0.5, 0.5, 4.8, 24 );
const instMeshDig1 = new THREE.InstancedMesh( geoDig1, matDig, countRAM );
positionInst( instMeshDig1, invisible );
RAM.add( instMeshDig1 )

scene.add( RAM );
RAM.position.y = 150;

let byteNo;
let bitNo;
 
animate();

// ........................................................................

function animate() {
	
	requestAnimationFrame( animate );
 
	byteNo = Math.floor( Math.random( ) * Math.floor( 256 ) );
	bitNo  = Math.floor( Math.random( ) * Math.floor(   8 ) );
	
	if ( Math.random( ) < 0.5 ) {
	
		visibilityRAM( instMeshDig0, byteNo, bitNo, invisible );
		visibilityRAM( instMeshDig1, byteNo, bitNo, visible );
		
	} else {
		
		visibilityRAM( instMeshDig0, byteNo, bitNo, visible );
		visibilityRAM( instMeshDig1, byteNo, bitNo, invisible );			
		
	}
 
	instMeshDig0.instanceMatrix.needsUpdate = true;
	instMeshDig1.instanceMatrix.needsUpdate = true;
	 
	renderer.render( scene, camera );
	
}

function positionInst( instMesh, z ) {
	
	let inst = 0;
	
	for ( let i = 0; i < 256; i ++ ) {	
		
		for ( let j = 0; j < 8; j ++ ) {
		
			transform.position.set( 6 * j, -10 * i, z );
			transform.updateMatrix();
			instMesh.setMatrixAt( inst, transform.matrix );
			inst ++;
			
		}
		
	}
		
}

function  visibilityRAM( instMesh, i, j, visibility ) {
	
	transform.position.set( 6 * j, -10 * i, visibility );	 
	transform.updateMatrix( );
	instMesh.setMatrixAt( i * 8 + j, transform.matrix );
	
}

</script>

</html>

I’ve added a PR for this right now: https://github.com/mrdoob/three.js/pull/20662

No, this is not possible. Layer testing only works for the entire instance (similar to other tests like view frustum culling).

2 Likes