diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 86c73ff..38faa9a 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -1,8 +1,14 @@ import { useIdeContext } from 'src/helpers/hooks/useIdeContext' -import { useRef, useState, useEffect, useLayoutEffect } from 'react' -import { Canvas, extend, useFrame, useThree } from '@react-three/fiber' -import { PerspectiveCamera, useEdgeSplit } from '@react-three/drei' -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' +import * as THREE from 'three' +import { useRef, useState, useEffect } from 'react' +import { Canvas, useThree } from '@react-three/fiber' +import { + PerspectiveCamera, + GizmoHelper, + GizmoViewport, + OrbitControls, +} from '@react-three/drei' +import { useEdgeSplit } from 'src/helpers/hooks/useEdegeSplit' import { Vector3 } from 'three' import { requestRender } from 'src/helpers/hooks/useIdeState' import texture from './dullFrontLitMetal.png' @@ -13,10 +19,15 @@ import DelayedPingAnimation from 'src/components/DelayedPingAnimation/DelayedPin const loader = new TextureLoader() const colorMap = loader.load(texture) -extend({ OrbitControls }) +const thresholdAngle = 12 function Asset({ geometry: incomingGeo }) { - const mesh = useEdgeSplit((12 * Math.PI) / 180, true) + const mesh = useEdgeSplit((thresholdAngle * Math.PI) / 180, true, incomingGeo) + const edges = React.useMemo( + () => + incomingGeo.length ? null : new THREE.EdgesGeometry(incomingGeo, thresholdAngle), + [incomingGeo] + ) if (!incomingGeo) return null if (incomingGeo.length) @@ -25,9 +36,14 @@ function Asset({ geometry: incomingGeo }) { )) return ( - - - + + + + + + + + ) } @@ -46,9 +62,6 @@ function Controls({ onCameraChange, onDragStart, onInit }) { camera.fov = 22.5 // matches default openscad fov camera.updateProjectionMatrix() - // Order matters with Euler rotations - // We want it to rotate around the z or vertical axis first then the x axis to match openscad - // in Three.js Y is the vertical axis (Z for openscad) camera.rotation._order = 'ZYX' const getRotations = (): number[] => { const { x, y, z } = camera?.rotation || {} @@ -104,13 +117,8 @@ function Controls({ onCameraChange, onDragStart, onInit }) { } }, [camera, controls]) - useFrame(() => controls.current?.update()) return ( - + ) } @@ -214,6 +222,12 @@ const IdeViewer = ({ Loading }) => { material-transparent rotation-x={Math.PI / 2} /> + + + {state.objectData?.type === 'png' && ( <> diff --git a/app/web/src/helpers/hooks/useEdegeSplit.ts b/app/web/src/helpers/hooks/useEdegeSplit.ts new file mode 100644 index 0000000..47d3bf1 --- /dev/null +++ b/app/web/src/helpers/hooks/useEdegeSplit.ts @@ -0,0 +1,30 @@ +// This code has been copied from https://github.com/pmndrs/drei/blob/master/src/core/useEdgeSplit.tsx +// but modified to allow for updating geometry with `dependantGeometry` + +import * as React from 'react' +import * as THREE from 'three' +import { EdgeSplitModifier } from 'three-stdlib' + +export function useEdgeSplit(cutOffAngle: number, tryKeepNormals: boolean = true, dependantGeometry?: any) { + const ref = React.useRef() + const original = React.useRef() + const modifier = React.useRef() + + React.useEffect(() => { + if (!original.current && ref.current) { + original.current = ref.current.geometry.clone() + modifier.current = new EdgeSplitModifier() + } + }, [dependantGeometry]) + + React.useEffect(() => { + if (original.current && ref.current && modifier.current) { + const modifiedGeometry = modifier.current.modify(original.current, cutOffAngle, tryKeepNormals) + modifiedGeometry.computeVertexNormals() + + ref.current.geometry = modifiedGeometry + } + }, [cutOffAngle, tryKeepNormals, dependantGeometry]) + + return ref +}