@tomorrowevening/hermes
Version:
An extendable set of Web Tools controlled via a separate window for non-intereference with content.
138 lines (118 loc) • 4.86 kB
JavaScript
import { ShaderMaterial as i, DoubleSide as t, GLSL3 as a, Color as o } from "three";
const r = `out vec3 worldPosition;
uniform float uDistance;
void main() {
// Scale the plane by the drawing distance
worldPosition = position.xzy * uDistance;
worldPosition.xz += cameraPosition.xz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(worldPosition, 1.0);
}`, n = `out vec4 fragColor;
in vec3 worldPosition;
uniform float uDivisions;
uniform float uScale;
uniform vec3 uColor;
uniform float uDistance;
uniform float uGridOpacity;
uniform float uSubgridOpacity;
float getGrid(float gapSize) {
vec2 worldPositionByDivision = worldPosition.xz / gapSize;
// Inverted, 0 where line, >1 where there's no line
// We use the worldPosition (which in this case we use similarly to UVs) differential to control the anti-aliasing
// We need to do the -0.5)-0.5 trick because the result fades out from 0 to 1, and we want both
// worldPositionByDivision == 0.3 and worldPositionByDivision == 0.7 to result in the same fade, i.e. 0.3,
// otherwise only one side of the line will be anti-aliased
vec2 grid = abs(fract(worldPositionByDivision-0.5)-0.5) / fwidth(worldPositionByDivision) / 2.0;
float gridLine = min(grid.x, grid.y);
// Uninvert and clamp
return 1.0 - min(gridLine, 1.0);
}
void main() {
float cameraDistanceToGridPlane = max(200.0, distance(cameraPosition.y, worldPosition.y));
float cameraDistanceToFragmentOnGridPlane = distance(cameraPosition.xyz, worldPosition.xyz);
// The size of the grid and subgrid are powers of each other and they are determined based on camera distance.
// The current grid will become the next subgrid when it becomes too small, and its next power becomes the new grid.
float subGridPower = pow(uDivisions, floor(log(cameraDistanceToGridPlane) / log(uDivisions)));
float gridPower = subGridPower * uDivisions;
// If we want to fade both the grid and its subgrid, we need to displays 3 different opacities, with the next grid being the third
float nextGridPower = gridPower * uDivisions;
// 1 where grid, 0 where no grid
float subgrid = getGrid(subGridPower * uScale);
float grid = getGrid(gridPower * uScale);
float nextGrid = getGrid(nextGridPower * uScale);
// Where we are between the introduction of the current grid power and when we switch to the next grid power
float stepPercentage = (cameraDistanceToGridPlane - subGridPower)/(gridPower - subGridPower);
// The last x percentage of the current step over which we want to fade
float fadeRange = 0.3;
// We calculate the fade percentage from the step percentage and the fade range
float fadePercentage = max(stepPercentage - 1.0 + fadeRange, 0.0) / fadeRange;
// Set base opacity based on how close we are to the drawing distance, with a cubic falloff
float baseOpacity = subgrid * pow(1.0 - min(cameraDistanceToFragmentOnGridPlane / uDistance, 1.0), 3.0);
// Shade the subgrid
fragColor = vec4(uColor.rgb, (baseOpacity - fadePercentage) * uSubgridOpacity);
// Somewhat arbitrary additional fade coefficient to counter anti-aliasing popping when switching between grid powers
float fadeCoefficient = 0.5;
// Shade the grid
fragColor.a = mix(fragColor.a, baseOpacity * uGridOpacity - fadePercentage * (uGridOpacity - uSubgridOpacity) * fadeCoefficient, grid);
// Shade the next grid
fragColor.a = mix(fragColor.a, baseOpacity * uGridOpacity, nextGrid);
if (fragColor.a <= minAlpha) discard;
}`;
class l extends i {
constructor(e) {
super({
extensions: {
// @ts-ignore
derivatives: !0
},
uniforms: {
uScale: {
value: e?.scale !== void 0 ? e?.scale : 0.1
},
uDivisions: {
value: e?.divisions !== void 0 ? e?.divisions : 10
},
uColor: {
value: e?.color !== void 0 ? e?.color : new o(16777215)
},
uDistance: {
value: e?.distance !== void 0 ? e?.distance : 1e4
},
uSubgridOpacity: {
value: e?.subgridOpacity !== void 0 ? e?.subgridOpacity : 0.15
},
uGridOpacity: {
value: e?.gridOpacity !== void 0 ? e?.gridOpacity : 0.25
}
},
glslVersion: a,
side: t,
transparent: !0,
name: "InfiniteGrid",
vertexShader: r,
fragmentShader: n
});
}
// Getters / Setters
get color() {
return this.uniforms.uColor.value;
}
set color(e) {
this.uniforms.uColor.value = e;
}
get gridOpacity() {
return this.uniforms.uGridOpacity.value;
}
set gridOpacity(e) {
this.uniforms.uGridOpacity.value = e;
}
get subgridOpacity() {
return this.uniforms.uSubgridOpacity.value;
}
set subgridOpacity(e) {
this.uniforms.uSubgridOpacity.value = e;
}
}
export {
l as default
};