@deck.gl/layers
Version:
deck.gl core layers
181 lines (152 loc) • 6.46 kB
text/typescript
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
export const shaderWGSL = /* wgsl */ `\
// TODO(ibgreen): Hack for Layer uniforms (move to new "color" module?)
struct LayerUniforms {
opacity: f32,
};
var<private> layer: LayerUniforms = LayerUniforms(1.0);
// @group(0) @binding(1) var<uniform> layer: LayerUniforms;
// ---------- Helper Structures & Functions ----------
// Placeholder filter functions.
fn deckgl_filter_size(offset: vec3<f32>, geometry: Geometry) -> vec3<f32> {
return offset;
}
fn deckgl_filter_gl_position(p: vec4<f32>, geometry: Geometry) -> vec4<f32> {
return p;
}
fn deckgl_filter_color(color: vec4<f32>, geometry: Geometry) -> vec4<f32> {
return color;
}
// Compute an extrusion offset given a line direction (in clipspace),
// an offset direction (-1 or 1), and a width in pixels.
// Assumes a uniform "project" with a viewportSize field is available.
fn getExtrusionOffset(line_clipspace: vec2<f32>, offset_direction: f32, width: f32) -> vec2<f32> {
// project.viewportSize should be provided as a uniform (not shown here)
let dir_screenspace = normalize(line_clipspace * project.viewportSize);
// Rotate by 90°: (x,y) becomes (-y,x)
let rotated = vec2<f32>(-dir_screenspace.y, dir_screenspace.x);
return rotated * offset_direction * width / 2.0;
}
// Splits the line between two points at a given x coordinate.
// Interpolates the y and z components.
fn splitLine(a: vec3<f32>, b: vec3<f32>, x: f32) -> vec3<f32> {
let t: f32 = (x - a.x) / (b.x - a.x);
return vec3<f32>(x, a.yz + t * (b.yz - a.yz));
}
// ---------- Uniforms & Global Structures ----------
// Uniforms for line, layer, and project are assumed to be defined elsewhere.
// For example:
//
// @group(0) @binding(0)
// var<uniform> line: LineUniform;
//
// struct LayerUniform {
// opacity: f32,
// };
// @group(0) @binding(1)
// var<uniform> layer: LayerUniform;
//
// struct ProjectUniform {
// viewportSize: vec2<f32>,
// };
// @group(0) @binding(2)
// var<uniform> project: ProjectUniform;
// ---------- Vertex Output Structure ----------
struct Varyings {
gl_Position: vec4<f32>,
vColor: vec4<f32>,
uv: vec2<f32>,
};
// ---------- Vertex Shader Entry Point ----------
fn vertexMain(
-> Varyings {
positions: vec3<f32>,
instanceSourcePositions: vec3<f32>,
instanceTargetPositions: vec3<f32>,
instanceSourcePositions64Low: vec3<f32>,
instanceTargetPositions64Low: vec3<f32>,
instanceColors: vec4<f32>,
instancePickingColors: vec3<f32>,
instanceWidths: f32
)var geometry: Geometry;
geometry.worldPosition = instanceSourcePositions;
geometry.worldPositionAlt = instanceTargetPositions;
var source_world: vec3<f32> = instanceSourcePositions;
var target_world: vec3<f32> = instanceTargetPositions;
var source_world_64low: vec3<f32> = instanceSourcePositions64Low;
var target_world_64low: vec3<f32> = instanceTargetPositions64Low;
// Apply shortest-path adjustments if needed.
if (line.useShortestPath > 0.5 || line.useShortestPath < -0.5) {
source_world.x = (source_world.x + 180.0 % 360.0) - 180.0;
target_world.x = (target_world.x + 180.0 % 360.0) - 180.0;
let deltaLng: f32 = target_world.x - source_world.x;
if (deltaLng * line.useShortestPath > 180.0) {
source_world.x = source_world.x + 360.0 * line.useShortestPath;
source_world = splitLine(source_world, target_world, 180.0 * line.useShortestPath);
source_world_64low = vec3<f32>(0.0, 0.0, 0.0);
} else if (deltaLng * line.useShortestPath < -180.0) {
target_world.x = target_world.x + 360.0 * line.useShortestPath;
target_world = splitLine(source_world, target_world, 180.0 * line.useShortestPath);
target_world_64low = vec3<f32>(0.0, 0.0, 0.0);
} else if (line.useShortestPath < 0.0) {
var abortOut: Varyings;
abortOut.gl_Position = vec4<f32>(0.0);
abortOut.vColor = vec4<f32>(0.0);
abortOut.uv = vec2<f32>(0.0);
return abortOut;
}
}
// Project Pos and target positions to clip space.
let sourceResult = project_position_to_clipspace_and_commonspace(source_world, source_world_64low, vec3<f32>(0.0));
let targetResult = project_position_to_clipspace_and_commonspace(target_world, target_world_64low, vec3<f32>(0.0));
let sourcePos: vec4<f32> = sourceResult.clipPosition;
let targetPos: vec4<f32> = targetResult.clipPosition;
let source_commonspace: vec4<f32> = sourceResult.commonPosition;
let target_commonspace: vec4<f32> = targetResult.commonPosition;
// Interpolate along the line segment.
let segmentIndex: f32 = positions.x;
let p: vec4<f32> = sourcePos + segmentIndex * (targetPos - sourcePos);
geometry.position = source_commonspace + segmentIndex * (target_commonspace - source_commonspace);
let uv: vec2<f32> = positions.xy;
geometry.uv = uv;
geometry.pickingColor = instancePickingColors;
// Determine width in pixels.
let widthPixels: f32 = clamp(
project_unit_size_to_pixel(instanceWidths * line.widthScale, line.widthUnits),
line.widthMinPixels, line.widthMaxPixels
);
// Compute extrusion offset.
let extrusion: vec2<f32> = getExtrusionOffset(targetPos.xy - sourcePos.xy, positions.y, widthPixels);
let offset: vec3<f32> = vec3<f32>(extrusion, 0.0);
// Apply deck.gl filter functions.
let filteredOffset = deckgl_filter_size(offset, geometry);
let filteredP = deckgl_filter_gl_position(p, geometry);
let clipOffset: vec2<f32> = project_pixel_size_to_clipspace(filteredOffset.xy);
let finalPosition: vec4<f32> = filteredP + vec4<f32>(clipOffset, 0.0, 0.0);
// Compute color.
var vColor: vec4<f32> = vec4<f32>(instanceColors.rgb, instanceColors.a * layer.opacity);
// vColor = deckgl_filter_color(vColor, geometry);
var output: Varyings;
output.gl_Position = finalPosition;
output.vColor = vColor;
output.uv = uv;
return output;
}
fn fragmentMain(
-> vColor: vec4<f32>,
uv: vec2<f32>
) vec4<f32> {
// Create and initialize geometry with the provided uv.
var geometry: Geometry;
geometry.uv = uv;
// Start with the input color.
var fragColor: vec4<f32> = vColor;
// Apply the deck.gl filter to the color.
fragColor = deckgl_filter_color(fragColor, geometry);
return fragColor;
}
`;