@react-three/drei 9.74.16 → 9.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -157,7 +157,7 @@ The `native` route of the library **does not** export `Html` or `Loader`. The de
157
157
  <li><a href="#view">View</a></li>
158
158
  <li><a href="#rendertexture">RenderTexture</a></li>
159
159
  <li><a href="#mask">Mask</a></li>
160
- <li><a href="#portal">Portal</a></li>
160
+ <li><a href="#meshportalmaterial">MeshPortalMaterial</a></li>
161
161
  </ul>
162
162
  <li><a href="#modifiers">Modifiers</a></li>
163
163
  <ul>
@@ -609,7 +609,7 @@ The camera follows your face.
609
609
  <a href="https://codesandbox.io/s/zhjbhy"><img width="20%" src="https://github-production-user-asset-6210df.s3.amazonaws.com/76580/244052845-5cc535d7-3c97-46e3-a267-52e707c2d9b2.png" alt="demo"/></a>
610
610
  </p>
611
611
 
612
- Pre-requisite: wrap into a `FaceLandmarker` provider
612
+ Pre-requisite: wrap into a [`FaceLandmarker`](#facelandmarker) provider
613
613
 
614
614
  ```tsx
615
615
  <FaceLandmarker>...</FaceLandmarker>
@@ -2544,6 +2544,46 @@ const buffer = useSurfaceSampler(
2544
2544
 
2545
2545
  A @mediapipe/tasks-vision [`FaceLandmarker`](https://developers.google.com/mediapipe/api/solutions/js/tasks-vision.facelandmarker) provider, as well as a `useFaceLandmarker` hook.
2546
2546
 
2547
+ ```tsx
2548
+ <FaceLandmarker>{/* ... */}</FaceLandmarker>
2549
+ ```
2550
+
2551
+ It will instanciate a FaceLandmarker object with the following defaults:
2552
+
2553
+ ```tsx
2554
+ {
2555
+ basePath: "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@x.y.z/wasm", // x.y.z will value the @mediapipe/tasks-vision version, eg: 0.10.2
2556
+ options: {
2557
+ baseOptions: {
2558
+ modelAssetPath: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task",
2559
+ delegate: "GPU",
2560
+ },
2561
+ runningMode: "VIDEO",
2562
+ outputFaceBlendshapes: true,
2563
+ outputFacialTransformationMatrixes: true,
2564
+ }
2565
+ }
2566
+ ```
2567
+
2568
+ You can override defaults, like for example self-host tasks-vision's `wasm/` and `face_landmarker.task` model in you `public/` directory:
2569
+
2570
+ ```sh
2571
+ $ ln -s ../node_modules/@mediapipe/tasks-vision/wasm/ public/tasks-vision-wasm
2572
+ $ curl https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task -o public/face_landmarker.task
2573
+ ```
2574
+
2575
+ ```tsx
2576
+ import { FaceLandmarkerDefaults } from '@react-three/drei'
2577
+
2578
+ const visionBasePath = new URL("/tasks-vision-wasm", import.meta.url).toString()
2579
+ const modelAssetPath = new URL("/face_landmarker.task", import.meta.url).toString()
2580
+
2581
+ const faceLandmarkerOptions = { ...FaceLandmarkerDefaults.options };
2582
+ faceLandmarkerOptions.baseOptions.modelAssetPath = modelAssetPath;
2583
+
2584
+ <FaceLandmarker basePath={visionBasePath} options={faceLandmarkerOptions}>
2585
+ ```
2586
+
2547
2587
  # Loading
2548
2588
 
2549
2589
  #### Loader
@@ -2624,12 +2664,19 @@ useGLTF.preload(url)
2624
2664
  > You can accomplish this by adding two `<link>` tags to your `<head>` tag, as below. The version in those URLs must exactly match what [useGLTF](src/core/useGLTF.tsx#L18) uses for this to work. If you're using create-react-app, `public/index.html` file contains the `<head>` tag.
2625
2665
  >
2626
2666
  > ```html
2627
- > <link rel="prefetch" crossorigin="anonymous" href="https://www.gstatic.com/draco/versioned/decoders/1.5.5/draco_wasm_wrapper.js">
2628
- > <link rel="prefetch" crossorigin="anonymous" href="https://www.gstatic.com/draco/versioned/decoders/1.5.5/draco_decoder.wasm">
2667
+ > <link
2668
+ > rel="prefetch"
2669
+ > crossorigin="anonymous"
2670
+ > href="https://www.gstatic.com/draco/versioned/decoders/1.5.5/draco_wasm_wrapper.js"
2671
+ > />
2672
+ > <link
2673
+ > rel="prefetch"
2674
+ > crossorigin="anonymous"
2675
+ > href="https://www.gstatic.com/draco/versioned/decoders/1.5.5/draco_decoder.wasm"
2676
+ > />
2629
2677
  > ```
2630
2678
  >
2631
2679
  > It is recommended that you check your browser's network tab to confirm that the correct URLs are being used, and that the files do get loaded from the prefetch cache on subsequent requests.
2632
-
2633
2680
 
2634
2681
  #### useFBX
2635
2682
 
@@ -3338,14 +3385,17 @@ Invert masks individually by providing a 2nd boolean argument to the `useMask` h
3338
3385
  const stencil = useMask(1, true)
3339
3386
  ```
3340
3387
 
3341
- #### Portal
3388
+ #### MeshPortalMaterial
3342
3389
 
3343
3390
  <p>
3344
3391
  <a href="https://codesandbox.io/s/ik11ln"><img width="20%" src="https://codesandbox.io/api/v1/sandboxes/ik11ln/screenshot.png" alt="Demo"/></a>
3345
3392
  </p>
3346
3393
 
3347
3394
  ```tsx
3348
- export type PortalProps = JSX.IntrinsicElements['portalMaterialImpl'] & {
3395
+ export type PortalProps = JSX.IntrinsicElements['shaderMaterial'] & {
3396
+ /** Mix the portals own scene with the world scene, 0 = world scene render,
3397
+ * 0.5 = both scenes render, 1 = portal scene renders, defaults to 0 */
3398
+ blend?: number
3349
3399
  /** Edge fade blur, 0 = no blur (default) */
3350
3400
  blur?: number
3351
3401
  /** SDF resolution, the smaller the faster is the start-up time (default: 512) */
@@ -3356,6 +3406,8 @@ export type PortalProps = JSX.IntrinsicElements['portalMaterialImpl'] & {
3356
3406
  eventPriority?: number
3357
3407
  /** Optional render priority, defaults to 0 */
3358
3408
  renderPriority?: number
3409
+ /** Optionally diable events inside the portal, defaults to false */
3410
+ events?: boolean
3359
3411
  }
3360
3412
  ```
3361
3413
 
@@ -3378,6 +3430,12 @@ You can optionally fade or blur the edges of the portal by providing a `blur` pr
3378
3430
  <MeshPortalMaterial transparent blur={0.5}>
3379
3431
  ```
3380
3432
 
3433
+ It is also possible to _enter_ the portal. If blend is 0 your scene will render as usual, if blend is higher it will start to blend the root scene and the portal scene, if blend is 1 it will only render the portal scene. If you put a ref on the material you can transition entering the portal, for instance lerping blend if the camera is close, or on click.
3434
+
3435
+ ```jsx
3436
+ <MeshPortalMaterial blend={1}>
3437
+ ```
3438
+
3381
3439
  # Staging
3382
3440
 
3383
3441
  #### Center
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("three"),t=require("react"),n=require("@react-three/fiber"),a=require("./useFBO.cjs.js"),i=require("./RenderTexture.cjs.js"),l=require("./shaderMaterial.cjs.js"),o=require("three-stdlib");function u(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function s(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}var v=u(e),m=s(r),d=s(t);const c=l.shaderMaterial({blur:0,map:null,sdf:null,size:0,resolution:new m.Vector2},"varying vec2 vUv;\n void main() {\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n vUv = uv;\n }","uniform sampler2D sdf;\n uniform sampler2D map;\n uniform float blur;\n uniform float size;\n uniform float time;\n uniform vec2 resolution;\n varying vec2 vUv;\n #include <packing>\n void main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec4 t = texture2D(map, uv);\n float k = blur;\n float d = texture2D(sdf, vUv).r/size;\n float alpha = 1.0 - smoothstep(0.0, 1.0, clamp(d/k + 1.0, 0.0, 1.0));\n gl_FragColor = vec4(t.rgb, blur == 0.0 ? t.a : t.a * alpha);\n #include <tonemapping_fragment>\n #include <encodings_fragment>\n }"),f=d.forwardRef((({children:e,blur:r=0,eventPriority:t,renderPriority:l,worldUnits:o=!1,resolution:u=512,...s},f)=>{n.extend({PortalMaterialImpl:c});const p=d.useRef(null),{gl:F,size:h,events:y,viewport:w}=n.useThree(),M=a.useFBO(u,u);return d.useLayoutEffect((()=>{var e;let t=null==(e=p.current)?void 0:e.__r3f.parent;if(t&&r&&null===p.current.sdf){const e=new m.Mesh(t.geometry,new m.MeshBasicMaterial),r=(new m.Box3).setFromBufferAttribute(e.geometry.attributes.position),n=new m.OrthographicCamera(r.min.x*(1+2/u),r.max.x*(1+2/u),r.max.y*(1+2/u),r.min.y*(1+2/u),.1,1e3);n.position.set(0,0,1),n.lookAt(0,0,0),F.setRenderTarget(M),F.render(e,n);const a=g(u,u,F)(M.texture),i=new Float32Array(u*u);F.readRenderTargetPixels(a,0,0,u,u,i);let l=1/0;for(let e=0;e<i.length;e++)i[e]<l&&(l=i[e]);l=-l,p.current.size=l,p.current.sdf=a.texture,F.setRenderTarget(null)}}),[u,r]),d.useImperativeHandle(f,(()=>p.current)),d.createElement("portalMaterialImpl",v.default({ref:p,blur:r,resolution:[h.width*w.dpr,h.height*w.dpr],toneMapped:!1,attach:"material"},s),d.createElement(i.RenderTexture,{attach:"map",eventPriority:t,renderPriority:l,compute:y.compute},e,d.createElement(x,{material:p,worldUnits:o})))}));function x({material:e,worldUnits:r}){const t=n.useThree((e=>e.scene));return d.useLayoutEffect((()=>{t.matrixAutoUpdate=!1}),[]),n.useFrame((()=>{var n;let a=null==e||null==(n=e.current)?void 0:n.__r3f.parent;a&&(r?t.matrixWorld.identity():t.matrixWorld.copy(a.matrixWorld))})),d.createElement(d.Fragment,null)}const g=(e,r,t)=>{let n=new m.WebGLRenderTarget(e,r,{minFilter:m.LinearMipmapLinearFilter,magFilter:m.LinearFilter,type:m.FloatType,format:m.RedFormat,generateMipmaps:!0}),a=new m.WebGLRenderTarget(e,r,{minFilter:m.NearestFilter,magFilter:m.NearestFilter}),i=new m.WebGLRenderTarget(e,r,{minFilter:m.NearestFilter,magFilter:m.NearestFilter}),l=new m.WebGLRenderTarget(e,r,{minFilter:m.NearestFilter,magFilter:m.NearestFilter}),u=new m.WebGLRenderTarget(e,r,{minFilter:m.NearestFilter,magFilter:m.NearestFilter}),s=new m.WebGLRenderTarget(e,r,{minFilter:m.NearestFilter,magFilter:m.NearestFilter,type:m.FloatType,format:m.RedFormat}),v=new m.WebGLRenderTarget(e,r,{minFilter:m.NearestFilter,magFilter:m.NearestFilter,type:m.FloatType,format:m.RedFormat});const d=new o.FullScreenQuad(new m.ShaderMaterial({uniforms:{tex:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n uniform sampler2D tex;\n varying vec2 vUv;\n #include <packing>\n void main() {\n gl_FragColor = pack2HalfToRGBA(vUv * (round(texture2D(tex, vUv).x)));\n }"})),c=new o.FullScreenQuad(new m.ShaderMaterial({uniforms:{tex:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n uniform sampler2D tex;\n varying vec2 vUv;\n #include <packing>\n void main() {\n gl_FragColor = pack2HalfToRGBA(vUv * (1.0 - round(texture2D(tex, vUv).x)));\n }"})),f=new o.FullScreenQuad(new m.ShaderMaterial({uniforms:{tex:{value:null},offset:{value:0},level:{value:0},maxSteps:{value:0}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:`\n varying vec2 vUv;\n uniform sampler2D tex;\n uniform float offset;\n uniform float level;\n uniform float maxSteps;\n #include <packing>\n void main() {\n float closestDist = 9999999.9;\n vec2 closestPos = vec2(0.0);\n for (float x = -1.0; x <= 1.0; x += 1.0) {\n for (float y = -1.0; y <= 1.0; y += 1.0) {\n vec2 voffset = vUv;\n voffset += vec2(x, y) * vec2(${1/e}, ${1/r}) * offset;\n vec2 pos = unpackRGBATo2Half(texture2D(tex, voffset));\n float dist = distance(pos.xy, vUv);\n if(pos.x != 0.0 && pos.y != 0.0 && dist < closestDist) {\n closestDist = dist;\n closestPos = pos;\n }\n }\n }\n gl_FragColor = pack2HalfToRGBA(closestPos);\n }`})),x=new o.FullScreenQuad(new m.ShaderMaterial({uniforms:{tex:{value:null},size:{value:new m.Vector2(e,r)}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n varying vec2 vUv;\n uniform sampler2D tex;\n uniform vec2 size;\n #include <packing>\n void main() {\n gl_FragColor = vec4(distance(size * unpackRGBATo2Half(texture2D(tex, vUv)), size * vUv), 0.0, 0.0, 0.0);\n }"})),g=new o.FullScreenQuad(new m.ShaderMaterial({uniforms:{inside:{value:v.texture},outside:{value:s.texture},tex:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n varying vec2 vUv;\n uniform sampler2D inside;\n uniform sampler2D outside;\n uniform sampler2D tex;\n #include <packing>\n void main() {\n float i = texture2D(inside, vUv).x;\n float o =texture2D(outside, vUv).x;\n if (texture2D(tex, vUv).x == 0.0) {\n gl_FragColor = vec4(o, 0.0, 0.0, 0.0);\n } else {\n gl_FragColor = vec4(-i, 0.0, 0.0, 0.0);\n }\n }"}));return o=>{let p=n;o.minFilter=m.NearestFilter,o.magFilter=m.NearestFilter,d.material.uniforms.tex.value=o,t.setRenderTarget(a),d.render(t);const F=Math.ceil(Math.log(Math.max(e,r))/Math.log(2));let h=a,y=null;for(let e=0;e<F;e++){const r=Math.pow(2,F-e-1);y=h===a?l:a,f.material.uniforms.level.value=e,f.material.uniforms.maxSteps.value=F,f.material.uniforms.offset.value=r,f.material.uniforms.tex.value=h.texture,t.setRenderTarget(y),f.render(t),h=y}t.setRenderTarget(s),x.material.uniforms.tex.value=y.texture,x.render(t),c.material.uniforms.tex.value=o,t.setRenderTarget(i),c.render(t),h=i;for(let e=0;e<F;e++){const r=Math.pow(2,F-e-1);y=h===i?u:i,f.material.uniforms.level.value=e,f.material.uniforms.maxSteps.value=F,f.material.uniforms.offset.value=r,f.material.uniforms.tex.value=h.texture,t.setRenderTarget(y),f.render(t),h=y}return t.setRenderTarget(v),x.material.uniforms.tex.value=y.texture,x.render(t),t.setRenderTarget(p),g.material.uniforms.tex.value=o,g.render(t),t.setRenderTarget(null),p}};exports.MeshPortalMaterial=f;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("three"),t=require("react"),n=require("@react-three/fiber"),a=require("./useIntersect.cjs.js"),i=require("./useFBO.cjs.js"),l=require("./RenderTexture.cjs.js"),o=require("./shaderMaterial.cjs.js"),u=require("three-stdlib");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function v(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}var c=s(e),d=v(r),m=v(t);const f=o.shaderMaterial({blur:0,map:null,sdf:null,blend:0,size:0,resolution:new d.Vector2},"varying vec2 vUv;\n void main() {\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n vUv = uv;\n }","uniform sampler2D sdf;\n uniform sampler2D map;\n uniform float blur;\n uniform float size;\n uniform float time;\n uniform vec2 resolution;\n varying vec2 vUv;\n #include <packing>\n void main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec4 t = texture2D(map, uv);\n float k = blur;\n float d = texture2D(sdf, vUv).r/size;\n float alpha = 1.0 - smoothstep(0.0, 1.0, clamp(d/k + 1.0, 0.0, 1.0));\n gl_FragColor = vec4(t.rgb, blur == 0.0 ? t.a : t.a * alpha);\n #include <tonemapping_fragment>\n #include <encodings_fragment>\n }"),g=m.forwardRef((({children:e,events:r,blur:t=0,eventPriority:o=0,renderPriority:u=0,worldUnits:s=!1,resolution:v=512,...g},F)=>{n.extend({PortalMaterialImpl:f});const h=m.useRef(null),{scene:y,gl:b,size:w,viewport:M,setEvents:U}=n.useThree(),T=i.useFBO(v,v),[R,S]=m.useState(0);n.useFrame((()=>{const e=h.current.blend>0?Math.max(1,u):0;R!==e&&S(e)})),m.useEffect((()=>{void 0!==r&&U({enabled:!r})}),[r]);const[_,D]=m.useState(!0),j=a.useIntersect(D);m.useLayoutEffect((()=>{var e;j.current=null==(e=h.current)?void 0:e.__r3f.parent}),[]),m.useLayoutEffect((()=>{if(j.current&&t&&null===h.current.sdf){const e=new d.Mesh(j.current.geometry,new d.MeshBasicMaterial),r=(new d.Box3).setFromBufferAttribute(e.geometry.attributes.position),t=new d.OrthographicCamera(r.min.x*(1+2/v),r.max.x*(1+2/v),r.max.y*(1+2/v),r.min.y*(1+2/v),.1,1e3);t.position.set(0,0,1),t.lookAt(0,0,0),b.setRenderTarget(T),b.render(e,t);const n=p(v,v,b)(T.texture),a=new Float32Array(v*v);b.readRenderTargetPixels(n,0,0,v,v,a);let i=1/0;for(let e=0;e<a.length;e++)a[e]<i&&(i=a[e]);i=-i,h.current.size=i,h.current.sdf=n.texture,b.setRenderTarget(null)}}),[v,t]),m.useImperativeHandle(F,(()=>h.current));const P=m.useCallback(((e,r,t)=>{var n;if(!j.current)return!1;if(r.pointer.set(e.offsetX/r.size.width*2-1,-e.offsetY/r.size.height*2+1),r.raycaster.setFromCamera(r.pointer,r.camera),0===(null==(n=h.current)?void 0:n.blend)){const[e]=r.raycaster.intersectObject(j.current);if(!e)return r.raycaster.camera=void 0,!1}}),[]);return m.createElement("portalMaterialImpl",c.default({ref:h,blur:t,blend:0,resolution:[w.width*M.dpr,w.height*M.dpr],toneMapped:!1,attach:"material"},g),m.createElement(l.RenderTexture,{attach:"map",frames:_?1/0:0,eventPriority:o,renderPriority:u,compute:P},e,m.createElement(x,{events:r,rootScene:y,priority:R,material:h,worldUnits:s})))}));function x({events:e,rootScene:r,material:t,priority:a,worldUnits:l}){const o=n.useThree((e=>e.scene)),s=n.useThree((e=>e.setEvents)),v=i.useFBO(),c=i.useFBO();m.useLayoutEffect((()=>{o.matrixAutoUpdate=!1}),[]),m.useEffect((()=>{void 0!==e&&s({enabled:e})}),[e]);const[f,g]=m.useMemo((()=>{const e={value:0};return[new u.FullScreenQuad(new d.ShaderMaterial({uniforms:{a:{value:v.texture},b:{value:c.texture},blend:e},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n uniform sampler2D a;\n uniform sampler2D b;\n uniform float blend;\n varying vec2 vUv;\n #include <packing>\n void main() {\n vec4 ta = texture2D(a, vUv);\n vec4 tb = texture2D(b, vUv);\n gl_FragColor = mix(tb, ta, blend);\n #include <encodings_fragment>\n }"})),e]}),[]);return n.useFrame((e=>{var n;let i=null==t||null==(n=t.current)?void 0:n.__r3f.parent;var u,s,d;i&&(l?o.matrixWorld.identity():o.matrixWorld.copy(i.matrixWorld),a&&((null==(u=t.current)?void 0:u.blend)>0&&(null==(s=t.current)?void 0:s.blend)<1&&i?(g.value=t.current.blend,e.gl.setRenderTarget(v),e.gl.render(o,e.camera),e.gl.setRenderTarget(c),e.gl.render(r,e.camera),e.gl.setRenderTarget(null),f.render(e.gl)):1===(null==(d=t.current)?void 0:d.blend)&&e.gl.render(o,e.camera)))}),a),m.createElement(m.Fragment,null)}const p=(e,r,t)=>{let n=new d.WebGLRenderTarget(e,r,{minFilter:d.LinearMipmapLinearFilter,magFilter:d.LinearFilter,type:d.FloatType,format:d.RedFormat,generateMipmaps:!0}),a=new d.WebGLRenderTarget(e,r,{minFilter:d.NearestFilter,magFilter:d.NearestFilter}),i=new d.WebGLRenderTarget(e,r,{minFilter:d.NearestFilter,magFilter:d.NearestFilter}),l=new d.WebGLRenderTarget(e,r,{minFilter:d.NearestFilter,magFilter:d.NearestFilter}),o=new d.WebGLRenderTarget(e,r,{minFilter:d.NearestFilter,magFilter:d.NearestFilter}),s=new d.WebGLRenderTarget(e,r,{minFilter:d.NearestFilter,magFilter:d.NearestFilter,type:d.FloatType,format:d.RedFormat}),v=new d.WebGLRenderTarget(e,r,{minFilter:d.NearestFilter,magFilter:d.NearestFilter,type:d.FloatType,format:d.RedFormat});const c=new u.FullScreenQuad(new d.ShaderMaterial({uniforms:{tex:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n uniform sampler2D tex;\n varying vec2 vUv;\n #include <packing>\n void main() {\n gl_FragColor = pack2HalfToRGBA(vUv * (round(texture2D(tex, vUv).x)));\n }"})),m=new u.FullScreenQuad(new d.ShaderMaterial({uniforms:{tex:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n uniform sampler2D tex;\n varying vec2 vUv;\n #include <packing>\n void main() {\n gl_FragColor = pack2HalfToRGBA(vUv * (1.0 - round(texture2D(tex, vUv).x)));\n }"})),f=new u.FullScreenQuad(new d.ShaderMaterial({uniforms:{tex:{value:null},offset:{value:0},level:{value:0},maxSteps:{value:0}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:`\n varying vec2 vUv;\n uniform sampler2D tex;\n uniform float offset;\n uniform float level;\n uniform float maxSteps;\n #include <packing>\n void main() {\n float closestDist = 9999999.9;\n vec2 closestPos = vec2(0.0);\n for (float x = -1.0; x <= 1.0; x += 1.0) {\n for (float y = -1.0; y <= 1.0; y += 1.0) {\n vec2 voffset = vUv;\n voffset += vec2(x, y) * vec2(${1/e}, ${1/r}) * offset;\n vec2 pos = unpackRGBATo2Half(texture2D(tex, voffset));\n float dist = distance(pos.xy, vUv);\n if(pos.x != 0.0 && pos.y != 0.0 && dist < closestDist) {\n closestDist = dist;\n closestPos = pos;\n }\n }\n }\n gl_FragColor = pack2HalfToRGBA(closestPos);\n }`})),g=new u.FullScreenQuad(new d.ShaderMaterial({uniforms:{tex:{value:null},size:{value:new d.Vector2(e,r)}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n varying vec2 vUv;\n uniform sampler2D tex;\n uniform vec2 size;\n #include <packing>\n void main() {\n gl_FragColor = vec4(distance(size * unpackRGBATo2Half(texture2D(tex, vUv)), size * vUv), 0.0, 0.0, 0.0);\n }"})),x=new u.FullScreenQuad(new d.ShaderMaterial({uniforms:{inside:{value:v.texture},outside:{value:s.texture},tex:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n varying vec2 vUv;\n uniform sampler2D inside;\n uniform sampler2D outside;\n uniform sampler2D tex;\n #include <packing>\n void main() {\n float i = texture2D(inside, vUv).x;\n float o =texture2D(outside, vUv).x;\n if (texture2D(tex, vUv).x == 0.0) {\n gl_FragColor = vec4(o, 0.0, 0.0, 0.0);\n } else {\n gl_FragColor = vec4(-i, 0.0, 0.0, 0.0);\n }\n }"}));return u=>{let p=n;u.minFilter=d.NearestFilter,u.magFilter=d.NearestFilter,c.material.uniforms.tex.value=u,t.setRenderTarget(a),c.render(t);const F=Math.ceil(Math.log(Math.max(e,r))/Math.log(2));let h=a,y=null;for(let e=0;e<F;e++){const r=Math.pow(2,F-e-1);y=h===a?l:a,f.material.uniforms.level.value=e,f.material.uniforms.maxSteps.value=F,f.material.uniforms.offset.value=r,f.material.uniforms.tex.value=h.texture,t.setRenderTarget(y),f.render(t),h=y}t.setRenderTarget(s),g.material.uniforms.tex.value=y.texture,g.render(t),m.material.uniforms.tex.value=u,t.setRenderTarget(i),m.render(t),h=i;for(let e=0;e<F;e++){const r=Math.pow(2,F-e-1);y=h===i?o:i,f.material.uniforms.level.value=e,f.material.uniforms.maxSteps.value=F,f.material.uniforms.offset.value=r,f.material.uniforms.tex.value=h.texture,t.setRenderTarget(y),f.render(t),h=y}return t.setRenderTarget(v),g.material.uniforms.tex.value=y.texture,g.render(t),t.setRenderTarget(p),x.material.uniforms.tex.value=u,x.render(t),t.setRenderTarget(null),p}};exports.MeshPortalMaterial=g;
@@ -4,6 +4,7 @@ import { ReactThreeFiber } from '@react-three/fiber';
4
4
  export declare type PortalMaterialType = {
5
5
  resolution: ReactThreeFiber.Vector2;
6
6
  blur: number;
7
+ blend: number;
7
8
  size?: number;
8
9
  sdf?: THREE.Texture;
9
10
  map?: THREE.Texture;
@@ -16,16 +17,20 @@ declare global {
16
17
  }
17
18
  }
18
19
  export declare type PortalProps = JSX.IntrinsicElements['shaderMaterial'] & {
20
+ blend?: number;
19
21
  blur?: number;
20
22
  resolution?: number;
21
23
  worldUnits?: boolean;
22
24
  eventPriority?: number;
23
25
  renderPriority?: number;
26
+ events?: boolean;
24
27
  };
25
28
  export declare const MeshPortalMaterial: React.ForwardRefExoticComponent<Pick<ReactThreeFiber.ExtendedColors<ReactThreeFiber.Overwrite<Partial<THREE.ShaderMaterial>, ReactThreeFiber.NodeProps<THREE.ShaderMaterial, [THREE.ShaderMaterialParameters]>>> & {
29
+ blend?: number | undefined;
26
30
  blur?: number | undefined;
27
31
  resolution?: number | undefined;
28
32
  worldUnits?: boolean | undefined;
29
33
  eventPriority?: number | undefined;
30
34
  renderPriority?: number | undefined;
31
- }, "attach" | "args" | "children" | "key" | "onUpdate" | keyof THREE.ShaderMaterial | "blur" | "resolution" | "worldUnits" | "renderPriority" | "eventPriority"> & React.RefAttributes<PortalMaterialType>>;
35
+ events?: boolean | undefined;
36
+ }, "attach" | "args" | "children" | "key" | "onUpdate" | "events" | keyof THREE.ShaderMaterial | "blur" | "resolution" | "worldUnits" | "renderPriority" | "blend" | "eventPriority"> & React.RefAttributes<PortalMaterialType>>;
@@ -2,6 +2,7 @@ import _extends from '@babel/runtime/helpers/esm/extends';
2
2
  import * as THREE from 'three';
3
3
  import * as React from 'react';
4
4
  import { extend, useThree, useFrame } from '@react-three/fiber';
5
+ import { useIntersect } from './useIntersect.js';
5
6
  import { useFBO } from './useFBO.js';
6
7
  import { RenderTexture } from './RenderTexture.js';
7
8
  import { shaderMaterial } from './shaderMaterial.js';
@@ -11,6 +12,7 @@ const PortalMaterialImpl = shaderMaterial({
11
12
  blur: 0,
12
13
  map: null,
13
14
  sdf: null,
15
+ blend: 0,
14
16
  size: 0,
15
17
  resolution: new THREE.Vector2()
16
18
  }, `varying vec2 vUv;
@@ -37,9 +39,10 @@ const PortalMaterialImpl = shaderMaterial({
37
39
  }`);
38
40
  const MeshPortalMaterial = /*#__PURE__*/React.forwardRef(({
39
41
  children,
42
+ events = undefined,
40
43
  blur = 0,
41
- eventPriority,
42
- renderPriority,
44
+ eventPriority = 0,
45
+ renderPriority = 0,
43
46
  worldUnits = false,
44
47
  resolution = 512,
45
48
  ...props
@@ -49,20 +52,39 @@ const MeshPortalMaterial = /*#__PURE__*/React.forwardRef(({
49
52
  });
50
53
  const ref = React.useRef(null);
51
54
  const {
55
+ scene,
52
56
  gl,
53
57
  size,
54
- events,
55
- viewport
58
+ viewport,
59
+ setEvents
56
60
  } = useThree();
57
61
  const maskRenderTarget = useFBO(resolution, resolution);
62
+ const [priority, setPriority] = React.useState(0);
63
+ useFrame(() => {
64
+ // If blend is > 0 then the portal is being entered, the render-priority must change
65
+ const p = ref.current.blend > 0 ? Math.max(1, renderPriority) : 0;
66
+ if (priority !== p) setPriority(p);
67
+ });
68
+ React.useEffect(() => {
69
+ if (events !== undefined) setEvents({
70
+ enabled: !events
71
+ });
72
+ }, [events]);
73
+ const [visible, setVisible] = React.useState(true); // See if the parent mesh is in the camera frustum
74
+
75
+ const parent = useIntersect(setVisible);
58
76
  React.useLayoutEffect(() => {
59
77
  var _ref$current;
60
78
 
61
- let mask = (_ref$current = ref.current) == null ? void 0 : _ref$current.__r3f.parent;
62
- if (!mask) return; // Apply the SDF mask only once
79
+ // Since the ref above is not tied to a mesh directly (we're inside a material),
80
+ // it has to be tied to the parent mesh here
81
+ parent.current = (_ref$current = ref.current) == null ? void 0 : _ref$current.__r3f.parent;
82
+ }, []);
83
+ React.useLayoutEffect(() => {
84
+ if (!parent.current) return; // Apply the SDF mask only once
63
85
 
64
86
  if (blur && ref.current.sdf === null) {
65
- const tempMesh = new THREE.Mesh(mask.geometry, new THREE.MeshBasicMaterial());
87
+ const tempMesh = new THREE.Mesh(parent.current.geometry, new THREE.MeshBasicMaterial());
66
88
  const boundingBox = new THREE.Box3().setFromBufferAttribute(tempMesh.geometry.attributes.position);
67
89
  const orthoCam = new THREE.OrthographicCamera(boundingBox.min.x * (1 + 2 / resolution), boundingBox.max.x * (1 + 2 / resolution), boundingBox.max.y * (1 + 2 / resolution), boundingBox.min.y * (1 + 2 / resolution), 0.1, 1000);
68
90
  orthoCam.position.set(0, 0, 1);
@@ -87,40 +109,130 @@ const MeshPortalMaterial = /*#__PURE__*/React.forwardRef(({
87
109
  }
88
110
  }, [resolution, blur]);
89
111
  React.useImperativeHandle(fref, () => ref.current);
112
+ const compute = React.useCallback((event, state, previous) => {
113
+ var _ref$current2;
114
+
115
+ if (!parent.current) return false;
116
+ state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
117
+ state.raycaster.setFromCamera(state.pointer, state.camera);
118
+
119
+ if (((_ref$current2 = ref.current) == null ? void 0 : _ref$current2.blend) === 0) {
120
+ // We run a quick check against the parent, if it isn't hit there's no need to raycast at all
121
+ const [intersection] = state.raycaster.intersectObject(parent.current);
122
+
123
+ if (!intersection) {
124
+ // Cancel out the raycast camera if the parent mesh isn't hit
125
+ state.raycaster.camera = undefined;
126
+ return false;
127
+ }
128
+ }
129
+ }, []);
90
130
  return /*#__PURE__*/React.createElement("portalMaterialImpl", _extends({
91
131
  ref: ref,
92
132
  blur: blur,
133
+ blend: 0,
93
134
  resolution: [size.width * viewport.dpr, size.height * viewport.dpr],
94
135
  toneMapped: false,
95
136
  attach: "material"
96
137
  }, props), /*#__PURE__*/React.createElement(RenderTexture, {
97
138
  attach: "map",
139
+ frames: visible ? Infinity : 0,
98
140
  eventPriority: eventPriority,
99
141
  renderPriority: renderPriority,
100
- compute: events.compute
142
+ compute: compute
101
143
  }, children, /*#__PURE__*/React.createElement(CopyMatrix, {
144
+ events: events,
145
+ rootScene: scene,
146
+ priority: priority,
102
147
  material: ref,
103
148
  worldUnits: worldUnits
104
149
  })));
105
150
  });
106
151
 
107
152
  function CopyMatrix({
153
+ events = undefined,
154
+ rootScene,
108
155
  material,
156
+ priority,
109
157
  worldUnits
110
158
  }) {
111
159
  const scene = useThree(state => state.scene);
160
+ const setEvents = useThree(state => state.setEvents);
161
+ const buffer1 = useFBO();
162
+ const buffer2 = useFBO();
112
163
  React.useLayoutEffect(() => {
113
164
  scene.matrixAutoUpdate = false;
114
165
  }, []);
115
- useFrame(() => {
166
+ React.useEffect(() => {
167
+ if (events !== undefined) setEvents({
168
+ enabled: events
169
+ });
170
+ }, [events]);
171
+ const [quad, blend] = React.useMemo(() => {
172
+ // This fullscree-quad is used to blend the two textures
173
+ const blend = {
174
+ value: 0
175
+ };
176
+ const quad = new FullScreenQuad(new THREE.ShaderMaterial({
177
+ uniforms: {
178
+ a: {
179
+ value: buffer1.texture
180
+ },
181
+ b: {
182
+ value: buffer2.texture
183
+ },
184
+ blend
185
+ },
186
+ vertexShader:
187
+ /*glsl*/
188
+ `
189
+ varying vec2 vUv;
190
+ void main() {
191
+ vUv = uv;
192
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
193
+ }`,
194
+ fragmentShader:
195
+ /*glsl*/
196
+ `
197
+ uniform sampler2D a;
198
+ uniform sampler2D b;
199
+ uniform float blend;
200
+ varying vec2 vUv;
201
+ #include <packing>
202
+ void main() {
203
+ vec4 ta = texture2D(a, vUv);
204
+ vec4 tb = texture2D(b, vUv);
205
+ gl_FragColor = mix(tb, ta, blend);
206
+ #include <encodings_fragment>
207
+ }`
208
+ }));
209
+ return [quad, blend];
210
+ }, []);
211
+ useFrame(state => {
116
212
  var _material$current;
117
213
 
118
214
  let parent = material == null ? void 0 : (_material$current = material.current) == null ? void 0 : _material$current.__r3f.parent;
119
215
 
120
216
  if (parent) {
121
217
  if (!worldUnits) scene.matrixWorld.copy(parent.matrixWorld);else scene.matrixWorld.identity();
218
+
219
+ if (priority) {
220
+ var _material$current2, _material$current3, _material$current4;
221
+
222
+ if (((_material$current2 = material.current) == null ? void 0 : _material$current2.blend) > 0 && ((_material$current3 = material.current) == null ? void 0 : _material$current3.blend) < 1 && parent) {
223
+ blend.value = material.current.blend;
224
+ state.gl.setRenderTarget(buffer1);
225
+ state.gl.render(scene, state.camera);
226
+ state.gl.setRenderTarget(buffer2);
227
+ state.gl.render(rootScene, state.camera);
228
+ state.gl.setRenderTarget(null);
229
+ quad.render(state.gl);
230
+ } else if (((_material$current4 = material.current) == null ? void 0 : _material$current4.blend) === 1) {
231
+ state.gl.render(scene, state.camera);
232
+ }
233
+ }
122
234
  }
123
- });
235
+ }, priority);
124
236
  return /*#__PURE__*/React.createElement(React.Fragment, null);
125
237
  }
126
238