Implement dynamic scene trees in r3f

This makes it possible to add/remove objects on the fly, do hot-module reloading, change object configs on the fly, and more.
This commit is contained in:
Aria Minaei 2022-10-18 10:18:10 +02:00 committed by Aria
parent 151fcce298
commit a9c3c00153
4 changed files with 95 additions and 41 deletions

View file

@ -43,21 +43,21 @@ const EditableProxy: VFC<EditableProxyProps> = ({storeKey, object}) => {
useLayoutEffect(() => {
const originalVisibility = object.visible
if (editable.visibleOnlyInEditor) {
if (editable?.visibleOnlyInEditor) {
object.visible = true
}
return () => {
object.visible = originalVisibility
}
}, [editable.visibleOnlyInEditor, object.visible])
}, [editable?.visibleOnlyInEditor, object.visible])
const [hovered, setHovered] = useState(false)
// Helpers
const scene = useThree((state) => state.scene)
const helper = useMemo<Helper | undefined>(
() => editable.objectConfig.createHelper?.(object),
() => editable?.objectConfig.createHelper?.(object),
[object],
)
useEffect(() => {
@ -92,6 +92,7 @@ const EditableProxy: VFC<EditableProxyProps> = ({storeKey, object}) => {
// subscribe to external changes
useEffect(() => {
if (!editable) return
const sheetObject = editable.sheetObject
const objectConfig = editable.objectConfig
@ -114,6 +115,8 @@ const EditableProxy: VFC<EditableProxyProps> = ({storeKey, object}) => {
}
}, [editable])
if (!editable) return null
return (
<>
<group

View file

@ -58,18 +58,19 @@ const ProxyManager: VFC<ProxyManagerProps> = ({orbitControlsRef}) => {
sceneProxy.traverse((object) => {
if (object.userData.__editable) {
// there are duplicate theatreKeys in the scene, only display one instance in the editor
if (editableProxies[object.userData.__storeKey]) {
const theatreKey = object.userData.__storeKey
if (
// there are duplicate theatreKeys in the scene, only display one instance in the editor
editableProxies[theatreKey] ||
// this object has been unmounted
!editables[theatreKey]
) {
object.parent!.remove(object)
} else {
const theatreKey = object.userData.__storeKey
editableProxies[theatreKey] = {
portal: createPortal(
<EditableProxy
storeKey={object.userData.__storeKey}
object={object}
/>,
<EditableProxy storeKey={theatreKey} object={object} />,
object.parent!,
),
object: object,