feat: enhance conveyor collider functionality and improve scene visibility toggle

This commit is contained in:
2025-09-01 14:57:27 +05:30
parent f3ea48fcfd
commit a88c0e594b
8 changed files with 368 additions and 349 deletions

View File

@@ -168,7 +168,7 @@ const SideBarRight: React.FC = () => {
}
setDisplayComponent("none");
}, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorItem, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
}, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorItem, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal, selectedCollider]);
const renderComponent = () => {
switch (displayComponent) {

View File

@@ -232,7 +232,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
asset={asset}
/> */}
{asset.eventData && asset.eventData.type === 'Conveyor' && fieldData &&
{asset.eventData && asset.eventData.type === 'Conveyor' && fieldData && activeModule === 'simulation' &&
<RibbonCollider
key={asset.modelUuid}
boundingBox={boundingBox}

View File

@@ -19,5 +19,5 @@ export default function StatsHelper() {
return () => window.removeEventListener("keydown", handleKeyDown);
}, []);
return visible ? <Perf position="bottom-left" className="scene-performance-stats"/> : null;
return visible ? <Perf position="bottom-left" className="scene-performance-stats" /> : null;
}

View File

@@ -4,368 +4,370 @@ import { useEffect, useMemo, useRef, useState } from 'react';
import { useFrame } from '@react-three/fiber';
function CurvedConveyorCollider({
points,
boundingBox,
asset,
forward,
isPaused,
onDirectionChange
points,
boundingBox,
asset,
forward,
isPaused,
onDirectionChange
}: {
points: [number, number, number][][];
boundingBox: THREE.Box3 | null;
asset: Asset;
forward: boolean;
isPaused: boolean;
onDirectionChange?: (newDirection: boolean) => void;
points: [number, number, number][][];
boundingBox: THREE.Box3 | null;
asset: Asset;
forward: boolean;
isPaused: boolean;
onDirectionChange?: (newDirection: boolean) => void;
}) {
const conveyorRef = useRef<any>(null);
const [objectsOnConveyor, setObjectsOnConveyor] = useState<Set<any>>(new Set());
const conveyorDirection = useRef<THREE.Vector3>(new THREE.Vector3());
// const [forward, setForward] = useState(initialForward);
const [showDirection, setShowDirection] = useState(false);
const [hoverState, setHoverState] = useState(false);
const conveyorSpeed = 2;
const lastClickTime = useRef(0);
const arrowRefs = useRef<THREE.Group[]>([]);
const [geometryKey, setGeometryKey] = useState(0);
const conveyorRef = useRef<any>(null);
const [objectsOnConveyor, setObjectsOnConveyor] = useState<Set<any>>(new Set());
const conveyorDirection = useRef<THREE.Vector3>(new THREE.Vector3());
// const [forward, setForward] = useState(initialForward);
const [showDirection, setShowDirection] = useState(false);
const [hoverState, setHoverState] = useState(false);
const conveyorSpeed = 2;
const lastClickTime = useRef(0);
const arrowRefs = useRef<THREE.Group[]>([]);
const [geometryKey, setGeometryKey] = useState(0);
// Toggle direction on double right click
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (e.button === 2 && hoverState) { // Right click and hovering over conveyor
const now = Date.now();
if (now - lastClickTime.current < 300) {
if (onDirectionChange) {
console.log('forwardcurve: ', forward);
onDirectionChange(!forward);
}
// Toggle direction on double right click
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (e.button === 2 && hoverState) { // Right click and hovering over conveyor
const now = Date.now();
if (now - lastClickTime.current < 300) {
if (onDirectionChange) {
console.log('forwardcurve: ', forward);
onDirectionChange(!forward);
}
}
lastClickTime.current = now;
}
};
window.addEventListener('mousedown', handleClick);
return () => window.removeEventListener('mousedown', handleClick);
}, [forward, hoverState]);
const bezierPoints = useMemo(() => {
const segments = 20;
const allPoints: THREE.Vector3[] = [];
points.forEach(segment => {
let vectorPoints = segment.map(p => new THREE.Vector3(...p));
if (!forward) vectorPoints.reverse();
for (let group = 0; group + 2 < vectorPoints.length; group += 2) {
const p0 = vectorPoints[group];
const p1 = vectorPoints[group + 1];
const p2 = vectorPoints[group + 2];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const point = new THREE.Vector3()
.copy(p0)
.multiplyScalar((1 - t) ** 2)
.addScaledVector(p1, 2 * (1 - t) * t)
.addScaledVector(p2, t ** 2);
allPoints.push(point);
}
}
});
return allPoints;
}, [points, forward]);
const geometries = useMemo(() => {
const width = 1;
const segments = 20;
const geos: THREE.BufferGeometry[] = [];
points.forEach(segment => {
const vertices: number[] = [];
const indices: number[] = [];
const vectorPoint = segment.map(p => new THREE.Vector3(...p));
if (vectorPoint.length < 3) return;
for (let group = 0; group + 2 < vectorPoint.length; group += 2) {
const p0 = vectorPoint[group];
const p1 = vectorPoint[group + 1];
const p2 = vectorPoint[group + 2];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const point = new THREE.Vector3()
.copy(p0)
.multiplyScalar((1 - t) ** 2)
.addScaledVector(p1, 2 * (1 - t) * t)
.addScaledVector(p2, t ** 2);
const tangent = new THREE.Vector3()
.copy(p0)
.multiplyScalar(-2 * (1 - t))
.addScaledVector(p1, 2 - 4 * t)
.addScaledVector(p2, 2 * t)
.normalize();
const normal = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize();
const left = new THREE.Vector3().copy(point).addScaledVector(normal, -width / 2);
const right = new THREE.Vector3().copy(point).addScaledVector(normal, width / 2);
vertices.push(...left.toArray(), ...right.toArray());
}
}
const totalSegments = ((vectorPoint.length - 1) / 2) * segments;
for (let i = 0; i < totalSegments; i++) {
const base = i * 2;
indices.push(base, base + 1, base + 2);
indices.push(base + 1, base + 3, base + 2);
}
const ribbonGeometry = new THREE.BufferGeometry();
ribbonGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
ribbonGeometry.setIndex(indices);
ribbonGeometry.computeVertexNormals();
geos.push(ribbonGeometry);
});
setGeometryKey(k => k + 1);
return geos;
}, [points, asset.position, asset.rotation]);
useEffect(() => {
if (bezierPoints.length >= 2) {
const start = bezierPoints[0];
const end = bezierPoints[bezierPoints.length - 1];
conveyorDirection.current.copy(end).sub(start).normalize();
const rotation = new THREE.Euler().fromArray(asset.rotation || [0, 0, 0]);
conveyorDirection.current.applyEuler(rotation);
}
}, [bezierPoints, forward, asset.rotation]);
const handleMaterialEnter = (e: CollisionPayload) => {
if (e.other.rigidBody) {
setObjectsOnConveyor(prev => {
const newSet = new Set(prev);
newSet.add(e.other.rigidBody);
return newSet;
});
}
lastClickTime.current = now;
}
};
window.addEventListener('mousedown', handleClick);
return () => window.removeEventListener('mousedown', handleClick);
}, [forward, hoverState]);
const bezierPoints = useMemo(() => {
const segments = 20;
const allPoints: THREE.Vector3[] = [];
points.forEach(segment => {
let vectorPoints = segment.map(p => new THREE.Vector3(...p));
if (!forward) vectorPoints.reverse();
for (let group = 0; group + 2 < vectorPoints.length; group += 2) {
const p0 = vectorPoints[group];
const p1 = vectorPoints[group + 1];
const p2 = vectorPoints[group + 2];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const point = new THREE.Vector3()
.copy(p0)
.multiplyScalar((1 - t) ** 2)
.addScaledVector(p1, 2 * (1 - t) * t)
.addScaledVector(p2, t ** 2);
allPoints.push(point);
const handleMaterialExit = (e: CollisionPayload) => {
if (e.other.rigidBody) {
setObjectsOnConveyor(prev => {
const newSet = new Set(prev);
newSet.delete(e.other.rigidBody);
return newSet;
});
}
}
});
return allPoints;
}, [points, forward]);
const geometries = useMemo(() => {
const width = 1;
const segments = 20;
const geos: THREE.BufferGeometry[] = [];
points.forEach(segment => {
const vertices: number[] = [];
const indices: number[] = [];
const vectorPoint = segment.map(p => new THREE.Vector3(...p));
if (vectorPoint.length < 3) return;
for (let group = 0; group + 2 < vectorPoint.length; group += 2) {
const p0 = vectorPoint[group];
const p1 = vectorPoint[group + 1];
const p2 = vectorPoint[group + 2];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const point = new THREE.Vector3()
.copy(p0)
.multiplyScalar((1 - t) ** 2)
.addScaledVector(p1, 2 * (1 - t) * t)
.addScaledVector(p2, t ** 2);
const tangent = new THREE.Vector3()
.copy(p0)
.multiplyScalar(-2 * (1 - t))
.addScaledVector(p1, 2 - 4 * t)
.addScaledVector(p2, 2 * t)
.normalize();
const normal = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize();
const left = new THREE.Vector3().copy(point).addScaledVector(normal, -width / 2);
const right = new THREE.Vector3().copy(point).addScaledVector(normal, width / 2);
vertices.push(...left.toArray(), ...right.toArray());
}
}
const totalSegments = ((vectorPoint.length - 1) / 2) * segments;
for (let i = 0; i < totalSegments; i++) {
const base = i * 2;
indices.push(base, base + 1, base + 2);
indices.push(base + 1, base + 3, base + 2);
}
const ribbonGeometry = new THREE.BufferGeometry();
ribbonGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
ribbonGeometry.setIndex(indices);
ribbonGeometry.computeVertexNormals();
geos.push(ribbonGeometry);
});
setGeometryKey(k => k + 1);
return geos;
}, [points, asset.position, asset.rotation]);
useEffect(() => {
if (bezierPoints.length >= 2) {
const start = bezierPoints[0];
const end = bezierPoints[bezierPoints.length - 1];
conveyorDirection.current.copy(end).sub(start).normalize();
const rotation = new THREE.Euler().fromArray(asset.rotation || [0, 0, 0]);
conveyorDirection.current.applyEuler(rotation);
}
}, [bezierPoints, forward, asset.rotation]);
};
const handleMaterialEnter = (e: CollisionPayload) => {
if (e.other.rigidBody) {
setObjectsOnConveyor(prev => {
const newSet = new Set(prev);
newSet.add(e.other.rigidBody);
return newSet;
});
}
};
useFrame(({ clock }) => {
if (isPaused) return;
const handleMaterialExit = (e: CollisionPayload) => {
if (e.other.rigidBody) {
setObjectsOnConveyor(prev => {
const newSet = new Set(prev);
newSet.delete(e.other.rigidBody);
return newSet;
});
}
};
// Physics simulation
const assetPos = new THREE.Vector3(...(asset.position || [0, 0, 0]));
const assetRot = new THREE.Euler(...(asset.rotation || [0, 0, 0]));
const assetQuat = new THREE.Quaternion().setFromEuler(assetRot);
const inverseQuat = assetQuat.clone().invert();
objectsOnConveyor.forEach(rigidBody => {
const worldPos = new THREE.Vector3().copy(rigidBody.translation());
const localPos = worldPos.clone().sub(assetPos).applyQuaternion(inverseQuat);
useFrame(({ clock }) => {
if (isPaused) return;
// Physics simulation
const assetPos = new THREE.Vector3(...(asset.position || [0, 0, 0]));
const assetRot = new THREE.Euler(...(asset.rotation || [0, 0, 0]));
const assetQuat = new THREE.Quaternion().setFromEuler(assetRot);
const inverseQuat = assetQuat.clone().invert();
objectsOnConveyor.forEach(rigidBody => {
const worldPos = new THREE.Vector3().copy(rigidBody.translation());
const localPos = worldPos.clone().sub(assetPos).applyQuaternion(inverseQuat);
let closestIndex = 0;
let minDist = Infinity;
for (let i = 0; i < bezierPoints.length; i++) {
const dist = bezierPoints[i].distanceToSquared(localPos);
if (dist < minDist) {
minDist = dist;
closestIndex = i;
}
}
const point = bezierPoints[closestIndex];
const prev = bezierPoints[closestIndex - 1] || point;
const next = bezierPoints[closestIndex + 1] || point;
const tangent = new THREE.Vector3().subVectors(next, prev).normalize();
const side = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize();
const relative = new THREE.Vector3().subVectors(localPos, point);
const sideOffset = relative.dot(side);
const centeringForce = side.clone().multiplyScalar(-sideOffset * 10);
const forwardForce = tangent.clone().multiplyScalar(conveyorSpeed);
const totalForce = forwardForce.add(centeringForce).applyQuaternion(assetQuat);
rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true);
rigidBody.setLinvel(totalForce, true);
});
// Arrow animations
if (showDirection && arrowRefs.current.length > 0) {
const elapsedTime = clock.getElapsedTime();
arrowRefs.current.forEach((arrowGroup, index) => {
// Pulse animation
const pulseScale = 0.9 + 0.1 * Math.sin(elapsedTime * 5 + index * 0.5);
arrowGroup.scale.setScalar(pulseScale);
// Flow animation (color intensity)
const intensity = 0.7 + 0.3 * Math.sin(elapsedTime * 3 + index * 0.3);
arrowGroup.children.forEach(child => {
if (child instanceof THREE.Mesh) {
const material = child.material as THREE.MeshBasicMaterial;
if (forward) {
material.color.setRGB(0, intensity, 0);
} else {
material.color.setRGB(intensity, 0, 0);
let closestIndex = 0;
let minDist = Infinity;
for (let i = 0; i < bezierPoints.length; i++) {
const dist = bezierPoints[i].distanceToSquared(localPos);
if (dist < minDist) {
minDist = dist;
closestIndex = i;
}
}
}
const point = bezierPoints[closestIndex];
const prev = bezierPoints[closestIndex - 1] || point;
const next = bezierPoints[closestIndex + 1] || point;
const tangent = new THREE.Vector3().subVectors(next, prev).normalize();
const side = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize();
const relative = new THREE.Vector3().subVectors(localPos, point);
const sideOffset = relative.dot(side);
const centeringForce = side.clone().multiplyScalar(-sideOffset * 10);
const forwardForce = tangent.clone().multiplyScalar(conveyorSpeed);
const totalForce = forwardForce.add(centeringForce).applyQuaternion(assetQuat);
rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true);
rigidBody.setLinvel(totalForce, true);
});
});
}
});
// Arrow animations
if (showDirection && arrowRefs.current.length > 0) {
const elapsedTime = clock.getElapsedTime();
arrowRefs.current.forEach((arrowGroup, index) => {
// Pulse animation
const pulseScale = 0.9 + 0.1 * Math.sin(elapsedTime * 5 + index * 0.5);
arrowGroup.scale.setScalar(pulseScale);
// Create curved direction indicators
const directionArrows = useMemo(() => {
if (!showDirection) return null;
const arrows: THREE.Group[] = [];
const arrowHeight = 0.2;
const arrowRadius = 0.05;
const segments = 8; // Fewer arrows for curved conveyors
points.forEach(segment => {
let vectorPoints = segment.map(p => new THREE.Vector3(...p));
if (!forward) vectorPoints.reverse();
for (let group = 0; group + 2 < vectorPoints.length; group += 2) {
const p0 = vectorPoints[group];
const p1 = vectorPoints[group + 1];
const p2 = vectorPoints[group + 2];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const point = new THREE.Vector3()
.copy(p0)
.multiplyScalar((1 - t) ** 2)
.addScaledVector(p1, 2 * (1 - t) * t)
.addScaledVector(p2, t ** 2);
const tangent = new THREE.Vector3()
.copy(p0)
.multiplyScalar(-2 * (1 - t))
.addScaledVector(p1, 2 - 4 * t)
.addScaledVector(p2, 2 * t)
.normalize();
// Create arrow group
const arrowGroup = new THREE.Group();
// Arrow shaft (cylinder)
const shaftLength = arrowHeight * 0.7;
const shaftGeometry = new THREE.CylinderGeometry(arrowRadius * 0.3, arrowRadius * 0.3, shaftLength, 8);
const shaftMaterial = new THREE.MeshBasicMaterial({
color: forward ? 0x00ff00 : 0xff0000
});
const shaft = new THREE.Mesh(shaftGeometry, shaftMaterial);
shaft.position.y = shaftLength / 2;
shaft.rotation.x = Math.PI / 2;
// Arrow head (cone)
const headGeometry = new THREE.ConeGeometry(arrowRadius, arrowHeight * 0.3, 8);
const headMaterial = new THREE.MeshBasicMaterial({
color: forward ? 0x00ff00 : 0xff0000
});
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.y = shaftLength;
// Position and orient the entire arrow
arrowGroup.add(shaft);
arrowGroup.add(head);
arrowGroup.position.copy(point);
arrowGroup.position.y += 0.1; // Slightly above conveyor
arrowGroup.quaternion.setFromUnitVectors(
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(tangent.x, 0.1, tangent.z)
);
arrows.push(arrowGroup);
// Flow animation (color intensity)
const intensity = 0.7 + 0.3 * Math.sin(elapsedTime * 3 + index * 0.3);
arrowGroup.children.forEach(child => {
if (child instanceof THREE.Mesh) {
const material = child.material as THREE.MeshBasicMaterial;
if (forward) {
material.color.setRGB(0, intensity, 0);
} else {
material.color.setRGB(intensity, 0, 0);
}
}
});
});
}
}
});
arrowRefs.current = arrows;
return arrows;
}, [points, showDirection, forward]);
return (
<group
onPointerOver={() => {
setShowDirection(true);
setHoverState(true);
}}
onPointerOut={() => {
setShowDirection(false);
setHoverState(false);
}}
>
{/* Conveyor surface */}
{geometries.length > 0 && (
<RigidBody
key={geometryKey}
ref={conveyorRef}
type="fixed"
position={[0, 0.001, 0]}
userData={{ isConveyor: true }}
onCollisionEnter={handleMaterialEnter}
onCollisionExit={handleMaterialExit}
colliders="trimesh"
// Create curved direction indicators
const directionArrows = useMemo(() => {
if (!showDirection) return null;
const arrows: THREE.Group[] = [];
const arrowHeight = 0.2;
const arrowRadius = 0.05;
const segments = 8; // Fewer arrows for curved conveyors
points.forEach(segment => {
let vectorPoints = segment.map(p => new THREE.Vector3(...p));
if (!forward) vectorPoints.reverse();
for (let group = 0; group + 2 < vectorPoints.length; group += 2) {
const p0 = vectorPoints[group];
const p1 = vectorPoints[group + 1];
const p2 = vectorPoints[group + 2];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const point = new THREE.Vector3()
.copy(p0)
.multiplyScalar((1 - t) ** 2)
.addScaledVector(p1, 2 * (1 - t) * t)
.addScaledVector(p2, t ** 2);
const tangent = new THREE.Vector3()
.copy(p0)
.multiplyScalar(-2 * (1 - t))
.addScaledVector(p1, 2 - 4 * t)
.addScaledVector(p2, 2 * t)
.normalize();
// Create arrow group
const arrowGroup = new THREE.Group();
// Arrow shaft (cylinder)
const shaftLength = arrowHeight * 0.7;
const shaftGeometry = new THREE.CylinderGeometry(arrowRadius * 0.3, arrowRadius * 0.3, shaftLength, 8);
const shaftMaterial = new THREE.MeshBasicMaterial({
color: forward ? 0x00ff00 : 0xff0000
});
const shaft = new THREE.Mesh(shaftGeometry, shaftMaterial);
shaft.position.y = shaftLength / 2;
shaft.rotation.x = Math.PI / 2;
// Arrow head (cone)
const headGeometry = new THREE.ConeGeometry(arrowRadius, arrowHeight * 0.3, 8);
const headMaterial = new THREE.MeshBasicMaterial({
color: forward ? 0x00ff00 : 0xff0000
});
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.y = shaftLength;
// Position and orient the entire arrow
arrowGroup.add(shaft);
arrowGroup.add(head);
arrowGroup.position.copy(point);
arrowGroup.position.y += 0.1; // Slightly above conveyor
arrowGroup.quaternion.setFromUnitVectors(
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(tangent.x, 0.1, tangent.z)
);
arrows.push(arrowGroup);
}
}
});
arrowRefs.current = arrows;
return arrows;
}, [points, showDirection, forward]);
return (
<group
onPointerOver={() => {
setShowDirection(true);
setHoverState(true);
}}
onPointerOut={() => {
setShowDirection(false);
setHoverState(false);
}}
>
{geometries.map((geometry, index) => (
<mesh key={index} geometry={geometry}>
<meshStandardMaterial
color={forward ? "#64b5f6" : "#f48fb1"}
side={THREE.DoubleSide}
transparent
opacity={0.7}
/>
</mesh>
))}
</RigidBody>
)}
{/* Conveyor surface */}
{geometries.length > 0 && (
<RigidBody
key={geometryKey}
ref={conveyorRef}
type="fixed"
position={[0, 0.001, 0]}
userData={{ isConveyor: true }}
onCollisionEnter={handleMaterialEnter}
onCollisionExit={handleMaterialExit}
colliders="trimesh"
>
{geometries.map((geometry, index) => (
<mesh key={index} geometry={geometry}>
<meshStandardMaterial
color={forward ? "#64b5f6" : "#f48fb1"}
side={THREE.DoubleSide}
transparent
opacity={0.7}
visible={false}
/>
</mesh>
))}
</RigidBody>
)}
{/* Direction indicators */}
{showDirection && directionArrows?.map((arrow, i) => (
<primitive key={`arrow-${i}`} object={arrow} />
))}
{/* Direction indicators */}
{showDirection && directionArrows?.map((arrow, i) => (
<primitive key={`arrow-${i}`} object={arrow} />
))}
{/* Hover highlight */}
{hoverState && (
<group>
{geometries.map((geometry, index) => (
<mesh
key={`highlight-${index}`}
geometry={geometry}
position={[0, 0.002, 0]} // Slightly above conveyor
>
<meshBasicMaterial
color={forward ? "#00ff0044" : "#ff000044"}
transparent
opacity={0.3}
/>
</mesh>
))}
{/* Hover highlight */}
{hoverState && (
<group>
{geometries.map((geometry, index) => (
<mesh
key={`highlight-${index}`}
geometry={geometry}
position={[0, 0.002, 0]} // Slightly above conveyor
// visible={false}
>
<meshBasicMaterial
color={forward ? "#00ff0044" : "#ff000044"}
transparent
opacity={0.3}
/>
</mesh>
))}
</group>
)}
</group>
)}
</group>
);
);
}
export default CurvedConveyorCollider;

View File

@@ -20,7 +20,7 @@ function NormalConveyorCollider({ points, boundingBox, asset, forward, isPaused,
const conveyorSpeed = 2;
const lastClickTime = useRef(0);
const [hoverState, setHoverState] = useState(false);
const[localForward,setLocalForward]=useState()
const [localForward, setLocalForward] = useState()
useEffect(() => {
const handleClick = (e: MouseEvent) => {
@@ -215,6 +215,7 @@ function NormalConveyorCollider({ points, boundingBox, asset, forward, isPaused,
side={THREE.DoubleSide}
transparent
opacity={0.5}
visible={false}
/>
</mesh>
</RigidBody>
@@ -231,6 +232,7 @@ function NormalConveyorCollider({ points, boundingBox, asset, forward, isPaused,
key={`highlight-${index}`}
geometry={geometry}
position={[0, 0.002, 0]}
// visible={false}
>
<meshBasicMaterial
color={forward ? "#00ff0044" : "#ff000044"}

View File

@@ -26,8 +26,8 @@ function YSplitConveyorCollider({ points, boundingBox, asset, forward, isPaused,
if (e.button === 2) {
const now = Date.now();
if (now - lastClickTime.current < 300) {
if (onDirectionChange) {
console.log('forwardySplit: ', forward);
if (onDirectionChange) {
console.log('forwardySplit: ', forward);
onDirectionChange(!forward);
}
}
@@ -214,6 +214,7 @@ function YSplitConveyorCollider({ points, boundingBox, asset, forward, isPaused,
side={THREE.DoubleSide}
transparent
opacity={0.5}
visible={false}
/>
</mesh>
</RigidBody>
@@ -230,6 +231,7 @@ function YSplitConveyorCollider({ points, boundingBox, asset, forward, isPaused,
key={`highlight-${index}`}
geometry={geometry}
position={[0, 0.002, 0]}
// visible={false}
>
<meshBasicMaterial
color={forward ? "green" : "red"}

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { Canvas } from "@react-three/fiber";
import { Physics } from "@react-three/rapier";
import { Color, SRGBColorSpace } from "three";
@@ -8,7 +8,6 @@ import Builder from "../builder/builder";
import Visualization from "../visualization/visualization";
import Setup from "./setup/setup";
import Simulation from "../simulation/simulation";
import PhysicsSimulator from "./physics/physicsSimulator";
import Collaboration from "../collaboration/collaboration";
import useModuleStore from "../../store/useModuleStore";
import { useParams } from "react-router-dom";
@@ -19,6 +18,7 @@ import { useLoadingProgress, useSocketStore } from "../../store/builder/store";
import { compressImage } from "../../utils/compressImage";
export default function Scene({ layout }: { readonly layout: "Main Layout" | "Comparison Layout"; }) {
const [visible, setVisible] = useState(false);
const map = useMemo(() => [
{ name: "forward", keys: ["ArrowUp", "w", "W"] },
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
@@ -58,6 +58,18 @@ export default function Scene({ layout }: { readonly layout: "Main Layout" | "Co
// eslint-disable-next-line
}, [activeModule, assets, loadingProgress]);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "F1") {
event.preventDefault();
setVisible(prev => !prev);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, []);
return (
<KeyboardControls map={map}>
<Canvas
@@ -72,11 +84,9 @@ export default function Scene({ layout }: { readonly layout: "Main Layout" | "Co
>
<Setup />
<Collaboration />
<Physics gravity={[0, -9.81, 0]} allowedLinearError={50} numSolverIterations={50} debug >
<Physics gravity={[0, -9.81, 0]} allowedLinearError={50} numSolverIterations={50} debug={visible} >
<Builder />
{/* <Physics gravity={[0, -9.81, 0]} allowedLinearError={50} numSolverIterations={50} > */}
<Simulation />
<PhysicsSimulator />
</Physics>
<Visualization />
</Canvas>

View File

@@ -13,6 +13,7 @@ import Products from './products/products';
import Trigger from './triggers/trigger';
import useModuleStore from '../../store/useModuleStore';
import SimulationAnalysis from './analysis/simulationAnalysis';
import PhysicsSimulator from '../scene/physics/physicsSimulator';
import { useSceneContext } from '../scene/sceneContext';
function Simulation() {
@@ -62,6 +63,8 @@ function Simulation() {
<SimulationAnalysis />
<PhysicsSimulator />
</>
}