@react-three/drei 9.52.3 → 9.52.5

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
@@ -1830,6 +1830,8 @@ Enable shadows using the `castShadow` and `recieveShadow` prop.
1830
1830
  />
1831
1831
  ```
1832
1832
 
1833
+ > Note: Html 'blending' mode only correctly occludes rectangular HTML elements by default. Use the `geometry` prop to swap the backing geometry to a custom one if your Html has a different shape.
1834
+
1833
1835
  #### CycleRaycast
1834
1836
 
1835
1837
  ![](https://img.shields.io/badge/-Dom only-red)
@@ -2841,6 +2843,8 @@ export type Props = JSX.IntrinsicElements['group'] & {
2841
2843
  left?: boolean
2842
2844
  front?: boolean
2843
2845
  back?: boolean
2846
+ /** Disable all axes */
2847
+ disable?: boolean
2844
2848
  /** Disable x-axis centering */
2845
2849
  disableX?: boolean
2846
2850
  /** Disable y-axis centering */
@@ -3117,14 +3121,14 @@ Caustics are swirls of light that appear when light passes through transmissive
3117
3121
 
3118
3122
  ```tsx
3119
3123
  type CausticsProps = JSX.IntrinsicElements['group'] & {
3124
+ /** How many frames it will render, set it to Infinity for runtime, default: 1 */
3125
+ frames?: number
3120
3126
  /** Enables visual cues to help you stage your scene, default: false */
3121
3127
  debug?: boolean
3122
3128
  /** Will display caustics only and skip the models, default: false */
3123
3129
  causticsOnly: boolean
3124
3130
  /** Will include back faces and enable the backfaceIor prop, default: false */
3125
3131
  backfaces: boolean
3126
- /** The size of the camera frustum, default: 2 */
3127
- frustum?: number
3128
3132
  /** The IOR refraction index, default: 1.1 */
3129
3133
  ior?: number
3130
3134
  /** The IOR refraction index for back faces (only available when backfaces is enabled), default: 1.1 */
@@ -3137,14 +3141,8 @@ type CausticsProps = JSX.IntrinsicElements['group'] & {
3137
3141
  color?: ReactThreeFiber.Color
3138
3142
  /** Buffer resolution, default: 2048 */
3139
3143
  resolution?: number
3140
- /** Camera near, default: 0.1 */
3141
- near?: number
3142
- /** Camera far, default: 100 */
3143
- far?: number
3144
- /** Camera position, default: [5, 5, 5] */
3145
- lightSource?: [x: number, y: number, z: number]
3146
- /** Camera lookAt, default: [0, 0, 0] */
3147
- focus?: [x: number, y: number, z: number]
3144
+ /** Camera position, it will point towards the contents bounds center, default: [5, 5, 5] */
3145
+ lightSource?: [x: number, y: number, z: number] | React.MutableRefObject<THREE.Object3D>
3148
3146
  }
3149
3147
  ```
3150
3148
 
@@ -3153,7 +3151,7 @@ It will create a transparent plane that blends the caustics of the objects it re
3153
3151
  Make sure to use the `debug` flag to help you stage your contents. Like ContactShadows and AccumulativeShadows the plane faces Y up. It is recommended to use [leva](https://github.com/pmndrs/leva) to configue the props above as some can be micro fractional depending on the models (intensity, worldRadius, ior and backfaceIor especially).
3154
3152
 
3155
3153
  ```jsx
3156
- <Caustics debug backfaces lightSource={[2.5, 5, -2.5]} frustum={4}>
3154
+ <Caustics debug backfaces lightSource={[2.5, 5, -2.5]}>
3157
3155
  <Bottle />
3158
3156
  <WineGlass>
3159
3157
  </Caustics>
@@ -3162,12 +3160,23 @@ Make sure to use the `debug` flag to help you stage your contents. Like ContactS
3162
3160
  Sometimes you want to combine caustics for even better visuals, or if you want to emulate multiple lightsources. Use the `causticsOnly` flag in such cases and it will use the model inside only for calculations. Since all loaders in Fiber should be cached there is no expense or memory overhead doing this.
3163
3161
 
3164
3162
  ```jsx
3165
- <Caustics lightSource={[2.5, 5, -2.5]} >
3163
+ <Caustics backfaces lightSource={[2.5, 5, -2.5]} >
3164
+ <WineGlass />
3165
+ </Caustics>
3166
+ <Caustics causticsOnly backfaces lightSource={[-2.5, 5, 2.5]} ior={0.79} worldRadius={0.0124}>
3166
3167
  <WineGlass />
3167
3168
  </Caustics>
3168
- <Caustics causticsOnly lightSource={[-2.5, 5, 2.5]} ior={0.79} worldRadius={0.0124}>
3169
+ ```
3170
+
3171
+ The light source can either be defined by prop or by reference. Use the latter if you want to control the light source, for instance in order to move or animate it. Runtime caustics with frames set to `Infinity`, a low resolution and no backfaces can be feasible.
3172
+
3173
+ ```jsx
3174
+ const lightSource = useRef()
3175
+
3176
+ <Caustics frames={Infinity} resolution={256} lightSource={lightSource} >
3169
3177
  <WineGlass />
3170
3178
  </Caustics>
3179
+ <object3d ref={lightSource} position={[2.5, 5, -2.5]} />
3171
3180
  ```
3172
3181
 
3173
3182
  #### ContactShadows
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("three"),n=require("react"),t=require("@react-three/fiber"),i=require("./useFBO.cjs.js"),o=require("./useHelper.cjs.js"),a=require("./shaderMaterial.cjs.js"),l=require("three-stdlib");function c(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(n){if("default"!==n){var t=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,t.get?t:{enumerable:!0,get:function(){return e[n]}})}})),r.default=e,Object.freeze(r)}var u=c(e),d=s(r),v=s(n);function f(e=d.FrontSide){const r={value:new d.Matrix4};return Object.assign(new d.MeshNormalMaterial({side:e}),{viewMatrix:r,onBeforeCompile:e=>{e.uniforms.viewMatrix=r,e.fragmentShader="vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n }\n"+e.fragmentShader.replace("#include <normal_fragment_maps>","#include <normal_fragment_maps>\n normal = inverseTransformDirection( normal, viewMatrix );\n")}})}const p=a.shaderMaterial({causticsTexture:null,causticsTextureB:null,color:new d.Color("white"),lightProjMatrix:new d.Matrix4,lightViewMatrix:new d.Matrix4},"varying vec3 vWorldPosition; \n void main() {\n gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);\n vec4 worldPosition = modelMatrix * vec4(position, 1.);\n vWorldPosition = worldPosition.xyz;\n }","varying vec3 vWorldPosition;\n uniform vec3 color;\n uniform sampler2D causticsTexture; \n uniform sampler2D causticsTextureB; \n uniform mat4 lightProjMatrix;\n uniform mat4 lightViewMatrix;\n void main() {\n // Apply caustics \n vec4 lightSpacePos = lightProjMatrix * lightViewMatrix * vec4(vWorldPosition, 1.0);\n lightSpacePos.xyz /= lightSpacePos.w;\n lightSpacePos.xyz = lightSpacePos.xyz * 0.5 + 0.5; \n vec3 front = texture2D(causticsTexture, lightSpacePos.xy).rgb;\n vec3 back = texture2D(causticsTextureB, lightSpacePos.xy).rgb;\n gl_FragColor = vec4((front + back) * color, 1.0);\n #include <tonemapping_fragment>\n #include <encodings_fragment>\n }"),m=a.shaderMaterial({cameraMatrixWorld:new d.Matrix4,cameraProjectionMatrixInv:new d.Matrix4,normalTexture:null,depthTexture:null,lightDir:new d.Vector3(0,1,0),near:.1,far:100,modelMatrix:new d.Matrix4,worldRadius:1/40,ior:1.1,bounces:0,resolution:1024,size:10,intensity:.5},"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }"," \n uniform mat4 cameraMatrixWorld;\n uniform mat4 cameraProjectionMatrixInv;\n uniform vec3 lightDir;\n uniform float near;\n uniform float far;\n uniform float time;\n uniform float worldRadius;\n uniform float resolution;\n uniform float size;\n uniform float intensity;\n uniform float ior;\n precision highp isampler2D;\n precision highp usampler2D;\n uniform sampler2D normalTexture;\n uniform sampler2D depthTexture;\n uniform float bounces;\n varying vec2 vUv;\n vec3 WorldPosFromDepth(float depth, vec2 coord) {\n float z = depth * 2.0 - 1.0;\n vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);\n vec4 viewSpacePosition = cameraProjectionMatrixInv * clipSpacePosition;\n // Perspective division\n viewSpacePosition /= viewSpacePosition.w;\n vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition;\n return worldSpacePosition.xyz;\n } \n float sdPlane( vec3 p, vec3 n, float h ) {\n // n must be normalized\n return dot(p,n) + h;\n }\n float planeIntersect( vec3 ro, vec3 rd, vec4 p ) {\n return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);\n }\n vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 pos, vec3 normal, float ior, out vec3 rayOrigin, out vec3 rayDirection) {\n rayOrigin = ro;\n rayDirection = rd;\n rayDirection = refract(rayDirection, normal, 1.0 / ior);\n rayOrigin = pos + rayDirection * 0.1;\n return rayDirection;\n }\n void main() {\n // Each sample consists of random offset in the x and y direction\n float caustic = 0.0;\n float causticTexelSize = (1.0 / resolution) * size * 2.0;\n float texelsNeeded = worldRadius / causticTexelSize;\n float sampleRadius = texelsNeeded / resolution;\n float sum = 0.0;\n if (texture2D(depthTexture, vUv).x == 1.0) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n vec2 offset1 = vec2(-0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 offset2 = vec2(-0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 offset3 = vec2(0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 offset4 = vec2(0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 uv1 = vUv + offset1 * sampleRadius;\n vec2 uv2 = vUv + offset2 * sampleRadius;\n vec2 uv3 = vUv + offset3 * sampleRadius;\n vec2 uv4 = vUv + offset4 * sampleRadius;\n vec3 normal1 = texture2D(normalTexture, uv1, -10.0).rgb * 2.0 - 1.0;\n vec3 normal2 = texture2D(normalTexture, uv2, -10.0).rgb * 2.0 - 1.0;\n vec3 normal3 = texture2D(normalTexture, uv3, -10.0).rgb * 2.0 - 1.0;\n vec3 normal4 = texture2D(normalTexture, uv4, -10.0).rgb * 2.0 - 1.0;\n float depth1 = texture2D(depthTexture, uv1, -10.0).x;\n float depth2 = texture2D(depthTexture, uv2, -10.0).x;\n float depth3 = texture2D(depthTexture, uv3, -10.0).x;\n float depth4 = texture2D(depthTexture, uv4, -10.0).x;\n // Sanity check the depths\n if (depth1 == 1.0 || depth2 == 1.0 || depth3 == 1.0 || depth4 == 1.0) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n vec3 pos1 = WorldPosFromDepth(depth1, uv1);\n vec3 pos2 = WorldPosFromDepth(depth2, uv2);\n vec3 pos3 = WorldPosFromDepth(depth3, uv3);\n vec3 pos4 = WorldPosFromDepth(depth4, uv4);\n vec3 originPos1 = WorldPosFromDepth(0.0, uv1);\n vec3 originPos2 = WorldPosFromDepth(0.0, uv2);\n vec3 originPos3 = WorldPosFromDepth(0.0, uv3);\n vec3 originPos4 = WorldPosFromDepth(0.0, uv4);\n vec3 endPos1, endPos2, endPos3, endPos4;\n vec3 endDir1, endDir2, endDir3, endDir4;\n totalInternalReflection(originPos1, lightDir, pos1, normal1, ior, endPos1, endDir1);\n totalInternalReflection(originPos2, lightDir, pos2, normal2, ior, endPos2, endDir2);\n totalInternalReflection(originPos3, lightDir, pos3, normal3, ior, endPos3, endDir3);\n totalInternalReflection(originPos4, lightDir, pos4, normal4, ior, endPos4, endDir4);\n float lightPosArea = length(cross(originPos2 - originPos1, originPos3 - originPos1)) + length(cross(originPos3 - originPos1, originPos4 - originPos1));\n float t1 = planeIntersect(endPos1, endDir1, vec4(0.0, 1.0, 0.0, 0.0));\n float t2 = planeIntersect(endPos2, endDir2, vec4(0.0, 1.0, 0.0, 0.0));\n float t3 = planeIntersect(endPos3, endDir3, vec4(0.0, 1.0, 0.0, 0.0));\n float t4 = planeIntersect(endPos4, endDir4, vec4(0.0, 1.0, 0.0, 0.0));\n vec3 finalPos1 = endPos1 + endDir1 * t1;\n vec3 finalPos2 = endPos2 + endDir2 * t2;\n vec3 finalPos3 = endPos3 + endDir3 * t3;\n vec3 finalPos4 = endPos4 + endDir4 * t4;\n float finalArea = length(cross(finalPos2 - finalPos1, finalPos3 - finalPos1)) + length(cross(finalPos3 - finalPos1, finalPos4 - finalPos1));\n caustic += intensity * (lightPosArea / finalArea);\n // Calculate the area of the triangle in light spaces\n gl_FragColor = vec4(vec3(max(caustic, 0.0)), 1.0);\n }"),x={depth:!0,minFilter:d.LinearFilter,magFilter:d.LinearFilter,encoding:d.LinearEncoding,type:d.UnsignedByteType},g={minFilter:d.LinearMipmapLinearFilter,magFilter:d.LinearFilter,encoding:d.LinearEncoding,format:d.RGBAFormat,type:d.FloatType,generateMipmaps:!0},h=v.forwardRef((({debug:e,children:r,frustum:n=2,ior:a=1.1,color:c="white",causticsOnly:s=!1,backfaces:h=!1,backfaceIor:P=1.1,worldRadius:D=.3125,intensity:M=.05,resolution:y=2024,near:w=.1,far:T=100,lightSource:b=[5,5,5],focus:F=[0,0,0],...S},j)=>{t.extend({CausticsProjectionMaterial:p});const R=v.useRef(null),W=v.useRef(null),z=v.useRef(null),I=v.useRef(null),O=t.useThree((e=>e.gl)),_=o.useHelper(e&&W,d.CameraHelper),B=o.useHelper(e&&I,d.BoxHelper),C=i.useFBO(y,y,x),E=i.useFBO(y,y,x),U=i.useFBO(y,y,g),k=i.useFBO(y,y,g),[q]=v.useState((()=>f())),[A]=v.useState((()=>f(d.BackSide))),[L]=v.useState((()=>new m)),[V]=v.useState((()=>new l.FullScreenQuad(L))),H=new d.Vector3;return v.useLayoutEffect((()=>{var r,t;(R.current.updateWorldMatrix(!1,!0),W.current.position.set(...b),W.current.lookAt(...F),W.current.updateWorldMatrix(!1,!1),W.current.updateProjectionMatrix(),e)&&(null==(r=_.current)||r.update(),null==(t=B.current)||t.update());A.viewMatrix.value=q.viewMatrix.value=W.current.matrixWorldInverse,L.cameraMatrixWorld=W.current.matrixWorld,L.cameraProjectionMatrixInv=W.current.projectionMatrixInverse,L.lightDir=W.current.getWorldPosition(H).normalize().multiplyScalar(-1),L.near=W.current.near,L.far=W.current.far,L.resolution=y,L.size=n,L.intensity=M,L.worldRadius=D,z.current.visible=!0,O.setRenderTarget(C),O.clear(),z.current.overrideMaterial=q,O.render(z.current,W.current),O.setRenderTarget(E),O.clear(),h&&(z.current.overrideMaterial=A,O.render(z.current,W.current)),z.current.overrideMaterial=null,L.ior=a,I.current.material.lightProjMatrix=W.current.projectionMatrix,I.current.material.lightViewMatrix=W.current.matrixWorldInverse,L.normalTexture=C.texture,L.depthTexture=C.depthTexture,O.setRenderTarget(U),O.clear(),V.render(O),L.ior=P,L.normalTexture=E.texture,L.depthTexture=E.depthTexture,O.setRenderTarget(k),O.clear(),h&&V.render(O),O.setRenderTarget(null),s&&(z.current.visible=!1)})),v.createElement("group",u.default({ref:R},S),v.createElement("orthographicCamera",{ref:W,up:[0,1,0],left:-n,right:n,top:n,bottom:-n,near:w,far:T}),v.createElement("scene",{ref:z},r),v.createElement("mesh",{ref:I,"rotation-x":-Math.PI/2,scale:2*n},v.createElement("planeGeometry",null),v.createElement("causticsProjectionMaterial",{transparent:!0,color:c,causticsTexture:U.texture,causticsTextureB:k.texture,blending:d.CustomBlending,blendSrc:d.OneFactor,blendDst:d.SrcAlphaFactor,depthWrite:!1})))}));exports.Caustics=h;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("three"),n=require("react"),t=require("@react-three/fiber"),o=require("./useFBO.cjs.js"),i=require("./useHelper.cjs.js"),a=require("./shaderMaterial.cjs.js"),l=require("./Edges.cjs.js"),c=require("three-stdlib");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function u(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var t=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,t.get?t:{enumerable:!0,get:function(){return e[n]}})}})),r.default=e,Object.freeze(r)}var d=s(e),m=u(r),p=u(n);function v(e=m.FrontSide){const r={value:new m.Matrix4};return Object.assign(new m.MeshNormalMaterial({side:e}),{viewMatrix:r,onBeforeCompile:e=>{e.uniforms.viewMatrix=r,e.fragmentShader="vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n }\n"+e.fragmentShader.replace("#include <normal_fragment_maps>","#include <normal_fragment_maps>\n normal = inverseTransformDirection( normal, viewMatrix );\n")}})}const f=a.shaderMaterial({causticsTexture:null,causticsTextureB:null,color:new m.Color,lightProjMatrix:new m.Matrix4,lightViewMatrix:new m.Matrix4},"varying vec3 vWorldPosition; \n void main() {\n gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);\n vec4 worldPosition = modelMatrix * vec4(position, 1.);\n vWorldPosition = worldPosition.xyz;\n }","varying vec3 vWorldPosition;\n uniform vec3 color;\n uniform sampler2D causticsTexture; \n uniform sampler2D causticsTextureB; \n uniform mat4 lightProjMatrix;\n uniform mat4 lightViewMatrix;\n void main() {\n // Apply caustics \n vec4 lightSpacePos = lightProjMatrix * lightViewMatrix * vec4(vWorldPosition, 1.0);\n lightSpacePos.xyz /= lightSpacePos.w;\n lightSpacePos.xyz = lightSpacePos.xyz * 0.5 + 0.5; \n vec3 front = texture2D(causticsTexture, lightSpacePos.xy).rgb;\n vec3 back = texture2D(causticsTextureB, lightSpacePos.xy).rgb;\n gl_FragColor = vec4((front + back) * color, 1.0);\n #include <tonemapping_fragment>\n #include <encodings_fragment>\n }"),x=a.shaderMaterial({cameraMatrixWorld:new m.Matrix4,cameraProjectionMatrixInv:new m.Matrix4,normalTexture:null,depthTexture:null,lightDir:new m.Vector3(0,1,0),lightPlaneNormal:new m.Vector3(0,1,0),lightPlaneConstant:0,near:.1,far:100,modelMatrix:new m.Matrix4,worldRadius:1/40,ior:1.1,bounces:0,resolution:1024,size:10,intensity:.5},"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }"," \n uniform mat4 cameraMatrixWorld;\n uniform mat4 cameraProjectionMatrixInv;\n uniform vec3 lightDir;\n uniform vec3 lightPlaneNormal;\n uniform float lightPlaneConstant;\n uniform float near;\n uniform float far;\n uniform float time;\n uniform float worldRadius;\n uniform float resolution;\n uniform float size;\n uniform float intensity;\n uniform float ior;\n precision highp isampler2D;\n precision highp usampler2D;\n uniform sampler2D normalTexture;\n uniform sampler2D depthTexture;\n uniform float bounces;\n varying vec2 vUv;\n vec3 WorldPosFromDepth(float depth, vec2 coord) {\n float z = depth * 2.0 - 1.0;\n vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);\n vec4 viewSpacePosition = cameraProjectionMatrixInv * clipSpacePosition;\n // Perspective division\n viewSpacePosition /= viewSpacePosition.w;\n vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition;\n return worldSpacePosition.xyz;\n } \n float sdPlane( vec3 p, vec3 n, float h ) {\n // n must be normalized\n return dot(p,n) + h;\n }\n float planeIntersect( vec3 ro, vec3 rd, vec4 p ) {\n return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);\n }\n vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 pos, vec3 normal, float ior, out vec3 rayOrigin, out vec3 rayDirection) {\n rayOrigin = ro;\n rayDirection = rd;\n rayDirection = refract(rayDirection, normal, 1.0 / ior);\n rayOrigin = pos + rayDirection * 0.1;\n return rayDirection;\n }\n void main() {\n // Each sample consists of random offset in the x and y direction\n float caustic = 0.0;\n float causticTexelSize = (1.0 / resolution) * size * 2.0;\n float texelsNeeded = worldRadius / causticTexelSize;\n float sampleRadius = texelsNeeded / resolution;\n float sum = 0.0;\n if (texture2D(depthTexture, vUv).x == 1.0) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n vec2 offset1 = vec2(-0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 offset2 = vec2(-0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 offset3 = vec2(0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 offset4 = vec2(0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5);\n vec2 uv1 = vUv + offset1 * sampleRadius;\n vec2 uv2 = vUv + offset2 * sampleRadius;\n vec2 uv3 = vUv + offset3 * sampleRadius;\n vec2 uv4 = vUv + offset4 * sampleRadius;\n vec3 normal1 = texture2D(normalTexture, uv1, -10.0).rgb * 2.0 - 1.0;\n vec3 normal2 = texture2D(normalTexture, uv2, -10.0).rgb * 2.0 - 1.0;\n vec3 normal3 = texture2D(normalTexture, uv3, -10.0).rgb * 2.0 - 1.0;\n vec3 normal4 = texture2D(normalTexture, uv4, -10.0).rgb * 2.0 - 1.0;\n float depth1 = texture2D(depthTexture, uv1, -10.0).x;\n float depth2 = texture2D(depthTexture, uv2, -10.0).x;\n float depth3 = texture2D(depthTexture, uv3, -10.0).x;\n float depth4 = texture2D(depthTexture, uv4, -10.0).x;\n // Sanity check the depths\n if (depth1 == 1.0 || depth2 == 1.0 || depth3 == 1.0 || depth4 == 1.0) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n vec3 pos1 = WorldPosFromDepth(depth1, uv1);\n vec3 pos2 = WorldPosFromDepth(depth2, uv2);\n vec3 pos3 = WorldPosFromDepth(depth3, uv3);\n vec3 pos4 = WorldPosFromDepth(depth4, uv4);\n vec3 originPos1 = WorldPosFromDepth(0.0, uv1);\n vec3 originPos2 = WorldPosFromDepth(0.0, uv2);\n vec3 originPos3 = WorldPosFromDepth(0.0, uv3);\n vec3 originPos4 = WorldPosFromDepth(0.0, uv4);\n vec3 endPos1, endPos2, endPos3, endPos4;\n vec3 endDir1, endDir2, endDir3, endDir4;\n totalInternalReflection(originPos1, lightDir, pos1, normal1, ior, endPos1, endDir1);\n totalInternalReflection(originPos2, lightDir, pos2, normal2, ior, endPos2, endDir2);\n totalInternalReflection(originPos3, lightDir, pos3, normal3, ior, endPos3, endDir3);\n totalInternalReflection(originPos4, lightDir, pos4, normal4, ior, endPos4, endDir4);\n float lightPosArea = length(cross(originPos2 - originPos1, originPos3 - originPos1)) + length(cross(originPos3 - originPos1, originPos4 - originPos1));\n float t1 = planeIntersect(endPos1, endDir1, vec4(lightPlaneNormal, lightPlaneConstant));\n float t2 = planeIntersect(endPos2, endDir2, vec4(lightPlaneNormal, lightPlaneConstant));\n float t3 = planeIntersect(endPos3, endDir3, vec4(lightPlaneNormal, lightPlaneConstant));\n float t4 = planeIntersect(endPos4, endDir4, vec4(lightPlaneNormal, lightPlaneConstant));\n vec3 finalPos1 = endPos1 + endDir1 * t1;\n vec3 finalPos2 = endPos2 + endDir2 * t2;\n vec3 finalPos3 = endPos3 + endDir3 * t3;\n vec3 finalPos4 = endPos4 + endDir4 * t4;\n float finalArea = length(cross(finalPos2 - finalPos1, finalPos3 - finalPos1)) + length(cross(finalPos3 - finalPos1, finalPos4 - finalPos1));\n caustic += intensity * (lightPosArea / finalArea);\n // Calculate the area of the triangle in light spaces\n gl_FragColor = vec4(vec3(max(caustic, 0.0)), 1.0);\n }"),h={depth:!0,minFilter:m.LinearFilter,magFilter:m.LinearFilter,encoding:m.LinearEncoding,type:m.UnsignedByteType},g={minFilter:m.LinearMipmapLinearFilter,magFilter:m.LinearFilter,encoding:m.LinearEncoding,format:m.RGBAFormat,type:m.FloatType,generateMipmaps:!0},P=p.forwardRef((({debug:e,children:r,frames:n=1,ior:a=1.1,color:s="white",causticsOnly:u=!1,backfaces:P=!1,backfaceIor:y=1.1,worldRadius:M=.3125,intensity:w=.05,resolution:D=2024,lightSource:T=[5,5,5],...F},S)=>{t.extend({CausticsProjectionMaterial:f});const b=p.useRef(null),j=p.useRef(null),z=p.useRef(null),W=p.useRef(null),R=t.useThree((e=>e.gl)),I=i.useHelper(e&&j,m.CameraHelper),C=o.useFBO(D,D,h),O=o.useFBO(D,D,h),V=o.useFBO(D,D,g),B=o.useFBO(D,D,g),[_]=p.useState((()=>v())),[E]=p.useState((()=>v(m.BackSide))),[A]=p.useState((()=>new x)),[N]=p.useState((()=>new c.FullScreenQuad(A)));p.useLayoutEffect((()=>{b.current.updateWorldMatrix(!1,!0)}));let k=0;const q=new m.Vector3,L=new m.Frustum,U=new m.Matrix4,H=new m.Plane,G=new m.Vector3,Q=new m.Vector3,J=new m.Box3,K=new m.Vector3;return t.useFrame(((r,t)=>{if(n===1/0||k++<n){var o,i;Array.isArray(T)?G.fromArray(T).normalize():G.copy(b.current.worldToLocal(T.current.getWorldPosition(q)).normalize()),Q.copy(G).multiplyScalar(-1);let r=[];null==(o=z.current.parent)||o.matrixWorld.identity(),J.setFromObject(z.current,!0),r.push(new m.Vector3(J.min.x,J.min.y,J.min.z)),r.push(new m.Vector3(J.min.x,J.min.y,J.max.z)),r.push(new m.Vector3(J.min.x,J.max.y,J.min.z)),r.push(new m.Vector3(J.min.x,J.max.y,J.max.z)),r.push(new m.Vector3(J.max.x,J.min.y,J.min.z)),r.push(new m.Vector3(J.max.x,J.min.y,J.max.z)),r.push(new m.Vector3(J.max.x,J.max.y,J.min.z)),r.push(new m.Vector3(J.max.x,J.max.y,J.max.z));const n=r.map((e=>e.clone()));J.getCenter(K),r=r.map((e=>e.clone().sub(K)));const t=H.set(Q,0),l=r.map((e=>t.projectPoint(e,new m.Vector3))),c=l.reduce(((e,r)=>e.add(r)),q.set(0,0,0)).divideScalar(l.length),s=l.map((e=>e.distanceTo(c))).reduce(((e,r)=>Math.max(e,r))),d=r.map((e=>e.dot(G))).reduce(((e,r)=>Math.max(e,r)));j.current.position.copy(G.clone().multiplyScalar(d).add(K)),j.current.lookAt(z.current.localToWorld(K.clone()));const p=U.lookAt(j.current.position,K,q.set(0,1,0));j.current.left=-s,j.current.right=s,j.current.top=s,j.current.bottom=-s;const v=q.set(0,s,0).applyMatrix4(p),f=(j.current.position.y+v.y)/G.y;j.current.near=.1,j.current.far=f,j.current.updateProjectionMatrix(),j.current.updateMatrixWorld();const x=n.map((e=>e.add(G.clone().multiplyScalar(-e.y/G.y)))),h=x.reduce(((e,r)=>e.add(r)),q.set(0,0,0)).divideScalar(x.length),g=2*x.map((e=>Math.hypot(e.x-h.x,e.z-h.z))).reduce(((e,r)=>Math.max(e,r)));W.current.scale.setScalar(g),W.current.position.copy(h),e&&(null==(i=I.current)||i.update()),E.viewMatrix.value=_.viewMatrix.value=j.current.matrixWorldInverse;const F=L.setFromProjectionMatrix(U.multiplyMatrices(j.current.projectionMatrix,j.current.matrixWorldInverse)).planes[4];A.cameraMatrixWorld=j.current.matrixWorld,A.cameraProjectionMatrixInv=j.current.projectionMatrixInverse,A.lightDir=Q,A.lightPlaneNormal=F.normal,A.lightPlaneConstant=F.constant,A.near=j.current.near,A.far=j.current.far,A.resolution=D,A.size=s,A.intensity=w,A.worldRadius=M,z.current.visible=!0,R.setRenderTarget(C),R.clear(),z.current.overrideMaterial=_,R.render(z.current,j.current),R.setRenderTarget(O),R.clear(),P&&(z.current.overrideMaterial=E,R.render(z.current,j.current)),z.current.overrideMaterial=null,A.ior=a,W.current.material.lightProjMatrix=j.current.projectionMatrix,W.current.material.lightViewMatrix=j.current.matrixWorldInverse,A.normalTexture=C.texture,A.depthTexture=C.depthTexture,R.setRenderTarget(V),R.clear(),N.render(R),A.ior=y,A.normalTexture=O.texture,A.depthTexture=O.depthTexture,R.setRenderTarget(B),R.clear(),P&&N.render(R),R.setRenderTarget(null),u&&(z.current.visible=!1)}})),p.useImperativeHandle(S,(()=>b.current),[]),p.createElement("group",d.default({ref:b},F),p.createElement("scene",{ref:z},p.createElement("orthographicCamera",{ref:j,up:[0,1,0]}),r),p.createElement("mesh",{renderOrder:2,ref:W,"rotation-x":-Math.PI/2},p.createElement("planeGeometry",null),p.createElement("causticsProjectionMaterial",{transparent:!0,color:s,causticsTexture:V.texture,causticsTextureB:B.texture,blending:m.CustomBlending,blendSrc:m.OneFactor,blendDst:m.SrcAlphaFactor,depthWrite:!1}),e&&p.createElement(l.Edges,null,p.createElement("lineBasicMaterial",{color:"#ffff00",toneMapped:!1}))))}));exports.Caustics=P;
@@ -36,18 +36,15 @@ export declare const Caustics: React.ForwardRefExoticComponent<Pick<Omit<ReactTh
36
36
  layers?: ReactThreeFiber.Layers | undefined;
37
37
  dispose?: (() => void) | null | undefined;
38
38
  } & import("@react-three/fiber/dist/declarations/src/core/events").EventHandlers & {
39
+ frames?: number | undefined;
39
40
  debug?: boolean | undefined;
40
41
  causticsOnly: boolean;
41
42
  backfaces: boolean;
42
- frustum?: number | undefined;
43
43
  ior?: number | undefined;
44
44
  backfaceIor?: number | undefined;
45
45
  worldRadius?: number | undefined;
46
46
  intensity?: number | undefined;
47
47
  color?: ReactThreeFiber.Color | undefined;
48
48
  resolution?: number | undefined;
49
- near?: number | undefined;
50
- far?: number | undefined;
51
- lightSource?: [x: number, y: number, z: number] | undefined;
52
- focus?: [x: number, y: number, z: number] | undefined;
53
- }, "visible" | "attach" | "args" | "children" | "key" | "onUpdate" | "position" | "up" | "scale" | "rotation" | "matrix" | "quaternion" | "layers" | "dispose" | "type" | "isGroup" | "id" | "uuid" | "name" | "parent" | "modelViewMatrix" | "normalMatrix" | "matrixWorld" | "matrixAutoUpdate" | "matrixWorldNeedsUpdate" | "castShadow" | "receiveShadow" | "frustumCulled" | "renderOrder" | "animations" | "userData" | "customDepthMaterial" | "customDistanceMaterial" | "isObject3D" | "onBeforeRender" | "onAfterRender" | "applyMatrix4" | "applyQuaternion" | "setRotationFromAxisAngle" | "setRotationFromEuler" | "setRotationFromMatrix" | "setRotationFromQuaternion" | "rotateOnAxis" | "rotateOnWorldAxis" | "rotateX" | "rotateY" | "rotateZ" | "translateOnAxis" | "translateX" | "translateY" | "translateZ" | "localToWorld" | "worldToLocal" | "lookAt" | "add" | "remove" | "removeFromParent" | "clear" | "getObjectById" | "getObjectByName" | "getObjectByProperty" | "getWorldPosition" | "getWorldQuaternion" | "getWorldScale" | "getWorldDirection" | "raycast" | "traverse" | "traverseVisible" | "traverseAncestors" | "updateMatrix" | "updateMatrixWorld" | "updateWorldMatrix" | "toJSON" | "clone" | "copy" | "addEventListener" | "hasEventListener" | "removeEventListener" | "dispatchEvent" | "color" | keyof import("@react-three/fiber/dist/declarations/src/core/events").EventHandlers | "near" | "far" | "intensity" | "focus" | "ior" | "resolution" | "debug" | "frustum" | "worldRadius" | "causticsOnly" | "backfaces" | "backfaceIor" | "lightSource"> & React.RefAttributes<unknown>>;
49
+ lightSource?: React.MutableRefObject<THREE.Object3D<THREE.Event>> | [x: number, y: number, z: number] | undefined;
50
+ }, "visible" | "attach" | "args" | "children" | "key" | "onUpdate" | "position" | "up" | "scale" | "rotation" | "matrix" | "quaternion" | "layers" | "dispose" | "type" | "isGroup" | "id" | "uuid" | "name" | "parent" | "modelViewMatrix" | "normalMatrix" | "matrixWorld" | "matrixAutoUpdate" | "matrixWorldNeedsUpdate" | "castShadow" | "receiveShadow" | "frustumCulled" | "renderOrder" | "animations" | "userData" | "customDepthMaterial" | "customDistanceMaterial" | "isObject3D" | "onBeforeRender" | "onAfterRender" | "applyMatrix4" | "applyQuaternion" | "setRotationFromAxisAngle" | "setRotationFromEuler" | "setRotationFromMatrix" | "setRotationFromQuaternion" | "rotateOnAxis" | "rotateOnWorldAxis" | "rotateX" | "rotateY" | "rotateZ" | "translateOnAxis" | "translateX" | "translateY" | "translateZ" | "localToWorld" | "worldToLocal" | "lookAt" | "add" | "remove" | "removeFromParent" | "clear" | "getObjectById" | "getObjectByName" | "getObjectByProperty" | "getWorldPosition" | "getWorldQuaternion" | "getWorldScale" | "getWorldDirection" | "raycast" | "traverse" | "traverseVisible" | "traverseAncestors" | "updateMatrix" | "updateMatrixWorld" | "updateWorldMatrix" | "toJSON" | "clone" | "copy" | "addEventListener" | "hasEventListener" | "removeEventListener" | "dispatchEvent" | "color" | keyof import("@react-three/fiber/dist/declarations/src/core/events").EventHandlers | "intensity" | "ior" | "resolution" | "debug" | "frames" | "worldRadius" | "causticsOnly" | "backfaces" | "backfaceIor" | "lightSource"> & React.RefAttributes<unknown>>;
package/core/Caustics.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import _extends from '@babel/runtime/helpers/esm/extends';
2
2
  import * as THREE from 'three';
3
3
  import * as React from 'react';
4
- import { extend, useThree } from '@react-three/fiber';
4
+ import { extend, useThree, useFrame } from '@react-three/fiber';
5
5
  import { useFBO } from './useFBO.js';
6
6
  import { useHelper } from './useHelper.js';
7
7
  import { shaderMaterial } from './shaderMaterial.js';
8
+ import { Edges } from './Edges.js';
8
9
  import { FullScreenQuad } from 'three-stdlib';
9
10
 
10
11
  function createNormalMaterial(side = THREE.FrontSide) {
@@ -28,7 +29,7 @@ function createNormalMaterial(side = THREE.FrontSide) {
28
29
  const CausticsProjectionMaterial = shaderMaterial({
29
30
  causticsTexture: null,
30
31
  causticsTextureB: null,
31
- color: new THREE.Color('white'),
32
+ color: new THREE.Color(),
32
33
  lightProjMatrix: new THREE.Matrix4(),
33
34
  lightViewMatrix: new THREE.Matrix4()
34
35
  }, `varying vec3 vWorldPosition;
@@ -59,6 +60,8 @@ const CausticsMaterial = shaderMaterial({
59
60
  normalTexture: null,
60
61
  depthTexture: null,
61
62
  lightDir: new THREE.Vector3(0, 1, 0),
63
+ lightPlaneNormal: new THREE.Vector3(0, 1, 0),
64
+ lightPlaneConstant: 0,
62
65
  near: 0.1,
63
66
  far: 100,
64
67
  modelMatrix: new THREE.Matrix4(),
@@ -81,6 +84,8 @@ const CausticsMaterial = shaderMaterial({
81
84
  uniform mat4 cameraMatrixWorld;
82
85
  uniform mat4 cameraProjectionMatrixInv;
83
86
  uniform vec3 lightDir;
87
+ uniform vec3 lightPlaneNormal;
88
+ uniform float lightPlaneConstant;
84
89
  uniform float near;
85
90
  uniform float far;
86
91
  uniform float time;
@@ -165,10 +170,10 @@ const CausticsMaterial = shaderMaterial({
165
170
  totalInternalReflection(originPos3, lightDir, pos3, normal3, ior, endPos3, endDir3);
166
171
  totalInternalReflection(originPos4, lightDir, pos4, normal4, ior, endPos4, endDir4);
167
172
  float lightPosArea = length(cross(originPos2 - originPos1, originPos3 - originPos1)) + length(cross(originPos3 - originPos1, originPos4 - originPos1));
168
- float t1 = planeIntersect(endPos1, endDir1, vec4(0.0, 1.0, 0.0, 0.0));
169
- float t2 = planeIntersect(endPos2, endDir2, vec4(0.0, 1.0, 0.0, 0.0));
170
- float t3 = planeIntersect(endPos3, endDir3, vec4(0.0, 1.0, 0.0, 0.0));
171
- float t4 = planeIntersect(endPos4, endDir4, vec4(0.0, 1.0, 0.0, 0.0));
173
+ float t1 = planeIntersect(endPos1, endDir1, vec4(lightPlaneNormal, lightPlaneConstant));
174
+ float t2 = planeIntersect(endPos2, endDir2, vec4(lightPlaneNormal, lightPlaneConstant));
175
+ float t3 = planeIntersect(endPos3, endDir3, vec4(lightPlaneNormal, lightPlaneConstant));
176
+ float t4 = planeIntersect(endPos4, endDir4, vec4(lightPlaneNormal, lightPlaneConstant));
172
177
  vec3 finalPos1 = endPos1 + endDir1 * t1;
173
178
  vec3 finalPos2 = endPos2 + endDir2 * t2;
174
179
  vec3 finalPos3 = endPos3 + endDir3 * t3;
@@ -196,7 +201,7 @@ const CAUSTICPROPS = {
196
201
  const Caustics = /*#__PURE__*/React.forwardRef(({
197
202
  debug,
198
203
  children,
199
- frustum = 2,
204
+ frames = 1,
200
205
  ior = 1.1,
201
206
  color = 'white',
202
207
  causticsOnly = false,
@@ -205,10 +210,7 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
205
210
  worldRadius = 0.3125,
206
211
  intensity = 0.05,
207
212
  resolution = 2024,
208
- near = 0.1,
209
- far = 100,
210
213
  lightSource = [5, 5, 5],
211
- focus = [0, 0, 0],
212
214
  ...props
213
215
  }, fref) => {
214
216
  extend({
@@ -219,8 +221,7 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
219
221
  const scene = React.useRef(null);
220
222
  const plane = React.useRef(null);
221
223
  const gl = useThree(state => state.gl);
222
- const helper = useHelper(debug && camera, THREE.CameraHelper);
223
- const boxHelper = useHelper(debug && plane, THREE.BoxHelper); // Buffers for front and back faces
224
+ const helper = useHelper(debug && camera, THREE.CameraHelper); // Buffers for front and back faces
224
225
 
225
226
  const normalTarget = useFBO(resolution, resolution, NORMALPROPS);
226
227
  const normalTargetB = useFBO(resolution, resolution, NORMALPROPS);
@@ -232,89 +233,131 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
232
233
 
233
234
  const [causticsMaterial] = React.useState(() => new CausticsMaterial());
234
235
  const [causticsQuad] = React.useState(() => new FullScreenQuad(causticsMaterial));
235
- const pos = new THREE.Vector3();
236
236
  React.useLayoutEffect(() => {
237
- // Update matrix world and the camera
238
237
  ref.current.updateWorldMatrix(false, true);
239
- camera.current.position.set(...lightSource);
240
- camera.current.lookAt(...focus);
241
- camera.current.updateWorldMatrix(false, false);
242
- camera.current.updateProjectionMatrix();
238
+ });
239
+ let count = 0;
240
+ const v = new THREE.Vector3();
241
+ const lpF = new THREE.Frustum();
242
+ const lpM = new THREE.Matrix4();
243
+ const lpP = new THREE.Plane();
244
+ const lightDir = new THREE.Vector3();
245
+ const lightDirInv = new THREE.Vector3();
246
+ const bounds = new THREE.Box3();
247
+ const focusPos = new THREE.Vector3();
248
+ useFrame((state, delta) => {
249
+ if (frames === Infinity || count++ < frames) {
250
+ var _scene$current$parent, _helper$current;
251
+
252
+ if (Array.isArray(lightSource)) lightDir.fromArray(lightSource).normalize();else lightDir.copy(ref.current.worldToLocal(lightSource.current.getWorldPosition(v)).normalize());
253
+ lightDirInv.copy(lightDir).multiplyScalar(-1);
254
+ let boundsVertices = [];
255
+ (_scene$current$parent = scene.current.parent) == null ? void 0 : _scene$current$parent.matrixWorld.identity();
256
+ bounds.setFromObject(scene.current, true);
257
+ boundsVertices.push(new THREE.Vector3(bounds.min.x, bounds.min.y, bounds.min.z));
258
+ boundsVertices.push(new THREE.Vector3(bounds.min.x, bounds.min.y, bounds.max.z));
259
+ boundsVertices.push(new THREE.Vector3(bounds.min.x, bounds.max.y, bounds.min.z));
260
+ boundsVertices.push(new THREE.Vector3(bounds.min.x, bounds.max.y, bounds.max.z));
261
+ boundsVertices.push(new THREE.Vector3(bounds.max.x, bounds.min.y, bounds.min.z));
262
+ boundsVertices.push(new THREE.Vector3(bounds.max.x, bounds.min.y, bounds.max.z));
263
+ boundsVertices.push(new THREE.Vector3(bounds.max.x, bounds.max.y, bounds.min.z));
264
+ boundsVertices.push(new THREE.Vector3(bounds.max.x, bounds.max.y, bounds.max.z));
265
+ const worldVerts = boundsVertices.map(v => v.clone());
266
+ bounds.getCenter(focusPos);
267
+ boundsVertices = boundsVertices.map(v => v.clone().sub(focusPos));
268
+ const lightPlane = lpP.set(lightDirInv, 0);
269
+ const projectedVerts = boundsVertices.map(v => lightPlane.projectPoint(v, new THREE.Vector3()));
270
+ const centralVert = projectedVerts.reduce((a, b) => a.add(b), v.set(0, 0, 0)).divideScalar(projectedVerts.length);
271
+ const radius = projectedVerts.map(v => v.distanceTo(centralVert)).reduce((a, b) => Math.max(a, b));
272
+ const dirLength = boundsVertices.map(x => x.dot(lightDir)).reduce((a, b) => Math.max(a, b)); // Shadows
243
273
 
244
- if (debug) {
245
- var _helper$current, _boxHelper$current;
274
+ camera.current.position.copy(lightDir.clone().multiplyScalar(dirLength).add(focusPos));
275
+ camera.current.lookAt(scene.current.localToWorld(focusPos.clone()));
276
+ const dirMatrix = lpM.lookAt(camera.current.position, focusPos, v.set(0, 1, 0));
277
+ camera.current.left = -radius;
278
+ camera.current.right = radius;
279
+ camera.current.top = radius;
280
+ camera.current.bottom = -radius;
281
+ const yOffset = v.set(0, radius, 0).applyMatrix4(dirMatrix);
282
+ const yTime = (camera.current.position.y + yOffset.y) / lightDir.y;
283
+ camera.current.near = 0.1;
284
+ camera.current.far = yTime;
285
+ camera.current.updateProjectionMatrix();
286
+ camera.current.updateMatrixWorld(); // Now find size of ground plane
246
287
 
247
- (_helper$current = helper.current) == null ? void 0 : _helper$current.update();
248
- (_boxHelper$current = boxHelper.current) == null ? void 0 : _boxHelper$current.update();
249
- } // Inject uniforms
288
+ const groundProjectedCoords = worldVerts.map(v => v.add(lightDir.clone().multiplyScalar(-v.y / lightDir.y)));
289
+ const centerPos = groundProjectedCoords.reduce((a, b) => a.add(b), v.set(0, 0, 0)).divideScalar(groundProjectedCoords.length);
290
+ const maxSize = 2 * groundProjectedCoords.map(v => Math.hypot(v.x - centerPos.x, v.z - centerPos.z)).reduce((a, b) => Math.max(a, b));
291
+ plane.current.scale.setScalar(maxSize);
292
+ plane.current.position.copy(centerPos);
293
+ if (debug) (_helper$current = helper.current) == null ? void 0 : _helper$current.update(); // Inject uniforms
250
294
 
295
+ normalMatB.viewMatrix.value = normalMat.viewMatrix.value = camera.current.matrixWorldInverse;
296
+ const dirLightNearPlane = lpF.setFromProjectionMatrix(lpM.multiplyMatrices(camera.current.projectionMatrix, camera.current.matrixWorldInverse)).planes[4];
297
+ causticsMaterial.cameraMatrixWorld = camera.current.matrixWorld;
298
+ causticsMaterial.cameraProjectionMatrixInv = camera.current.projectionMatrixInverse;
299
+ causticsMaterial.lightDir = lightDirInv;
300
+ causticsMaterial.lightPlaneNormal = dirLightNearPlane.normal;
301
+ causticsMaterial.lightPlaneConstant = dirLightNearPlane.constant; //console.log(causticsMaterial.lightDir)
251
302
 
252
- normalMatB.viewMatrix.value = normalMat.viewMatrix.value = camera.current.matrixWorldInverse;
253
- causticsMaterial.cameraMatrixWorld = camera.current.matrixWorld;
254
- causticsMaterial.cameraProjectionMatrixInv = camera.current.projectionMatrixInverse;
255
- causticsMaterial.lightDir = camera.current.getWorldPosition(pos).normalize().multiplyScalar(-1);
256
- causticsMaterial.near = camera.current.near;
257
- causticsMaterial.far = camera.current.far;
258
- causticsMaterial.resolution = resolution;
259
- causticsMaterial.size = frustum;
260
- causticsMaterial.intensity = intensity;
261
- causticsMaterial.worldRadius = worldRadius; // Switch the scene on
303
+ causticsMaterial.near = camera.current.near;
304
+ causticsMaterial.far = camera.current.far;
305
+ causticsMaterial.resolution = resolution;
306
+ causticsMaterial.size = radius;
307
+ causticsMaterial.intensity = intensity;
308
+ causticsMaterial.worldRadius = worldRadius; // Switch the scene on
262
309
 
263
- scene.current.visible = true; // Render front face normals
310
+ scene.current.visible = true; // Render front face normals
264
311
 
265
- gl.setRenderTarget(normalTarget);
266
- gl.clear();
267
- scene.current.overrideMaterial = normalMat;
268
- gl.render(scene.current, camera.current); // Render back face normals, if enabled
312
+ gl.setRenderTarget(normalTarget);
313
+ gl.clear();
314
+ scene.current.overrideMaterial = normalMat;
315
+ gl.render(scene.current, camera.current); // Render back face normals, if enabled
269
316
 
270
- gl.setRenderTarget(normalTargetB);
271
- gl.clear();
317
+ gl.setRenderTarget(normalTargetB);
318
+ gl.clear();
272
319
 
273
- if (backfaces) {
274
- scene.current.overrideMaterial = normalMatB;
275
- gl.render(scene.current, camera.current);
276
- } // Remove the override material
320
+ if (backfaces) {
321
+ scene.current.overrideMaterial = normalMatB;
322
+ gl.render(scene.current, camera.current);
323
+ } // Remove the override material
277
324
 
278
325
 
279
- scene.current.overrideMaterial = null; // Render front face caustics
326
+ scene.current.overrideMaterial = null; // Render front face caustics
280
327
 
281
- causticsMaterial.ior = ior;
282
- plane.current.material.lightProjMatrix = camera.current.projectionMatrix;
283
- plane.current.material.lightViewMatrix = camera.current.matrixWorldInverse;
284
- causticsMaterial.normalTexture = normalTarget.texture;
285
- causticsMaterial.depthTexture = normalTarget.depthTexture;
286
- gl.setRenderTarget(causticsTarget);
287
- gl.clear();
288
- causticsQuad.render(gl); // Render back face caustics, if enabled
328
+ causticsMaterial.ior = ior;
329
+ plane.current.material.lightProjMatrix = camera.current.projectionMatrix;
330
+ plane.current.material.lightViewMatrix = camera.current.matrixWorldInverse;
331
+ causticsMaterial.normalTexture = normalTarget.texture;
332
+ causticsMaterial.depthTexture = normalTarget.depthTexture;
333
+ gl.setRenderTarget(causticsTarget);
334
+ gl.clear();
335
+ causticsQuad.render(gl); // Render back face caustics, if enabled
289
336
 
290
- causticsMaterial.ior = backfaceIor;
291
- causticsMaterial.normalTexture = normalTargetB.texture;
292
- causticsMaterial.depthTexture = normalTargetB.depthTexture;
293
- gl.setRenderTarget(causticsTargetB);
294
- gl.clear();
295
- if (backfaces) causticsQuad.render(gl); // Reset render target
337
+ causticsMaterial.ior = backfaceIor;
338
+ causticsMaterial.normalTexture = normalTargetB.texture;
339
+ causticsMaterial.depthTexture = normalTargetB.depthTexture;
340
+ gl.setRenderTarget(causticsTargetB);
341
+ gl.clear();
342
+ if (backfaces) causticsQuad.render(gl); // Reset render target
296
343
 
297
- gl.setRenderTarget(null); // Switch the scene off if caustics is all that's wanted
344
+ gl.setRenderTarget(null); // Switch the scene off if caustics is all that's wanted
298
345
 
299
- if (causticsOnly) scene.current.visible = false;
346
+ if (causticsOnly) scene.current.visible = false;
347
+ }
300
348
  });
349
+ React.useImperativeHandle(fref, () => ref.current, []);
301
350
  return /*#__PURE__*/React.createElement("group", _extends({
302
351
  ref: ref
303
- }, props), /*#__PURE__*/React.createElement("orthographicCamera", {
304
- ref: camera,
305
- up: [0, 1, 0],
306
- left: -frustum,
307
- right: frustum,
308
- top: frustum,
309
- bottom: -frustum,
310
- near: near,
311
- far: far
312
- }), /*#__PURE__*/React.createElement("scene", {
352
+ }, props), /*#__PURE__*/React.createElement("scene", {
313
353
  ref: scene
314
- }, children), /*#__PURE__*/React.createElement("mesh", {
354
+ }, /*#__PURE__*/React.createElement("orthographicCamera", {
355
+ ref: camera,
356
+ up: [0, 1, 0]
357
+ }), children), /*#__PURE__*/React.createElement("mesh", {
358
+ renderOrder: 2,
315
359
  ref: plane,
316
- "rotation-x": -Math.PI / 2,
317
- scale: frustum * 2
360
+ "rotation-x": -Math.PI / 2
318
361
  }, /*#__PURE__*/React.createElement("planeGeometry", null), /*#__PURE__*/React.createElement("causticsProjectionMaterial", {
319
362
  transparent: true,
320
363
  color: color,
@@ -324,7 +367,10 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
324
367
  blendSrc: THREE.OneFactor,
325
368
  blendDst: THREE.SrcAlphaFactor,
326
369
  depthWrite: false
327
- })));
370
+ }), debug && /*#__PURE__*/React.createElement(Edges, null, /*#__PURE__*/React.createElement("lineBasicMaterial", {
371
+ color: "#ffff00",
372
+ toneMapped: false
373
+ }))));
328
374
  });
329
375
 
330
376
  export { Caustics };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("three"),r=require("react");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function u(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var o=n(e),i=u(r);const c=i.forwardRef((function({children:e,disableX:r,disableY:n,disableZ:u,left:c,right:a,top:l,bottom:f,front:d,back:s,onCentered:p,precise:b=!0,...m},g){const h=i.useRef(null),x=i.useRef(null),y=i.useRef(null);return i.useLayoutEffect((()=>{x.current.matrixWorld.identity();const e=(new t.Box3).setFromObject(y.current,b),o=new t.Vector3,i=new t.Sphere,m=e.max.x-e.min.x,g=e.max.y-e.min.y,j=e.max.z-e.min.z;e.getCenter(o),e.getBoundingSphere(i);const v=l?g/2:f?-g/2:0,O=c?-m/2:a?m/2:0,w=d?j/2:s?-j/2:0;x.current.position.set(r?0:-o.x+O,n?0:-o.y+v,u?0:-o.z+w),void 0!==p&&p({parent:h.current.parent,container:h.current,width:m,height:g,depth:j,boundingBox:e,boundingSphere:i,center:o,verticalAlignment:v,horizontalAlignment:O,depthAlignment:w})}),[e]),i.useImperativeHandle(g,(()=>h.current),[]),i.createElement("group",o.default({ref:h},m),i.createElement("group",{ref:x},i.createElement("group",{ref:y},e)))}));exports.Center=c;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("three"),r=require("react");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function u(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var i=n(e),o=u(r);const c=o.forwardRef((function({children:e,disable:r,disableX:n,disableY:u,disableZ:c,left:a,right:l,top:f,bottom:d,front:s,back:p,onCentered:b,precise:m=!0,...g},h){const x=o.useRef(null),y=o.useRef(null),j=o.useRef(null);return o.useLayoutEffect((()=>{y.current.matrixWorld.identity();const e=(new t.Box3).setFromObject(j.current,m),i=new t.Vector3,o=new t.Sphere,g=e.max.x-e.min.x,h=e.max.y-e.min.y,v=e.max.z-e.min.z;e.getCenter(i),e.getBoundingSphere(o);const O=f?h/2:d?-h/2:0,w=a?-g/2:l?g/2:0,z=s?v/2:p?-v/2:0;y.current.position.set(r||n?0:-i.x+w,r||u?0:-i.y+O,r||c?0:-i.z+z),void 0!==b&&b({parent:x.current.parent,container:x.current,width:g,height:h,depth:v,boundingBox:e,boundingSphere:o,center:i,verticalAlignment:O,horizontalAlignment:w,depthAlignment:z})}),[e]),o.useImperativeHandle(h,(()=>x.current),[]),o.createElement("group",i.default({ref:x},g),o.createElement("group",{ref:y},o.createElement("group",{ref:j},e)))}));exports.Center=c;
package/core/Center.d.ts CHANGED
@@ -20,6 +20,7 @@ export declare type CenterProps = {
20
20
  left?: boolean;
21
21
  front?: boolean;
22
22
  back?: boolean;
23
+ disable?: boolean;
23
24
  disableX?: boolean;
24
25
  disableY?: boolean;
25
26
  disableZ?: boolean;
package/core/Center.js CHANGED
@@ -4,6 +4,7 @@ import * as React from 'react';
4
4
 
5
5
  const Center = /*#__PURE__*/React.forwardRef(function Center({
6
6
  children,
7
+ disable,
7
8
  disableX,
8
9
  disableY,
9
10
  disableZ,
@@ -33,7 +34,7 @@ const Center = /*#__PURE__*/React.forwardRef(function Center({
33
34
  const vAlign = top ? height / 2 : bottom ? -height / 2 : 0;
34
35
  const hAlign = left ? -width / 2 : right ? width / 2 : 0;
35
36
  const dAlign = front ? depth / 2 : back ? -depth / 2 : 0;
36
- outer.current.position.set(disableX ? 0 : -center.x + hAlign, disableY ? 0 : -center.y + vAlign, disableZ ? 0 : -center.z + dAlign);
37
+ outer.current.position.set(disable || disableX ? 0 : -center.x + hAlign, disable || disableY ? 0 : -center.y + vAlign, disable || disableZ ? 0 : -center.z + dAlign);
37
38
 
38
39
  if (typeof onCentered !== 'undefined') {
39
40
  onCentered({
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),r=require("three-mesh-bvh");function t(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var u=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,u.get?u:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}var u=t(e);exports.useBVH=function(e,t){u.useEffect((()=>{if(e.current){e.current.raycast=r.acceleratedRaycast;const u=e.current.geometry;return u.computeBoundsTree=r.computeBoundsTree,u.disposeBoundsTree=r.disposeBoundsTree,u.computeBoundsTree(t),()=>{u.boundsTree&&u.disposeBoundsTree()}}}),[e,t])};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),r=require("three-mesh-bvh");function t(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var u=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,u.get?u:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}var u=t(e);exports.useBVH=function(e,t){t={splitStrategy:"SAH",verbose:!1,setBoundingBox:!0,maxDepth:40,maxLeafTris:10,...t},u.useEffect((()=>{if(e.current){e.current.raycast=r.acceleratedRaycast;const u=e.current.geometry;return u.computeBoundsTree=r.computeBoundsTree,u.disposeBoundsTree=r.disposeBoundsTree,u.computeBoundsTree(t),()=>{u.boundsTree&&u.disposeBoundsTree()}}}),[e,JSON.stringify(t)])};
package/core/useBVH.js CHANGED
@@ -2,6 +2,14 @@ import * as React from 'react';
2
2
  import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh';
3
3
 
4
4
  function useBVH(mesh, options) {
5
+ options = {
6
+ splitStrategy: 'SAH',
7
+ verbose: false,
8
+ setBoundingBox: true,
9
+ maxDepth: 40,
10
+ maxLeafTris: 10,
11
+ ...options
12
+ };
5
13
  React.useEffect(() => {
6
14
  if (mesh.current) {
7
15
  mesh.current.raycast = acceleratedRaycast;
@@ -15,7 +23,7 @@ function useBVH(mesh, options) {
15
23
  }
16
24
  };
17
25
  }
18
- }, [mesh, options]);
26
+ }, [mesh, JSON.stringify(options)]);
19
27
  }
20
28
 
21
29
  export { useBVH };