UNPKG

@react-three/drei

Version:

useful add-ons for react-three-fiber

164 lines (143 loc) 6.45 kB
import * as THREE from 'three'; import { shaderMaterial } from '../core/shaderMaterial.js'; import { shaderStructs, shaderIntersectFunction, MeshBVHUniformStruct } from 'three-mesh-bvh'; import { version } from '../helpers/constants.js'; // Author: N8Programs const MeshRefractionMaterial = /* @__PURE__ */shaderMaterial({ envMap: null, bounces: 3, ior: 2.4, correctMips: true, aberrationStrength: 0.01, fresnel: 0, bvh: /* @__PURE__ */new MeshBVHUniformStruct(), color: /* @__PURE__ */new THREE.Color('white'), opacity: 1, resolution: /* @__PURE__ */new THREE.Vector2(), viewMatrixInverse: /* @__PURE__ */new THREE.Matrix4(), projectionMatrixInverse: /* @__PURE__ */new THREE.Matrix4() }, /*glsl*/` uniform mat4 viewMatrixInverse; varying vec3 vWorldPosition; varying vec3 vNormal; varying mat4 vModelMatrixInverse; #include <color_pars_vertex> void main() { #include <color_vertex> vec4 transformedNormal = vec4(normal, 0.0); vec4 transformedPosition = vec4(position, 1.0); #ifdef USE_INSTANCING transformedNormal = instanceMatrix * transformedNormal; transformedPosition = instanceMatrix * transformedPosition; #endif #ifdef USE_INSTANCING vModelMatrixInverse = inverse(modelMatrix * instanceMatrix); #else vModelMatrixInverse = inverse(modelMatrix); #endif vWorldPosition = (modelMatrix * transformedPosition).xyz; vNormal = normalize((viewMatrixInverse * vec4(normalMatrix * transformedNormal.xyz, 0.0)).xyz); gl_Position = projectionMatrix * viewMatrix * modelMatrix * transformedPosition; }`, /*glsl*/` #define ENVMAP_TYPE_CUBE_UV precision highp isampler2D; precision highp usampler2D; varying vec3 vWorldPosition; varying vec3 vNormal; varying mat4 vModelMatrixInverse; #include <color_pars_fragment> #ifdef ENVMAP_TYPE_CUBEM uniform samplerCube envMap; #else uniform sampler2D envMap; #endif uniform float bounces; ${shaderStructs} ${shaderIntersectFunction} uniform BVH bvh; uniform float ior; uniform bool correctMips; uniform vec2 resolution; uniform float fresnel; uniform mat4 modelMatrix; uniform mat4 projectionMatrixInverse; uniform mat4 viewMatrixInverse; uniform float aberrationStrength; uniform vec3 color; uniform float opacity; float fresnelFunc(vec3 viewDirection, vec3 worldNormal) { return pow( 1.0 + dot( viewDirection, worldNormal), 10.0 ); } vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 normal, float ior, mat4 modelMatrixInverse) { vec3 rayOrigin = ro; vec3 rayDirection = rd; rayDirection = refract(rayDirection, normal, 1.0 / ior); rayOrigin = vWorldPosition + rayDirection * 0.001; rayOrigin = (modelMatrixInverse * vec4(rayOrigin, 1.0)).xyz; rayDirection = normalize((modelMatrixInverse * vec4(rayDirection, 0.0)).xyz); for(float i = 0.0; i < bounces; i++) { uvec4 faceIndices = uvec4( 0u ); vec3 faceNormal = vec3( 0.0, 0.0, 1.0 ); vec3 barycoord = vec3( 0.0 ); float side = 1.0; float dist = 0.0; bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist ); vec3 hitPos = rayOrigin + rayDirection * max(dist - 0.001, 0.0); vec3 tempDir = refract(rayDirection, faceNormal, ior); if (length(tempDir) != 0.0) { rayDirection = tempDir; break; } rayDirection = reflect(rayDirection, faceNormal); rayOrigin = hitPos + rayDirection * 0.01; } rayDirection = normalize((modelMatrix * vec4(rayDirection, 0.0)).xyz); return rayDirection; } #include <common> #include <cube_uv_reflection_fragment> #ifdef ENVMAP_TYPE_CUBEM vec4 textureGradient(samplerCube envMap, vec3 rayDirection, vec3 directionCamPerfect) { return textureGrad(envMap, rayDirection, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection)); } #else vec4 textureGradient(sampler2D envMap, vec3 rayDirection, vec3 directionCamPerfect) { vec2 uvv = equirectUv( rayDirection ); vec2 smoothUv = equirectUv( directionCamPerfect ); return textureGrad(envMap, uvv, dFdx(correctMips ? smoothUv : uvv), dFdy(correctMips ? smoothUv : uvv)); } #endif void main() { vec2 uv = gl_FragCoord.xy / resolution; vec3 directionCamPerfect = (projectionMatrixInverse * vec4(uv * 2.0 - 1.0, 0.0, 1.0)).xyz; directionCamPerfect = (viewMatrixInverse * vec4(directionCamPerfect, 0.0)).xyz; directionCamPerfect = normalize(directionCamPerfect); vec3 normal = vNormal; vec3 rayOrigin = cameraPosition; vec3 rayDirection = normalize(vWorldPosition - cameraPosition); vec4 diffuseColor = vec4(color, opacity); #include <color_fragment> #ifdef CHROMATIC_ABERRATIONS vec3 rayDirectionG = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), vModelMatrixInverse); #ifdef FAST_CHROMA vec3 rayDirectionR = normalize(rayDirectionG + 1.0 * vec3(aberrationStrength / 2.0)); vec3 rayDirectionB = normalize(rayDirectionG - 1.0 * vec3(aberrationStrength / 2.0)); #else vec3 rayDirectionR = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 - aberrationStrength), 1.0), vModelMatrixInverse); vec3 rayDirectionB = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 + aberrationStrength), 1.0), vModelMatrixInverse); #endif float finalColorR = textureGradient(envMap, rayDirectionR, directionCamPerfect).r; float finalColorG = textureGradient(envMap, rayDirectionG, directionCamPerfect).g; float finalColorB = textureGradient(envMap, rayDirectionB, directionCamPerfect).b; diffuseColor.rgb *= vec3(finalColorR, finalColorG, finalColorB); #else rayDirection = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), vModelMatrixInverse); diffuseColor.rgb *= textureGradient(envMap, rayDirection, directionCamPerfect).rgb; #endif vec3 viewDirection = normalize(vWorldPosition - cameraPosition); float nFresnel = fresnelFunc(viewDirection, normal) * fresnel; gl_FragColor = vec4(mix(diffuseColor.rgb, vec3(1.0), nFresnel), diffuseColor.a); #include <tonemapping_fragment> #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}> }`); export { MeshRefractionMaterial };