Can not make a mesh blink because it is an InstancedMesh

I would like to make a mesh blink. Since it is sharing material with another mesh I must duplicate the material.

BABYLON.SceneLoader.Load("/assets/", "map.gltf", engine, function (newScene) {
	const mesh = newScene.getMeshByID("6558.dat.001") 
	console.log(mesh)
	try {
		mesh.material = mesh.material.clone()
	} catch(err) {
		console.log(err)
	}
});

This results in

TypeError: Cannot set property material of [object Object] which has only a getter

How can I make this mesh blink?

Thanks.

Update:

Trying to registerInstancedBuffer following
https://doc.babylonjs.com/how_to/how_to_use_instances
but an error occurs:

mesh.registerInstancedBuffer is not a function

What I end up doing is cloning all the meshes when I need them to blink and disposing them when I don’t

This is terrible for performance and It is slow.

const meshes = []
		babylonNode.getChildMeshes().forEach((mesh) => {
			if(mesh.getClassName() == "InstancedMesh") {
				const newMesh = mesh.sourceMesh.clone(mesh.name+"blink_tmp", mesh.parent)
				newMesh.position = mesh.position.clone();
				if(mesh.rotationQuaternion)
					newMesh.rotationQuaternion = mesh.rotationQuaternion.clone();
				newMesh.scaling = mesh.scaling.clone();
				meshes.push(newMesh);
			} else {
				const newMesh = mesh.clone(mesh.name+"blink_tmp", mesh.parent)
				newMesh.position = mesh.position.clone();
				if(mesh.rotationQuaternion)
					newMesh.rotationQuaternion = mesh.rotationQuaternion.clone();
				newMesh.scaling = mesh.scaling.clone();
				meshes.push(newMesh);
			}
		});

You should keep your instances because they are good for performance :slight_smile:
To make an instance blink you were correct by using the new InstancedBuffer. But you need to be on the latest preview version (as this is a brand new feature)

Something like that should work: https://www.babylonjs-playground.com/#YPABS1#1

Thanks.

When I was trying it today I was at the latest preview, or at least I think so

This should get me the latest preview, right?

<script src="https://preview.babylonjs.com/babylon.js"></script>
<script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
<script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
<script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
<script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
<script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
<script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
<script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
<script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>

correct

Any suggestion why I got if I was at the latest preview. Anything I could do?

mesh.registerInstancedBuffer is not a function

It was published yesterday so you may have missed the update

I am doing it right now.

if(mesh.getClassName() == "InstancedMesh") {
	mesh.registerInstancedBuffer("color",4)

as shown at
https://doc.babylonjs.com/how_to/how_to_use_instances

and the error is:

Uncaught TypeError: mesh.registerInstancedBuffer is not a function
```

## Update
Importing as

You must have something wrong on your side as the demo I linked before (https://www.babylonjs-playground.com/#YPABS1#1 ) is working and it is using preview as well

I see the example

I’ve reproduce the problem on the example and I check mesh.registerInstancedBuffer is undefined:

if(mesh.getClassName() == "InstancedMesh") {
                console.log(mesh.registerInstancedBuffer)
            }

https://www.babylonjs-playground.com/#YPABS1#5

The method is undefined.

The console logs

Babylon.js v4.1.0-alpha.24 - WebGL2 babylon.js:16:426120
undefined 76 main.js line 98 > eval:50:25

I think I understand the idea of the registerInstancedBuffer but it should be called while loading the GLTF and not after that. Am I right?

Oh gotcha, this is a MESH function. You have to call it to enable the instanced buffers (like in the example). After that all instances will receive the new property (instance.instancedBuffer.color here)

It can be done afterwards

Changed and doing it afterwards and calling on the sourceMesh.

if(mesh.getClassName() == "InstancedMesh") {
	mesh.sourceMesh.registerInstancedBuffer("color",4)

And the following error occurs:

Uncaught TypeError: Cannot read property 'toArray' of null
    at t.s.a._processInstancedBuffers (babylon.js:16)
    at t._renderWithInstances (babylon.js:16)
    at t._processRendering (babylon.js:16)
    at t.e._renderSubMesh (babylon.js:16)
    at _mainTexture.customRenderFunction (babylon.js:16)
    at e.render (babylon.js:16)
    at e.render (babylon.js:16)
    at t.renderToTarget (babylon.js:16)
    at t.render (babylon.js:16)
    at e._renderMainTexture (babylon.js:16)

Can you repro in the playground?

Trying to, but the only difference I could see for now is that in my case the gltf scene is the main scene.

I am not creating a default scene. I am creating the engine, loading the gltf and from then on using the scene from the Load method.

How can I return the scene from the gtlf method in the playground. Can I return a promise that would resolve a scene in the playground instead of returning the scene?

Yes if the function return a promise

Reproduced in the playground - https://www.babylonjs-playground.com/#YPABS1#11

Exception is

TypeError: this.instancedBuffers[n] is null
_processInstancedBuffers https://preview.babylonjs.com/babylon.js:16
    _renderWithInstances https://preview.babylonjs.com/babylon.js:16
    _processRendering https://preview.babylonjs.com/babylon.js:16
    render https://preview.babylonjs.com/babylon.js:16
    render https://preview.babylonjs.com/babylon.js:16
    renderUnsorted https://preview.babylonjs.com/babylon.js:16
    render https://preview.babylonjs.com/babylon.js:16
    render https://preview.babylonjs.com/babylon.js:16
    _renderForCamera https://preview.babylonjs.com/babylon.js:16
    _processSubCameras https://preview.babylonjs.com/babylon.js:16
    render https://preview.babylonjs.com/babylon.js:16
    compileAndRun https://www.babylonjs-playground.com/js/main.js:135
    <anonymous> self-hosted:1007
    _renderLoop https://preview.babylonjs.com/babylon.js:16
    <anonymous> self-hosted:1009

I suspect you are registering the buffer but not creating it like :

Yeah and you are calling clone for some reasons…
https://www.babylonjs-playground.com/#YPABS1#12

Thanks. clone was from another try.

To summarize for anyone with this question

  1. check if sourceMesh has instancedBuffers
  2. if not then register to source
  3. Then create to source
  4. Then create to instanced.
if(mesh.getClassName() == "InstancedMesh") {
      if (!mesh.sourceMesh.instancedBuffers) {
                        mesh.sourceMesh.registerInstancedBuffer("color",4)
                        mesh.sourceMesh.instancedBuffers.color = new BABYLON.Color4(1, 0, 0, 1);
      }
      mesh.instancedBuffers.color = new BABYLON.Color4(1, 0, 0, 1);
}
1 Like