Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v9] refactor!: remove viewport, add dpr #2887

Merged
merged 6 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 29 additions & 29 deletions docs/API/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function App() {

## useThree

This hook gives you access to the state model which contains the default renderer, the scene, your camera, and so on. It also gives you the current size of the canvas in screen and viewport coordinates.
This hook gives you access to the state model which contains the default renderer, the scene, your camera, and so on. It also gives you the current size of the canvas.

```jsx
import { useThree } from '@react-three/fiber'
Expand All @@ -49,33 +49,33 @@ The hook is reactive, if you resize the browser for instance, you get fresh meas

### State properties

| Prop | Description | Type |
| --------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| gl | Renderer | `THREE.WebGLRenderer` |
| scene | Scene | `THREE.Scene` |
| camera | Camera | `THREE.PerspectiveCamera` |
| raycaster | Default raycaster | `THREE.Raycaster` |
| pointer | Contains updated, normalized, centric pointer coordinates | `THREE.Vector2` |
| mouse | Note: this is deprecated, use `pointer` instead! Normalized event coordinates | `THREE.Vector2` |
| clock | Running system clock | `THREE.Clock` |
| linear | True when the colorspace is linear | `boolean` |
| flat | True when no tonemapping is used | `boolean` |
| legacy | Disables global color management via `THREE.ColorManagement` | `boolean` |
| frameloop | Render mode: always, demand, never | `always`, `demand`, `never` |
| performance | System regression | `{ current: number, min: number, max: number, debounce: number, regress: () => void }` |
| size | Canvas size in pixels | `{ width: number, height: number, top: number, left: number }` |
| viewport | Viewport size in three.js units | `{ width: number, height: number, initialDpr: number, dpr: number, factor: number, distance: number, aspect: number, getCurrentViewport: (camera?: Camera, target?: THREE.Vector3, size?: Size) => Viewport }` |
| xr | XR interface, manages WebXR rendering | `{ connect: () => void, disconnect: () => void }` |
| set | Allows you to set any state property | `(state: SetState<RootState>) => void` |
| get | Allows you to retrieve any state property non-reactively | `() => GetState<RootState>` |
| invalidate | Request a new render, given that `frameloop === 'demand'` | `() => void` |
| advance | Advance one tick, given that `frameloop === 'never'` | `(timestamp: number, runGlobalEffects?: boolean) => void` |
| setSize | Resize the canvas | `(width: number, height: number, top?: number, left?: number) => void` |
| setDpr | Set the pixel-ratio | `(dpr: number) => void` |
| setFrameloop | Shortcut to set the current render mode | `(frameloop?: 'always', 'demand', 'never') => void` |
| setEvents | Shortcut to setting the event layer | `(events: Partial<EventManager<any>>) => void` |
| onPointerMissed | Response for pointer clicks that have missed a target | `() => void` |
| events | Pointer-event handling | `{ connected: TargetNode, handlers: Events, connect: (target: TargetNode) => void, disconnect: () => void }` |
| Prop | Description | Type |
| --------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| gl | Renderer | `THREE.WebGLRenderer` |
| scene | Scene | `THREE.Scene` |
| camera | Camera | `THREE.PerspectiveCamera` |
| raycaster | Default raycaster | `THREE.Raycaster` |
| pointer | Contains updated, normalized, centric pointer coordinates | `THREE.Vector2` |
| mouse | Note: this is deprecated, use `pointer` instead! Normalized event coordinates | `THREE.Vector2` |
| clock | Running system clock | `THREE.Clock` |
| linear | True when the colorspace is linear | `boolean` |
| flat | True when no tonemapping is used | `boolean` |
| legacy | Disables global color management via `THREE.ColorManagement` | `boolean` |
| frameloop | Render mode: always, demand, never | `always`, `demand`, `never` |
| performance | System regression | `{ current: number, min: number, max: number, debounce: number, regress: () => void }` |
| dpr | The current pixel ratio | `number` |
| size | Canvas size in pixels | `{ width: number, height: number, top: number, left: number }` |
| xr | XR interface, manages WebXR rendering | `{ connect: () => void, disconnect: () => void }` |
| set | Allows you to set any state property | `(state: SetState<RootState>) => void` |
| get | Allows you to retrieve any state property non-reactively | `() => GetState<RootState>` |
| invalidate | Request a new render, given that `frameloop === 'demand'` | `() => void` |
| advance | Advance one tick, given that `frameloop === 'never'` | `(timestamp: number, runGlobalEffects?: boolean) => void` |
| setSize | Resize the canvas | `(width: number, height: number, top?: number, left?: number) => void` |
| setDpr | Set the pixel-ratio | `(dpr: number) => void` |
| setFrameloop | Shortcut to set the current render mode | `(frameloop?: 'always', 'demand', 'never') => void` |
| setEvents | Shortcut to setting the event layer | `(events: Partial<EventManager<any>>) => void` |
| onPointerMissed | Response for pointer clicks that have missed a target | `() => void` |
| events | Pointer-event handling | `{ connected: TargetNode, handlers: Events, connect: (target: TargetNode) => void, disconnect: () => void }` |

### Selector

Expand All @@ -85,7 +85,7 @@ You can also select properties, this allows you to avoid needless re-render for
// Will only trigger re-render when the default camera is exchanged
const camera = useThree((state) => state.camera)
// Will only re-render on resize changes
const viewport = useThree((state) => state.viewport)
const { width, height } = useThree((state) => state.size)
// ❌ You cannot expect reactivity from three.js internals!
const zoom = useThree((state) => state.camera.zoom)
```
Expand Down
4 changes: 2 additions & 2 deletions example/src/demos/Gestures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { Canvas, useThree, useFrame } from '@react-three/fiber'
import { useDrag } from '@use-gesture/react'

function Obj({ scale = 1, z = 0, opacity = 1 }) {
const { viewport } = useThree()
const { size } = useThree()
const [hovered, hover] = useState(false)
const [position, set] = useState<[number, number, number]>([0, 0, z])
const bind = useDrag(({ event, offset: [x, y] }) => {
event.stopPropagation()
const aspect = viewport.getCurrentViewport().factor
const aspect = size.width / size.height
set([x / aspect, -y / aspect, z])
})

Expand Down
8 changes: 5 additions & 3 deletions example/src/demos/ResetProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ import { OrbitControls } from '@react-three/drei'
function AdaptivePixelRatio() {
const gl = useThree((state) => state.gl)
const current = useThree((state) => state.performance.current)
const initialDpr = useThree((state) => state.viewport.initialDpr)
const initialDpr = useRef(1)
const dpr = useThree((state) => state.dpr)
initialDpr.current ??= dpr
const setDpr = useThree((state) => state.setDpr)
// Restore initial pixelratio on unmount
useEffect(() => {
const domElement = gl.domElement
return () => {
setDpr(initialDpr)
setDpr(initialDpr.current)
domElement.style.imageRendering = 'auto'
}
}, [])
// Set adaptive pixelratio
useEffect(() => {
setDpr(current * initialDpr)
setDpr(current * initialDpr.current)
gl.domElement.style.imageRendering = current === 1 ? 'auto' : 'pixelated'
}, [current])
return null
Expand Down
1 change: 0 additions & 1 deletion packages/fiber/src/core/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export type {
Subscription,
Dpr,
Size,
Viewport,
RenderCallback,
UpdateCallback,
LegacyAlways,
Expand Down
8 changes: 2 additions & 6 deletions packages/fiber/src/core/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ export function createRoot<TCanvas extends HTMLCanvasElement | OffscreenCanvas>(
state.setSize(size.width, size.height, size.top, size.left)
}
// Check pixelratio
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr)
if (dpr && state.dpr !== calculateDpr(dpr)) state.setDpr(dpr)
// Check frameloop
if (state.frameloop !== frameloop) state.setFrameloop(frameloop)
// Check pointer missed
Expand Down Expand Up @@ -537,11 +537,8 @@ function Portal({ state = {}, children, container }: PortalProps): JSX.Element {
const [pointer] = React.useState(() => new THREE.Vector2())

const inject = useMutableCallback((rootState: RootState, injectState: RootState) => {
let viewport
if (injectState.camera && size) {
const camera = injectState.camera
// Calculate the override viewport, if present
viewport = rootState.viewport.getCurrentViewport(camera, new THREE.Vector3(), size)
// Update the portal camera, if it differs from the previous layer
if (camera !== rootState.camera) updateCamera(camera, size)
}
Expand All @@ -558,10 +555,9 @@ function Portal({ state = {}, children, container }: PortalProps): JSX.Element {
mouse: pointer,
// Their previous root is the layer before it
previousRoot,
// Events, size and viewport can be overridden by the inject layer
// Events and size can be overridden by the inject layer
events: { ...rootState.events, ...injectState.events, ...events },
size: { ...rootState.size, ...size },
viewport: { ...rootState.viewport, ...viewport },
// Layers are allowed to override events
setEvents: (events: Partial<EventManager<any>>) =>
injectState.set((state) => ({ ...state, events: { ...state.events, ...events } })),
Expand Down
Loading