InstancedMesh Blink

Hey, everybody. I need to make an individual element blink in InstancedMesh. How can this be achieved?

Move it into outer space, or scale it to 0 sizeā€¦
Or swap it with the last matrix in the matrix array and reduce the .count by one.

2 Likes

Right?

import { useEffect, useRef, useState } from "react";
import { observer } from "mobx-react-lite";
import { HeadingPitchRoll, Cartesian3, Transforms } from "cesium";
import { Matrix4, Vector3, Quaternion, InstancedBufferAttribute } from "three";
import entController from "./entController";
import stores from "./stores";

const Entity = observer(({ entData }) => {
    const wallData = useRef(null);
    const [init, setInit] = useState(false);
    const blinkIntervals = useRef(new Map());
    if (wallData.current === null) wallData.current = new Map();
    const visibleStatus = stores.entStore.visibleStatus;

    const three = entController.getThree();
    const dummy = three.ent.dummy;

    let uvOffset = [];

    useEffect(() => {
        if (!entData || !three.ent.mesh) return;

        entController.removeEntMissingFromMessage(entData, three.ent.group, three.core.scene, three.ent.wall, three.ent.polyline);

        // Reset the instanced mesh count to avoid leftover objects from previous updates
        three.ent.mesh.children[0].count = entData.length;

        entData.forEach((item, index) => {
            let oldEntModel = three.core.scene.children[0].children.filter(items => items.uuid === item.UID);
            item.Q = item.Q ? item.Q : 0;
            const hpr = new HeadingPitchRoll(item.Q, 0, 0);
            let positionUp = Cartesian3.fromDegrees(item.L, item.B, item.H);
            let orientation = Transforms.headingPitchRollQuaternion(positionUp, hpr);
            let uOffset = getTypeColor( item.color, item.IO) % 98;

            let matrix = new Matrix4();
            let newPos = new Vector3(positionUp.x, positionUp.y, positionUp.z);
            let newQua = new Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
            matrix.makeRotationFromQuaternion(newQua);
            matrix.setPosition(newPos);

            if (item.isBlink) {
                if (!blinkIntervals.current.has(item.UID)) {
                    const interval = setInterval(() => {
                        const isVisible = blinkIntervals.current.get(item.UID);
                        if (isVisible) {
                            // Move to outer space
                            dummy.position.set(1e6, 1e6, 1e6);
                        } else {
                            dummy.position.set(positionUp.x, positionUp.y, positionUp.z);
                        }
                        blinkIntervals.current.set(item.UID, !isVisible);
                        dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w);
                        dummy.updateMatrix();
                        three.ent.mesh.children[0].setMatrixAt(index, dummy.matrix);
                        three.ent.mesh.children[0].instanceMatrix.needsUpdate = true;
                    }, 300);
                    blinkIntervals.current.set(item.UID, true);
                }
            } else {
                if (blinkIntervals.current.has(item.UID)) {
                    clearInterval(blinkIntervals.current.get(item.UID));
                    blinkIntervals.current.delete(item.UID);
                }
                dummy.position.set(positionUp.x, positionUp.y, positionUp.z);
                dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w);
                dummy.updateMatrix();
                three.ent.mesh.children[0].setMatrixAt(index, dummy.matrix);
                three.ent.mesh.children[0].instanceMatrix.needsUpdate = true;
            }

            uvOffset.push(uOffset, 0);
            if (uvOffset.length > 0) three.ent.mesh.children[0].geometry.setAttribute("uvOffset", new InstancedBufferAttribute(new Float32Array(uvOffset), 2));
        });

        three.ent.mesh.children[0].instanceMatrix.needsUpdate = true;
        if (uvOffset.length > 0) three.ent.mesh.children[0].geometry.setAttribute("uvOffset", new InstancedBufferAttribute(new Float32Array(uvOffset), 2));
        if (!init) {
            three.core.scene.add(three.ent.mesh);
            setInit(true);
        }

        return () => {
            blinkIntervals.current.forEach((interval) => clearInterval(interval));
            blinkIntervals.current.clear();
        };

    }, [entData]);

    return null;
});
export default Entity;

That looks mostly legitā€¦

Dunno if you want to use setInterval/clearInterval if youā€™re gonna have a lot of those thingsā€¦

Maybe just store a three.ent.mesh.userData.nextBlinkTime = performance.now()+1000
and compare it / reset it each frame as youā€™re looping through the instances.

Looks like this stuff is kinda not used?

            let matrix = new Matrix4();
            let newPos = new Vector3(positionUp.x, positionUp.y, positionUp.z);
            let newQua = new Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
            matrix.makeRotationFromQuaternion(newQua);
            matrix.setPosition(newPos);

I usually find it simpler to just deal with the dummy object like youā€™re doing, than directly mucking with matricesā€¦

Butā€¦ looks pretty legitā€¦ is it working? :smiley:

1 Like

I have a blinker that works that way. But the problem is that at each move the past position of each InstancedMesh element is saved and it turns out that the objects blink at the past position and where they are now. And this is the worst picture for epileptics. What is the problem?

 setInterval(() => {
                         hasColor = !hasColor
                         
                         if(hasColor) {
                            dummy.position.set(positionUp.x, positionUp.y, positionUp.z)
                            dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w)
                            dummy.updateMatrix() 
                            three.air.mesh.children[0].instanceMatrix.needsUpdate = true;
                            three.air.mesh.children[0].setMatrixAt(index, dummy.matrix)
                         } else {
                             dummy.position.set(1e6, 1e6, 1.e6);
                            
                             dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w)
                             dummy.updateMatrix()
                            three.air.mesh.children[0].instanceMatrix.needsUpdate = true;
                             three.air.mesh.children[0].setMatrixAt(index, dummy.matrix)
                      } 

                     }, 300);

hasColor = ((performance.now()/1000)|0)&1

Blinking, but now not moving. Code:

сonst Entity = observer(({ airData }) => {
    // const cesium = useCesium();
    const wallData = useRef(null);
    const [init, setInit] = useState(false)
    if (wallData.current === null) wallData.current = new Map();
    const visibleStatus = stores.airStore.visibleStatus;
const [intervalCreated, setIntervalCreated] = useState(false);
    const three = airController.getThree()
    const dummy = three.air.dummy;

    let uvOffset = [];

    useEffect(() => {
        if (!airData || !three.air.mesh) return;
        airController.removeAirMissingFromMessage(airData, three.air.group, three.core.scene, three.air.wall, three.air.polyline);
        airData.forEach((item, index) => {
            let oldAirModel = three.core.scene.children[0].children.filter(items => items.uuid === item.UID)
            item.Q = item.Q ? item.Q : 0;
            const hpr = new HeadingPitchRoll(item.Q, 0, 0);
            let positionUp = Cartesian3.fromDegrees(item.L, item.B, item.H);
           
            let orientation = Transforms.headingPitchRollQuaternion(positionUp, hpr);
;
            let uOffset = getTypeColor() % 98;

          
            if (oldAirModel.length > 0) {

 


if (!intervalCreated) {
target);
                    let hasColor = false;
                    
                    setInterval(() => {
                        hasColor = ((performance.now()/300)|0)&1
                         
                        if(hasColor) {
                           dummy.position.set(positionUp.x, positionUp.y, positionUp.z)
                           dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w)
                           dummy.updateMatrix() 
                     
                        } else {
                            dummy.position.set(1e6, 1e6, 1.e6);
                           
                            dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w)
                            dummy.updateMatrix()
                           
                         
                     } 
three.air.mesh.children[0].setMatrixAt(index, dummy.matrix)
                        three.air.mesh.children[0].instanceMatrix.needsUpdate = true;
                        
                        
                    }, 300);
                    setIntervalCreated(true);
                } else if (intervalCreated) {
                    return;
                } else {
                    stopInterval(item.UID);
                    setIntervalCreated(false);
                }
                uvOffset.push(uOffset, 0);
                if (uvOffset.length > 0) three.air.mesh.children[0].geometry.setAttribute("uvOffset", new InstancedBufferAttribute(new Float32Array(uvOffset), 2));
                
            } else {
                uvOffset.push(uOffset, 0);
                dummy.position.set(positionUp.x, positionUp.y, positionUp.z);
                dummy.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w)
                dummy.visible = false
                dummy.updateMatrix();
                three.air.mesh.children[0].setMatrixAt(index, dummy.matrix);
                three.air.mesh.children[0].visible = true

            }
        });
        three.air.mesh.children[0].instanceMatrix.needsUpdate = true;
        if (uvOffset.length > 0) three.air.mesh.children[0].geometry.setAttribute("uvOffset", new InstancedBufferAttribute(new Float32Array(uvOffset), 2));
        if (!init) {
            three.core.scene.add(three.air.mesh);
            
            setInit(true)
        }

    }, [airData]);

});
export default Entity;