Add instant editable cameras to the r3f extension (#315)
Add spruced up editable orthographic/perspective camera
This commit is contained in:
parent
25cf1d7fe8
commit
6497bf2097
5 changed files with 182 additions and 13 deletions
87
packages/r3f/src/drei/OrthographicCamera.tsx
Normal file
87
packages/r3f/src/drei/OrthographicCamera.tsx
Normal file
|
@ -0,0 +1,87 @@
|
|||
import * as React from 'react'
|
||||
import type {
|
||||
OrthographicCamera as OrthographicCameraImpl,
|
||||
Object3D,
|
||||
} from 'three'
|
||||
import {useFrame, useThree} from '@react-three/fiber'
|
||||
import mergeRefs from 'react-merge-refs'
|
||||
import {editable} from '../index'
|
||||
import {Vector3} from 'three'
|
||||
import type {MutableRefObject} from 'react'
|
||||
import {editorStore} from '../main/store'
|
||||
|
||||
export type OrthographicCameraProps = Omit<
|
||||
JSX.IntrinsicElements['orthographicCamera'],
|
||||
'lookAt'
|
||||
> & {
|
||||
lookAt?:
|
||||
| [number, number, number]
|
||||
| Vector3
|
||||
| MutableRefObject<Object3D | null | undefined>
|
||||
makeDefault?: boolean
|
||||
manual?: boolean
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
export const OrthographicCamera = editable(
|
||||
React.forwardRef(
|
||||
({makeDefault, lookAt, ...props}: OrthographicCameraProps, ref) => {
|
||||
const set = useThree(({set}) => set)
|
||||
const camera = useThree(({camera}) => camera)
|
||||
const size = useThree(({size}) => size)
|
||||
const cameraRef = React.useRef<OrthographicCameraImpl>(null!)
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
if (!props.manual) {
|
||||
cameraRef.current.updateProjectionMatrix()
|
||||
}
|
||||
}, [size, props])
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
cameraRef.current.updateProjectionMatrix()
|
||||
})
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
if (makeDefault) {
|
||||
const oldCam = camera
|
||||
set(() => ({camera: cameraRef.current!}))
|
||||
return () => set(() => ({camera: oldCam}))
|
||||
}
|
||||
// The camera should not be part of the dependency list because this components camera is a stable reference
|
||||
// that must exchange the default, and clean up after itself on unmount.
|
||||
}, [cameraRef, makeDefault, set])
|
||||
|
||||
useFrame(() => {
|
||||
if (lookAt && cameraRef.current) {
|
||||
cameraRef.current.lookAt(
|
||||
Array.isArray(lookAt)
|
||||
? new Vector3(...lookAt)
|
||||
: (lookAt as MutableRefObject<Object3D>).current
|
||||
? (lookAt as MutableRefObject<Object3D>).current.position
|
||||
: (lookAt as Vector3),
|
||||
)
|
||||
|
||||
// how could we make it possible for users to do something like this too?
|
||||
const snapshot = editorStore.getState().editablesSnapshot
|
||||
if (snapshot) {
|
||||
snapshot[
|
||||
cameraRef.current.userData.__storeKey
|
||||
].proxyObject?.rotation.copy(cameraRef.current.rotation)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<orthographicCamera
|
||||
left={size.width / -2}
|
||||
right={size.width / 2}
|
||||
top={size.height / 2}
|
||||
bottom={size.height / -2}
|
||||
ref={mergeRefs([cameraRef, ref])}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
},
|
||||
),
|
||||
'orthographicCamera',
|
||||
)
|
75
packages/r3f/src/drei/PerspectiveCamera.tsx
Normal file
75
packages/r3f/src/drei/PerspectiveCamera.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
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 {editable} from '../index'
|
||||
import {Vector3} from 'three'
|
||||
import {editorStore} from '../main/store'
|
||||
import type {MutableRefObject} from 'react'
|
||||
|
||||
export type PerspectiveCameraProps = Omit<
|
||||
JSX.IntrinsicElements['perspectiveCamera'],
|
||||
'lookAt'
|
||||
> & {
|
||||
lookAt?:
|
||||
| [number, number, number]
|
||||
| Vector3
|
||||
| MutableRefObject<Object3D | null | undefined>
|
||||
makeDefault?: boolean
|
||||
manual?: boolean
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
export const PerspectiveCamera = editable(
|
||||
React.forwardRef(
|
||||
({makeDefault, lookAt, ...props}: PerspectiveCameraProps, ref) => {
|
||||
const set = useThree(({set}) => set)
|
||||
const camera = useThree(({camera}) => camera)
|
||||
const size = useThree(({size}) => size)
|
||||
const cameraRef = React.useRef<PerspectiveCameraImpl>(null!)
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
if (!props.manual) {
|
||||
cameraRef.current.aspect = size.width / size.height
|
||||
}
|
||||
}, [size, props])
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
cameraRef.current.updateProjectionMatrix()
|
||||
})
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
if (makeDefault) {
|
||||
const oldCam = camera
|
||||
set(() => ({camera: cameraRef.current!}))
|
||||
return () => set(() => ({camera: oldCam}))
|
||||
}
|
||||
// The camera should not be part of the dependency list because this components camera is a stable reference
|
||||
// that must exchange the default, and clean up after itself on unmount.
|
||||
}, [cameraRef, makeDefault, set])
|
||||
|
||||
useFrame(() => {
|
||||
if (lookAt && cameraRef.current) {
|
||||
cameraRef.current.lookAt(
|
||||
Array.isArray(lookAt)
|
||||
? new Vector3(...lookAt)
|
||||
: (lookAt as MutableRefObject<Object3D>).current
|
||||
? (lookAt as MutableRefObject<Object3D>).current.position
|
||||
: (lookAt as Vector3),
|
||||
)
|
||||
|
||||
// how could we make it possible for users to do something like this too?
|
||||
const snapshot = editorStore.getState().editablesSnapshot
|
||||
if (snapshot) {
|
||||
snapshot[
|
||||
cameraRef.current.userData.__storeKey
|
||||
].proxyObject?.rotation.copy(cameraRef.current.rotation)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return <perspectiveCamera ref={mergeRefs([cameraRef, ref])} {...props} />
|
||||
},
|
||||
),
|
||||
'perspectiveCamera',
|
||||
)
|
2
packages/r3f/src/drei/index.ts
Normal file
2
packages/r3f/src/drei/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './PerspectiveCamera'
|
||||
export * from './OrthographicCamera'
|
Loading…
Add table
Add a link
Reference in a new issue