@react-three/drei 9.51.10 → 9.51.12

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
@@ -1482,9 +1482,9 @@ return (
1482
1482
 
1483
1483
  An improved THREE.MeshPhysicalMaterial. It acts like a normal PhysicalMaterial in terms of transmission support, thickness, ior, roughness, etc., but has chromatic aberration, noise-based roughness blur, (primitive) anisotropy support, and unlike the original it can "see" other transmissive or transparent objects which leads to improved visuals.
1484
1484
 
1485
- Keep in mind that it can be expensive as it causes an additional render pass of the scene, minus the host mesh which gets removed from the render-stack temporarily. If you have other objects that you don't want to see reflected in the material just add them to the parent mesh as children. Low samples and low resolution will make it faster.
1485
+ Although it should be faster than MPM (~10x) keep in mind that it can still be expensive as it causes an additional render pass of the scene. Low samples and low resolution will make it faster. If you use roughness consider using a tiny resolution, for instance 32x32 pixels, it will still look good but perform much faster.
1486
1486
 
1487
- If you use roughness consider using a tiny resolution, for instance 32x32 pixels, it will still look good but perform much faster.
1487
+ For performance and visual reasons the host mesh gets removed from the render-stack temporarily. If you have other objects that you don't want to see reflected in the material just add them to the parent mesh as children.
1488
1488
 
1489
1489
  ```tsx
1490
1490
  type MeshTransmissionMaterialProps = JSX.IntrinsicElements['meshPhysicalMaterial'] & {
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var n=require("@babel/runtime/helpers/extends"),e=require("three"),t=require("react"),o=require("@react-three/fiber"),a=require("./useFBO.cjs.js");function r(n){return n&&"object"==typeof n&&"default"in n?n:{default:n}}function i(n){if(n&&n.__esModule)return n;var e=Object.create(null);return n&&Object.keys(n).forEach((function(t){if("default"!==t){var o=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,o.get?o:{enumerable:!0,get:function(){return n[t]}})}})),e.default=n,Object.freeze(e)}var s=r(n),l=i(e),c=i(t);class m extends l.MeshPhysicalMaterial{constructor({samples:n=6,...e}={}){super(e),this.uniforms={chromaticAberration:{value:.05},transmission:{value:1},thickness:{value:1},anisotropy:{value:.1},time:{value:0},distortion:{value:0},distortionScale:{value:.5},temporalDistortion:{value:.5},buffer:{value:null},resolution:{value:new l.Vector2}},this.onBeforeCompile=e=>{e.uniforms={...e.uniforms,...this.uniforms},e.fragmentShader="\n uniform float chromaticAberration;\n uniform vec2 resolution; \n uniform float anisotropy; \n uniform float time;\n uniform float distortion;\n uniform float distortionScale;\n uniform float temporalDistortion;\n uniform sampler2D buffer;\n \n vec3 sat(vec3 rgb, float adjustment) {\n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n vec3 intensity = vec3(dot(rgb, W));\n return mix(intensity, rgb, adjustment);\n }\n vec3 random3(vec3 c) {\n float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0*j);\n j *= .125;\n r.x = fract(512.0*j);\n j *= .125;\n r.y = fract(512.0*j);\n return r-0.5;\n }\n\n float seed = 0.0;\n uint hash( uint x ) {\n x += ( x << 10u );\n x ^= ( x >> 6u );\n x += ( x << 3u );\n x ^= ( x >> 11u );\n x += ( x << 15u );\n return x;\n }\n\n // Compound versions of the hashing algorithm I whipped together.\n uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y) ); }\n uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ); }\n uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }\n\n // Construct a float with half-open range [0:1] using low 23 bits.\n // All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0.\n float floatConstruct( uint m ) {\n const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask\n const uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32\n\n m &= ieeeMantissa; // Keep only mantissa bits (fractional part)\n m |= ieeeOne; // Add fractional part to 1.0\n\n float f = uintBitsToFloat( m ); // Range [1:2]\n return f - 1.0; // Range [0:1]\n }\n\n // Pseudo-random value in half-open range [0:1].\n float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); }\n float random( vec2 v ) { return floatConstruct(hash(floatBitsToUint(v))); }\n float random( vec3 v ) { return floatConstruct(hash(floatBitsToUint(v))); }\n float random( vec4 v ) { return floatConstruct(hash(floatBitsToUint(v))); }\n\n float rand() {\n float result = random(vec3(gl_FragCoord.xy, seed));\n seed += 1.0;\n return result;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float snoise(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e*(1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy*(1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0*G3;\n vec3 x3 = x - 1.0 + 3.0*G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float snoiseFractal(vec3 m) {\n return 0.5333333* snoise(m)\n +0.2666667* snoise(2.0*m)\n +0.1333333* snoise(4.0*m)\n +0.0666667* snoise(8.0*m);\n }\n"+e.fragmentShader,e.fragmentShader=e.fragmentShader.replace("#include <transmission_pars_fragment>","\n #ifdef USE_TRANSMISSION\n // Transmission code is based on glTF-Sampler-Viewer\n // https://github.com/KhronosGroup/glTF-Sample-Viewer\n uniform float transmission;\n uniform float thickness;\n uniform float attenuationDistance;\n uniform vec3 attenuationColor;\n #ifdef USE_TRANSMISSIONMAP\n uniform sampler2D transmissionMap;\n #endif\n #ifdef USE_THICKNESSMAP\n uniform sampler2D thicknessMap;\n #endif\n uniform vec2 transmissionSamplerSize;\n uniform sampler2D transmissionSamplerMap;\n uniform mat4 modelMatrix;\n uniform mat4 projectionMatrix;\n varying vec3 vWorldPosition;\n vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n // Direction of refracted light.\n vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n // Compute rotation-independant scaling of the model matrix.\n vec3 modelScale;\n modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n // The thickness is specified in local space.\n return normalize( refractionVector ) * thickness * modelScale;\n }\n float applyIorToRoughness( const in float roughness, const in float ior ) {\n // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and\n // an IOR of 1.5 results in the default amount of microfacet refraction.\n return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n }\n vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n return texture2D(buffer, fragCoord.xy);\n }\n vec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n if ( isinf( attenuationDistance ) ) {\n // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all.\n return radiance;\n } else {\n // Compute light attenuation using Beer's law.\n vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); // Beer's law\n return transmittance * radiance;\n }\n }\n vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n const in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n const in vec3 attenuationColor, const in float attenuationDistance ) {\n vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n vec3 refractedRayExit = position + transmissionRay;\n // Project refracted vector on the framebuffer, while mapping to normalized device coordinates.\n vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n vec2 refractionCoords = ndcPos.xy / ndcPos.w;\n refractionCoords += 1.0;\n refractionCoords /= 2.0;\n // Sample framebuffer to get pixel the refracted ray hits.\n vec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n vec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n // Get the specular component.\n vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n return vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n }\n #endif\n"),e.fragmentShader=e.fragmentShader.replace("#include <transmission_fragment>",`\n vec2 uv = gl_FragCoord.xy / resolution.xy; \n // Improve the refraction to use the world pos\n material.transmission = transmission;\n material.transmissionAlpha = 1.0;\n material.thickness = thickness;\n material.attenuationDistance = attenuationDistance;\n material.attenuationColor = attenuationColor;\n #ifdef USE_TRANSMISSIONMAP\n material.transmission *= texture2D( transmissionMap, vUv ).r;\n #endif\n #ifdef USE_THICKNESSMAP\n material.thickness *= texture2D( thicknessMap, vUv ).g;\n #endif\n \n vec3 pos = vWorldPosition;\n vec3 v = normalize( cameraPosition - pos );\n vec3 n = inverseTransformDirection( normal, viewMatrix );\n vec3 transmission = vec3(0.0);\n float transmissionR, transmissionB, transmissionG;\n float randomCoords = rand();\n float thickness_smear = thickness * max(pow(roughness, 0.33), anisotropy);\n vec3 distortionNormal = vec3(0.0);\n vec3 temporalOffset = vec3(time, -time, -time) * temporalDistortion;\n if (distortion > 0.0) {\n distortionNormal = distortion * vec3(snoiseFractal(vec3((pos * distortionScale + temporalOffset))), snoiseFractal(vec3(pos.zxy * distortionScale - temporalOffset)), snoiseFractal(vec3(pos.yxz * distortionScale + temporalOffset)));\n }\n for (float i = 0.0; i < ${n}.0; i ++) {\n vec3 sampleNorm = normalize(n + roughness * roughness * 2.0 * normalize(vec3(rand() - 0.5, rand() - 0.5, rand() - 0.5)) * pow(rand(), 0.33) + distortionNormal);\n transmissionR = getIBLVolumeRefraction(\n sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n pos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness + thickness_smear * (i + randomCoords) / float(${n}),\n material.attenuationColor, material.attenuationDistance\n ).r;\n transmissionG = getIBLVolumeRefraction(\n sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + chromaticAberration * (i + randomCoords) / float(${n})) , material.thickness + thickness_smear * (i + randomCoords) / float(${n}),\n material.attenuationColor, material.attenuationDistance\n ).g;\n transmissionB = getIBLVolumeRefraction(\n sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + 2.0 * chromaticAberration * (i + randomCoords) / float(${n})), material.thickness + thickness_smear * (i + randomCoords) / float(${n}),\n material.attenuationColor, material.attenuationDistance\n ).b;\n transmission.r += transmissionR;\n transmission.g += transmissionG;\n transmission.b += transmissionB;\n }\n transmission /= ${n}.0;\n material.transmissionAlpha = 1.0;\n totalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n`)},Object.keys(this.uniforms).forEach((n=>Object.defineProperty(this,n,{get:()=>this.uniforms[n].value,set:e=>this.uniforms[n].value=e})))}}const u=c.forwardRef((({buffer:n,distortionSpeed:e=1,samples:t=10,resolution:r,background:i,...l},u)=>{o.extend({MeshTransmissionMaterial:m});const f=c.useRef(null),{size:d,viewport:v}=o.useThree(),h=a.useFBO(r);let p,x,g;return o.useFrame((t=>{n||(g=f.current.__r3f.parent,f.current.time=t.clock.getElapsedTime()*e,g&&(x=g.visible,g.visible=!1,t.gl.setRenderTarget(h),p=t.scene.background,i&&(t.scene.background=i),t.gl.render(t.scene,t.camera),t.scene.background=p,t.gl.setRenderTarget(null),g.visible=x))})),c.useImperativeHandle(u,(()=>f.current),[]),c.createElement("meshTransmissionMaterial",s.default({args:[c.useMemo((()=>({samples:t})),[t])],ref:f,buffer:n||h.texture,resolution:[d.width*v.dpr,d.height*v.dpr]},l))}));exports.MeshTransmissionMaterial=u;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var n=require("@babel/runtime/helpers/extends"),e=require("three"),t=require("react"),a=require("@react-three/fiber"),o=require("./useFBO.cjs.js");function r(n){return n&&"object"==typeof n&&"default"in n?n:{default:n}}function i(n){if(n&&n.__esModule)return n;var e=Object.create(null);return n&&Object.keys(n).forEach((function(t){if("default"!==t){var a=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,a.get?a:{enumerable:!0,get:function(){return n[t]}})}})),e.default=n,Object.freeze(e)}var s=r(n),l=i(e),c=i(t);class m extends l.MeshPhysicalMaterial{constructor({samples:n=6,...e}={}){super(e),this.uniforms={chromaticAberration:{value:.05},transmission:{value:0},_transmission:{value:1},transmissionMap:{value:null},thickness:{value:1},thicknessMap:{value:null},attenuationDistance:{value:0},attenuationColor:{value:new l.Color},anisotropy:{value:.1},time:{value:0},distortion:{value:0},distortionScale:{value:.5},temporalDistortion:{value:.5},buffer:{value:null},resolution:{value:new l.Vector2}},this.onBeforeCompile=e=>{e.uniforms={...e.uniforms,...this.uniforms},e.defines.USE_TRANSMISSION="",e.fragmentShader="\n uniform float chromaticAberration;\n uniform vec2 resolution; \n uniform float anisotropy; \n uniform float time;\n uniform float distortion;\n uniform float distortionScale;\n uniform float temporalDistortion;\n uniform sampler2D buffer;\n \n vec3 sat(vec3 rgb, float adjustment) {\n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n vec3 intensity = vec3(dot(rgb, W));\n return mix(intensity, rgb, adjustment);\n }\n vec3 random3(vec3 c) {\n float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0*j);\n j *= .125;\n r.x = fract(512.0*j);\n j *= .125;\n r.y = fract(512.0*j);\n return r-0.5;\n }\n\n float seed = 0.0;\n uint hash( uint x ) {\n x += ( x << 10u );\n x ^= ( x >> 6u );\n x += ( x << 3u );\n x ^= ( x >> 11u );\n x += ( x << 15u );\n return x;\n }\n\n // Compound versions of the hashing algorithm I whipped together.\n uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y) ); }\n uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ); }\n uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }\n\n // Construct a float with half-open range [0:1] using low 23 bits.\n // All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0.\n float floatConstruct( uint m ) {\n const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask\n const uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32\n\n m &= ieeeMantissa; // Keep only mantissa bits (fractional part)\n m |= ieeeOne; // Add fractional part to 1.0\n\n float f = uintBitsToFloat( m ); // Range [1:2]\n return f - 1.0; // Range [0:1]\n }\n\n // Pseudo-random value in half-open range [0:1].\n float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); }\n float random( vec2 v ) { return floatConstruct(hash(floatBitsToUint(v))); }\n float random( vec3 v ) { return floatConstruct(hash(floatBitsToUint(v))); }\n float random( vec4 v ) { return floatConstruct(hash(floatBitsToUint(v))); }\n\n float rand() {\n float result = random(vec3(gl_FragCoord.xy, seed));\n seed += 1.0;\n return result;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float snoise(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e*(1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy*(1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0*G3;\n vec3 x3 = x - 1.0 + 3.0*G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float snoiseFractal(vec3 m) {\n return 0.5333333* snoise(m)\n +0.2666667* snoise(2.0*m)\n +0.1333333* snoise(4.0*m)\n +0.0666667* snoise(8.0*m);\n }\n"+e.fragmentShader,e.fragmentShader=e.fragmentShader.replace("#include <transmission_pars_fragment>","\n #ifdef USE_TRANSMISSION\n // Transmission code is based on glTF-Sampler-Viewer\n // https://github.com/KhronosGroup/glTF-Sample-Viewer\n uniform float _transmission;\n uniform float thickness;\n uniform float attenuationDistance;\n uniform vec3 attenuationColor;\n #ifdef USE_TRANSMISSIONMAP\n uniform sampler2D transmissionMap;\n #endif\n #ifdef USE_THICKNESSMAP\n uniform sampler2D thicknessMap;\n #endif\n uniform vec2 transmissionSamplerSize;\n uniform sampler2D transmissionSamplerMap;\n uniform mat4 modelMatrix;\n uniform mat4 projectionMatrix;\n varying vec3 vWorldPosition;\n vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n // Direction of refracted light.\n vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n // Compute rotation-independant scaling of the model matrix.\n vec3 modelScale;\n modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n // The thickness is specified in local space.\n return normalize( refractionVector ) * thickness * modelScale;\n }\n float applyIorToRoughness( const in float roughness, const in float ior ) {\n // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and\n // an IOR of 1.5 results in the default amount of microfacet refraction.\n return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n }\n vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n return texture2D(buffer, fragCoord.xy);\n }\n vec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n if ( isinf( attenuationDistance ) ) {\n // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all.\n return radiance;\n } else {\n // Compute light attenuation using Beer's law.\n vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); // Beer's law\n return transmittance * radiance;\n }\n }\n vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n const in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n const in vec3 attenuationColor, const in float attenuationDistance ) {\n vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n vec3 refractedRayExit = position + transmissionRay;\n // Project refracted vector on the framebuffer, while mapping to normalized device coordinates.\n vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n vec2 refractionCoords = ndcPos.xy / ndcPos.w;\n refractionCoords += 1.0;\n refractionCoords /= 2.0;\n // Sample framebuffer to get pixel the refracted ray hits.\n vec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n vec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n // Get the specular component.\n vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n return vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n }\n #endif\n"),e.fragmentShader=e.fragmentShader.replace("#include <transmission_fragment>",`\n vec2 uv = gl_FragCoord.xy / resolution.xy; \n // Improve the refraction to use the world pos\n material.transmission = _transmission;\n material.transmissionAlpha = 1.0;\n material.thickness = thickness;\n material.attenuationDistance = attenuationDistance;\n material.attenuationColor = attenuationColor;\n #ifdef USE_TRANSMISSIONMAP\n material.transmission *= texture2D( transmissionMap, vUv ).r;\n #endif\n #ifdef USE_THICKNESSMAP\n material.thickness *= texture2D( thicknessMap, vUv ).g;\n #endif\n \n vec3 pos = vWorldPosition;\n vec3 v = normalize( cameraPosition - pos );\n vec3 n = inverseTransformDirection( normal, viewMatrix );\n vec3 transmission = vec3(0.0);\n float transmissionR, transmissionB, transmissionG;\n float randomCoords = rand();\n float thickness_smear = thickness * max(pow(roughness, 0.33), anisotropy);\n vec3 distortionNormal = vec3(0.0);\n vec3 temporalOffset = vec3(time, -time, -time) * temporalDistortion;\n if (distortion > 0.0) {\n distortionNormal = distortion * vec3(snoiseFractal(vec3((pos * distortionScale + temporalOffset))), snoiseFractal(vec3(pos.zxy * distortionScale - temporalOffset)), snoiseFractal(vec3(pos.yxz * distortionScale + temporalOffset)));\n }\n for (float i = 0.0; i < ${n}.0; i ++) {\n vec3 sampleNorm = normalize(n + roughness * roughness * 2.0 * normalize(vec3(rand() - 0.5, rand() - 0.5, rand() - 0.5)) * pow(rand(), 0.33) + distortionNormal);\n transmissionR = getIBLVolumeRefraction(\n sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n pos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness + thickness_smear * (i + randomCoords) / float(${n}),\n material.attenuationColor, material.attenuationDistance\n ).r;\n transmissionG = getIBLVolumeRefraction(\n sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + chromaticAberration * (i + randomCoords) / float(${n})) , material.thickness + thickness_smear * (i + randomCoords) / float(${n}),\n material.attenuationColor, material.attenuationDistance\n ).g;\n transmissionB = getIBLVolumeRefraction(\n sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + 2.0 * chromaticAberration * (i + randomCoords) / float(${n})), material.thickness + thickness_smear * (i + randomCoords) / float(${n}),\n material.attenuationColor, material.attenuationDistance\n ).b;\n transmission.r += transmissionR;\n transmission.g += transmissionG;\n transmission.b += transmissionB;\n }\n transmission /= ${n}.0;\n totalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n`)},Object.keys(this.uniforms).forEach((n=>Object.defineProperty(this,n,{get:()=>this.uniforms[n].value,set:e=>this.uniforms[n].value=e})))}}const u=c.forwardRef((({buffer:n,transmission:e=1,distortionSpeed:t=1,samples:r=10,resolution:i,background:u,...f},d)=>{a.extend({MeshTransmissionMaterial:m});const v=c.useRef(null),{size:h,viewport:p}=a.useThree(),x=o.useFBO(i);let g,M,C,y;return a.useFrame((e=>{n||(y=v.current.__r3f.parent,v.current.time=e.clock.getElapsedTime()*t,y&&(C=e.gl.toneMapping,M=y.visible,e.gl.toneMapping=l.NoToneMapping,y.visible=!1,e.gl.setRenderTarget(x),g=e.scene.background,u&&(e.scene.background=u),e.gl.render(e.scene,e.camera),e.scene.background=g,e.gl.setRenderTarget(null),y.visible=M,e.gl.toneMapping=C))})),c.useImperativeHandle(d,(()=>v.current),[]),c.createElement("meshTransmissionMaterial",s.default({args:[c.useMemo((()=>({samples:r})),[r])],ref:v},f,{buffer:n||x.texture,_transmission:e,transmission:0,resolution:[h.width*p.dpr,h.height*p.dpr]}))}));exports.MeshTransmissionMaterial=u;
@@ -2,11 +2,12 @@ import * as THREE from 'three';
2
2
  import * as React from 'react';
3
3
  import { ReactThreeFiber } from '@react-three/fiber';
4
4
  declare type MeshTransmissionMaterialType = Omit<JSX.IntrinsicElements['meshPhysicalMaterial'], 'args'> & {
5
+ transmission?: number;
5
6
  chromaticAberration?: number;
6
7
  anisotropy?: number;
7
8
  distortion?: number;
8
- distortionScale?: number;
9
- temporalDistortion?: number;
9
+ distortionScale: Uniform<number>;
10
+ temporalDistortion: Uniform<number>;
10
11
  time?: number;
11
12
  resolution?: ReactThreeFiber.Vector2;
12
13
  buffer?: THREE.Texture;
@@ -14,6 +15,9 @@ declare type MeshTransmissionMaterialType = Omit<JSX.IntrinsicElements['meshPhys
14
15
  samples: number;
15
16
  }];
16
17
  };
18
+ interface Uniform<T> {
19
+ value: T;
20
+ }
17
21
  declare global {
18
22
  namespace JSX {
19
23
  interface IntrinsicElements {
@@ -14,12 +14,29 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
14
14
  chromaticAberration: {
15
15
  value: 0.05
16
16
  },
17
+ // Transmission must always be 0
17
18
  transmission: {
19
+ value: 0
20
+ },
21
+ // Instead a workaround is used, see below for reasons why
22
+ _transmission: {
18
23
  value: 1
19
24
  },
25
+ transmissionMap: {
26
+ value: null
27
+ },
20
28
  thickness: {
21
29
  value: 1
22
30
  },
31
+ thicknessMap: {
32
+ value: null
33
+ },
34
+ attenuationDistance: {
35
+ value: 0
36
+ },
37
+ attenuationColor: {
38
+ value: new THREE.Color()
39
+ },
23
40
  anisotropy: {
24
41
  value: 0.1
25
42
  },
@@ -46,7 +63,8 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
46
63
  this.onBeforeCompile = shader => {
47
64
  shader.uniforms = { ...shader.uniforms,
48
65
  ...this.uniforms
49
- }; // Head
66
+ };
67
+ shader.defines.USE_TRANSMISSION = ''; // Head
50
68
 
51
69
  shader.fragmentShader =
52
70
  /*glsl*/
@@ -149,7 +167,7 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
149
167
  +0.2666667* snoise(2.0*m)
150
168
  +0.1333333* snoise(4.0*m)
151
169
  +0.0666667* snoise(8.0*m);
152
- }\n` + shader.fragmentShader; // Replace transmission
170
+ }\n` + shader.fragmentShader; // Remove transmission
153
171
 
154
172
  shader.fragmentShader = shader.fragmentShader.replace('#include <transmission_pars_fragment>',
155
173
  /*glsl*/
@@ -157,7 +175,7 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
157
175
  #ifdef USE_TRANSMISSION
158
176
  // Transmission code is based on glTF-Sampler-Viewer
159
177
  // https://github.com/KhronosGroup/glTF-Sample-Viewer
160
- uniform float transmission;
178
+ uniform float _transmission;
161
179
  uniform float thickness;
162
180
  uniform float attenuationDistance;
163
181
  uniform vec3 attenuationColor;
@@ -220,13 +238,14 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
220
238
  vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );
221
239
  return vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );
222
240
  }
223
- #endif\n`);
241
+ #endif\n`); // Add refraction
242
+
224
243
  shader.fragmentShader = shader.fragmentShader.replace('#include <transmission_fragment>',
225
244
  /*glsl*/
226
245
  `
227
246
  vec2 uv = gl_FragCoord.xy / resolution.xy;
228
247
  // Improve the refraction to use the world pos
229
- material.transmission = transmission;
248
+ material.transmission = _transmission;
230
249
  material.transmissionAlpha = 1.0;
231
250
  material.thickness = thickness;
232
251
  material.attenuationDistance = attenuationDistance;
@@ -272,7 +291,6 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
272
291
  transmission.b += transmissionB;
273
292
  }
274
293
  transmission /= ${samples}.0;
275
- material.transmissionAlpha = 1.0;
276
294
  totalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n`);
277
295
  };
278
296
 
@@ -286,6 +304,7 @@ class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
286
304
 
287
305
  const MeshTransmissionMaterial = /*#__PURE__*/React.forwardRef(({
288
306
  buffer,
307
+ transmission = 1,
289
308
  distortionSpeed = 1,
290
309
  samples = 10,
291
310
  resolution,
@@ -303,6 +322,7 @@ const MeshTransmissionMaterial = /*#__PURE__*/React.forwardRef(({
303
322
  const fbo = useFBO(resolution);
304
323
  let oldBg;
305
324
  let oldVis;
325
+ let oldTone;
306
326
  let parent;
307
327
  useFrame(state => {
308
328
  if (!buffer) {
@@ -310,8 +330,12 @@ const MeshTransmissionMaterial = /*#__PURE__*/React.forwardRef(({
310
330
  ref.current.time = state.clock.getElapsedTime() * distortionSpeed;
311
331
 
312
332
  if (parent) {
313
- // Hide the outer groups contents
314
- oldVis = parent.visible;
333
+ // Save defaults
334
+ oldTone = state.gl.toneMapping;
335
+ oldVis = parent.visible; // Switch off tonemapping lest it double tone maps
336
+
337
+ state.gl.toneMapping = THREE.NoToneMapping; // Hide the outer groups contents
338
+
315
339
  parent.visible = false; // Set render target to the local buffer
316
340
 
317
341
  state.gl.setRenderTarget(fbo); // Save the current background and set the HDR as the new BG
@@ -325,6 +349,7 @@ const MeshTransmissionMaterial = /*#__PURE__*/React.forwardRef(({
325
349
  state.scene.background = oldBg;
326
350
  state.gl.setRenderTarget(null);
327
351
  parent.visible = oldVis;
352
+ state.gl.toneMapping = oldTone;
328
353
  }
329
354
  }
330
355
  }); // Forward ref
@@ -334,10 +359,16 @@ const MeshTransmissionMaterial = /*#__PURE__*/React.forwardRef(({
334
359
  args: [React.useMemo(() => ({
335
360
  samples
336
361
  }), [samples])],
337
- ref: ref,
338
- buffer: buffer || fbo.texture,
362
+ ref: ref
363
+ }, props, {
364
+ buffer: buffer || fbo.texture // @ts-ignore
365
+ ,
366
+ _transmission: transmission // In order for this to not incur extra cost "transmission" must be set to 0 and treated as a reserved prop.
367
+ // This is because THREE.WebGLRenderer will check for transmission > 0 and executed extra renders.
368
+ ,
369
+ transmission: 0,
339
370
  resolution: [size.width * viewport.dpr, size.height * viewport.dpr]
340
- }, props));
371
+ }));
341
372
  });
342
373
 
343
374
  export { MeshTransmissionMaterial };