Skip to content

Commit

Permalink
Merge pull request #2805 from Nicetouchco/feat/scene-prop
Browse files Browse the repository at this point in the history
[v9] feat: `scene` render prop for custom THREE.Scene (#2803)
  • Loading branch information
krispya authored May 30, 2023
2 parents c25f990 + 76276c0 commit 6a873aa
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 3 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
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/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 6a873aa

Please sign in to comment.