@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 +22 -13
- package/core/Caustics.cjs.js +1 -1
- package/core/Caustics.d.ts +3 -6
- package/core/Caustics.js +121 -75
- package/core/Center.cjs.js +1 -1
- package/core/Center.d.ts +1 -0
- package/core/Center.js +2 -1
- package/core/useBVH.cjs.js +1 -1
- package/core/useBVH.js +9 -1
- package/index.cjs.js +1 -1
- package/package.json +1 -1
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
|

|
|
@@ -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
|
|
3141
|
-
|
|
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]}
|
|
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
|
-
|
|
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
|
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"),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;
|
package/core/Caustics.d.ts
CHANGED
|
@@ -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
|
-
|
|
50
|
-
|
|
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(
|
|
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(
|
|
169
|
-
float t2 = planeIntersect(endPos2, endDir2, vec4(
|
|
170
|
-
float t3 = planeIntersect(endPos3, endDir3, vec4(
|
|
171
|
-
float t4 = planeIntersect(endPos4, endDir4, vec4(
|
|
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
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
245
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
310
|
+
scene.current.visible = true; // Render front face normals
|
|
264
311
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
271
|
-
|
|
317
|
+
gl.setRenderTarget(normalTargetB);
|
|
318
|
+
gl.clear();
|
|
272
319
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
-
|
|
326
|
+
scene.current.overrideMaterial = null; // Render front face caustics
|
|
280
327
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
344
|
+
gl.setRenderTarget(null); // Switch the scene off if caustics is all that's wanted
|
|
298
345
|
|
|
299
|
-
|
|
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("
|
|
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
|
-
},
|
|
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 };
|
package/core/Center.cjs.js
CHANGED
|
@@ -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
|
|
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
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({
|
package/core/useBVH.cjs.js
CHANGED
|
@@ -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 };
|