You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hey im currently working on a 3D path visualizer and want to visualize all kinds of pathfinding algorithms. In the current state i have an floor with a character and a flag on it and you can build houses as obstacles. The floor is a instancedMesh with a planeBufferGeometry each plane is 1 by 1.
For each plane I have a Node class Object that is stores in a global store as grid (Note: grid is a 2d array for the algorithms later).
Each Node has a instanceId attribute so we can identify which Node object is related to which plane and can access this plane with the instanceId in the Node object.
So my problem is now that i implemented a solution that works fine but not really how I want it to be. My knowledge lacks in react-spring and I do not know if there is a better solution.
My solution is that I run a pathfinding algorithm and add all nodes that I want to animate in a nodesToAnimate array that is also located in a global store. Than I use useFrame to check if there is a any Plane that needs to be updated if yes, then I get the instanceId of the Node to find the plane that I need to update and animate the color of the plane with useSpring. Each time a plane color updates I block that a other plane can be updated so that we can animate each plane only one by one. Why I do this ?
Because if I do not block this the animation of the first plane stops and the next animation begins.
So my question is how I can animate plane colors simultaneously.
I tried to use useSprings and other hooks of react-spring but nothing really worked fine. This is my best solution right now.
Note I know that its bad style to use setState in useFrame.
Recent changes are in the grid branch if you want to run it on your computer.
import{useSpring}from"react-spring";import{ThreeEvent,useFrame}from"@react-three/fiber";importReact,{useLayoutEffect,useRef,useState}from"react";import{Color,DoubleSide,InstancedMesh,Matrix4,Mesh,Plane,PlaneBufferGeometry,Vector3,}from"three";import{useGlobalStore}from"../global-stores/useGlobalStore";import{getGraphIndexes}from"../utils/getGraphIndexes";importCharacterfrom"./Character";importObstaclefrom"./Obstacle";importTargetfrom"./Target";import{animated}from"@react-spring/three";constGround: React.FC=()=>{// used for the raycasterconstfloor: Plane=newPlane(newVector3(0,-0.001,0),0);constplane=newPlaneBufferGeometry(1,1,1,1);plane.rotateX(-Math.PI/2);const[block,setblock]=useState(false);// size of the grid planeconstplaneSize=31;const{ grid, setGrid, isDragging, nodesToAnimate }=useGlobalStore((state)=>({grid: state.grid,setGrid: state.setGrid,isDragging: state.isDragging,nodesToAnimate: state.nodesToAnimate,}));// refsconstmesh=useRef<InstancedMesh>(null!);constray=useRef<Mesh>(null!);/** * Checks if an obstacle can be added at the given position. * If there is already an obstacle at the position, * it will be removed. * * @param vector Specified position */constaddBuilding=(vector: Vector3)=>{const[i,j]=getGraphIndexes(vector);consttempGraph=[...grid];// Copies old graphconstnewNode=tempGraph[i][j];if(!newNode.isFinish&&!newNode.isStart){newNode.isWall=!newNode.isWall;// Add or remove wall}setGrid(tempGraph);// We set a new graph every time, because otherwise we don't re-render};constupdateColor=(id: number)=>{api.start({to: [{color: "#FFD36E",},{color: "#FFF56D",},{color: "#99FFCD",},{color: "#9FB4FF",},],from: {color: "#ECECEC",},onRest: ()=>{setblock(false);},onChange: ()=>{mesh.current.setColorAt(id,newColor().setStyle(spring.color.get()));mesh.current.instanceColor!.needsUpdate=true;},});};useLayoutEffect(()=>{leti=0;constoffset=-0;constmatrix=newMatrix4();constcolor=newColor(0xececec);for(letx=0;x<planeSize;x++){for(lety=0;y<planeSize;y++){matrix.setPosition(offset-x,0,offset-y);mesh.current.setMatrixAt(i,matrix);mesh.current.setColorAt(i,color);i++;}mesh.current.instanceColor!.needsUpdate=true;mesh.current.instanceMatrix.needsUpdate=true;}},[]);const[spring,api]=useSpring(()=>({color: "#ECECEC",config: {duration: 100},}));useFrame(()=>{if(nodesToAnimate.length&&block){constnode=nodesToAnimate.shift();if(node){updateColor(node?.instanceId);setblock(true);}}});return(<>{/* Grid Helper */}<gridHelperargs={[planeSize,planeSize]}receiveShadow/>{/* Grid */}<animated.instancedMeshref={mesh}receiveShadowargs={[nullasunknownasPlaneBufferGeometry,undefined,Math.pow(planeSize,2),]}position={[15,-0.001,15]}
onClick={(e: ThreeEvent<MouseEvent>)=>{e.stopPropagation();if(!isDragging){addBuilding(e.point);}}}onPointerMove={(e: ThreeEvent<MouseEvent>)=>{e.stopPropagation();// Move mouse pointer planeray.current?.position.copy(newVector3(Math.round(e.point.x),0,Math.round(e.point.z)).floor().addScalar(0.0001));}}><planeBufferGeometryargs={[1,1,1,1]}{...floor}attach="geometry"{...plane}/><meshPhongMaterialside={DoubleSide}color="#ECECEC"attach="material"/></animated.instancedMesh>{/* Mouse Pointer Plane */}<meshposition={[0,0,0]}rotation={[-Math.PI/2,0,0]}ref={ray}><planeGeometryargs={[1,1,1,1]}/><meshStandardMaterialside={DoubleSide}color="#F29191"attach="material"/></mesh>{/* Obstacles */}<instancedMeshcount={961}>{grid.map((obstacles)=>{returnobstacles.map((obstacle,idx)=>{if(obstacle.isWall){return(<Obstacleposition={newVector3(obstacle.x-15,5,obstacle.z-15)}key={idx}/>);}returnnull;});})}</instancedMesh>{/* Character */}<Characterfloor={floor}/>{/* Target */}<Targetfloor={floor}/></>);};exportdefaultGround;
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Hey im currently working on a 3D path visualizer and want to visualize all kinds of pathfinding algorithms. In the current state i have an floor with a character and a flag on it and you can build houses as obstacles. The floor is a instancedMesh with a planeBufferGeometry each plane is 1 by 1.
InstancedMesh - Ground
For each plane I have a Node class Object that is stores in a global store as grid (Note: grid is a 2d array for the algorithms later).
Each Node has a instanceId attribute so we can identify which Node object is related to which plane and can access this plane with the instanceId in the Node object.
So my problem is now that i implemented a solution that works fine but not really how I want it to be. My knowledge lacks in react-spring and I do not know if there is a better solution.
My solution is that I run a pathfinding algorithm and add all nodes that I want to animate in a nodesToAnimate array that is also located in a global store. Than I use useFrame to check if there is a any Plane that needs to be updated if yes, then I get the instanceId of the Node to find the plane that I need to update and animate the color of the plane with useSpring. Each time a plane color updates I block that a other plane can be updated so that we can animate each plane only one by one. Why I do this ?
Because if I do not block this the animation of the first plane stops and the next animation begins.
So my question is how I can animate plane colors simultaneously.
I tried to use useSprings and other hooks of react-spring but nothing really worked fine. This is my best solution right now.
Note I know that its bad style to use setState in useFrame.
Recent changes are in the grid branch if you want to run it on your computer.
Complete file here:
Github repo: https://github.com/Louis3797/3d-path-visualizer
Beta Was this translation helpful? Give feedback.
All reactions