Skip to content

Commit

Permalink
feat: image border radius
Browse files Browse the repository at this point in the history
  • Loading branch information
drcmda committed Jan 18, 2024
1 parent de94ed2 commit 4d741a2
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1310,10 +1310,26 @@ api.eyeRightRef.current.irisDirRef.current.localToWorld(new THREE.Vector3(0, 0,

A shader-based image component with auto-cover (similar to css/background: cover).

```tsx
export type ImageProps = Omit<JSX.IntrinsicElements['mesh'], 'scale'> & {
segments?: number
scale?: number | [number, number]
color?: Color
zoom?: number
radius?: number
grayscale?: number
toneMapped?: boolean
transparent?: boolean
opacity?: number
side?: THREE.Side
}
```

```jsx
function Foo() {
const ref = useRef()
useFrame(() => {
ref.current.material.radius = ... // between 0 and 1
ref.current.material.zoom = ... // 1 and higher
ref.current.material.grayscale = ... // between 0 and 1
ref.current.material.color.set(...) // mix-in color
Expand Down
33 changes: 31 additions & 2 deletions src/core/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react'
import * as THREE from 'three'
import { Color, extend } from '@react-three/fiber'
import { Color, extend, useThree } from '@react-three/fiber'
import { shaderMaterial } from './shaderMaterial'
import { useTexture } from './useTexture'
import { ForwardRefComponent } from '../helpers/ts-utils'
Expand All @@ -11,6 +11,7 @@ export type ImageProps = Omit<JSX.IntrinsicElements['mesh'], 'scale'> & {
scale?: number | [number, number]
color?: Color
zoom?: number
radius?: number
grayscale?: number
toneMapped?: boolean
transparent?: boolean
Expand All @@ -21,6 +22,8 @@ export type ImageProps = Omit<JSX.IntrinsicElements['mesh'], 'scale'> & {
type ImageMaterialType = JSX.IntrinsicElements['shaderMaterial'] & {
scale?: number[]
imageBounds?: number[]
radius?: number
resolution?: number
color?: Color
map: THREE.Texture
zoom?: number
Expand All @@ -40,25 +43,32 @@ const ImageMaterialImpl = /* @__PURE__ */ shaderMaterial(
color: /* @__PURE__ */ new THREE.Color('white'),
scale: /* @__PURE__ */ new THREE.Vector2(1, 1),
imageBounds: /* @__PURE__ */ new THREE.Vector2(1, 1),
resolution: 1024,
map: null,
zoom: 1,
radius: 0,
grayscale: 0,
opacity: 1,
},
/* glsl */ `
varying vec2 vUv;
varying vec2 vPos;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);
vUv = uv;
vPos = position.xy;
}
`,
/* glsl */ `
// mostly from https://gist.github.com/statico/df64c5d167362ecf7b34fca0b1459a44
varying vec2 vUv;
varying vec2 vPos;
uniform vec2 scale;
uniform vec2 imageBounds;
uniform float resolution;
uniform vec3 color;
uniform sampler2D map;
uniform float radius;
uniform float zoom;
uniform float grayscale;
uniform float opacity;
Expand All @@ -69,6 +79,14 @@ const ImageMaterialImpl = /* @__PURE__ */ shaderMaterial(
vec2 aspect(vec2 size) {
return size / min(size.x, size.y);
}
const float PI = 3.14159265;
// from https://iquilezles.org/articles/distfunctions
float udRoundBox( vec2 p, vec2 b, float r ) {
return length(max(abs(p)-b+r,0.0))-r;
}
void main() {
vec2 s = aspect(scale);
vec2 i = aspect(imageBounds);
Expand All @@ -78,7 +96,12 @@ const ImageMaterialImpl = /* @__PURE__ */ shaderMaterial(
vec2 offset = (rs < ri ? vec2((new.x - s.x) / 2.0, 0.0) : vec2(0.0, (new.y - s.y) / 2.0)) / new;
vec2 uv = vUv * s / new + offset;
vec2 zUv = (uv - vec2(0.5, 0.5)) / zoom + vec2(0.5, 0.5);
gl_FragColor = toGrayscale(texture2D(map, zUv) * vec4(color, opacity), grayscale);
vec2 res = vec2(scale * resolution);
vec2 halfRes = 0.5 * res;
float b = udRoundBox(vUv.xy * res - halfRes, halfRes, resolution * radius);
vec3 a = mix(vec3(1.0,0.0,0.0), vec3(0.0,0.0,0.0), smoothstep(0.0, 1.0, b));
gl_FragColor = toGrayscale(texture2D(map, zUv) * vec4(color, opacity * a), grayscale);
#include <tonemapping_fragment>
#include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
Expand All @@ -96,6 +119,7 @@ const ImageBase: ForwardRefComponent<Omit<ImageProps, 'url'>, THREE.Mesh> = /* @
zoom = 1,
grayscale = 0,
opacity = 1,
radius = 0,
texture,
toneMapped,
transparent,
Expand All @@ -106,8 +130,10 @@ const ImageBase: ForwardRefComponent<Omit<ImageProps, 'url'>, THREE.Mesh> = /* @
) => {
extend({ ImageMaterial: ImageMaterialImpl })
const ref = React.useRef<THREE.Mesh>(null!)
const size = useThree((state) => state.size)
const planeBounds = Array.isArray(scale) ? [scale[0], scale[1]] : [scale, scale]
const imageBounds = [texture!.image.width, texture!.image.height]
const resolution = Math.max(size.width, size.height)
React.useImperativeHandle(fref, () => ref.current, [])
React.useLayoutEffect(() => {
// Support arbitrary plane geometries (for instance with rounded corners)
Expand All @@ -133,9 +159,12 @@ const ImageBase: ForwardRefComponent<Omit<ImageProps, 'url'>, THREE.Mesh> = /* @
opacity={opacity}
scale={planeBounds}
imageBounds={imageBounds}
resolution={resolution}
radius={radius}
toneMapped={toneMapped}
transparent={transparent}
side={side}
key={ImageMaterialImpl.key}
/>
{children}
</mesh>
Expand Down

0 comments on commit 4d741a2

Please sign in to comment.