Skip to content

Commit

Permalink
Merge branch 'v9' into experiment/object-constructor-effects
Browse files Browse the repository at this point in the history
  • Loading branch information
krispya committed Jun 5, 2023
2 parents 5883610 + 35333c9 commit a83e06e
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/API/canvas.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const App = () => (
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| children | three.js JSX elements or regular components | |
| gl | Props that go into the default renderer, or your own renderer. Also accepts a synchronous callback like `gl={canvas => new Renderer({ canvas })}` | `{}` |
| scene | Props that go into the default camera, or your own `THREE.Scene` | `{}` |
| camera | Props that go into the default camera, or your own `THREE.Camera` | `{ fov: 75, near: 0.1, far: 1000, position: [0, 0, 5] }` |
| shadows | Props that go into `gl.shadowMap`, can be set true for `PCFsoft` or one of the following: 'basic', 'percentage', 'soft', 'variance' | `false` |
| raycaster | Props that go into the default raycaster | `{}` |
Expand Down
19 changes: 15 additions & 4 deletions packages/fiber/src/core/reconciler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ import * as THREE from 'three'
import Reconciler from 'react-reconciler'
import { ContinuousEventPriority, DiscreteEventPriority, DefaultEventPriority } from 'react-reconciler/constants'
import { unstable_IdlePriority as idlePriority, unstable_scheduleCallback as scheduleCallback } from 'scheduler'
import { is, diffProps, applyProps, invalidateInstance, attach, detach, prepare, globalScope, now } from './utils'
import {
is,
diffProps,
applyProps,
invalidateInstance,
attach,
detach,
prepare,
globalScope,
now,
isObject3D,
} from './utils'
import type { RootStore } from './store'
import { removeInteractivity, type EventHandlers } from './events'

Expand Down Expand Up @@ -176,7 +187,7 @@ function removeChild(
// Eagerly tear down tree
if (child.props.attach) {
detach(parent, child)
} else if (child.object instanceof THREE.Object3D && parent.object instanceof THREE.Object3D) {
} else if (isObject3D(child.object) && isObject3D(parent.object)) {
parent.object.remove(child.object)
removeInteractivity(child.root, child.object)
}
Expand Down Expand Up @@ -351,7 +362,7 @@ export const reconciler = Reconciler<
hideInstance(instance) {
if (instance.props.attach && instance.parent?.object) {
detach(instance.parent, instance)
} else if (instance.object instanceof THREE.Object3D) {
} else if (isObject3D(instance.object)) {
instance.object.visible = false
}

Expand All @@ -362,7 +373,7 @@ export const reconciler = Reconciler<
if (instance.isHidden) {
if (instance.props.attach && instance.parent?.object) {
attach(instance.parent, instance)
} else if (instance.object instanceof THREE.Object3D && instance.props.visible !== false) {
} else if (isObject3D(instance.object) && instance.props.visible !== false) {
instance.object.visible = true
}
}
Expand Down
20 changes: 20 additions & 0 deletions packages/fiber/src/core/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
updateCamera,
applyProps,
ColorManagement,
prepare,
} from './utils'
import { useStore } from './hooks'
import { Stage, Lifecycle, Stages } from './stages'
Expand Down Expand Up @@ -101,6 +102,8 @@ export interface RenderProps<TCanvas extends Canvas> {
dpr?: Dpr
/** Props that go into the default raycaster */
raycaster?: Partial<THREE.Raycaster>
/** A `THREE.Scene` instance or props that go into the default scene */
scene?: THREE.Scene | Partial<THREE.Scene>
/** A `THREE.Camera` instance or props that go into the default camera */
camera?: CameraProps
/** An R3F event manager to manage elements' pointer events */
Expand Down Expand Up @@ -220,6 +223,7 @@ export function createRoot<TCanvas extends Canvas>(canvas: TCanvas): ReconcilerR
let {
gl: glConfig,
size: propsSize,
scene: sceneOptions,
events,
onCreated: onCreatedCallback,
shadows = false,
Expand Down Expand Up @@ -269,6 +273,22 @@ export function createRoot<TCanvas extends Canvas>(canvas: TCanvas): ReconcilerR
state.set({ camera })
}

// Set up scene (one time only!)
if (!state.scene) {
let scene: THREE.Scene

if (sceneOptions instanceof THREE.Scene) {
scene = sceneOptions
prepare(scene, store, '', {})
} else {
scene = new THREE.Scene()
prepare(scene, store, '', {})
if (sceneOptions) applyProps(scene as any, sceneOptions as any)
}

state.set({ scene })
}

// Set up XR (one time only!)
if (!state.xr) {
// Handle frame behavior in WebXR
Expand Down
4 changes: 1 addition & 3 deletions packages/fiber/src/core/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ export const createStore = (
camera: null as unknown as Camera,
raycaster: null as unknown as THREE.Raycaster,
events: { priority: 1, enabled: true, connected: false },
scene: null as unknown as THREE.Scene,
xr: null as unknown as XRManager,

invalidate: (frames = 1) => invalidate(get(), frames),
Expand All @@ -221,7 +222,6 @@ export const createStore = (
legacy: false,
linear: false,
flat: false,
scene: new THREE.Scene(),

controls: null,
clock: new THREE.Clock(),
Expand Down Expand Up @@ -355,8 +355,6 @@ export const createStore = (

const state = rootStore.getState()

prepare(state.scene, rootStore, '', {})

let oldSize = state.size
let oldDpr = state.viewport.dpr
let oldCamera = state.camera
Expand Down
2 changes: 2 additions & 0 deletions packages/fiber/src/core/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,5 @@ export const globalScope =
(typeof global !== 'undefined' && global) ||
(typeof self !== 'undefined' && self) ||
(typeof window !== 'undefined' && window)

export const isObject3D = (object: any): object is THREE.Object3D => object?.isObject3D
2 changes: 2 additions & 0 deletions packages/fiber/src/native/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const CanvasImpl = /*#__PURE__*/ React.forwardRef<View, CanvasProps>(
onPointerMissed,
onCreated,
stages,
scene,
...props
},
forwardedRef,
Expand Down Expand Up @@ -100,6 +101,7 @@ const CanvasImpl = /*#__PURE__*/ React.forwardRef<View, CanvasProps>(
raycaster,
camera,
stages,
scene,
// expo-gl can only render at native dpr/resolution
// https://github.com/expo/expo-three/issues/39
dpr: PixelRatio.get(),
Expand Down
2 changes: 2 additions & 0 deletions packages/fiber/src/web/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const CanvasImpl = /*#__PURE__*/ React.forwardRef<HTMLCanvasElement, CanvasProps
onPointerMissed,
onCreated,
stages,
scene,
...props
},
forwardedRef,
Expand Down Expand Up @@ -100,6 +101,7 @@ const CanvasImpl = /*#__PURE__*/ React.forwardRef<HTMLCanvasElement, CanvasProps
raycaster,
camera,
stages,
scene,
size: containerRect,
// Pass mutable reference to onPointerMissed so it's free to update
onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
Expand Down
28 changes: 28 additions & 0 deletions packages/fiber/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,34 @@ describe('createRoot', () => {
expect(gl.physicallyCorrectLights).toBe(true)
})

it('should update scene via scene prop', async () => {
let scene: THREE.Scene = null!

await act(async () => {
scene = root
.configure({ scene: { name: 'test' } })
.render(<group />)
.getState().scene
})

expect(scene.name).toBe('test')
})

it('should set a custom scene via scene prop', async () => {
let scene: THREE.Scene = null!

const prop = new THREE.Scene()

await act(async () => {
scene = root
.configure({ scene: prop })
.render(<group />)
.getState().scene
})

expect(prop).toBe(scene)
})

it('should set a renderer via gl callback', async () => {
class Renderer extends THREE.WebGLRenderer {}

Expand Down

0 comments on commit a83e06e

Please sign in to comment.