@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
119 lines (98 loc) • 5.21 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */
import{ReadDepth as e}from"../output/ReadDepth.glsl.js";import{Float2BindUniform as t}from"../../shaderModules/Float2BindUniform.js";import{FloatBindUniform as o}from"../../shaderModules/FloatBindUniform.js";import{glsl as r}from"../../shaderModules/glsl.js";import{Matrix4BindUniform as i}from"../../shaderModules/Matrix4BindUniform.js";import{Texture2DBindUniform as a}from"../../shaderModules/Texture2DBindUniform.js";function d(d,n){if(!n.screenSpaceReflections)return;const c=d.fragment;c.include(e),c.uniforms.add(new t("nearFar",e=>e.camera.nearFar),new a("depthMap",e=>e.depth?.attachment),new i("proj",e=>e.camera.projectionMatrix),new o("invResolutionHeight",e=>1/e.camera.height),new i("reprojectionMatrix",e=>e.ssr.reprojectionMatrix)).code.add(r`
vec2 reprojectionCoordinate(vec3 projectionCoordinate)
{
vec4 zw = proj * vec4(0.0, 0.0, -projectionCoordinate.z, 1.0);
vec4 reprojectedCoord = reprojectionMatrix * vec4(zw.w * (projectionCoordinate.xy * 2.0 - 1.0), zw.z, zw.w);
reprojectedCoord.xy /= reprojectedCoord.w;
return reprojectedCoord.xy * 0.5 + 0.5;
}
const int maxSteps = ${n.highStepCount?"150":"75"};
vec4 applyProjectionMat(mat4 projectionMat, vec3 x)
{
vec4 projectedCoord = projectionMat * vec4(x, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy*0.5 + 0.5;
return projectedCoord;
}
vec3 screenSpaceIntersection(vec3 dir, vec3 startPosition, vec3 viewDir, vec3 normal)
{
vec3 viewPos = startPosition;
vec3 viewPosEnd = startPosition;
// Project the start position to the screen
vec4 projectedCoordStart = applyProjectionMat(proj, viewPos);
vec3 Q0 = viewPos / projectedCoordStart.w; // homogeneous camera space
float k0 = 1.0/ projectedCoordStart.w;
// advance the position in the direction of the reflection
viewPos += dir;
vec4 projectedCoordVanishingPoint = applyProjectionMat(proj, dir);
// Project the advanced position to the screen
vec4 projectedCoordEnd = applyProjectionMat(proj, viewPos);
vec3 Q1 = viewPos / projectedCoordEnd.w; // homogeneous camera space
float k1 = 1.0/ projectedCoordEnd.w;
// calculate the reflection direction in the screen space
vec2 projectedCoordDir = (projectedCoordEnd.xy - projectedCoordStart.xy);
vec2 projectedCoordDistVanishingPoint = (projectedCoordVanishingPoint.xy - projectedCoordStart.xy);
float yMod = min(abs(projectedCoordDistVanishingPoint.y), 1.0);
float projectedCoordDirLength = length(projectedCoordDir);
float maxSt = float(maxSteps);
// normalize the projection direction depending on maximum steps
// this determines how blocky the reflection looks
vec2 dP = yMod * (projectedCoordDir)/(maxSt * projectedCoordDirLength);
// Normalize the homogeneous camera space coordinates
vec3 dQ = yMod * (Q1 - Q0)/(maxSt * projectedCoordDirLength);
float dk = yMod * (k1 - k0)/(maxSt * projectedCoordDirLength);
// initialize the variables for ray marching
vec2 P = projectedCoordStart.xy;
vec3 Q = Q0;
float k = k0;
float rayStartZ = -startPosition.z; // estimated ray start depth value
float rayEndZ = -startPosition.z; // estimated ray end depth value
float prevEstimateZ = -startPosition.z;
float rayDiffZ = 0.0;
float dDepth;
float depth;
float rayDiffZOld = 0.0;
// early outs
if (dot(normal, dir) < 0.0 || dot(-viewDir, normal) < 0.0)
return vec3(P, 0.0);
float dDepthBefore = 0.0;
for(int i = 0; i < maxSteps-1; i++)
{
depth = -linearDepthFromTexture(depthMap, P); // get linear depth from the depth buffer
// estimate depth of the marching ray
rayStartZ = prevEstimateZ;
dDepth = -rayStartZ - depth;
rayEndZ = (dQ.z * 0.5 + Q.z)/ ((dk * 0.5 + k));
rayDiffZ = rayEndZ- rayStartZ;
prevEstimateZ = rayEndZ;
if(-rayEndZ > nearFar[1] || -rayEndZ < nearFar[0] || P.y < 0.0 || P.y > 1.0 )
{
return vec3(P, 0.);
}
// If we detect a hit - return the intersection point, two conditions:
// - dDepth > 0.0 - sampled point depth is in front of estimated depth
// - if difference between dDepth and rayDiffZOld is not too large
// - if difference between dDepth and 0.025/abs(k) is not too large
// - if the sampled depth is not behind far plane or in front of near plane
if((dDepth) < 0.025/abs(k) + abs(rayDiffZ) && dDepth > 0.0 && depth > nearFar[0] && depth < nearFar[1] && abs(P.y - projectedCoordStart.y) > invResolutionHeight)
{
float weight = dDepth / (dDepth - dDepthBefore);
vec2 Pf = mix(P - dP, P, 1.0 - weight);
if (abs(Pf.y - projectedCoordStart.y) > invResolutionHeight) {
return vec3(Pf, depth);
}
else {
return vec3(P, depth);
}
}
// continue with ray marching
P = clamp(P + dP, vec2(0.0), vec2(0.999));
Q.z += dQ.z;
k += dk;
rayDiffZOld = rayDiffZ;
dDepthBefore = dDepth;
}
return vec3(P, 0.0);
}
`)}export{d as ScreenSpaceReflections};