From 872323ced236d758669877c60f6052e68c43729d Mon Sep 17 00:00:00 2001 From: Raphael Fakhri <153192858+RaphaelFakhri@users.noreply.github.com> Date: Mon, 19 Oct 2026 06:55:42 +0000 Subject: [PATCH] fix(N8AO): use the EffectComposer's camera and scene --- src/passes/N8AO.tsx | 7 ++++--- src/tests/N8AO.test.tsx | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/passes/N8AO.tsx b/src/passes/N8AO.tsx index f0f52c9..7e38cd2 100644 --- a/src/passes/N8AO.tsx +++ b/src/passes/N8AO.tsx @@ -2,10 +2,10 @@ // https://twitter.com/N8Programs/status/1660996748485984261 import { ReactThreeFiber, applyProps, useThree } from '@react-three/fiber' -import { Ref, useLayoutEffect, useMemo } from 'react' +import { Ref, use, useLayoutEffect, useMemo } from 'react' /* @ts-ignore */ import { N8AOPostPass } from 'n8ao' -import { groupPasses } from '../EffectComposer' +import { EffectComposerContext, groupPasses } from '../EffectComposer' import { useDispose } from '../util' export type N8AOProps = { @@ -41,7 +41,8 @@ export function N8AO({ renderMode = 0, ref, }: N8AOProps) { - const { camera, scene, invalidate } = useThree() + const { camera, scene } = use(EffectComposerContext) + const invalidate = useThree((state) => state.invalidate) const effect = useMemo(() => { const instance = new N8AOPostPass(scene, camera) // N8AOPostPass isn't a postprocessing Effect, so it's not mergeable via diff --git a/src/tests/N8AO.test.tsx b/src/tests/N8AO.test.tsx index 447dc7b..f9c6f9b 100644 --- a/src/tests/N8AO.test.tsx +++ b/src/tests/N8AO.test.tsx @@ -1,5 +1,6 @@ import { CopyPass, EffectComposer as EffectComposerImpl } from 'postprocessing' import * as React from 'react' +import { PerspectiveCamera, Scene } from 'three' import { describe, expect, it, vi } from 'vitest' import { EffectComposer } from '../EffectComposer' import { N8AO } from '../passes/N8AO' @@ -89,4 +90,29 @@ describe('N8AO', () => { await React.act(async () => root.render(null)) }) + + it("uses the EffectComposer's camera and scene props, not the canvas defaults", async () => { + const ref = React.createRef() + const cameraA = new PerspectiveCamera() + const cameraB = new PerspectiveCamera() + const scene = new Scene() + + const render = (camera: PerspectiveCamera) => + root.render( + + + + ) + + await React.act(async () => render(cameraA)) + await flush() + expect(ref.current.camera).toBe(cameraA) + expect(ref.current.scene).toBe(scene) + + await React.act(async () => render(cameraB)) + await flush() + expect(ref.current.camera).toBe(cameraB) + + await React.act(async () => root.render(null)) + }) })