From b99791eabb0387c10d889a65114a06782931e2e2 Mon Sep 17 00:00:00 2001 From: Jens Schmidt Date: Tue, 16 Feb 2021 07:30:08 -0800 Subject: [PATCH] code review --- .../stories/BlenderViewportGizmo.stories.tsx | 10 +- .storybook/stories/ViewCubeGizmo.stories.tsx | 15 +-- README.md | 2 +- src/core/GizmoHelper.tsx | 32 ++--- src/core/index.ts | 2 - src/{core => web}/BlenderViewportGizmo.tsx | 37 +++--- src/{core => web}/ViewCubeGizmo.tsx | 114 ++++++++++-------- src/web/index.ts | 4 + 8 files changed, 120 insertions(+), 96 deletions(-) rename src/{core => web}/BlenderViewportGizmo.tsx (76%) rename src/{core => web}/ViewCubeGizmo.tsx (50%) diff --git a/.storybook/stories/BlenderViewportGizmo.stories.tsx b/.storybook/stories/BlenderViewportGizmo.stories.tsx index 9c269d8eb..7aba80a64 100644 --- a/.storybook/stories/BlenderViewportGizmo.stories.tsx +++ b/.storybook/stories/BlenderViewportGizmo.stories.tsx @@ -46,8 +46,10 @@ const BlenderViewportGizmoStory = () => { ) } +export const DefaultStory = () => ( + + + +) -export const BlenderViewportGizmoStorySt = () => -BlenderViewportGizmoStorySt.story = { - name: 'Default', -} +DefaultStory.storyName = 'Default' diff --git a/.storybook/stories/ViewCubeGizmo.stories.tsx b/.storybook/stories/ViewCubeGizmo.stories.tsx index b4c8ed798..66a475288 100644 --- a/.storybook/stories/ViewCubeGizmo.stories.tsx +++ b/.storybook/stories/ViewCubeGizmo.stories.tsx @@ -27,9 +27,7 @@ const ViewCubeGizmoStory = () => { return ( <> - - - + { ) } -export const ViewCubeGizmoStorySt = () => -ViewCubeGizmoStorySt.story = { - name: 'Default', -} +export const DefaultStory = () => ( + + + +) + +DefaultStory.storyName = 'Default' diff --git a/README.md b/README.md index 70316a401..e6a8de43c 100644 --- a/README.md +++ b/README.md @@ -282,7 +282,7 @@ Adds a `` that always faces the camera. Used by widgets that visualize and control camera position. -Two example gizmos are included: BlenderViewportGizmo and ViewCubeGizmo, and `useGizmoHelper` makes it easy to create your own. +Two example gizmos are included: BlenderViewportGizmo and ViewCubeGizmo, and `useGizmoContext` makes it easy to create your own. ```jsx ({} as GizmoHelperContext) -export const useGizmoHelper = () => { +export const useGizmoContext = () => { return React.useContext(Context) } @@ -41,15 +41,15 @@ export const GizmoHelper = ({ const gizmoRef = React.useRef() const virtualCam = React.useRef() const virtualScene = React.useMemo(() => new Scene(), []) - const [animating, setAnimating] = React.useState(false) - const [radius, setRadius] = React.useState(0) - const [focusPoint, setFocusPoint] = React.useState(new Vector3(0, 0, 0)) - function tweenCamera(direction: Vector3) { - const radius = mainCamera.position.distanceTo(target) - setRadius(radius) - setFocusPoint(onTarget()) - setAnimating(true) + const animating = React.useRef(false) + const radius = React.useRef(0) + const focusPoint = React.useRef(new Vector3(0, 0, 0)) + + const tweenCamera = (direction: Vector3) => { + animating.current = true + focusPoint.current = onTarget() + radius.current = mainCamera.position.distanceTo(target) // Rotate from current camera orientation dummy.position.copy(target) @@ -57,27 +57,27 @@ export const GizmoHelper = ({ q1.copy(dummy.quaternion) // To new current camera orientation - targetPosition.copy(direction).multiplyScalar(radius).add(target) + targetPosition.copy(direction).multiplyScalar(radius.current).add(target) dummy.lookAt(targetPosition) q2.copy(dummy.quaternion) } - function animateStep(delta: number): void { - if (!animating) return + const animateStep = (delta: number) => { + if (!animating.current) return const step = delta * turnRate // animate position by doing a slerp and then scaling the position on the unit sphere q1.rotateTowards(q2, step) - mainCamera.position.set(0, 0, 1).applyQuaternion(q1).multiplyScalar(radius).add(focusPoint) + mainCamera.position.set(0, 0, 1).applyQuaternion(q1).multiplyScalar(radius.current).add(focusPoint.current) // animate orientation mainCamera.quaternion.rotateTowards(targetQuaternion, step) mainCamera.updateProjectionMatrix() onUpdate && onUpdate() - if (q1.angleTo(q2) === 0) { - setAnimating(false) + if (q1.angleTo(q2) < 0.01) { + animating.current = false } } @@ -98,7 +98,7 @@ export const GizmoHelper = ({ gl.clearDepth() gl.render(virtualScene, virtualCam.current) } - }, 1) + }) const gizmoHelperContext = { tweenCamera, diff --git a/src/core/index.ts b/src/core/index.ts index 537a87ecf..be398903e 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -23,8 +23,6 @@ export * from './PointerLockControls' // Gizmos export * from './GizmoHelper' -export * from './BlenderViewportGizmo' -export * from './ViewCubeGizmo' // Loaders export * from './useCubeTexture' diff --git a/src/core/BlenderViewportGizmo.tsx b/src/web/BlenderViewportGizmo.tsx similarity index 76% rename from src/core/BlenderViewportGizmo.tsx rename to src/web/BlenderViewportGizmo.tsx index fe7a2a477..2870ef616 100644 --- a/src/core/BlenderViewportGizmo.tsx +++ b/src/web/BlenderViewportGizmo.tsx @@ -1,22 +1,29 @@ import * as React from 'react' -import { BoxGeometry, CanvasTexture, Event } from 'three' -import { useGizmoHelper } from './GizmoHelper' +import { CanvasTexture, Event } from 'three' +import { useGizmoContext } from '../core/GizmoHelper' -function Axis({ color, rotation }: JSX.IntrinsicElements['mesh'] & { color: string }) { - const geometry = React.useMemo(() => new BoxGeometry(0.8, 0.05, 0.05).translate(0.4, 0, 0), []) +type NewType = JSX.IntrinsicElements['mesh'] & { + color: string +} + +function Axis({ color, rotation }: NewType) { return ( - - - + + + + + + ) } -function AxisHead({ - arcStyle, - label, - labelColor, - ...props -}: JSX.IntrinsicElements['sprite'] & { arcStyle: string; label?: string; labelColor: string }) { +type AxisHeadProps = JSX.IntrinsicElements['sprite'] & { + arcStyle: string + label?: string + labelColor: string +} + +function AxisHead({ arcStyle, label, labelColor, ...props }: AxisHeadProps) { const texture = React.useMemo(() => { const canvas = document.createElement('canvas') canvas.width = 64 @@ -49,7 +56,7 @@ function AxisHead({ ) } -type BlenderViewportGizmoProps = { +type BlenderViewportGizmoProps = JSX.IntrinsicElements['group'] & { axisColors?: [string, string, string] labelColor?: string } @@ -60,7 +67,7 @@ export const BlenderViewportGizmo = ({ ...props }: BlenderViewportGizmoProps) => { const [colorX, colorY, colorZ] = axisColors - const { tweenCamera, raycast } = useGizmoHelper() + const { tweenCamera, raycast } = useGizmoContext() const axisHeadProps = { labelColor, onPointerDown: (e: Event) => void (tweenCamera(e.object.position), e.stopPropagation()), diff --git a/src/core/ViewCubeGizmo.tsx b/src/web/ViewCubeGizmo.tsx similarity index 50% rename from src/core/ViewCubeGizmo.tsx rename to src/web/ViewCubeGizmo.tsx index 424c9a16a..1aa454f7f 100644 --- a/src/core/ViewCubeGizmo.tsx +++ b/src/web/ViewCubeGizmo.tsx @@ -1,10 +1,27 @@ import * as React from 'react' +import { useGizmoContext } from '../core/GizmoHelper' import { CanvasTexture, Event, Vector3 } from 'three' -import { useGizmoHelper } from './GizmoHelper' -const faces = ['RIGHT', 'LEFT', 'TOP', 'BOTTOM', 'FRONT', 'BACK'] +type XYZ = [number, number, number] -const edges: Array<[number, number, number]> = [ +const faces = ['right', 'left', 'top', 'bottom', 'front', 'back'] + +const makePositionVector = (xyz) => new Vector3(...xyz).multiplyScalar(0.38) + +const corners: Vector3[] = [ + [1, 1, 1], + [1, 1, -1], + [1, -1, 1], + [1, -1, -1], + [-1, 1, 1], + [-1, 1, -1], + [-1, -1, 1], + [-1, -1, -1], +].map(makePositionVector) + +const cornerDimensions: XYZ = [0.25, 0.25, 0.25] + +const edges: Vector3[] = [ [1, 1, 0], [1, 0, 1], [1, 0, -1], @@ -17,18 +34,11 @@ const edges: Array<[number, number, number]> = [ [-1, 0, 1], [-1, 0, -1], [-1, -1, 0], -] +].map(makePositionVector) -const corners: Array<[number, number, number]> = [ - [1, 1, 1], - [1, 1, -1], - [1, -1, 1], - [1, -1, -1], - [-1, 1, 1], - [-1, 1, -1], - [-1, -1, 1], - [-1, -1, -1], -] +const edgeDimensions = edges.map( + (edge) => edge.toArray().map((axis: number): number => (axis == 0 ? 0.5 : 0.25)) as XYZ +) const FaceMaterial = ({ hover, index }: { hover: boolean; index: number }) => { const texture = React.useMemo(() => { @@ -45,21 +55,29 @@ const FaceMaterial = ({ hover, index }: { hover: boolean; index: number }) => { context.font = '28px Arial' context.textAlign = 'center' context.fillStyle = '#222' - context.fillText(faces[index], 64, 76) + context.fillText(faces[index].toUpperCase(), 64, 76) return new CanvasTexture(canvas) }, [index]) return } const FaceCube = () => { - const { tweenCamera, raycast } = useGizmoHelper() + const { tweenCamera, raycast } = useGizmoContext() const [hover, set] = React.useState(null) + const handlePointerDown = (e: Event) => { + tweenCamera(e.face.normal) + e.stopPropagation() + } + const handlePointerMove = (e: Event) => { + set(Math.floor(e.faceIndex / 2)) + e.stopPropagation() + } return ( set(null)} - onPointerMove={(e: Event) => set(Math.floor(e.faceIndex / 2))} - onPointerDown={(e: Event) => void (tweenCamera(e.face.normal), e.stopPropagation())} + onPointerMove={handlePointerMove} + onPointerDown={handlePointerDown} > {[...Array(6)].map((_, index) => ( @@ -69,41 +87,36 @@ const FaceCube = () => { ) } -const EdgeCube = ({ direction }: { direction: [number, number, number] }): JSX.Element => { - const [x, y, z] = direction - const dimensions: [number, number, number] = [x == 0 ? 1 / 2 : 1 / 4, y == 0 ? 1 / 2 : 1 / 4, z == 0 ? 1 / 2 : 1 / 4] - const { tweenCamera, raycast } = useGizmoHelper() - const [hover, set] = React.useState(false) - const position = new Vector3().set(...direction).setLength(1 - 1 / 2 + 0.1) - return ( - void (set(false), e.stopPropagation())} - onPointerOver={(e: Event) => void (set(true), e.stopPropagation())} - onPointerDown={(e: Event) => void (tweenCamera(position), e.stopPropagation())} - > - - - - ) +type EdgeCubeProps = { + dimensions: XYZ + position: Vector3 } -const CornerCube = ({ direction }: { direction: [number, number, number] }) => { - const size = 1 / 4 - const { tweenCamera, raycast } = useGizmoHelper() +const EdgeCube = ({ dimensions, position }: EdgeCubeProps): JSX.Element => { + const { tweenCamera, raycast } = useGizmoContext() const [hover, set] = React.useState(false) - const position = new Vector3().set(...direction).setLength(1 - 2 * size + 0.2) + const handlePointerOut = (e: Event) => { + set(false) + e.stopPropagation() + } + const handlePointerOver = (e: Event) => { + set(true) + e.stopPropagation() + } + const handlePointerDown = (e: Event) => { + tweenCamera(position) + e.stopPropagation() + } return ( void (set(false), e.stopPropagation())} - onPointerOver={(e: Event) => void (set(true), e.stopPropagation())} - onPointerDown={(e: Event) => void (tweenCamera(position), e.stopPropagation())} + onPointerOver={handlePointerOver} + onPointerOut={handlePointerOut} + onPointerDown={handlePointerDown} > - - + + ) } @@ -111,14 +124,13 @@ const CornerCube = ({ direction }: { direction: [number, number, number] }) => { export const ViewCubeGizmo = () => { return ( - {corners.map((corner, index) => ( - - ))} + {edges.map((edge, index) => ( - + + ))} + {corners.map((corner, index) => ( + ))} - - diff --git a/src/web/index.ts b/src/web/index.ts index 455eceafa..7f3eb1d44 100644 --- a/src/web/index.ts +++ b/src/web/index.ts @@ -2,5 +2,9 @@ export { Html } from './Html' export { Loader } from './Loader' +export { BlenderViewportGizmo } from './BlenderViewportGizmo' + +export { ViewCubeGizmo } from './ViewCubeGizmo' + export * from '../core' export * from '../materials'