1 | import * as THREE from 'three';
|
2 | import { shaderMaterial } from '../core/shaderMaterial.js';
|
3 | import { shaderStructs, shaderIntersectFunction, MeshBVHUniformStruct } from 'three-mesh-bvh';
|
4 |
|
5 |
|
6 | const MeshRefractionMaterial = shaderMaterial({
|
7 | envMap: null,
|
8 | bounces: 3,
|
9 | ior: 2.4,
|
10 | correctMips: true,
|
11 | aberrationStrength: 0.01,
|
12 | fresnel: 0,
|
13 | bvh: new MeshBVHUniformStruct(),
|
14 | color: new THREE.Color('white'),
|
15 | resolution: new THREE.Vector2()
|
16 | },
|
17 |
|
18 | `
|
19 | varying vec3 vWorldPosition;
|
20 | varying vec3 vNormal;
|
21 | varying mat4 projectionMatrixInv;
|
22 | varying mat4 viewMatrixInv;
|
23 | varying vec3 viewDirection;
|
24 | varying mat4 vInstanceMatrix;
|
25 |
|
26 | void main() {
|
27 | vec4 transformedNormal = vec4(normal, 0.0);
|
28 | vec4 transformedPosition = vec4(position, 1.0);
|
29 | #ifdef USE_INSTANCING
|
30 | vInstanceMatrix = instanceMatrix;
|
31 | transformedNormal = instanceMatrix * transformedNormal;
|
32 | transformedPosition = instanceMatrix * transformedPosition;
|
33 | #else
|
34 | vInstanceMatrix = mat4(1.0);
|
35 | #endif
|
36 |
|
37 | projectionMatrixInv = inverse(projectionMatrix);
|
38 | viewMatrixInv = inverse(viewMatrix);
|
39 |
|
40 | vWorldPosition = (modelMatrix * transformedPosition).xyz;
|
41 | vNormal = (viewMatrixInv * vec4(normalMatrix * transformedNormal.xyz, 0.0)).xyz;
|
42 | viewDirection = normalize(vWorldPosition - cameraPosition);
|
43 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * transformedPosition;
|
44 | }`,
|
45 |
|
46 | `
|
47 | #define ENVMAP_TYPE_CUBE_UV
|
48 | precision highp isampler2D;
|
49 | precision highp usampler2D;
|
50 | varying vec3 vWorldPosition;
|
51 | varying vec3 vNormal;
|
52 |
|
53 | #ifdef ENVMAP_TYPE_CUBEM
|
54 | uniform samplerCube envMap;
|
55 | #else
|
56 | uniform sampler2D envMap;
|
57 | #endif
|
58 |
|
59 | uniform float bounces;
|
60 | ${shaderStructs}
|
61 | ${shaderIntersectFunction}
|
62 | uniform BVH bvh;
|
63 | uniform float ior;
|
64 | uniform vec3 color;
|
65 | uniform bool correctMips;
|
66 | uniform vec2 resolution;
|
67 | uniform float fresnel;
|
68 | uniform mat4 modelMatrix;
|
69 |
|
70 | uniform float aberrationStrength;
|
71 | varying mat4 projectionMatrixInv;
|
72 | varying mat4 viewMatrixInv;
|
73 | varying vec3 viewDirection;
|
74 | varying mat4 vInstanceMatrix;
|
75 |
|
76 | float fresnelFunc(vec3 viewDirection, vec3 worldNormal) {
|
77 | return pow( 1.0 + dot( viewDirection, worldNormal), 10.0 );
|
78 | }
|
79 |
|
80 | vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 normal, float ior, mat4 modelMatrixInverse) {
|
81 | vec3 rayOrigin = ro;
|
82 | vec3 rayDirection = rd;
|
83 | rayDirection = refract(rayDirection, normal, 1.0 / ior);
|
84 | rayOrigin = vWorldPosition + rayDirection * 0.001;
|
85 | rayOrigin = (modelMatrixInverse * vec4(rayOrigin, 1.0)).xyz;
|
86 | rayDirection = normalize((modelMatrixInverse * vec4(rayDirection, 0.0)).xyz);
|
87 | for(float i = 0.0; i < bounces; i++) {
|
88 | uvec4 faceIndices = uvec4( 0u );
|
89 | vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
|
90 | vec3 barycoord = vec3( 0.0 );
|
91 | float side = 1.0;
|
92 | float dist = 0.0;
|
93 | bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
|
94 | vec3 hitPos = rayOrigin + rayDirection * max(dist - 0.001, 0.0);
|
95 | vec3 tempDir = refract(rayDirection, faceNormal, ior);
|
96 | if (length(tempDir) != 0.0) {
|
97 | rayDirection = tempDir;
|
98 | break;
|
99 | }
|
100 | rayDirection = reflect(rayDirection, faceNormal);
|
101 | rayOrigin = hitPos + rayDirection * 0.01;
|
102 | }
|
103 | rayDirection = normalize((modelMatrix * vec4(rayDirection, 0.0)).xyz);
|
104 | return rayDirection;
|
105 | }
|
106 |
|
107 | #include <common>
|
108 | #include <cube_uv_reflection_fragment>
|
109 |
|
110 | #ifdef ENVMAP_TYPE_CUBEM
|
111 | vec4 textureGradient(samplerCube envMap, vec3 rayDirection, vec3 directionCamPerfect) {
|
112 | return textureGrad(envMap, rayDirection, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection));
|
113 | }
|
114 | #else
|
115 | vec4 textureGradient(sampler2D envMap, vec3 rayDirection, vec3 directionCamPerfect) {
|
116 | vec2 uvv = equirectUv( rayDirection );
|
117 | vec2 smoothUv = equirectUv( directionCamPerfect );
|
118 | return textureGrad(envMap, uvv, dFdx(correctMips ? smoothUv : uvv), dFdy(correctMips ? smoothUv : uvv));
|
119 | }
|
120 | #endif
|
121 |
|
122 | void main() {
|
123 | mat4 modelMatrixInverse = inverse(modelMatrix * vInstanceMatrix);
|
124 | vec2 uv = gl_FragCoord.xy / resolution;
|
125 | vec3 directionCamPerfect = (projectionMatrixInv * vec4(uv * 2.0 - 1.0, 0.0, 1.0)).xyz;
|
126 | directionCamPerfect = (viewMatrixInv * vec4(directionCamPerfect, 0.0)).xyz;
|
127 | directionCamPerfect = normalize(directionCamPerfect);
|
128 | vec3 normal = vNormal;
|
129 | vec3 rayOrigin = cameraPosition;
|
130 | vec3 rayDirection = normalize(vWorldPosition - cameraPosition);
|
131 | vec3 finalColor;
|
132 | #ifdef CHROMATIC_ABERRATIONS
|
133 | vec3 rayDirectionG = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), modelMatrixInverse);
|
134 | #ifdef FAST_CHROMA
|
135 | vec3 rayDirectionR = normalize(rayDirectionG + 1.0 * vec3(aberrationStrength / 2.0));
|
136 | vec3 rayDirectionB = normalize(rayDirectionG - 1.0 * vec3(aberrationStrength / 2.0));
|
137 | #else
|
138 | vec3 rayDirectionR = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 - aberrationStrength), 1.0), modelMatrixInverse);
|
139 | vec3 rayDirectionB = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 + aberrationStrength), 1.0), modelMatrixInverse);
|
140 | #endif
|
141 | float finalColorR = textureGradient(envMap, rayDirectionR, directionCamPerfect).r;
|
142 | float finalColorG = textureGradient(envMap, rayDirectionG, directionCamPerfect).g;
|
143 | float finalColorB = textureGradient(envMap, rayDirectionB, directionCamPerfect).b;
|
144 | finalColor = vec3(finalColorR, finalColorG, finalColorB) * color;
|
145 | #else
|
146 | rayDirection = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), modelMatrixInverse);
|
147 | finalColor = textureGradient(envMap, rayDirection, directionCamPerfect).rgb;
|
148 | finalColor *= color;
|
149 | #endif
|
150 | float nFresnel = fresnelFunc(viewDirection, normal) * fresnel;
|
151 | gl_FragColor = vec4(mix(finalColor, vec3(1.0), nFresnel), 1.0);
|
152 | #include <tonemapping_fragment>
|
153 | #include <encodings_fragment>
|
154 | }`);
|
155 |
|
156 | export { MeshRefractionMaterial };
|