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

feat: add color prop to Environment #2180

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
22 changes: 22 additions & 0 deletions .storybook/stories/Environment.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,25 @@ export const EnvironmentSt4 = {
},
name: 'Gainmap',
} satisfies Story

function EnvironmentScene5(props: ComponentProps<typeof Environment>) {
return (
<>
<Environment {...props} />
<mesh>
<torusKnotGeometry args={[1, 0.5, 128, 32]} />
<meshStandardMaterial metalness={1} roughness={0} />
</mesh>
<OrbitControls autoRotate />
</>
)
}

export const EnvironmentSt5 = {
render: (args) => <EnvironmentScene5 {...args} />,
args: {
color: '#ff0000',
background: true,
},
name: 'Color',
} satisfies Story
7 changes: 7 additions & 0 deletions docs/staging/environment.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Sets up a global cubemap, which affects the default `scene.environment`, and opt
backgroundRotation={[0, Math.PI / 2, 0]} // optional rotation (default: 0, only works with three 0.163 and up)
environmentIntensity={1} // optional intensity factor (default: 1, only works with three 0.163 and up)
environmentRotation={[0, Math.PI / 2, 0]} // optional rotation (default: 0, only works with three 0.163 and up)
color={'red'} // uses a solid color and overridden by files, preset or scene
files={['px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png']}
path="/"
preset={null}
Expand Down Expand Up @@ -82,6 +83,12 @@ const city = import('@pmndrs/assets/hdri/city.exr').then((module) => module.defa
<Environment files={suspend(city)} />
```

In the simplest case you a solid color can be used.

```jsx
<Environment color="red" background />
```

If you already have a cube texture you can pass it directly:

```jsx
Expand Down
67 changes: 65 additions & 2 deletions src/core/Environment.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import * as React from 'react'
import { useThree, createPortal, useFrame, extend, Object3DNode, Euler, applyProps } from '@react-three/fiber'
import { WebGLCubeRenderTarget, Texture, Scene, CubeCamera, HalfFloatType, CubeTexture } from 'three'
import {
useThree,
createPortal,
useFrame,
extend,
Object3DNode,
Euler,
applyProps,
ReactThreeFiber,
} from '@react-three/fiber'
import {
WebGLCubeRenderTarget,
Texture,
Scene,
CubeCamera,
HalfFloatType,
CubeTexture,
Color,
DataTexture,
PMREMGenerator,
} from 'three'
import { GroundProjectedEnv as GroundProjectedEnvImpl } from 'three-stdlib'
import { PresetsType } from '../helpers/environment-assets'
import { EnvironmentLoaderProps, useEnvironment } from './useEnvironment'
Expand All @@ -21,6 +40,7 @@ export type EnvironmentProps = {
environmentIntensity?: number
environmentRotation?: Euler

color?: ReactThreeFiber.Color
map?: Texture
preset?: PresetsType
scene?: Scene | React.MutableRefObject<Scene>
Expand Down Expand Up @@ -209,13 +229,56 @@ function EnvironmentGround(props: EnvironmentProps) {
)
}

function EnvironmentColor(props: EnvironmentProps) {
const { scene, gl } = useThree()
const color = props.color
const background = props.background

const cubeRenderTarget = React.useMemo(() => new WebGLCubeRenderTarget(128), [gl])
const cubeCamera = React.useMemo(() => new CubeCamera(0.1, 100, cubeRenderTarget), [cubeRenderTarget])
const colorScene = React.useMemo(() => new Scene(), [])

React.useEffect(() => {
if (!color) return

let bgColor: Color
if (color instanceof Color) {
bgColor = color
} else if (Array.isArray(color)) {
bgColor = new Color(...color)
} else {
bgColor = new Color(color)
}

// Set the color scene background
colorScene.background = bgColor

// Render the cube map
cubeCamera.update(gl, colorScene)

// Apply to the main scene
const prevBackground = scene.background
if (background) scene.background = bgColor
if (background !== 'only') scene.environment = cubeRenderTarget.texture

return () => {
if (background) scene.background = prevBackground
if (background !== 'only') scene.environment = null
}
}, [color, scene, colorScene, cubeCamera, gl, cubeRenderTarget, background])

return null
}

export function Environment(props: EnvironmentProps) {
return props.ground ? (
<EnvironmentGround {...props} />
) : props.map ? (
<EnvironmentMap {...props} />
) : props.children ? (
<EnvironmentPortal {...props} />
) : props.color ? (
<EnvironmentColor {...props} />
) : (
<EnvironmentCube {...props} />
)
Expand Down