# InstancedMesh won't show materials but using mesh does

**URL:** <https://discourse.threejs.org/t/instancedmesh-wont-show-materials-but-using-mesh-does/62991>\
**Category:** Questions\
**Tags:** react-threedrei, mesh, materials, instanced-mesh, react-three-fiber\
**Created:** [March 19, 2024, 9:58am UTC](https://discourse.threejs.org/t/instancedmesh-wont-show-materials-but-using-mesh-does/62991 "2024-03-19T09:58:34Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![BillySwaggyKidy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/billyswaggykidy/32/45166_2.png) [@BillySwaggyKidy](https://discourse.threejs.org/u/BillySwaggyKidy)\
**Post date:** [March 19, 2024, 9:58am UTC](https://discourse.threejs.org/t/instancedmesh-wont-show-materials-but-using-mesh-does/62991/1 "2024-03-19T09:58:34Z")

</div>

Hello, I am struggling to render multiple instance of a mesh. 🙁  
I want to create a smoke animation in the background of my page using a canvas that is similar like this [example](https://codesandbox.io/p/sandbox/smoke-animation-threejs-kcq7p?file=%2Fsrc%2FApp.js).  
I tried replicate this using the regular **mesh** to display multiple smoke texture inside a map and transform all of them inside a useFrame:

```javascript
const Smoke = ({position, scale, smokeNum, color} : { position?: [number,number,number], scale? : number, smokeNum : NumericRange<CreateArrayWithLengthX<0>,99>, color? : string}) => {
    const smokeTexture = new TextureLoader().load(smoke.src);
    smokeTexture.colorSpace = SRGBColorSpace
    let smokeParticles = useRef<Array<Mesh | null>>(Array(smokeNum).fill(null));

    useFrame((state, delta)=>{
        console.log(smokeParticles.current)
        smokeParticles.current.forEach((smoke: Mesh | null, index)=>{
            if (smoke) {
                smoke.rotation.z += (delta*0.2); 
            }
        });
    });

    return (
        <group 
            position={position}
            dispose={null}
            scale={scale ?? 1}
        >
            <spotLight
                position={[0, 0, 2]}
                angle={1}
                penumbra={1}
                intensity={300}
                castShadow
                shadow-mapSize={1024}
            />
            {
                smokeParticles.current.map((refMesh, index)=>{
                    const position = [getRandomNumber(-20,20),getRandomNumber(-20,20),getRandomNumber(-60,-50)] as [number,number,number];
                    const rotationZ = Math.random() * 360;
                    return (
                        <mesh
                            key={`smoke${index}`}
                            ref={el => smokeParticles.current[index] = el}
                            scale={[1,1,1]}
                            position={position}
                            rotation={[0,0,rotationZ]}
                            matrix={new Matrix4()}
                            count={smokeNum}
                        >
                            <planeGeometry args={[300,300]}/>
                            <meshLambertMaterial 
                                map={smokeTexture} 
                                emissive={0x222222} 
                                color={new Color(color)} 
                                opacity={1}
                                transparent={true}
                            />
                        </mesh>
                    );
                })
            }
        </group>
    );
};

export default Smoke;

```

This code work fine and display the smoke but based on the Three.js doc, you should use an instancedMesh when creating a lot of objects with the same geometry and material but have different world transformations.  
So I tried code it using the **instancedMesh** by following the react-three-fiber [docs](https://docs.pmnd.rs/react-three-fiber/advanced/scaling-performance#instancing) and the minimal instanced mesh [example](https://github.com/pmndrs/react-three-fiber/discussions/761):

```javascript
let temp3dObj = new Object3D();
const Smoke = ({position, scale, smokeCount, color} : { position?: [number,number,number], scale? : number, smokeCount : NumericRange<CreateArrayWithLengthX<0>,99>, color? : string}) => {
    const smokeTexture = new TextureLoader().load(smoke.src);
    smokeTexture.colorSpace = SRGBColorSpace
    const instancedMeshRef = useRef<InstancedMesh>(null);

    useEffect(() => {
        if (instancedMeshRef.current) {
            console.log(instancedMeshRef.current);
            // Set positions
            for (let i = 0; i < smokeCount; i++) {
                temp3dObj.position.set(getRandomNumber(-20,20),getRandomNumber(-20,20),getRandomNumber(-60,-50));
                temp3dObj.rotation.z = Math.random() * 360;
                temp3dObj.updateMatrix()
                instancedMeshRef.current.setMatrixAt(i, temp3dObj.matrix)
            }
            // Update the instance
            instancedMeshRef.current.instanceMatrix.needsUpdate = true
            }
    }, [])

    return (
        <group 
            position={position}
            dispose={null}
            scale={scale ?? 1}
        >
            <spotLight
                position={[0, 0, 2]}
                angle={1}
                penumbra={1}
                intensity={300}
                castShadow
                shadow-mapSize={1024}
            />
            <instancedMesh 
                ref={instancedMeshRef}
                scale={[1,1,1]}
                matrix={new Matrix4()}
                count={smokeCount}
            >
                <planeGeometry args={[300,300]}/>
                <meshLambertMaterial 
                    map={smokeTexture} 
                    emissive={0x222222} 
                    color={new Color(color)} 
                    opacity={0.15}
                    transparent={true}
                />
            </instancedMesh>
        </group>
    );
};

export default Smoke;

```

But it is not showing anything in the page, I don’t have any error in the console, only a warning:

> drawElementsInstanced: Instance fetch requires 30, but attribs only supply 0.

What did I do wrong in my code?  
Thank you advance for your responses.

---

<div class="post-metadata">

**Author:** ![drcmda](https://avatars.discourse-cdn.com/v4/letter/d/91b2a8/32.png) [@drcmda](https://discourse.threejs.org/u/drcmda)\
**Post date:** [March 19, 2024, 11:55am UTC](https://discourse.threejs.org/t/instancedmesh-wont-show-materials-but-using-mesh-does/62991/2 "2024-03-19T11:55:00Z")

</div>

it’s not how THREE.InstancedMesh works, you use it the same exact way as in vanilla [three.js docs](https://threejs.org/docs/index.html?q=instance#api/en/objects/InstancedMesh)

```plaintext
Constructor
InstancedMesh( geometry : BufferGeometry, material : Material, count : Integer )
geometry - an instance of BufferGeometry.
material - an instance of Material. Default is a new MeshBasicMaterial.
count - the number of instances.

```

you’re doing the following, which is not correct since the buffers are created in the constructor

```jsx
const instance = new THREE.InstancedMesh()
instance.count = smokeCount
instance.geometry = new THREE.PlaneGeometry()
instance.material = new THREE.MeshLambertMaterial()

```

THREE.InstancedMesh has a bad api, optional args by language convention must always go last. i opened an issue for this but authors disagreed. so …

```jsx
const instance = new THREE.InstancedMesh(null, null, smokeCount)
instance.geometry = new THREE.PlaneGeometry()
instance.material = new THREE.MeshLambertMaterial()

```

which in fiber is equal to

```jsx
<instancedMesh args={[null, null, smokeCount]}>
  <planeGeometry />
  <meshLambertMaterial />

```

more mistakes

```diff
- scale={[1,1,1]} // scale is 1 by default, short form would be ={1}
- matrix={new Matrix4()} // you don't need this, instances have their own matrices

- color={new Color(color)} 
+ color={color} 

- <planeGeometry args={[300,300]}/>
+ <planeGeometry /> // scale the instances instead

```

[https://codesandbox.io/p/sandbox/instanced-vertex-colors-8fo01](https://codesandbox.io/p/sandbox/instanced-vertex-colors-8fo01)

---

<div class="post-metadata">

**Author:** ![BillySwaggyKidy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/billyswaggykidy/32/45166_2.png) [@BillySwaggyKidy](https://discourse.threejs.org/u/BillySwaggyKidy)\
**Post date:** [March 19, 2024, 3:17pm UTC](https://discourse.threejs.org/t/instancedmesh-wont-show-materials-but-using-mesh-does/62991/3 "2024-03-19T15:17:52Z")

</div>

Hello thank you for your response, I see some progress .  
I don’t see the warning in the console anymore but I can still not see the smoke in the canvas.  
I can assure that they do exist inside the canvas by the use of the onBeforeRender function but I cannot see them on the screen.

```javascript
let temp3dObj = new Object3D();
const Smoke = ({position, scale, count, color} : { position?: [number,number,number], scale? : number, count : NumericRange<CreateArrayWithLengthX<0>,99>, color? : string}) => {
    const smokeTexture = new TextureLoader().load(smoke.src);
    smokeTexture.colorSpace = SRGBColorSpace;
    const instancedMeshRef = useRef<InstancedMesh>(null);

    useEffect(() => {
        if (instancedMeshRef.current) {
            console.log(instancedMeshRef.current);
            // Set positions
            for (let i = 0; i < count; i++) {
                temp3dObj.position.set(getRandomNumber(-20,20),getRandomNumber(-20,20),getRandomNumber(-60,-50));
                temp3dObj.rotation.z = Math.random() * 360;
                temp3dObj.updateMatrix()
                instancedMeshRef.current.setMatrixAt(i, temp3dObj.matrix)
            }
            // Update the instance
            instancedMeshRef.current.instanceMatrix.needsUpdate = true
            instancedMeshRef.current.onBeforeRender = () => {console.log("temp3dObj.rotation.z")};
        }
    }, []);

    return (
        <group 
            position={position}
            dispose={null}
            scale={scale ?? 1}
        >
            <spotLight
                position={[0, 0, 2]}
                angle={1}
                penumbra={1}
                intensity={300}
                castShadow
                shadow-mapSize={1024}
            />
            <instancedMesh 
                ref={instancedMeshRef}
                args={[undefined,undefined,count]}
            >
                <planeGeometry/>
                <meshLambertMaterial
                    map={smokeTexture}
                    emissive={0x222222}
                    color={color}
                    opacity={0.15}
                    transparent={true}
                />

            </instancedMesh>
        </group>
    );
};

export default Smoke;

```

Should I change in the level of the group component, what more can I do?
