diff --git a/.storybook/public/images/share-screen.jpg b/.storybook/public/images/share-screen.jpg
new file mode 100644
index 000000000..ea7523b17
Binary files /dev/null and b/.storybook/public/images/share-screen.jpg differ
diff --git a/.storybook/public/images/sintel-cover.jpg b/.storybook/public/images/sintel-cover.jpg
new file mode 100644
index 000000000..314d231d0
Binary files /dev/null and b/.storybook/public/images/sintel-cover.jpg differ
diff --git a/.storybook/stories/useVideoTexture.stories.tsx b/.storybook/stories/useVideoTexture.stories.tsx
index 951ac45e2..45ce50226 100644
--- a/.storybook/stories/useVideoTexture.stories.tsx
+++ b/.storybook/stories/useVideoTexture.stories.tsx
@@ -1,26 +1,28 @@
import * as React from 'react'
+import { useState } from 'react'
import * as THREE from 'three'
import { Setup } from '../Setup'
-import { Plane, useVideoTexture } from '../../src'
+import { Plane, useVideoTexture, useTexture } from '../../src'
export default {
- title: 'Loaders/VideoTexture',
+ title: 'Misc/useVideoTexture',
component: useVideoTexture,
decorators: [(storyFn) => {storyFn()}],
}
+//
+// simple
+//
+
function VideoTexturedPlane() {
- const videoTexture = useVideoTexture(
- 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4',
- {}
- )
+ const texture = useVideoTexture('http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4')
return (
<>
-
-
+
+
>
)
@@ -38,3 +40,79 @@ export const UseVideoTextureSceneSt = () =>
UseVideoTextureSceneSt.story = {
name: 'Default',
}
+
+//
+// Suspense
+//
+
+function VideoTexturedPlane2() {
+ return (
+ <>
+
+ }>
+
+
+
+ >
+ )
+}
+
+function VideoMaterial({ src }) {
+ const texture = useVideoTexture(src)
+ return
+}
+
+function FallbackMaterial({ url }: { url: string }) {
+ const texture = useTexture(url)
+ return
+}
+
+function UseVideoTextureScene2() {
+ return (
+
+
+
+ )
+}
+
+export const UseVideoTextureSceneSt2 = () =>
+UseVideoTextureSceneSt2.story = {
+ name: 'Suspense',
+}
+
+//
+// getDisplayMedia (Screen Capture API)
+//
+
+function VideoTexturedPlane3() {
+ const [mediaStream, setMediaStream] = useState(new MediaStream())
+
+ return (
+ <>
+ {
+ const mediaStream = await navigator.mediaDevices.getDisplayMedia({ video: true })
+ setMediaStream(mediaStream)
+ }}
+ >
+ }>
+
+
+
+ >
+ )
+}
+
+function UseVideoTextureScene3() {
+ return (
+
+
+
+ )
+}
+
+export const UseVideoTextureSceneSt3 = () =>
+UseVideoTextureSceneSt3.story = {
+ name: 'MediaStream',
+}
diff --git a/src/core/useVideoTexture.tsx b/src/core/useVideoTexture.tsx
index 3f3a65a7d..e9fdad535 100644
--- a/src/core/useVideoTexture.tsx
+++ b/src/core/useVideoTexture.tsx
@@ -8,7 +8,7 @@ interface VideoTextureProps extends HTMLVideoElement {
start?: boolean
}
-export function useVideoTexture(src: string, props: Partial) {
+export function useVideoTexture(src: string | MediaStream, props?: Partial) {
const { unsuspend, start, crossOrigin, muted, loop, ...rest } = {
unsuspend: 'loadedmetadata',
crossOrigin: 'Anonymous',
@@ -19,11 +19,12 @@ export function useVideoTexture(src: string, props: Partial)
...props,
}
const gl = useThree((state) => state.gl)
- const texture = suspend<[url: string], () => Promise>(
+ const texture = suspend(
() =>
new Promise((res, rej) => {
const video = Object.assign(document.createElement('video'), {
- src,
+ src: (typeof src === 'string' && src) || undefined,
+ srcObject: (src instanceof MediaStream && src) || undefined,
crossOrigin,
loop,
muted,
@@ -34,7 +35,7 @@ export function useVideoTexture(src: string, props: Partial)
video.addEventListener(unsuspend, () => res(texture))
}),
[src]
- )
+ ) as THREE.VideoTexture
useEffect(() => void (start && texture.image.play()), [texture, start])
return texture
}