import React, { useMemo } from 'react'; import { useFrame } from '@react-three/fiber'; import { SceneData, SceneNode } from './Generator'; import * as THREE from 'three'; const ObjectInstances: React.FC<{ data: SceneData }> = ({ data }) => { // We'll separate nodes by type to feed into distinct InstancedMeshes const windNodes = useMemo(() => data.nodes.filter(n => n.type === 'wind'), [data]); const solarNodes = useMemo(() => data.nodes.filter(n => n.type === 'solar'), [data]); const cityNodes = useMemo(() => data.nodes.filter(n => n.type === 'city_building'), [data]); const treeNodes = useMemo(() => data.nodes.filter(n => n.type === 'tree'), [data]); const towerNodes = useMemo(() => data.nodes.filter(n => n.type === 'tower'), [data]); const subNodes = useMemo(() => data.nodes.filter(n => n.type === 'substation'), [data]); const setMatrixAt = (mesh: THREE.InstancedMesh, i: number, node: SceneNode) => { const obj = new THREE.Object3D(); obj.position.set(node.position[0], node.position[1], node.position[2]); obj.rotation.set(node.rotation[0], node.rotation[1], node.rotation[2]); obj.scale.set(node.scale[0], node.scale[1], node.scale[2]); obj.updateMatrix(); mesh.setMatrixAt(i, obj.matrix); }; // Precompute instance matrices const windMatrices = useMemo(() => { const mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial(), windNodes.length); windNodes.forEach((node, i) => setMatrixAt(mesh, i, node)); mesh.instanceMatrix.needsUpdate = true; return mesh.instanceMatrix; }, [windNodes]); const solarMatrices = useMemo(() => { const mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial(), solarNodes.length); solarNodes.forEach((node, i) => setMatrixAt(mesh, i, node)); mesh.instanceMatrix.needsUpdate = true; return mesh.instanceMatrix; }, [solarNodes]); const treeMatrices = useMemo(() => { const mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial(), treeNodes.length); treeNodes.forEach((node, i) => setMatrixAt(mesh, i, node)); mesh.instanceMatrix.needsUpdate = true; return mesh.instanceMatrix; }, [treeNodes]); const towerMatrices = useMemo(() => { const mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial(), towerNodes.length); towerNodes.forEach((node, i) => setMatrixAt(mesh, i, node)); mesh.instanceMatrix.needsUpdate = true; return mesh.instanceMatrix; }, [towerNodes]); const subMatrices = useMemo(() => { const mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial(), subNodes.length); subNodes.forEach((node, i) => setMatrixAt(mesh, i, node)); mesh.instanceMatrix.needsUpdate = true; return mesh.instanceMatrix; }, [subNodes]); const cityMatrices = useMemo(() => { const mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial(), cityNodes.length); cityNodes.forEach((node, i) => setMatrixAt(mesh, i, node)); mesh.instanceMatrix.needsUpdate = true; return mesh.instanceMatrix; }, [cityNodes]); return ( {/* Trees */} {treeNodes.length > 0 && ( )} {/* Wind Turbines Towers */} {windNodes.length > 0 && ( )} {/* Solar Panels */} {solarNodes.length > 0 && ( )} {/* City Buildings */} {cityNodes.length > 0 && ( )} {/* Substations */} {subNodes.length > 0 && ( )} {/* Transition Towers (Grid) */} {towerNodes.length > 0 && ( )} ); }; export default ObjectInstances;