Skip to content

Commit

Permalink
example: performance demo
Browse files Browse the repository at this point in the history
feat: expose globalMatrix through ref.current.globalMatrix
fix: card demo
  • Loading branch information
bbohlender committed Nov 4, 2024
1 parent c1458cb commit cad0f11
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 31 deletions.
6 changes: 5 additions & 1 deletion docs/advanced/pitfalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ The `Content` component measures its content when the component is created. If t

</td>
</tr>
</table>
</table>

## Non-Transparent Objects inside `Content`

To render objects in the correct order, we are using a custom transparent object sorter. Therefore, all objects inside uikit must either be transparent or must write to the depth buffer and should have a small offset in the z-axis towards its parent.
2 changes: 1 addition & 1 deletion examples/card/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function CardPage() {
>
<Content transformTranslateZ={1} padding={14} keepAspectRatio={false} width="100%" height={400}>
<mesh geometry={cardGeometry}>
<MeshPortalMaterial>
<MeshPortalMaterial transparent>
<color attach="background" args={['white']} />
<ambientLight intensity={Math.PI} />
<Environment preset="city" />
Expand Down
3 changes: 2 additions & 1 deletion examples/performance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"@react-three/drei": "^9.96.1",
"@react-three/uikit": "workspace:^",
"r3f-perf": "^7.2.1",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"suspend-react": "^0.1.3"
},
"scripts": {
"dev": "vite --host"
Expand Down
Binary file added examples/performance/public/img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 67 additions & 24 deletions examples/performance/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,85 @@
import { Canvas } from '@react-three/fiber'
import { DefaultProperties, Container, Text, Root } from '@react-three/uikit'
import { DefaultProperties, Container, Text, Root, ComponentInternals } from '@react-three/uikit'
import { OrbitControls } from '@react-three/drei'
import { Perf } from 'r3f-perf'
import { noEvents, PointerEvents } from '@react-three/xr'
import { suspend } from 'suspend-react'
import { useEffect, useMemo, useRef } from 'react'
import { effect, signal } from '@preact/signals-core'
import { Color } from 'three'

const size = 2.4 * 1920
const elements = 60000

export default function App() {
const getPixel = suspend(loadGetPixel, ['img.png'])
return (
<Canvas events={noEvents} style={{ height: '100dvh', touchAction: 'none' }} gl={{ localClippingEnabled: true }}>
<color attach="background" args={['black']} />
<PointerEvents />
<OrbitControls />
<Perf />
<Root width={1920 * 2} positionType="relative">
<Root width={size} height={size} positionType="relative">
<DefaultProperties fontSize={4}>
<Container positionType="absolute" gap={1} flexWrap="wrap" inset={0}>
{new Array(20000).fill(null).map((_, i) => {
const borderWidth = Math.random() * 1
return (
<Container
key={i}
borderRadius={Math.random() * 5}
backgroundColor={Math.random() * 0xffffff}
borderWidth={borderWidth}
borderColor={Math.random() * 0xffffff}
height={4 + 4 + 2 * borderWidth}
padding={2}
pointerEvents="none"
hover={{ backgroundColor: 'white', borderColor: 'black' }}
>
<Text pointerEvents="auto" hover={{ color: 'red' }}>
Hello World
</Text>
</Container>
)
})}
<Container positionType="absolute" gap={1} justifyContent="space-between" flexWrap="wrap" inset={0}>
{new Array(elements).fill(null).map((_, i) => (
<Pixel key={i} getPixel={getPixel} />
))}
</Container>
</DefaultProperties>
</Root>
</Canvas>
)
}

type GetPixel = (x: number, y: number) => [number, number, number]

function Pixel({ getPixel }: { getPixel: GetPixel }) {
const borderWidth = Math.random() * 1
const color = useMemo(() => signal(new Color('black')), [])
const ref = useRef<ComponentInternals>(null)
useEffect(() => {
const internals = ref.current
if (internals == null) {
return
}
return effect(() => {
const center = internals.center.value
if (center == null) {
return
}
const [r, g, b] = getPixel((680 * (center[0] + size / 2)) / size, 680 * ((-center[1] + size / 2) / size))
color.value = new Color(r / 255, g / 255, b / 255)
})
}, [color, getPixel])
return (
<Container
ref={ref}
borderRadius={Math.random() * 5}
backgroundColor={color}
borderWidth={borderWidth}
borderColor={Math.random() * 0xffffff}
transformTranslateZ={Math.random() * 1}
height={4 + 4 + 2 * borderWidth}
padding={2}
hover={{ backgroundColor: 'white', borderColor: 'black' }}
>
<Text pointerEvents="none">Hello World</Text>
</Container>
)
}

async function loadGetPixel(url: string) {
return new Promise<GetPixel>((resolve) => {
const img = new Image()

img.onload = () => {
const canvas = document.createElement('canvas')
canvas.width = 680
canvas.height = 680
const ctx = canvas.getContext('2d')!
ctx.drawImage(img, 0, 0, 680, 680)
resolve((x, y) => ctx.getImageData(x, y, 1, 1).data as any)
}
img.src = url
})
}
7 changes: 5 additions & 2 deletions packages/react/src/ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import {
MergedProperties,
} from '@pmndrs/uikit/internals'
import { ForwardedRef, RefObject, useImperativeHandle } from 'react'
import { Vector2Tuple, Mesh } from 'three'
import { Vector2Tuple, Mesh, Matrix4 } from 'three'

export type ComponentInternals<T = ContainerProperties> = {
globalMatrix: ReadonlySignal<Matrix4 | undefined>
/**
* the size of one pixel
*/
Expand Down Expand Up @@ -93,7 +94,8 @@ export function useComponentInternals<T, O = {}>(
useImperativeHandle(
ref,
() => {
const { scrollPosition, paddingInset, borderInset, relativeCenter, size, maxScrollPosition } = internals
const { scrollPosition, paddingInset, borderInset, globalMatrix, relativeCenter, size, maxScrollPosition } =
internals
return {
isVisible: internals.isVisible,
setStyle: (style: T | undefined, replace?: boolean) =>
Expand All @@ -105,6 +107,7 @@ export function useComponentInternals<T, O = {}>(
borderInset,
paddingInset,
center: relativeCenter,
globalMatrix,
maxScrollPosition,
size,
interactionPanel: interactionPanel instanceof Mesh ? interactionPanel : interactionPanel.current!,
Expand Down
1 change: 1 addition & 0 deletions packages/uikit/src/components/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ function createMeasureContent(
}
object.material.depthTest = depthTest
object.material.depthWrite = depthWrite
object.material.transparent = true
})
root.requestRender()
}
Expand Down
2 changes: 0 additions & 2 deletions packages/uikit/src/components/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,6 @@ export function createRoot(
initializers,
)

console.log(outgoingDefaultProperties)

return Object.assign(flexState, {
defaultProperties: outgoingDefaultProperties,
globalMatrix,
Expand Down
3 changes: 3 additions & 0 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 cad0f11

Please sign in to comment.