Skip to content

Commit

Permalink
fix: fullscreen when using a orthographic camera
Browse files Browse the repository at this point in the history
  • Loading branch information
bbohlender committed Aug 28, 2024
1 parent 3170664 commit 3c91867
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 44 deletions.
4 changes: 2 additions & 2 deletions examples/apfel/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"type": "module",
"dependencies": {
"@coconut-xr/xinteraction": "^0.1.12",
"@preact/signals-core": "^1.5.1",
"@react-three/drei": "^9.96.1",
"@react-three/postprocessing": "^2.16.0",
Expand All @@ -12,7 +11,8 @@
"@vitejs/plugin-basic-ssl": "^1.1.0",
"maath": "^0.10.7",
"r3f-perf": "^7.1.2",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"@pmndrs/pointer-events": "6.2.1"
},
"scripts": {
"dev": "vite --host",
Expand Down
22 changes: 17 additions & 5 deletions examples/apfel/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Canvas } from '@react-three/fiber'
import { Canvas, useThree } from '@react-three/fiber'
import { Fullscreen, Text, Container } from '@react-three/uikit'
import { Copy } from '@react-three/uikit-lucide'
import { XWebPointers, noEvents } from '@coconut-xr/xinteraction/react'
import { Card } from '@/card.js'
import { Button } from '@/button.js'
import { Tabs, TabsButton } from '@/tabs.js'
import { Defaults } from '@/theme.js'
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { TextOnCard } from './components/card.js'
import { CheckboxOnCard } from './components/checkbox.js'
import { ButtonsOnCard } from './components/button.js'
Expand All @@ -17,6 +16,7 @@ import { TabBarWithText } from './components/tab-bar.js'
import { ProgressBarsOnCard } from './components/progress.js'
import { LoadingSpinnersOnCard } from './components/loading.js'
import { InputsOnCard } from './components/input.js'
import { forwardHtmlEvents } from '@pmndrs/pointer-events'

const componentPages = {
card: TextOnCard,
Expand Down Expand Up @@ -49,8 +49,12 @@ export default function App() {
}
const ComponentPage = componentPages[component]
return (
<Canvas events={noEvents} style={{ height: '100dvh', touchAction: 'none' }} gl={{ localClippingEnabled: true }}>
<XWebPointers />
<Canvas
events={() => ({ enabled: false, priority: 0 })}
style={{ height: '100dvh', touchAction: 'none' }}
gl={{ localClippingEnabled: true }}
>
<SwitchToXRPointerEvents />
<color attach="background" args={['black']} />
<ambientLight intensity={0.5} />
<directionalLight intensity={1} position={[-5, 5, 10]} />
Expand Down Expand Up @@ -99,3 +103,11 @@ export default function App() {
</Canvas>
)
}

function SwitchToXRPointerEvents() {
const domElement = useThree((s) => s.gl.domElement)
const camera = useThree((s) => s.camera)
const scene = useThree((s) => s.scene)
useEffect(() => forwardHtmlEvents(domElement, camera, scene), [domElement, camera, scene])
return null
}
4 changes: 2 additions & 2 deletions examples/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"type": "module",
"dependencies": {
"@coconut-xr/xinteraction": "^0.1.12",
"@react-three/drei": "^9.96.1",
"@react-three/postprocessing": "^2.16.0",
"@react-three/uikit": "workspace:^",
"@react-three/uikit-lucide": "workspace:^",
"r3f-perf": "^7.1.2",
"react-dom": "^18.2.0",
"vite-plugin-mkcert": "^1.17.4",
"zustand": "^4.4.7"
"zustand": "^4.4.7",
"@pmndrs/pointer-events": "6.2.1"
},
"scripts": {
"dev": "vite --host",
Expand Down
21 changes: 15 additions & 6 deletions examples/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { useEffect, useState } from 'react'
import { Canvas, useFrame, useThree } from '@react-three/fiber'
import { Container, Fullscreen, Text, setPreferredColorScheme } from '@react-three/uikit'
import { Activity, CreditCard, DollarSign, Users } from '@react-three/uikit-lucide'

Expand All @@ -8,14 +8,14 @@ import { Button } from '@/button.js'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/card.js'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/tabs.js'
import { DialogAnchor } from '@/dialog.js'
import { noEvents, XWebPointers } from '@coconut-xr/xinteraction/react'
import { CalendarDateRangePicker } from './components/DateRangePicker.js'
import { MainNav } from './components/MainNav.js'
import { Overview } from './components/Overview.js'
import { RecentSales } from './components/RecentSales.js'
import { TeamSwitcher } from './components/TeamSwitcher.js'
import { UserNav } from './components/UserNav.js'
import { create } from 'zustand'
import { forwardHtmlEvents } from '@pmndrs/pointer-events'

setPreferredColorScheme('light')

Expand All @@ -27,15 +27,16 @@ export default function App() {
<>
<FrameCounter />
<Canvas
events={noEvents}
events={() => ({ enabled: false, priority: 0 })}
frameloop="demand"
flat
camera={{ position: [0, 0, 18], fov: 35 }}
camera={{ position: [0, 0, 18], fov: 35, zoom: 100 }}
style={{ height: '100dvh', touchAction: 'none' }}
gl={{ localClippingEnabled: true }}
orthographic
>
<CountFrames />
<XWebPointers />
<SwitchToXRPointerEvents />
<Fullscreen distanceToCamera={1} backgroundColor={0xffffff} dark={{ backgroundColor: 0x0 }}>
<Defaults>
<DialogAnchor>
Expand Down Expand Up @@ -259,3 +260,11 @@ export function DashboardPage({ open, setOpen }: { open: boolean; setOpen: (open
</Container>
)
}

function SwitchToXRPointerEvents() {
const domElement = useThree((s) => s.gl.domElement)
const camera = useThree((s) => s.camera)
const scene = useThree((s) => s.scene)
useEffect(() => forwardHtmlEvents(domElement, camera, scene), [domElement, camera, scene])
return null
}
4 changes: 2 additions & 2 deletions examples/default/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"type": "module",
"dependencies": {
"@coconut-xr/xinteraction": "^0.1.12",
"@preact/signals-core": "^1.5.1",
"@react-three/drei": "^9.96.1",
"@react-three/uikit": "workspace:^",
"@react-three/uikit-lucide": "workspace:^",
"r3f-perf": "^7.1.2",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"@pmndrs/pointer-events": "6.2.1"
},
"scripts": {
"dev": "vite --host",
Expand Down
22 changes: 17 additions & 5 deletions examples/default/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react'
import { Canvas } from '@react-three/fiber'
import { useEffect, useState } from 'react'
import { Canvas, useThree } from '@react-three/fiber'
import { Fullscreen, Text, Container, getPreferredColorScheme, setPreferredColorScheme } from '@react-three/uikit'
import { Copy, Moon, Sun, SunMoon } from '@react-three/uikit-lucide'

Expand All @@ -9,7 +9,6 @@ import { Card } from '@/card.js'
import { Separator } from '@/separator.js'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/tabs.js'
import { DialogAnchor } from '@/dialog.js'
import { XWebPointers, noEvents } from '@coconut-xr/xinteraction/react'
import { TooltipDemo } from './components/tooltip.js'
import { AccordionDemo } from './components/accordion.js'
import { AlertDemo } from './components/alert.js'
Expand All @@ -33,6 +32,7 @@ import { ToggleGroupDemo } from './components/toggle-group.js'
import InputDemo from './components/input.js'
import TextareDemo from './components/textarea.js'
import { VideoDemo } from './components/video.js'
import { forwardHtmlEvents } from '@pmndrs/pointer-events'

const componentPages = {
accordion: AccordionDemo,
Expand Down Expand Up @@ -80,8 +80,12 @@ export default function App() {
}
const [pcs, updatePCS] = useState(() => getPreferredColorScheme())
return (
<Canvas events={noEvents} style={{ height: '100dvh', touchAction: 'none' }} gl={{ localClippingEnabled: true }}>
<XWebPointers />
<Canvas
events={() => ({ enabled: false, priority: 0 })}
style={{ height: '100dvh', touchAction: 'none' }}
gl={{ localClippingEnabled: true }}
>
<SwitchToXRPointerEvents />
<color attach="background" args={['black']} />
<ambientLight intensity={0.5} />
<directionalLight intensity={0} position={[5, 1, 10]} />
Expand Down Expand Up @@ -145,3 +149,11 @@ export default function App() {
</Canvas>
)
}

function SwitchToXRPointerEvents() {
const domElement = useThree((s) => s.gl.domElement)
const camera = useThree((s) => s.camera)
const scene = useThree((s) => s.scene)
useEffect(() => forwardHtmlEvents(domElement, camera, scene), [domElement, camera, scene])
return null
}
20 changes: 12 additions & 8 deletions packages/react/src/fullscreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactNode, RefAttributes, forwardRef, useEffect, useMemo } from 'react'
import { Root } from './root.js'
import { batch, signal } from '@preact/signals-core'
import { RootState, createPortal, useStore, useThree } from '@react-three/fiber'
import { createPortal, useFrame, useStore, useThree } from '@react-three/fiber'
import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js'
import {
FullscreenProperties as BaseFullscreenProperties,
Expand All @@ -22,15 +22,19 @@ export const Fullscreen: (
props: FullscreenProperties & RefAttributes<ComponentInternals<RootProperties & EventHandlers>>,
) => ReactNode = forwardRef((properties, ref) => {
const store = useStore()
const [sizeX, sizeY, pixelSize] = useMemo(() => [signal<number>(1), signal<number>(1), signal<number>(1)], [])
const camera = useThree((s) => s.camera)
const distanceToCamera = properties.distanceToCamera ?? camera.near + 0.1
useEffect(() => {
const fn = ({ camera, size: { height } }: RootState) =>
batch(() => updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, height))
fn(store.getState())
return store.subscribe(fn)
}, [pixelSize, sizeX, sizeY, store, distanceToCamera])
const [sizeX, sizeY, pixelSize] = useMemo(() => {
const sizeX = signal(1)
const sizeY = signal(1)
const pixelSize = signal(1)
updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, store.getState().size.height)
return [sizeX, sizeY, pixelSize]
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useFrame(({ camera, size: { height } }) =>
batch(() => updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, height)),
)
const attachCamera = properties.attachCamera ?? true
return (
<>
Expand Down
7 changes: 5 additions & 2 deletions packages/uikit/src/components/fullscreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import type { RootProperties } from './root.js'

export type FullscreenProperties = Omit<RootProperties, 'sizeX' | 'sizeY' | 'pixelSize' | 'anchorX' | 'anchorY'>

/**
* must be called when camera.fov, camera.top, camera.bottom, camera.right, camera.left, camera.zoom, camera.aspect changes
*/
export function updateSizeFullscreen(
sizeX: Signal<number>,
sizeY: Signal<number>,
Expand All @@ -19,8 +22,8 @@ export function updateSizeFullscreen(
sizeX.value = cameraHeight * camera.aspect
}
if (camera instanceof OrthographicCamera) {
const cameraHeight = camera.top - camera.bottom
const cameraWidth = camera.right - camera.left
const cameraHeight = (camera.top - camera.bottom) / camera.zoom
const cameraWidth = (camera.right - camera.left) / camera.zoom
pixelSize.value = cameraHeight / screenHeight
sizeY.value = cameraHeight
sizeX.value = cameraWidth
Expand Down
6 changes: 3 additions & 3 deletions packages/uikit/src/vanilla/fullscreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ export class Fullscreen extends Root {
}
this.parentCameraSignal.value = this.parent
this.distanceToCamera ??= this.parent.near + 0.1
this.updateSize()
this.update()
})
this.addEventListener('removed', () => (this.parentCameraSignal.value = undefined))
}

/**
* must be called when the screen size changes
* must be called when camera.fov, camera.top, camera.bottom, camera.right, camera.left, camera.zoom, camera.aspect changes
*/
updateSize() {
update() {
const parentCamera = this.parentCameraSignal.peek()
if (this.distanceToCamera == null || parentCamera == null) {
return
Expand Down
18 changes: 9 additions & 9 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3c91867

Please sign in to comment.