Last active
August 27, 2020 13:45
-
-
Save CharlieHess/203a561288f7b3b78eb2a3527ba21aa9 to your computer and use it in GitHub Desktop.
Helpers to track OutlinePass selection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Scene() { | |
return ( | |
<Canvas> | |
<OutlineItemsProvider> | |
<SomeMesh /> | |
<SomeMesh /> | |
<SomeMesh /> | |
<Effects /> | |
</OutlineItemsProvider> | |
</Canvas> | |
); | |
} | |
function Effects() { | |
const { gl, scene, camera, size } = useThree(); | |
const composer = useRef<EffectComposer>(); | |
const aspect = useMemo(() => new Vector2(size.width, size.height), [size]); | |
const { outlineItems } = useContext(OutlineContext); | |
useEffect(() => composer.current?.setSize(size.width, size.height), [size]); | |
useFrame(() => composer.current?.render(), 1); | |
return ( | |
<effectComposer ref={composer} args={[gl]}> | |
<renderPass attachArray="passes" args={[scene, camera]} /> | |
<outlinePass | |
attachArray="passes" | |
args={[aspect, scene, camera]} | |
selectedObjects={outlineItems} | |
/> | |
</effectComposer> | |
); | |
} | |
function SomeMesh() { | |
const ref = useRef<Object3D>(); | |
return ( | |
<mesh | |
ref={ref} | |
{...setOutlineOnHover(ref)} | |
/> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
createContext, | |
Dispatch, | |
MutableRefObject, | |
ReactNode, | |
SetStateAction, | |
useCallback, | |
useContext, | |
useEffect, | |
useState, | |
} from 'react'; | |
import { Object3D } from 'three'; | |
export interface OutlineItemsContext { | |
outlineItems?: Array<Object3D>; | |
setOutlineItems?: Dispatch<SetStateAction<Array<Object3D>>>; | |
} | |
export const OutlineContext = createContext<OutlineItemsContext>({}); | |
/** | |
* Set on the props of a mesh to trigger an outline effect whenever the mouse | |
* is hovered over it. | |
* | |
* @note The mesh must be beneath an OutlineItemsProvider | |
*/ | |
export function setOutlineOnHover(ref: MutableRefObject<Object3D | undefined>) { | |
const { setOutlineItems } = useContext(OutlineContext); | |
const onPointerOver = useCallback(() => { | |
if (setOutlineItems) setOutlineItems((items) => [...items, ref.current!]); | |
}, []); | |
const onPointerOut = useCallback(() => { | |
if (setOutlineItems) | |
setOutlineItems((items) => items.filter((item) => item !== ref.current!)); | |
}, []); | |
return { onPointerOver, onPointerOut }; | |
} | |
/** | |
* Wrap your scene in this provider to make it easier to assign outline items. | |
*/ | |
export const OutlineItemsProvider = ({ children }: { children: ReactNode }) => { | |
const [outlineItems, setOutlineItems] = useState<Array<Object3D>>([]); | |
return ( | |
<OutlineContext.Provider value={{ outlineItems, setOutlineItems }}> | |
{children} | |
</OutlineContext.Provider> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you're trying to keep your effects chain isolated from the rest of your code, tracking outline items for the
OutlinePass
selectedObjects
is a huge pain. Here are some helpers that useReact.Context
to allow setting theselectedObjects
without reaching into your effects chain.