import * as THREE from “three”;
import { OrbitControls } from “three/addons/controls/OrbitControls.js”;
import { useEffect, useMemo, useRef } from “react”;
import { OBJLoader } from “three/addons/loaders/OBJLoader.js”;
import { PCDLoader } from “three/examples/jsm/loaders/PCDLoader.js”;
import { GUI } from “dat.gui”;
import useSliderStore from “../store/store”;
function ThreeScene() {
// store
// const index: number = 300;
const sliderValue = useSliderStore((state) => state.sliderValue);
const pcdFile = useMemo(() => {
return /pcd/${sliderValue}.pcd;
// return ../../../backend/backend/output/00000000${sliderValue}.pcd;
}, [sliderValue]);
const pointsRef = useRef<THREE.Points | null>(null);
const sceneRef = useRef<HTMLDivElement | null>(null);
const sceneObjRef = useRef<THREE.Scene | null>(null);
const materialRef = useRef<THREE.PointsMaterial | null>(null);
const guiRef = useRef<GUI | null>(null);
const settingsRef = useRef({ pointSize: 0.05, color: “#ffffff” });
useEffect(() => {
const sceneNode = sceneRef.current;
const scene = new THREE.Scene();
sceneObjRef.current = scene;
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
sceneNode?.appendChild(renderer.domElement);
const objLoader = new OBJLoader();
objLoader.load(
"../public/8hd2hnno0ayo-aventador_sport/Avent_sport.obj",
(root) => {
const skeletonHelper = new THREE.SkeletonHelper(root);
scene.add(skeletonHelper);
root.translateY(0.5);
scene.add(root);
}
);
camera.position.z = 5;
const color = 0xffffff;
const intensity = 10;
const light = new THREE.PointLight(color, intensity);
light.position.set(0, 5, 0);
scene.add(light);
const pointLightHelper = new THREE.PointLightHelper(light, 1);
scene.add(pointLightHelper);
new OrbitControls(camera, sceneNode);
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
const gridHelper = new THREE.GridHelper(10, 10);
scene.add(gridHelper);
const animate = () => {
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
animate();
// Handle resize
const handleResize = () => {
if (!sceneRef.current) return;
const width = sceneRef.current.clientWidth;
const height = sceneRef.current.clientHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
window.addEventListener("resize", handleResize);
if (!guiRef.current) {
guiRef.current = new GUI();
guiRef.current
.add(settingsRef.current, "pointSize", 0.01, 1.0)
.onChange((value: number) => {
if (materialRef.current) {
materialRef.current.size = value;
}
});
guiRef.current
.addColor(settingsRef.current, "color")
.onChange((value: string) => {
if (materialRef.current) {
materialRef.current.color.set(value);
}
});
}
return () => {
// window.removeEventListener("resize", handleResize);
sceneNode?.removeChild(renderer.domElement);
renderer.dispose();
};
}, []);
useEffect(() => {
if (!sceneObjRef.current) return;
const pcdLoader = new PCDLoader();
console.log(pcdFile);
pcdLoader.load(
pcdFile,
(points) => {
points.rotateX(Math.PI / 2);
if (pointsRef.current) {
const oldPoints = pointsRef.current;
sceneObjRef.current!.remove(oldPoints);
if (oldPoints.geometry) oldPoints.geometry.dispose();
if (oldPoints.material) {
if (Array.isArray(oldPoints.material)) {
oldPoints.material.forEach((mat) => mat.dispose());
} else {
oldPoints.material.dispose();
}
}
pointsRef.current = null;
}
sceneObjRef.current!.add(points);
pointsRef.current = points;
materialRef.current = points.material as THREE.PointsMaterial;
materialRef.current.size = settingsRef.current.pointSize;
},
(progressEvent) => {
if (progressEvent.lengthComputable) {
const percent = Math.round(
(progressEvent.loaded / progressEvent.total) * 100
);
console.log(`PCD loading: ${percent}%`);
}
},
(error) => {
console.error("Error loading PCD file:", error);
}
);
}, [sliderValue, settingsRef, pcdFile]);
return (
<div ref={sceneRef} style={{ width: “100vw”, height: “100vh” }}>
);
}export default ThreeScene;