Struggling to set distinct colors for instances using MeshRefractionMaterial

I’m trying to extend from the Diamonds example on the three-fiber documentation site, the diamonds on the ring are instances of an instancedMesh component. I’ve been banging my head for a day but couldn’t figure out how to set a different color for say the 3 biggest stones. I tried to replace the MeshRefractionMaterial with just meshBasicMaterial/meshPhysicalMaterial, and then the setColorAt code in useFrame would work nicely, but it fails to set new colors with MeshRefractionMaterial, the diamonds defaults to white(more like transparent actually).

My code for the Ring component:

function Ring({ frame, diamonds, env, ...props }) {
    const { nodes, materials } = useGLTF(RingModel);
    const ref = useRef();
    const color = useMemo(() => new THREE.Color(0xffff00), []);
    let colorArray = new Float32Array(65 * 3);
    for (let i = 0; i < 65; i++) {
        colorArray.set([Math.random(), 0, 1], i * 3);
    }

    useFrame(() => {
        // I wanted to set specific colors for just a few stones eventually, but for ease of testing I set them all
        for (let i = 0; i < 65; i++) {
            ref.current.setColorAt(i, color);
        }
        ref.current.instanceColor.needsUpdate = true;
    });

    return (
        <group {...props} dispose={null}>
            <mesh castShadow geometry={nodes.mesh_0.geometry}>
                <meshStandardMaterial
                    color={frame}
                    roughness={0.15}
                    metalness={1}
                    envMapIntensity={1.5}
                />
            </mesh>
            <mesh
                castShadow
                geometry={nodes.mesh_9.geometry}
                material={materials.WhiteMetal}
            />
            <instancedMesh
                castShadow
                args={[nodes.Mesh_4.geometry, null, 65]}
                instanceMatrix={nodes.Mesh_4.instanceMatrix}
                ref={ref}
            >
                <instancedBufferAttribute
                    attach="instanceColor"
                    count={colorArray.length / 3}
                    array={colorArray}
                    itemSize={3}
                />
                <MeshRefractionMaterial
                    // color={diamonds}
                    side={THREE.DoubleSide}
                    envMap={env}
                    aberrationStrength={0.02}
                    toneMapped={false}
                    vertexColors={false}
                />
                {/* <meshPhysicalMaterial side={THREE.DoubleSide} /> */}
            </instancedMesh>
        </group>
    );
}

Just found a really similar example that sets different colors on each instance successfully with older versions of drei/three/fiber: https://codesandbox.io/p/sandbox/instanced-refraction-fl1j5l?file=%2Fsrc%2FApp.js%3A44%2C26

But I can’t get this to work with latest versions of the major dependencies(drei, threejs, fiber), the diamonds become the same color instead of having random colors.

does:

vertexColors={true} change anything?

Nope, turns out it’s a bug, but Cody Bennett at drei fixed it in release 9.108.3.

Thanks for taking a look!

1 Like