@react-three/drei 9.52.4 → 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 +16 -12
- package/core/Caustics.cjs.js +1 -1
- package/core/Caustics.d.ts +2 -4
- package/core/Caustics.js +10 -11
- package/index.cjs.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1830,7 +1830,7 @@ 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.
|
|
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
1834
|
|
|
1835
1835
|
#### CycleRaycast
|
|
1836
1836
|
|
|
@@ -3129,9 +3129,6 @@ type CausticsProps = JSX.IntrinsicElements['group'] & {
|
|
|
3129
3129
|
causticsOnly: boolean
|
|
3130
3130
|
/** Will include back faces and enable the backfaceIor prop, default: false */
|
|
3131
3131
|
backfaces: boolean
|
|
3132
|
-
/** The size of the camera frustum, make sure it fits your model perfectly
|
|
3133
|
-
* (with the debug flag)! The better it fits the more resolution you have. default: 2 */
|
|
3134
|
-
frustum?: number
|
|
3135
3132
|
/** The IOR refraction index, default: 1.1 */
|
|
3136
3133
|
ior?: number
|
|
3137
3134
|
/** The IOR refraction index for back faces (only available when backfaces is enabled), default: 1.1 */
|
|
@@ -3144,12 +3141,8 @@ type CausticsProps = JSX.IntrinsicElements['group'] & {
|
|
|
3144
3141
|
color?: ReactThreeFiber.Color
|
|
3145
3142
|
/** Buffer resolution, default: 2048 */
|
|
3146
3143
|
resolution?: number
|
|
3147
|
-
/** Camera near, default: 0.1 */
|
|
3148
|
-
near?: number
|
|
3149
|
-
/** Camera far, default: 100 */
|
|
3150
|
-
far?: number
|
|
3151
3144
|
/** Camera position, it will point towards the contents bounds center, default: [5, 5, 5] */
|
|
3152
|
-
lightSource?: [x: number, y: number, z: number]
|
|
3145
|
+
lightSource?: [x: number, y: number, z: number] | React.MutableRefObject<THREE.Object3D>
|
|
3153
3146
|
}
|
|
3154
3147
|
```
|
|
3155
3148
|
|
|
@@ -3158,7 +3151,7 @@ It will create a transparent plane that blends the caustics of the objects it re
|
|
|
3158
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).
|
|
3159
3152
|
|
|
3160
3153
|
```jsx
|
|
3161
|
-
<Caustics debug backfaces lightSource={[2.5, 5, -2.5]}
|
|
3154
|
+
<Caustics debug backfaces lightSource={[2.5, 5, -2.5]}>
|
|
3162
3155
|
<Bottle />
|
|
3163
3156
|
<WineGlass>
|
|
3164
3157
|
</Caustics>
|
|
@@ -3167,12 +3160,23 @@ Make sure to use the `debug` flag to help you stage your contents. Like ContactS
|
|
|
3167
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.
|
|
3168
3161
|
|
|
3169
3162
|
```jsx
|
|
3170
|
-
<Caustics lightSource={[2.5, 5, -2.5]} >
|
|
3163
|
+
<Caustics backfaces lightSource={[2.5, 5, -2.5]} >
|
|
3171
3164
|
<WineGlass />
|
|
3172
3165
|
</Caustics>
|
|
3173
|
-
<Caustics causticsOnly lightSource={[-2.5, 5, 2.5]} ior={0.79} worldRadius={0.0124}>
|
|
3166
|
+
<Caustics causticsOnly backfaces lightSource={[-2.5, 5, 2.5]} ior={0.79} worldRadius={0.0124}>
|
|
3167
|
+
<WineGlass />
|
|
3168
|
+
</Caustics>
|
|
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} >
|
|
3174
3177
|
<WineGlass />
|
|
3175
3178
|
</Caustics>
|
|
3179
|
+
<object3d ref={lightSource} position={[2.5, 5, -2.5]} />
|
|
3176
3180
|
```
|
|
3177
3181
|
|
|
3178
3182
|
#### ContactShadows
|
package/core/Caustics.cjs.js
CHANGED
|
@@ -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"),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,near:T=.1,far:F=100,lightSource:S=[5,5,5],...b},j)=>{t.extend({CausticsProjectionMaterial:f});const z=p.useRef(null),R=p.useRef(null),W=p.useRef(null),C=p.useRef(null),I=t.useThree((e=>e.gl)),V=i.useHelper(e&&R,m.CameraHelper),O=o.useFBO(D,D,h),B=o.useFBO(D,D,h),_=o.useFBO(D,D,g),E=o.useFBO(D,D,g),[A]=p.useState((()=>v())),[N]=p.useState((()=>v(m.BackSide))),[k]=p.useState((()=>new x)),[q]=p.useState((()=>new c.FullScreenQuad(k)));p.useLayoutEffect((()=>{z.current.updateWorldMatrix(!0,!0)}),[]);let U=0;const L=new m.Vector3,H=new m.Frustum,G=new m.Matrix4,Q=new m.Plane,J=new m.Vector3,K=new m.Vector3,X=new m.Box3,Y=new m.Vector3;return t.useFrame(((r,t)=>{if(n===1/0||U++<n){var o,i;J.fromArray(S).normalize(),K.copy(J).multiplyScalar(-1);let r=[];null==(o=W.current.parent)||o.matrixWorld.identity(),X.setFromObject(W.current,!0),r.push(new m.Vector3(X.min.x,X.min.y,X.min.z)),r.push(new m.Vector3(X.min.x,X.min.y,X.max.z)),r.push(new m.Vector3(X.min.x,X.max.y,X.min.z)),r.push(new m.Vector3(X.min.x,X.max.y,X.max.z)),r.push(new m.Vector3(X.max.x,X.min.y,X.min.z)),r.push(new m.Vector3(X.max.x,X.min.y,X.max.z)),r.push(new m.Vector3(X.max.x,X.max.y,X.min.z)),r.push(new m.Vector3(X.max.x,X.max.y,X.max.z));const n=r.map((e=>e.clone()));X.getCenter(Y),r=r.map((e=>e.clone().sub(Y)));const t=Q.set(K,0),l=r.map((e=>t.projectPoint(e,new m.Vector3))),c=l.reduce(((e,r)=>e.add(r)),L.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(J))).reduce(((e,r)=>Math.max(e,r)));R.current.position.copy(J.clone().multiplyScalar(d).add(Y)),R.current.lookAt(W.current.localToWorld(Y.clone()));const p=G.lookAt(R.current.position,Y,L.set(0,1,0));R.current.left=-s,R.current.right=s,R.current.top=s,R.current.bottom=-s;const v=L.set(0,s,0).applyMatrix4(p),f=(R.current.position.y+v.y)/J.y;R.current.near=.1,R.current.far=f,R.current.updateProjectionMatrix(),R.current.updateMatrixWorld();const x=n.map((e=>e.add(J.clone().multiplyScalar(-e.y/J.y)))),h=x.reduce(((e,r)=>e.add(r)),L.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)));C.current.scale.setScalar(g),C.current.position.copy(h),e&&(null==(i=V.current)||i.update());const T=H.setFromProjectionMatrix(G.multiplyMatrices(R.current.projectionMatrix,R.current.matrixWorldInverse)).planes[4];N.viewMatrix.value=A.viewMatrix.value=R.current.matrixWorldInverse,k.cameraMatrixWorld=R.current.matrixWorld,k.cameraProjectionMatrixInv=R.current.projectionMatrixInverse,k.lightDir=K,k.lightPlaneNormal=T.normal,k.lightPlaneConstant=T.constant,k.near=R.current.near,k.far=R.current.far,k.resolution=D,k.size=s,k.intensity=w,k.worldRadius=M,W.current.visible=!0,I.setRenderTarget(O),I.clear(),W.current.overrideMaterial=A,I.render(W.current,R.current),I.setRenderTarget(B),I.clear(),P&&(W.current.overrideMaterial=N,I.render(W.current,R.current)),W.current.overrideMaterial=null,k.ior=a,C.current.material.lightProjMatrix=R.current.projectionMatrix,C.current.material.lightViewMatrix=R.current.matrixWorldInverse,k.normalTexture=O.texture,k.depthTexture=O.depthTexture,I.setRenderTarget(_),I.clear(),q.render(I),k.ior=y,k.normalTexture=B.texture,k.depthTexture=B.depthTexture,I.setRenderTarget(E),I.clear(),P&&q.render(I),I.setRenderTarget(null),u&&(W.current.visible=!1)}})),p.createElement("group",d.default({ref:z},b),p.createElement("orthographicCamera",{ref:R,up:[0,1,0]}),p.createElement("scene",{ref:W},r),p.createElement("mesh",{ref:C,"rotation-x":-Math.PI/2},p.createElement("planeGeometry",null),p.createElement("causticsProjectionMaterial",{transparent:!0,color:s,causticsTexture:_.texture,causticsTextureB:E.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;
|
|
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;
|
package/core/Caustics.d.ts
CHANGED
|
@@ -46,7 +46,5 @@ export declare const Caustics: React.ForwardRefExoticComponent<Pick<Omit<ReactTh
|
|
|
46
46
|
intensity?: number | undefined;
|
|
47
47
|
color?: ReactThreeFiber.Color | undefined;
|
|
48
48
|
resolution?: number | undefined;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
lightSource?: [x: number, y: number, z: number] | undefined;
|
|
52
|
-
}, "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" | "ior" | "resolution" | "debug" | "frames" | "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
|
@@ -210,8 +210,6 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
|
|
|
210
210
|
worldRadius = 0.3125,
|
|
211
211
|
intensity = 0.05,
|
|
212
212
|
resolution = 2024,
|
|
213
|
-
near = 0.1,
|
|
214
|
-
far = 100,
|
|
215
213
|
lightSource = [5, 5, 5],
|
|
216
214
|
...props
|
|
217
215
|
}, fref) => {
|
|
@@ -236,9 +234,8 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
|
|
|
236
234
|
const [causticsMaterial] = React.useState(() => new CausticsMaterial());
|
|
237
235
|
const [causticsQuad] = React.useState(() => new FullScreenQuad(causticsMaterial));
|
|
238
236
|
React.useLayoutEffect(() => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}, []);
|
|
237
|
+
ref.current.updateWorldMatrix(false, true);
|
|
238
|
+
});
|
|
242
239
|
let count = 0;
|
|
243
240
|
const v = new THREE.Vector3();
|
|
244
241
|
const lpF = new THREE.Frustum();
|
|
@@ -252,7 +249,7 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
|
|
|
252
249
|
if (frames === Infinity || count++ < frames) {
|
|
253
250
|
var _scene$current$parent, _helper$current;
|
|
254
251
|
|
|
255
|
-
lightDir.fromArray(lightSource).normalize();
|
|
252
|
+
if (Array.isArray(lightSource)) lightDir.fromArray(lightSource).normalize();else lightDir.copy(ref.current.worldToLocal(lightSource.current.getWorldPosition(v)).normalize());
|
|
256
253
|
lightDirInv.copy(lightDir).multiplyScalar(-1);
|
|
257
254
|
let boundsVertices = [];
|
|
258
255
|
(_scene$current$parent = scene.current.parent) == null ? void 0 : _scene$current$parent.matrixWorld.identity();
|
|
@@ -295,8 +292,8 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
|
|
|
295
292
|
plane.current.position.copy(centerPos);
|
|
296
293
|
if (debug) (_helper$current = helper.current) == null ? void 0 : _helper$current.update(); // Inject uniforms
|
|
297
294
|
|
|
298
|
-
const dirLightNearPlane = lpF.setFromProjectionMatrix(lpM.multiplyMatrices(camera.current.projectionMatrix, camera.current.matrixWorldInverse)).planes[4];
|
|
299
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];
|
|
300
297
|
causticsMaterial.cameraMatrixWorld = camera.current.matrixWorld;
|
|
301
298
|
causticsMaterial.cameraProjectionMatrixInv = camera.current.projectionMatrixInverse;
|
|
302
299
|
causticsMaterial.lightDir = lightDirInv;
|
|
@@ -349,14 +346,16 @@ const Caustics = /*#__PURE__*/React.forwardRef(({
|
|
|
349
346
|
if (causticsOnly) scene.current.visible = false;
|
|
350
347
|
}
|
|
351
348
|
});
|
|
349
|
+
React.useImperativeHandle(fref, () => ref.current, []);
|
|
352
350
|
return /*#__PURE__*/React.createElement("group", _extends({
|
|
353
351
|
ref: ref
|
|
354
|
-
}, props), /*#__PURE__*/React.createElement("
|
|
352
|
+
}, props), /*#__PURE__*/React.createElement("scene", {
|
|
353
|
+
ref: scene
|
|
354
|
+
}, /*#__PURE__*/React.createElement("orthographicCamera", {
|
|
355
355
|
ref: camera,
|
|
356
356
|
up: [0, 1, 0]
|
|
357
|
-
}), /*#__PURE__*/React.createElement("
|
|
358
|
-
|
|
359
|
-
}, children), /*#__PURE__*/React.createElement("mesh", {
|
|
357
|
+
}), children), /*#__PURE__*/React.createElement("mesh", {
|
|
358
|
+
renderOrder: 2,
|
|
360
359
|
ref: plane,
|
|
361
360
|
"rotation-x": -Math.PI / 2
|
|
362
361
|
}, /*#__PURE__*/React.createElement("planeGeometry", null), /*#__PURE__*/React.createElement("causticsProjectionMaterial", {
|