Skip to content

Commit

Permalink
feat: Adds CubeCamera component (#298)
Browse files Browse the repository at this point in the history
Co-authored-by: Gianmarco Simone <[email protected]>
  • Loading branch information
drcmda and gsimone authored Feb 13, 2021
1 parent ea89c75 commit 362812b
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 2 deletions.
57 changes: 57 additions & 0 deletions .storybook/stories/CubeCamera.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from 'react'
import * as THREE from 'three'
import { useFrame } from 'react-three-fiber'

import { Setup } from '../Setup'

import { Box, CubeCamera } from '../../src'

export default {
title: 'Camera/CubeCamera',
component: CubeCamera,
decorators: [(storyFn) => <Setup cameraPosition={new THREE.Vector3(0, 10, 40)}>{storyFn()}</Setup>],
}

declare global {
namespace JSX {
interface IntrinsicElements {
axisHelper: object
}
}
}

function Sphere({ offset = 0, ...props }) {
const ref = React.useRef<THREE.Group>()
useFrame(({ clock }) => {
ref.current!.position.y = Math.sin(offset + clock.elapsedTime) * 5
})

return (
<CubeCamera {...props}>
{(texture) => (
<mesh ref={ref}>
<sphereBufferGeometry args={[5, 64, 64]} />
<meshStandardMaterial roughness={0} metalness={1} envMap={texture} />
</mesh>
)}
</CubeCamera>
)
}

function Scene() {
return (
<>
<fog attach="fog" args={['#f0f0f0', 100, 200]} />

<Sphere position={[-10, 10, 0]} />
<Sphere position={[10, 9, 0]} offset={2000} />

<Box material-color="hotpink" args={[5, 5, 5]} position-y={2.5} />

<gridHelper args={[100, 10]} />
</>
)
}

export const DefaultStory = () => <Scene />
DefaultStory.storyName = 'Default'
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ The `native` route of the library **does not** export `Html` or `Loader`. The de
<ul>
<li><a href="#perspectivecamera">PerspectiveCamera</a></li>
<li><a href="#orthographiccamera">OrthographicCamera</a></li>
<li><a href="#cubecamera">CubeCamera</a></li>
</ul>
<li><a href="#controls">Controls</a></li>
<ul>
Expand Down Expand Up @@ -167,6 +168,29 @@ A responsive [THREE.PerspectiveCamera](https://threejs.org/docs/index.html#api/e

A responsive [THREE.OrthographicCamera](https://threejs.org/docs/index.html#api/en/cameras/OrthographicCamera) that can set itself as the default.

#### CubeCamera

[![](https://img.shields.io/badge/-codesandbox-blue)](https://codesandbox.io/s/frosty-reflector-forked-6k71y)

A [THREE.CubeCamera](https://threejs.org/docs/index.html#api/en/cameras/CubeCamera) that returns its texture as a render-prop. It wraps children and makes them invisible while rendering to the internal buffer. Using the `frames` prop you can control if this renders indefinitively or statically (a given number of times). If you have two static objects in the scene, make it `frames={2}` for instance, so that both objects get to "see" one another in the reflections, which takes multiple renders. If you have moving objects, unset the prop and render with a smaller resolution instead.

```jsx
<CubeCamera
resolution={256} // Size of the off-buffer (256 by default)
frames={Infinity} // How many frames it should render (Indefinitively by default)
fog={customFog} // Allows you to pass a Fog or FogExp2 instance for a smaller frustrum
near={1}
far={1000}
>
{(texture) => (
<mesh>
<sphereGeometry />
<meshStandardMaterial envMap={texture} />
</mesh>
)}
</CubeCamera>
```

# Controls

If available controls have damping enabled by default, they manage their own updates, remove themselves on unmount, are compatible with the `invalidateFrameloop` canvas-flag. They inherit all props from their underlying [THREE controls](https://github.com/mrdoob/three.js/tree/dev/examples/jsm/controls).
Expand Down Expand Up @@ -553,8 +577,6 @@ Easily add reflections and/or blur to a planar surface. This reflector can also
maxDepthThreshold={1} // Upper edge for the depthTexture interpolation (default = 0)
depthScale={1} // Scale the depth factor (0 = no depth, default = 0)
depthToBlurRatioBias={0.25} // Adds a bias factor to the depthTexture before calculating the blur amount [blurFactor = blurTexture * (depthTexture + bias)]. It accepts values between 0 and 1, default is 0.25. An amount > 0 of bias makes sure that the blurTexture is not too sharp because of the multiplication with the depthTexture
distortionMap={distortionTexture} // The texture to create a distortion map. The black and white values map to the perceived distortion
distortion={1} // How much the distortion map affects the material (default = 0)
debug={0} /* Depending on the assigned value, one of the following channels is shown:
0 = no debug
1 = depth channel
Expand Down
63 changes: 63 additions & 0 deletions src/core/CubeCamera.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
Fog,
FogExp2,
Group,
Texture,
CubeCamera as CubeCameraImpl,
WebGLCubeRenderTarget,
LinearFilter,
RGBFormat,
} from 'three'
import * as React from 'react'
import { useFrame, useThree } from 'react-three-fiber'

type Props = JSX.IntrinsicElements['group'] & {
fog?: Fog | FogExp2
frames?: number
resolution?: number
near?: number
far?: number
children: (tex: Texture) => React.ReactNode
}

export function CubeCamera({
children,
fog,
frames = Infinity,
resolution = 256,
near = 1,
far = 1000,
...props
}: Props) {
const ref = React.useRef<Group>()
const [camera, setCamera] = React.useState<CubeCameraImpl>()
const { scene, gl } = useThree()
const fbo = React.useMemo(
() =>
new WebGLCubeRenderTarget(resolution, {
minFilter: LinearFilter,
magFilter: LinearFilter,
format: RGBFormat,
encoding: gl.outputEncoding,
}),
[resolution]
)
let count = 0
useFrame(() => {
if (camera && ref.current && (frames === Infinity || count < frames)) {
ref.current.traverse((obj) => (obj.visible = false))
const originalFog = scene.fog
scene.fog = fog ?? originalFog
camera.update(gl, scene)
scene.fog = originalFog
ref.current.traverse((obj) => (obj.visible = true))
count++
}
})
return (
<group {...props}>
<cubeCamera ref={setCamera} args={[near, far, fbo]} />
<group ref={ref}>{children(fbo.texture)}</group>
</group>
)
}
1 change: 1 addition & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './Effects'
// Cameras
export * from './OrthographicCamera'
export * from './PerspectiveCamera'
export * from './CubeCamera'

// Controls
export * from './DeviceOrientationControls'
Expand Down

1 comment on commit 362812b

@vercel
Copy link

@vercel vercel bot commented on 362812b Feb 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.