UNPKG

@react-three/drei

Version:

useful add-ons for react-three-fiber

109 lines (98 loc) 3.71 kB
import { useFrame } from '@react-three/fiber'; import * as React from 'react'; import * as THREE from 'three'; /** * Integration and compilation: Faraz Shaikh (https://twitter.com/CantBeFaraz) * * Based on: * - https://gkjohnson.github.io/threejs-sandbox/screendoor-transparency/ by Garrett Johnson (https://github.com/gkjohnson) * * Note: * - Must depreciate in favor of https://github.com/mrdoob/three.js/issues/10600 when it's ready. */ function ShadowAlpha({ opacity, alphaMap }) { const depthMaterialRef = React.useRef(null); const distanceMaterialRef = React.useRef(null); const uShadowOpacity = React.useRef({ value: 1 }); const uAlphaMap = React.useRef({ value: null }); const uHasAlphaMap = React.useRef({ value: false }); React.useLayoutEffect(() => { depthMaterialRef.current.onBeforeCompile = distanceMaterialRef.current.onBeforeCompile = shader => { // Need to get the "void main" line dynamically because the lines for // MeshDistanceMaterial and MeshDepthMaterial are different 🤦‍♂️ const mainLineStart = shader.fragmentShader.indexOf('void main'); let mainLine = ''; let ch; let i = mainLineStart; while (ch !== '\n' && i < mainLineStart + 100) { ch = shader.fragmentShader.charAt(i); mainLine += ch; i++; } mainLine = mainLine.trim(); shader.vertexShader = shader.vertexShader.replace('void main() {', ` varying vec2 custom_vUv; void main() { custom_vUv = uv; `); shader.fragmentShader = shader.fragmentShader.replace(mainLine, ` uniform float uShadowOpacity; uniform sampler2D uAlphaMap; uniform bool uHasAlphaMap; varying vec2 custom_vUv; float bayerDither2x2( vec2 v ) { return mod( 3.0 * v.y + 2.0 * v.x, 4.0 ); } float bayerDither4x4( vec2 v ) { vec2 P1 = mod( v, 2.0 ); vec2 P2 = mod( floor( 0.5 * v ), 2.0 ); return 4.0 * bayerDither2x2( P1 ) + bayerDither2x2( P2 ); } void main() { float alpha = uHasAlphaMap ? uShadowOpacity * texture2D(uAlphaMap, custom_vUv).x : uShadowOpacity; if( ( bayerDither4x4( floor( mod( gl_FragCoord.xy, 4.0 ) ) ) ) / 16.0 >= alpha ) discard; `); shader.uniforms['uShadowOpacity'] = uShadowOpacity.current; shader.uniforms['uAlphaMap'] = uAlphaMap.current; shader.uniforms['uHasAlphaMap'] = uHasAlphaMap.current; }; }, []); useFrame(() => { var _r3f; const parent = (_r3f = depthMaterialRef.current.__r3f) == null || (_r3f = _r3f.parent) == null ? void 0 : _r3f.object; if (parent) { const parentMainMaterial = parent.material; if (parentMainMaterial) { uShadowOpacity.current.value = opacity !== null && opacity !== void 0 ? opacity : parentMainMaterial.opacity; if (alphaMap === false) { uAlphaMap.current.value = null; uHasAlphaMap.current.value = false; } else { uAlphaMap.current.value = alphaMap || parentMainMaterial.alphaMap; uHasAlphaMap.current.value = !!uAlphaMap.current.value; } } } }); return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("meshDepthMaterial", { ref: depthMaterialRef, attach: "customDepthMaterial", depthPacking: THREE.RGBADepthPacking }), /*#__PURE__*/React.createElement("meshDistanceMaterial", { ref: distanceMaterialRef, attach: "customDistanceMaterial" })); } export { ShadowAlpha };