diff --git a/app/src/modules/builder/asset/models/model/conveyorCollider.tsx b/app/src/modules/builder/asset/models/model/conveyorCollider.tsx index 5cd9afe..6cdb29a 100644 --- a/app/src/modules/builder/asset/models/model/conveyorCollider.tsx +++ b/app/src/modules/builder/asset/models/model/conveyorCollider.tsx @@ -2,27 +2,27 @@ import * as THREE from 'three'; import { CollisionPayload, RapierRigidBody, RigidBody } from '@react-three/rapier'; import { useEffect, useRef, useState } from 'react'; import { useFrame } from '@react-three/fiber'; +import CurvedPlane from '../../../../scene/physics/curvedPlane'; -function ConveyorCollider({ boundingBox, asset, conveyorPlaneSize }: { +function ConveyorCollider({ boundingBox, asset, modelName, conveyorPlaneSize, scene }: { boundingBox: THREE.Box3 | null, asset: Asset, + modelName: string, + scene: THREE.Scene, conveyorPlaneSize: [number, number] | null, }) { const conveyorRef = useRef(null); const [objectsOnConveyor, setObjectsOnConveyor] = useState>(new Set()); const conveyorDirection = useRef(new THREE.Vector3()); const conveyorSpeed = 2; - useEffect(() => { if (!boundingBox || !conveyorPlaneSize) return; - const [width, depth] = conveyorPlaneSize; - if (width < depth) { + if (width < depth) { //z-axis conveyor conveyorDirection.current.set(0, 0, 1); - } else { + } else {//x-axis conveyor conveyorDirection.current.set(1, 0, 0); } - const rotation = new THREE.Euler().fromArray(asset.rotation || [0, 0, 0]); conveyorDirection.current.applyEuler(rotation); }, [boundingBox, conveyorPlaneSize, asset.rotation]); @@ -50,7 +50,6 @@ function ConveyorCollider({ boundingBox, asset, conveyorPlaneSize }: { useFrame(() => { const forward = conveyorDirection.current.clone().normalize(); const side = new THREE.Vector3().crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize(); - const force = forward.clone().multiplyScalar(conveyorSpeed); objectsOnConveyor.forEach(rigidBody => { @@ -124,12 +123,14 @@ function ConveyorCollider({ boundingBox, asset, conveyorPlaneSize }: { colliders="cuboid" > + {/* */} diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index 7c3f580..ffd9c6e 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -526,6 +526,8 @@ function Model({ asset }: { readonly asset: Asset }) { )} diff --git a/app/src/modules/scene/physics/curvedPlane.tsx b/app/src/modules/scene/physics/curvedPlane.tsx new file mode 100644 index 0000000..a51d924 --- /dev/null +++ b/app/src/modules/scene/physics/curvedPlane.tsx @@ -0,0 +1,115 @@ +import { useThree } from '@react-three/fiber'; +import * as THREE from 'three'; +export default function CurvedPlane({ modelName, scene }: { modelName: string, scene: THREE.Scene }) { + // console.log('scene: ', scene);n + // console.log('modelName: ', modelName); + + function computeCircleFromPoints(p1: THREE.Vector2, p2: THREE.Vector2, p3: THREE.Vector2) { + const temp = p2.clone().sub(p1); + const temp2 = p3.clone().sub(p1); + const cross = temp.x * temp2.y - temp.y * temp2.x; + if (Math.abs(cross) < 1e-10) return null; // colinear + + const A = p1.lengthSq(); + const B = p2.lengthSq(); + const C = p3.lengthSq(); + + const D = 2 * (p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)); + + const centerX = (A * (p2.y - p3.y) + B * (p3.y - p1.y) + C * (p1.y - p2.y)) / D; + const centerY = (A * (p3.x - p2.x) + B * (p1.x - p3.x) + C * (p2.x - p1.x)) / D; + + const center = new THREE.Vector2(centerX, centerY); + const radius = center.distanceTo(p1); + return { center, radius }; + } + function findFirstMesh(object: THREE.Object3D): THREE.Mesh | null { + if ((object as THREE.Mesh).isMesh) return object as THREE.Mesh; + + for (const child of object.children) { + const result = findFirstMesh(child); + if (result) return result; + } + + return null; + } + + const parentObject = scene.getObjectByName(modelName); // this is the group + if (!parentObject) return null; + + const mesh = findFirstMesh(parentObject); + console.log('mesh: ', mesh); + if (!mesh) { + console.warn('No mesh found inside group'); + return null; + } + + const geometry = mesh.geometry as THREE.BufferGeometry; + const positions = geometry?.attributes?.position; + + const points: THREE.Vector2[] = []; + for (let i = 0; i < positions.count; i += 20) { // sample every 20th vertex + const x = positions.getX(i); + const z = positions.getZ(i); // assuming Y is up + points.push(new THREE.Vector2(x, z)); + } + + console.log('points: ', points); + // Use three points to estimate curve + const p1 = points[0]; + const p2 = points[Math.floor(points.length / 2)]; + const p3 = points[points.length - 1]; + + const result = computeCircleFromPoints(p1, p2, p3); + if (!result) return null; + + const { center, radius } = result; + const angle = p1.clone().sub(center).angleTo(p3.clone().sub(center)); + + // Estimate width: take 2 points close to p2 but on either side + const width = 3; // placeholder, calculate from mesh later if needed + + const shape = new THREE.Shape(); + const segments = 32; + + const innerRadius = radius; + const outerRadius = radius + width; + + for (let i = 0; i <= segments; i++) { + const t = (angle * i) / segments; + const x = Math.cos(t) * outerRadius; + const y = Math.sin(t) * outerRadius; + if (i === 0) shape.moveTo(x, y); + else shape.lineTo(x, y); + } + + for (let i = segments; i >= 0; i--) { + const t = (angle * i) / segments; + const x = Math.cos(t) * innerRadius; + const y = Math.sin(t) * innerRadius; + shape.lineTo(x, y); + } + const helper = new THREE.BoxHelper(mesh, 0xffff00); + scene.add(helper); + + return ( + + + + + ); +} + diff --git a/app/src/modules/scene/physics/physicsSimulator.tsx b/app/src/modules/scene/physics/physicsSimulator.tsx index f6dddc0..279ef24 100644 --- a/app/src/modules/scene/physics/physicsSimulator.tsx +++ b/app/src/modules/scene/physics/physicsSimulator.tsx @@ -5,7 +5,7 @@ import ColliderCreator from './colliders/colliderCreator' function PhysicsSimulator() { return ( <> - + /> */} ) diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 2ac0377..4e760bf 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -74,6 +74,7 @@ export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Co + {/* */}