|
| 1 | +import * as THREE from 'three'; |
| 2 | +import { shaderMaterial } from '../shader-material/shader-material'; |
| 3 | + |
| 4 | +export const CausticsMaterial = shaderMaterial( |
| 5 | + { |
| 6 | + cameraMatrixWorld: new THREE.Matrix4(), |
| 7 | + cameraProjectionMatrixInv: new THREE.Matrix4(), |
| 8 | + normalTexture: null, |
| 9 | + depthTexture: null, |
| 10 | + lightDir: new THREE.Vector3(0, 1, 0), |
| 11 | + lightPlaneNormal: new THREE.Vector3(0, 1, 0), |
| 12 | + lightPlaneConstant: 0, |
| 13 | + near: 0.1, |
| 14 | + far: 100, |
| 15 | + modelMatrix: new THREE.Matrix4(), |
| 16 | + worldRadius: 1 / 40, |
| 17 | + ior: 1.1, |
| 18 | + bounces: 0, |
| 19 | + resolution: 1024, |
| 20 | + size: 10, |
| 21 | + intensity: 0.5, |
| 22 | + }, |
| 23 | + /* glsl */ `varying vec2 vUv; |
| 24 | +void main() { |
| 25 | + vUv = uv; |
| 26 | + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); |
| 27 | +}`, |
| 28 | + /* glsl */ `uniform mat4 cameraMatrixWorld; |
| 29 | +uniform mat4 cameraProjectionMatrixInv; |
| 30 | +uniform vec3 lightDir; |
| 31 | +uniform vec3 lightPlaneNormal; |
| 32 | +uniform float lightPlaneConstant; |
| 33 | +uniform float near; |
| 34 | +uniform float far; |
| 35 | +uniform float time; |
| 36 | +uniform float worldRadius; |
| 37 | +uniform float resolution; |
| 38 | +uniform float size; |
| 39 | +uniform float intensity; |
| 40 | +uniform float ior; |
| 41 | +precision highp isampler2D; |
| 42 | +precision highp usampler2D; |
| 43 | +uniform sampler2D normalTexture; |
| 44 | +uniform sampler2D depthTexture; |
| 45 | +uniform float bounces; |
| 46 | +varying vec2 vUv; |
| 47 | +vec3 WorldPosFromDepth(float depth, vec2 coord) { |
| 48 | + float z = depth * 2.0 - 1.0; |
| 49 | + vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0); |
| 50 | + vec4 viewSpacePosition = cameraProjectionMatrixInv * clipSpacePosition; |
| 51 | + // Perspective division |
| 52 | + viewSpacePosition /= viewSpacePosition.w; |
| 53 | + vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition; |
| 54 | + return worldSpacePosition.xyz; |
| 55 | +} |
| 56 | +float sdPlane( vec3 p, vec3 n, float h ) { |
| 57 | + // n must be normalized |
| 58 | + return dot(p,n) + h; |
| 59 | +} |
| 60 | +float planeIntersect( vec3 ro, vec3 rd, vec4 p ) { |
| 61 | + return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz); |
| 62 | +} |
| 63 | +vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 pos, vec3 normal, float ior, out vec3 rayOrigin, out vec3 rayDirection) { |
| 64 | + rayOrigin = ro; |
| 65 | + rayDirection = rd; |
| 66 | + rayDirection = refract(rayDirection, normal, 1.0 / ior); |
| 67 | + rayOrigin = pos + rayDirection * 0.1; |
| 68 | + return rayDirection; |
| 69 | +} |
| 70 | +void main() { |
| 71 | + // Each sample consists of random offset in the x and y direction |
| 72 | + float caustic = 0.0; |
| 73 | + float causticTexelSize = (1.0 / resolution) * size * 2.0; |
| 74 | + float texelsNeeded = worldRadius / causticTexelSize; |
| 75 | + float sampleRadius = texelsNeeded / resolution; |
| 76 | + float sum = 0.0; |
| 77 | + if (texture2D(depthTexture, vUv).x == 1.0) { |
| 78 | + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); |
| 79 | + return; |
| 80 | + } |
| 81 | + vec2 offset1 = vec2(-0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5); |
| 82 | + vec2 offset2 = vec2(-0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5); |
| 83 | + vec2 offset3 = vec2(0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5); |
| 84 | + vec2 offset4 = vec2(0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5); |
| 85 | + vec2 uv1 = vUv + offset1 * sampleRadius; |
| 86 | + vec2 uv2 = vUv + offset2 * sampleRadius; |
| 87 | + vec2 uv3 = vUv + offset3 * sampleRadius; |
| 88 | + vec2 uv4 = vUv + offset4 * sampleRadius; |
| 89 | + vec3 normal1 = texture2D(normalTexture, uv1, -10.0).rgb * 2.0 - 1.0; |
| 90 | + vec3 normal2 = texture2D(normalTexture, uv2, -10.0).rgb * 2.0 - 1.0; |
| 91 | + vec3 normal3 = texture2D(normalTexture, uv3, -10.0).rgb * 2.0 - 1.0; |
| 92 | + vec3 normal4 = texture2D(normalTexture, uv4, -10.0).rgb * 2.0 - 1.0; |
| 93 | + float depth1 = texture2D(depthTexture, uv1, -10.0).x; |
| 94 | + float depth2 = texture2D(depthTexture, uv2, -10.0).x; |
| 95 | + float depth3 = texture2D(depthTexture, uv3, -10.0).x; |
| 96 | + float depth4 = texture2D(depthTexture, uv4, -10.0).x; |
| 97 | + // Sanity check the depths |
| 98 | + if (depth1 == 1.0 || depth2 == 1.0 || depth3 == 1.0 || depth4 == 1.0) { |
| 99 | + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); |
| 100 | + return; |
| 101 | + } |
| 102 | + vec3 pos1 = WorldPosFromDepth(depth1, uv1); |
| 103 | + vec3 pos2 = WorldPosFromDepth(depth2, uv2); |
| 104 | + vec3 pos3 = WorldPosFromDepth(depth3, uv3); |
| 105 | + vec3 pos4 = WorldPosFromDepth(depth4, uv4); |
| 106 | + vec3 originPos1 = WorldPosFromDepth(0.0, uv1); |
| 107 | + vec3 originPos2 = WorldPosFromDepth(0.0, uv2); |
| 108 | + vec3 originPos3 = WorldPosFromDepth(0.0, uv3); |
| 109 | + vec3 originPos4 = WorldPosFromDepth(0.0, uv4); |
| 110 | + vec3 endPos1, endPos2, endPos3, endPos4; |
| 111 | + vec3 endDir1, endDir2, endDir3, endDir4; |
| 112 | + totalInternalReflection(originPos1, lightDir, pos1, normal1, ior, endPos1, endDir1); |
| 113 | + totalInternalReflection(originPos2, lightDir, pos2, normal2, ior, endPos2, endDir2); |
| 114 | + totalInternalReflection(originPos3, lightDir, pos3, normal3, ior, endPos3, endDir3); |
| 115 | + totalInternalReflection(originPos4, lightDir, pos4, normal4, ior, endPos4, endDir4); |
| 116 | + float lightPosArea = length(cross(originPos2 - originPos1, originPos3 - originPos1)) + length(cross(originPos3 - originPos1, originPos4 - originPos1)); |
| 117 | + float t1 = planeIntersect(endPos1, endDir1, vec4(lightPlaneNormal, lightPlaneConstant)); |
| 118 | + float t2 = planeIntersect(endPos2, endDir2, vec4(lightPlaneNormal, lightPlaneConstant)); |
| 119 | + float t3 = planeIntersect(endPos3, endDir3, vec4(lightPlaneNormal, lightPlaneConstant)); |
| 120 | + float t4 = planeIntersect(endPos4, endDir4, vec4(lightPlaneNormal, lightPlaneConstant)); |
| 121 | + vec3 finalPos1 = endPos1 + endDir1 * t1; |
| 122 | + vec3 finalPos2 = endPos2 + endDir2 * t2; |
| 123 | + vec3 finalPos3 = endPos3 + endDir3 * t3; |
| 124 | + vec3 finalPos4 = endPos4 + endDir4 * t4; |
| 125 | + float finalArea = length(cross(finalPos2 - finalPos1, finalPos3 - finalPos1)) + length(cross(finalPos3 - finalPos1, finalPos4 - finalPos1)); |
| 126 | + caustic += intensity * (lightPosArea / finalArea); |
| 127 | + // Calculate the area of the triangle in light spaces |
| 128 | + gl_FragColor = vec4(vec3(max(caustic, 0.0)), 1.0); |
| 129 | +}` |
| 130 | +); |
0 commit comments