|
| 1 | +import * as THREE from 'three' |
| 2 | + |
| 3 | +const DepthDownSample = { |
| 4 | + uniforms: { |
| 5 | + sceneDepth: { value: null }, |
| 6 | + resolution: { value: new THREE.Vector2() }, |
| 7 | + near: { value: 0.1 }, |
| 8 | + far: { value: 1000.0 }, |
| 9 | + viewMatrixInv: { value: new THREE.Matrix4() }, |
| 10 | + projectionMatrixInv: { value: new THREE.Matrix4() }, |
| 11 | + logDepth: { value: false }, |
| 12 | + }, |
| 13 | + depthWrite: false, |
| 14 | + depthTest: false, |
| 15 | + |
| 16 | + vertexShader: /* glsl */ ` |
| 17 | + varying vec2 vUv; |
| 18 | + void main() { |
| 19 | + vUv = uv; |
| 20 | + gl_Position = vec4(position, 1); |
| 21 | + }`, |
| 22 | + fragmentShader: /* glsl */ ` |
| 23 | + uniform highp sampler2D sceneDepth; |
| 24 | + uniform vec2 resolution; |
| 25 | + uniform float near; |
| 26 | + uniform float far; |
| 27 | + uniform bool logDepth; |
| 28 | + uniform mat4 viewMatrixInv; |
| 29 | + uniform mat4 projectionMatrixInv; |
| 30 | + varying vec2 vUv; |
| 31 | + layout(location = 1) out vec4 gNormal; |
| 32 | + vec3 getWorldPosLog(vec3 posS) { |
| 33 | + vec2 uv = posS.xy; |
| 34 | + float z = posS.z; |
| 35 | + float nearZ =near; |
| 36 | + float farZ = far; |
| 37 | + float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0; |
| 38 | + float a = farZ / (farZ - nearZ); |
| 39 | + float b = farZ * nearZ / (nearZ - farZ); |
| 40 | + float linDepth = a + b / depth; |
| 41 | + vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0; |
| 42 | + vec4 wpos = projectionMatrixInv * clipVec; |
| 43 | + return wpos.xyz / wpos.w; |
| 44 | + } |
| 45 | + vec3 getWorldPos(float depth, vec2 coord) { |
| 46 | + if (logDepth) { |
| 47 | + return getWorldPosLog(vec3(coord, depth)); |
| 48 | + } |
| 49 | + float z = depth * 2.0 - 1.0; |
| 50 | + vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0); |
| 51 | + vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition; |
| 52 | + // Perspective division |
| 53 | + vec4 worldSpacePosition = viewSpacePosition; |
| 54 | + worldSpacePosition.xyz /= worldSpacePosition.w; |
| 55 | + return worldSpacePosition.xyz; |
| 56 | + } |
| 57 | + |
| 58 | + vec3 computeNormal(vec3 worldPos, vec2 vUv) { |
| 59 | + ivec2 p = ivec2(vUv * resolution); |
| 60 | + float c0 = texelFetch(sceneDepth, p, 0).x; |
| 61 | + float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x; |
| 62 | + float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x; |
| 63 | + float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x; |
| 64 | + float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x; |
| 65 | + float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x; |
| 66 | + float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x; |
| 67 | + float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x; |
| 68 | + float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x; |
| 69 | + |
| 70 | + float dl = abs((2.0 * l1 - l2) - c0); |
| 71 | + float dr = abs((2.0 * r1 - r2) - c0); |
| 72 | + float db = abs((2.0 * b1 - b2) - c0); |
| 73 | + float dt = abs((2.0 * t1 - t2) - c0); |
| 74 | + |
| 75 | + vec3 ce = getWorldPos(c0, vUv).xyz; |
| 76 | + |
| 77 | + vec3 dpdx = (dl < dr) ? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz |
| 78 | + : -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz; |
| 79 | + vec3 dpdy = (db < dt) ? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz |
| 80 | + : -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz; |
| 81 | + |
| 82 | + return normalize(cross(dpdx, dpdy)); |
| 83 | + } |
| 84 | + void main() { |
| 85 | + vec2 uv = vUv - vec2(0.5) / resolution; |
| 86 | + vec2 pixelSize = vec2(1.0) / resolution; |
| 87 | + vec2[] uvSamples = vec2[4]( |
| 88 | + uv, |
| 89 | + uv + vec2(pixelSize.x, 0.0), |
| 90 | + uv + vec2(0.0, pixelSize.y), |
| 91 | + uv + pixelSize |
| 92 | + ); |
| 93 | + float depth00 = texture2D(sceneDepth, uvSamples[0]).r; |
| 94 | + float depth10 = texture2D(sceneDepth, uvSamples[1]).r; |
| 95 | + float depth01 = texture2D(sceneDepth, uvSamples[2]).r; |
| 96 | + float depth11 = texture2D(sceneDepth, uvSamples[3]).r; |
| 97 | + float minDepth = min(min(depth00, depth10), min(depth01, depth11)); |
| 98 | + float maxDepth = max(max(depth00, depth10), max(depth01, depth11)); |
| 99 | + float targetDepth = minDepth; |
| 100 | + // Checkerboard pattern to avoid artifacts |
| 101 | + if (mod(gl_FragCoord.x + gl_FragCoord.y, 2.0) > 0.5) { |
| 102 | + targetDepth = maxDepth; |
| 103 | + } |
| 104 | + int chosenIndex = 0; |
| 105 | + float[] samples = float[4](depth00, depth10, depth01, depth11); |
| 106 | + for(int i = 0; i < 4; ++i) { |
| 107 | + if (samples[i] == targetDepth) { |
| 108 | + chosenIndex = i; |
| 109 | + break; |
| 110 | + } |
| 111 | + } |
| 112 | + gl_FragColor = vec4(samples[chosenIndex], 0.0, 0.0, 1.0); |
| 113 | + gNormal = vec4(computeNormal( |
| 114 | + getWorldPos(samples[chosenIndex], uvSamples[chosenIndex]), uvSamples[chosenIndex] |
| 115 | + ), 0.0); |
| 116 | + /* float[] samples = float[4](depth00, depth10, depth01, depth11); |
| 117 | + float c = 0.25 * (depth00 + depth10 + depth01 + depth11); |
| 118 | + float[] distances = float[4](depth00, depth10, depth01, depth11); |
| 119 | + float maxDistance = max(max(distances[0], distances[1]), max(distances[2], distances[3])); |
| 120 | +
|
| 121 | + int remaining[3]; |
| 122 | + int rejected[3]; |
| 123 | + int i, j, k; |
| 124 | +
|
| 125 | + for(i = 0, j = 0, k = 0; i < 4; ++i) { |
| 126 | + if (distances[i] < maxDistance) { |
| 127 | + remaining[j++] = i; |
| 128 | + } else { |
| 129 | + rejected[k++] = i; |
| 130 | + } |
| 131 | + } |
| 132 | + for(;j < 3;++j) { |
| 133 | + remaining[j] = rejected[--k]; |
| 134 | + } |
| 135 | + vec3 s = vec3( |
| 136 | + samples[remaining[0]], |
| 137 | + samples[remaining[1]], |
| 138 | + samples[remaining[2]] |
| 139 | + ); |
| 140 | + c = (s.x + s.y + s.z) / 3.0; |
| 141 | +
|
| 142 | + distances[0] = abs(c - s.x); |
| 143 | + distances[1] = abs(c - s.y); |
| 144 | + distances[2] = abs(c - s.z); |
| 145 | +
|
| 146 | + float minDistance = min(min(distances[0], distances[1]), distances[2]); |
| 147 | +
|
| 148 | + for(i = 0; i < 3; ++i) { |
| 149 | + if (distances[i] == minDistance) { |
| 150 | + break; |
| 151 | + } |
| 152 | + }*/ |
| 153 | + /* gl_FragColor = vec4(samples[remaining[i]], 0.0, 0.0, 0.0); |
| 154 | + gNormal = vec4(computeNormal( |
| 155 | + getWorldPos(samples[remaining[i]], uvSamples[remaining[i]]), uvSamples[remaining[i]] |
| 156 | + ), 0.0);*/ |
| 157 | + }`, |
| 158 | +} |
| 159 | + |
| 160 | +export { DepthDownSample } |
0 commit comments