WIP: Upgrade to THREE 155: Upgrade OrbitControls
This commit is contained in:
parent
7a5b1c744c
commit
3837e179bb
14 changed files with 202 additions and 166 deletions
|
@ -31,13 +31,14 @@
|
|||
"@types/node": "^15.6.2",
|
||||
"@types/react": "^18.2.18",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"fast-glob": "^3.3.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"styled-components": "^5.3.5",
|
||||
"styled-components": "^5.3.11",
|
||||
"theatric": "workspace:*",
|
||||
"three": "^0.155.0",
|
||||
"typescript": "^4.4.2",
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
RawShaderMaterial,
|
||||
Scene,
|
||||
ShaderMaterial,
|
||||
SphereBufferGeometry,
|
||||
SphereGeometry,
|
||||
Vector2,
|
||||
Vector3,
|
||||
WebGLRenderer,
|
||||
|
@ -190,7 +190,7 @@ export default function ThreeScene(props: ThreeSceneProps) {
|
|||
light.position.set(1, 5, 4)
|
||||
scene.add(light)
|
||||
|
||||
mesh = new Mesh(new SphereBufferGeometry(3), new MeshPhongMaterial())
|
||||
mesh = new Mesh(new SphereGeometry(3), new MeshPhongMaterial())
|
||||
scene.add(mesh)
|
||||
|
||||
// RAF
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
"@types/node": "^15.6.2",
|
||||
"@types/react": "^18.2.18",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/styled-components": "^5.1.9",
|
||||
"@types/three": "0.131.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/three": "0.155.0",
|
||||
"esbuild": "^0.18.17",
|
||||
"esbuild-register": "^3.4.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
@ -66,18 +66,18 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.2.0",
|
||||
"react-merge-refs": "^1.1.0",
|
||||
"react-shadow": "^19.0.3",
|
||||
"react-use-measure": "^2.0.4",
|
||||
"react-merge-refs": "^2.0.2",
|
||||
"react-shadow": "^20.4.0",
|
||||
"react-use-measure": "^2.1.1",
|
||||
"reakit": "^1.3.8",
|
||||
"styled-components": "^5.3.5",
|
||||
"styled-components": "^5.3.11",
|
||||
"three": "0.155.0",
|
||||
"three-stdlib": "^2.24.1",
|
||||
"typescript": "^4.4.2",
|
||||
"zustand": "^3.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-three/fiber": ">=7.0.6",
|
||||
"@react-three/fiber": "^8.13.6",
|
||||
"@theatre/core": "*",
|
||||
"@theatre/studio": "*",
|
||||
"react": ">=17.0.2",
|
||||
|
|
|
@ -4,7 +4,7 @@ import type {
|
|||
Object3D,
|
||||
} from 'three'
|
||||
import {useFrame, useThree} from '@react-three/fiber'
|
||||
import mergeRefs from 'react-merge-refs'
|
||||
import {mergeRefs} from 'react-merge-refs'
|
||||
import {editable} from '../index'
|
||||
import {Vector3} from 'three'
|
||||
import type {MutableRefObject} from 'react'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import type {PerspectiveCamera as PerspectiveCameraImpl, Object3D} from 'three'
|
||||
import {useFrame, useThree} from '@react-three/fiber'
|
||||
import mergeRefs from 'react-merge-refs'
|
||||
import {mergeRefs} from 'react-merge-refs'
|
||||
import {editable} from '../index'
|
||||
import {Vector3} from 'three'
|
||||
import {editorStore} from '../main/store'
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* eslint-disable */
|
||||
import type {Matrix4} from 'three'
|
||||
import {
|
||||
Camera,
|
||||
EventDispatcher,
|
||||
Matrix4,
|
||||
MOUSE,
|
||||
OrthographicCamera,
|
||||
PerspectiveCamera,
|
||||
|
@ -13,6 +11,9 @@ import {
|
|||
Vector3,
|
||||
} from 'three'
|
||||
|
||||
// Almost an exact copy of https://github.com/pmndrs/three-stdlib/blob/4c04593ee49bb0b022025718844f3ce2b21f67bf/src/controls/OrbitControls.ts
|
||||
// The only change is that we added `(if (altKey)` at line 866 to only rotate if alt key is pressed
|
||||
|
||||
// This set of controls performs orbiting, dollying (zooming), and panning.
|
||||
// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
|
||||
//
|
||||
|
@ -23,8 +24,8 @@ import {
|
|||
const moduloWrapAround = (offset: number, capacity: number) =>
|
||||
((offset % capacity) + capacity) % capacity
|
||||
|
||||
class OrbitControlsImpl extends EventDispatcher {
|
||||
object: Camera
|
||||
class OrbitControls extends EventDispatcher {
|
||||
object: PerspectiveCamera | OrthographicCamera
|
||||
domElement: HTMLElement | undefined
|
||||
// Set to false to disable this control
|
||||
enabled = true
|
||||
|
@ -73,13 +74,20 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
BOTTOM: 'ArrowDown',
|
||||
}
|
||||
// Mouse buttons
|
||||
mouseButtons = {
|
||||
mouseButtons: Partial<{
|
||||
LEFT: MOUSE
|
||||
MIDDLE: MOUSE
|
||||
RIGHT: MOUSE
|
||||
}> = {
|
||||
LEFT: MOUSE.ROTATE,
|
||||
MIDDLE: MOUSE.DOLLY,
|
||||
RIGHT: MOUSE.PAN,
|
||||
}
|
||||
// Touch fingers
|
||||
touches = {ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN}
|
||||
touches: Partial<{
|
||||
ONE: TOUCH
|
||||
TWO: TOUCH
|
||||
}> = {ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN}
|
||||
target0: Vector3
|
||||
position0: Vector3
|
||||
zoom0: number
|
||||
|
@ -93,13 +101,17 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
getDistance: () => number
|
||||
|
||||
listenToKeyEvents: (domElement: HTMLElement) => void
|
||||
stopListenToKeyEvents: () => void
|
||||
saveState: () => void
|
||||
reset: () => void
|
||||
update: () => void
|
||||
connect: (domElement: HTMLElement) => void
|
||||
dispose: () => void
|
||||
|
||||
constructor(object: Camera, domElement?: HTMLElement) {
|
||||
constructor(
|
||||
object: PerspectiveCamera | OrthographicCamera,
|
||||
domElement?: HTMLElement,
|
||||
) {
|
||||
super()
|
||||
|
||||
this.object = object
|
||||
|
@ -108,7 +120,7 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
// for reset
|
||||
this.target0 = this.target.clone()
|
||||
this.position0 = this.object.position.clone()
|
||||
this.zoom0 = this.object instanceof PerspectiveCamera ? this.object.zoom : 1
|
||||
this.zoom0 = this.object.zoom
|
||||
|
||||
//
|
||||
// public methods
|
||||
|
@ -166,20 +178,22 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
this._domElementKeyEvents = domElement
|
||||
}
|
||||
|
||||
this.stopListenToKeyEvents = (): void => {
|
||||
this._domElementKeyEvents.removeEventListener('keydown', onKeyDown)
|
||||
this._domElementKeyEvents = null
|
||||
}
|
||||
|
||||
this.saveState = (): void => {
|
||||
scope.target0.copy(scope.target)
|
||||
scope.position0.copy(scope.object.position)
|
||||
scope.zoom0 =
|
||||
scope.object instanceof PerspectiveCamera ? scope.object.zoom : 1
|
||||
scope.zoom0 = scope.object.zoom
|
||||
}
|
||||
|
||||
this.reset = (): void => {
|
||||
scope.target.copy(scope.target0)
|
||||
scope.object.position.copy(scope.position0)
|
||||
if (scope.object instanceof PerspectiveCamera) {
|
||||
scope.object.zoom = scope.zoom0
|
||||
scope.object.updateProjectionMatrix()
|
||||
}
|
||||
scope.object.zoom = scope.zoom0
|
||||
scope.object.updateProjectionMatrix()
|
||||
|
||||
scope.dispatchEvent(changeEvent)
|
||||
|
||||
|
@ -191,12 +205,10 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
// this method is exposed, but perhaps it would be better if we can make it private...
|
||||
this.update = ((): (() => void) => {
|
||||
const offset = new Vector3()
|
||||
const up = new Vector3(0, 1, 0)
|
||||
|
||||
// so camera.up is the orbit axis
|
||||
const quat = new Quaternion().setFromUnitVectors(
|
||||
object.up,
|
||||
new Vector3(0, 1, 0),
|
||||
)
|
||||
const quat = new Quaternion().setFromUnitVectors(object.up, up)
|
||||
const quatInverse = quat.clone().invert()
|
||||
|
||||
const lastPosition = new Vector3()
|
||||
|
@ -207,6 +219,10 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
return function update(): boolean {
|
||||
const position = scope.object.position
|
||||
|
||||
// update new up direction
|
||||
quat.setFromUnitVectors(object.up, up)
|
||||
quatInverse.copy(quat).invert()
|
||||
|
||||
offset.copy(position).sub(scope.target)
|
||||
|
||||
// rotate offset to "y-axis-is-up" space
|
||||
|
@ -1059,8 +1075,11 @@ class OrbitControlsImpl extends EventDispatcher {
|
|||
// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
|
||||
// Pan - left mouse, or arrow keys / touch: one-finger move
|
||||
|
||||
class MapControls extends OrbitControlsImpl {
|
||||
constructor(object: Camera, domElement?: HTMLElement) {
|
||||
class MapControls extends OrbitControls {
|
||||
constructor(
|
||||
object: PerspectiveCamera | OrthographicCamera,
|
||||
domElement?: HTMLElement,
|
||||
) {
|
||||
super(object, domElement)
|
||||
|
||||
this.screenSpacePanning = false // pan orthogonal to world-space direction camera.up
|
||||
|
@ -1073,4 +1092,4 @@ class MapControls extends OrbitControlsImpl {
|
|||
}
|
||||
}
|
||||
|
||||
export {OrbitControlsImpl, MapControls}
|
||||
export {OrbitControls as OrbitControlsImpl, MapControls}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import type {EventManager, ReactThreeFiber} from '@react-three/fiber'
|
||||
import {useFrame, useThree} from '@react-three/fiber'
|
||||
import * as React from 'react'
|
||||
import {forwardRef, useEffect, useMemo} from 'react'
|
||||
import type {Camera, Event} from 'three'
|
||||
import {OrbitControlsImpl as OrbitControlsImpl} from './OrbitControlsImpl'
|
||||
import {OrbitControlsImpl} from './OrbitControlsImpl'
|
||||
|
||||
export type OrbitControlsChangeEvent = Event & {
|
||||
target: EventTarget & {object: Camera}
|
||||
}
|
||||
|
||||
export type OrbitControlsProps = Omit<
|
||||
ReactThreeFiber.Overwrite<
|
||||
|
@ -13,17 +16,21 @@ export type OrbitControlsProps = Omit<
|
|||
domElement?: HTMLElement
|
||||
enableDamping?: boolean
|
||||
makeDefault?: boolean
|
||||
onChange?: (e?: Event) => void
|
||||
onChange?: (e?: OrbitControlsChangeEvent) => void
|
||||
onEnd?: (e?: Event) => void
|
||||
onStart?: (e?: Event) => void
|
||||
regress?: boolean
|
||||
target?: ReactThreeFiber.Vector3
|
||||
keyEvents?: boolean | HTMLElement
|
||||
}
|
||||
>,
|
||||
'ref'
|
||||
>
|
||||
|
||||
export const OrbitControls = forwardRef<OrbitControlsImpl, OrbitControlsProps>(
|
||||
export const OrbitControls = React.forwardRef<
|
||||
OrbitControlsImpl,
|
||||
OrbitControlsProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
makeDefault,
|
||||
|
@ -31,6 +38,7 @@ export const OrbitControls = forwardRef<OrbitControlsImpl, OrbitControlsProps>(
|
|||
regress,
|
||||
domElement,
|
||||
enableDamping = true,
|
||||
keyEvents = false,
|
||||
onChange,
|
||||
onStart,
|
||||
onEnd,
|
||||
|
@ -38,56 +46,67 @@ export const OrbitControls = forwardRef<OrbitControlsImpl, OrbitControlsProps>(
|
|||
},
|
||||
ref,
|
||||
) => {
|
||||
const invalidate = useThree(({invalidate}) => invalidate)
|
||||
const defaultCamera = useThree(({camera}) => camera)
|
||||
const gl = useThree(({gl}) => gl)
|
||||
const events = useThree(({events}) => events) as EventManager<HTMLElement>
|
||||
const set = useThree(({set}) => set)
|
||||
const get = useThree(({get}) => get)
|
||||
const performance = useThree(({performance}) => performance)
|
||||
const explCamera = camera || defaultCamera
|
||||
const explDomElement =
|
||||
domElement ||
|
||||
(typeof events.connected !== 'boolean' ? events.connected : gl.domElement)
|
||||
const controls = useMemo(
|
||||
const invalidate = useThree((state) => state.invalidate)
|
||||
const defaultCamera = useThree((state) => state.camera)
|
||||
const gl = useThree((state) => state.gl)
|
||||
const events = useThree(
|
||||
(state) => state.events,
|
||||
) as EventManager<HTMLElement>
|
||||
const setEvents = useThree((state) => state.setEvents)
|
||||
const set = useThree((state) => state.set)
|
||||
const get = useThree((state) => state.get)
|
||||
const performance = useThree((state) => state.performance)
|
||||
const explCamera = (camera || defaultCamera) as
|
||||
| THREE.OrthographicCamera
|
||||
| THREE.PerspectiveCamera
|
||||
const explDomElement = (domElement ||
|
||||
events.connected ||
|
||||
gl.domElement) as HTMLElement
|
||||
const controls = React.useMemo(
|
||||
() => new OrbitControlsImpl(explCamera),
|
||||
[explCamera],
|
||||
)
|
||||
|
||||
useFrame(() => {
|
||||
if (controls.enabled) controls.update()
|
||||
})
|
||||
}, -1)
|
||||
|
||||
useEffect(() => {
|
||||
const callback = (e: Event) => {
|
||||
React.useEffect(() => {
|
||||
if (keyEvents) {
|
||||
controls.connect(keyEvents === true ? explDomElement : keyEvents)
|
||||
}
|
||||
|
||||
controls.connect(explDomElement)
|
||||
return () => void controls.dispose()
|
||||
}, [keyEvents, explDomElement, regress, controls, invalidate])
|
||||
|
||||
React.useEffect(() => {
|
||||
const callback = (e: OrbitControlsChangeEvent) => {
|
||||
invalidate()
|
||||
if (regress) performance.regress()
|
||||
if (onChange) onChange(e)
|
||||
}
|
||||
|
||||
controls.connect(explDomElement!)
|
||||
controls.addEventListener('change', callback)
|
||||
const onStartCb = (e: Event) => {
|
||||
if (onStart) onStart(e)
|
||||
}
|
||||
|
||||
if (onStart) controls.addEventListener('start', onStart)
|
||||
if (onEnd) controls.addEventListener('end', onEnd)
|
||||
const onEndCb = (e: Event) => {
|
||||
if (onEnd) onEnd(e)
|
||||
}
|
||||
|
||||
controls.addEventListener('change', callback)
|
||||
controls.addEventListener('start', onStartCb)
|
||||
controls.addEventListener('end', onEndCb)
|
||||
|
||||
return () => {
|
||||
controls.removeEventListener('start', onStartCb)
|
||||
controls.removeEventListener('end', onEndCb)
|
||||
controls.removeEventListener('change', callback)
|
||||
if (onStart) controls.removeEventListener('start', onStart)
|
||||
if (onEnd) controls.removeEventListener('end', onEnd)
|
||||
controls.dispose()
|
||||
}
|
||||
}, [
|
||||
explDomElement,
|
||||
onChange,
|
||||
onStart,
|
||||
onEnd,
|
||||
regress,
|
||||
controls,
|
||||
invalidate,
|
||||
])
|
||||
}, [onChange, onStart, onEnd, controls, invalidate, setEvents])
|
||||
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
if (makeDefault) {
|
||||
const old = get().controls
|
||||
set({controls})
|
||||
|
@ -105,5 +124,4 @@ export const OrbitControls = forwardRef<OrbitControlsImpl, OrbitControlsProps>(
|
|||
)
|
||||
},
|
||||
)
|
||||
|
||||
export {OrbitControlsImpl}
|
||||
|
|
|
@ -2,7 +2,7 @@ import type {ComponentProps, ComponentType, Ref, RefAttributes} from 'react'
|
|||
import {useMemo, useState} from 'react'
|
||||
import React, {forwardRef, useEffect, useLayoutEffect, useRef} from 'react'
|
||||
import {allRegisteredObjects, editorStore} from './store'
|
||||
import mergeRefs from 'react-merge-refs'
|
||||
import {mergeRefs} from 'react-merge-refs'
|
||||
import useInvalidate from './useInvalidate'
|
||||
import {useCurrentSheet} from './SheetProvider'
|
||||
import defaultEditableFactoryConfig from './defaultEditableFactoryConfig'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue