-
Notifications
You must be signed in to change notification settings - Fork 724
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cc8ea56
commit e0fafd8
Showing
6 changed files
with
168 additions
and
36 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import * as React from 'react' | ||
import { Vector3 } from 'three' | ||
import { Box, Html, ScreenSizer } from '../../src' | ||
|
||
import { Setup } from '../Setup' | ||
|
||
export default { | ||
title: 'Abstractions/ScreenSizer', | ||
component: ScreenSizer, | ||
decorators: [(storyFn) => <Setup cameraPosition={new Vector3(0, 0, 10)}>{storyFn()}</Setup>], | ||
} | ||
|
||
export const ScreenSizerStory = ({ scale }) => ( | ||
<> | ||
<Box args={[1, 1, 1]} position={[-1, 0, 0]}> | ||
<meshPhysicalMaterial color="#69d2e7" /> | ||
<Html | ||
center | ||
sprite | ||
style={{ | ||
textAlign: 'center', | ||
background: 'rgba(255,255,255,0.5)', | ||
pointerEvents: 'none', | ||
boxShadow: '0px 0px 10px 10px rgba(255,255,255, 0.5)', | ||
}} | ||
> | ||
Normal Box | ||
</Html> | ||
</Box> | ||
<ScreenSizer scale={scale} position={[1, 0, 0]}> | ||
<Box args={[100, 100, 100]}> | ||
<meshPhysicalMaterial color="#f38630" /> | ||
<Html | ||
center | ||
sprite | ||
style={{ | ||
textAlign: 'center', | ||
background: 'rgba(255,255,255,0.5)', | ||
pointerEvents: 'none', | ||
boxShadow: '0px 0px 10px 10px rgba(255,255,255, 0.5)', | ||
}} | ||
> | ||
Box wrapped in ScreenSizer | ||
</Html> | ||
</Box> | ||
</ScreenSizer> | ||
<Html | ||
center | ||
sprite | ||
position={[0, -3, 0]} | ||
style={{ | ||
textAlign: 'center', | ||
background: 'rgba(255,255,255,0.5)', | ||
pointerEvents: 'none', | ||
width: '10rem', | ||
}} | ||
> | ||
Zoom in/out to see the difference | ||
</Html> | ||
</> | ||
) | ||
|
||
ScreenSizerStory.args = { | ||
scale: 1, | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Object3DProps, useFrame } from '@react-three/fiber' | ||
import { ForwardRefComponent } from 'helpers/ts-utils' | ||
import * as React from 'react' | ||
import { forwardRef, useRef } from 'react' | ||
import mergeRefs from 'react-merge-refs' | ||
import { Object3D, Vector3 } from 'three' | ||
import { calculateScaleFactor } from './calculateScaleFactor' | ||
|
||
const worldPos = /* @__PURE__ */ new Vector3() | ||
|
||
export interface ScreenSizerProps extends Object3DProps { | ||
/** Scale factor. Defaults to 1, which equals 1 pixel size. */ | ||
scale: number | ||
} | ||
|
||
/** | ||
* Wraps children in an `Object3D` and attempts to scale from | ||
* world units to screen units * scale factor. | ||
* | ||
* For example, this will render a box of roughly 1x1 pixel size, | ||
* independently of how far the camera is. | ||
* | ||
* ```jsx | ||
* <ScreenSizer> | ||
* <Box /> | ||
* </ScreenSizer> | ||
* ``` | ||
*/ | ||
export const ScreenSizer: ForwardRefComponent<ScreenSizerProps, Object3D> = /* @__PURE__ */ forwardRef< | ||
Object3D, | ||
ScreenSizerProps | ||
>(({ scale = 1, ...props }, ref) => { | ||
const container = useRef<Object3D>(null) | ||
|
||
useFrame((state) => { | ||
const obj = container.current | ||
if (!obj) return | ||
const sf = calculateScaleFactor(obj.getWorldPosition(worldPos), scale, state.camera, state.size) | ||
obj.scale.setScalar(sf * scale) | ||
}) | ||
|
||
return <object3D ref={mergeRefs([container, ref])} {...props} /> | ||
}) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Size } from '@react-three/fiber' | ||
import * as THREE from 'three' | ||
|
||
const tV0 = /* @__PURE__ */ new THREE.Vector3() | ||
const tV1 = /* @__PURE__ */ new THREE.Vector3() | ||
const tV2 = /* @__PURE__ */ new THREE.Vector3() | ||
|
||
const getPoint2 = (point3: THREE.Vector3, camera: THREE.Camera, size: Size) => { | ||
const widthHalf = size.width / 2 | ||
const heightHalf = size.height / 2 | ||
camera.updateMatrixWorld(false) | ||
const vector = point3.project(camera) | ||
vector.x = vector.x * widthHalf + widthHalf | ||
vector.y = -(vector.y * heightHalf) + heightHalf | ||
return vector | ||
} | ||
|
||
const getPoint3 = (point2: THREE.Vector3, camera: THREE.Camera, size: Size, zValue: number = 1) => { | ||
const vector = tV0.set((point2.x / size.width) * 2 - 1, -(point2.y / size.height) * 2 + 1, zValue) | ||
vector.unproject(camera) | ||
return vector | ||
} | ||
|
||
export const calculateScaleFactor = (point3: THREE.Vector3, radiusPx: number, camera: THREE.Camera, size: Size) => { | ||
const point2 = getPoint2(tV2.copy(point3), camera, size) | ||
let scale = 0 | ||
for (let i = 0; i < 2; ++i) { | ||
const point2off = tV1.copy(point2).setComponent(i, point2.getComponent(i) + radiusPx) | ||
const point3off = getPoint3(point2off, camera, size, point2off.z) | ||
scale = Math.max(scale, point3.distanceTo(point3off)) | ||
} | ||
return scale | ||
} |
This file contains 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
This file contains 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